mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-28 09:03:52 +01:00 
			
		
		
		
	clk: exynos: Add Samsung clock framework
Heavily based on Linux kernel Samsung clock framework, with some changes to accommodate the differences in U-Boot CCF implementation. It's also quite minimal as compared to the Linux version. Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org> Reviewed-by: Chanho Park <chanho61.park@samsung.com> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
This commit is contained in:
		
				
					committed by
					
						 Minkyu Kang
						Minkyu Kang
					
				
			
			
				
	
			
			
			
						parent
						
							0caae9fdc2
						
					
				
				
					commit
					ff3e8b8c6c
				
			| @@ -1,6 +1,11 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0+ | ||||
| # | ||||
| # Copyright (C) 2016 Samsung Electronics | ||||
| # Thomas Abraham <thomas.ab@samsung.com> | ||||
| # Copyright (C) 2023 Linaro Ltd. | ||||
| # | ||||
| # Authors: | ||||
| #   Thomas Abraham <thomas.ab@samsung.com> | ||||
| #   Sam Protsenko <semen.protsenko@linaro.org> | ||||
|  | ||||
| obj-$(CONFIG_CLK_EXYNOS7420)	+= clk-exynos7420.o | ||||
| obj-$(CONFIG_$(SPL_TPL_)CLK_CCF)	+= clk.o clk-pll.o | ||||
| obj-$(CONFIG_CLK_EXYNOS7420)		+= clk-exynos7420.o | ||||
|   | ||||
							
								
								
									
										167
									
								
								drivers/clk/exynos/clk-pll.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								drivers/clk/exynos/clk-pll.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2016 Samsung Electronics | ||||
|  * Copyright (C) 2023 Linaro Ltd. | ||||
|  * | ||||
|  * Authors: | ||||
|  *   Thomas Abraham <thomas.ab@samsung.com> | ||||
|  *   Sam Protsenko <semen.protsenko@linaro.org> | ||||
|  * | ||||
|  * This file contains the utility functions to register the pll clocks. | ||||
|  */ | ||||
|  | ||||
| #include <asm/io.h> | ||||
| #include <div64.h> | ||||
| #include <malloc.h> | ||||
| #include <clk-uclass.h> | ||||
| #include <dm/device.h> | ||||
| #include <clk.h> | ||||
| #include "clk.h" | ||||
|  | ||||
| #define UBOOT_DM_CLK_SAMSUNG_PLL0822X	"samsung_clk_pll0822x" | ||||
| #define UBOOT_DM_CLK_SAMSUNG_PLL0831X	"samsung_clk_pll0831x" | ||||
|  | ||||
| struct samsung_clk_pll { | ||||
| 	struct clk		clk; | ||||
| 	void __iomem		*con_reg; | ||||
| 	enum samsung_pll_type	type; | ||||
| }; | ||||
|  | ||||
| #define to_clk_pll(_clk) container_of(_clk, struct samsung_clk_pll, clk) | ||||
|  | ||||
| /* | ||||
|  * PLL0822x Clock Type | ||||
|  */ | ||||
|  | ||||
| #define PLL0822X_MDIV_MASK		0x3ff | ||||
| #define PLL0822X_PDIV_MASK		0x3f | ||||
| #define PLL0822X_SDIV_MASK		0x7 | ||||
| #define PLL0822X_MDIV_SHIFT		16 | ||||
| #define PLL0822X_PDIV_SHIFT		8 | ||||
| #define PLL0822X_SDIV_SHIFT		0 | ||||
|  | ||||
| static unsigned long samsung_pll0822x_recalc_rate(struct clk *clk) | ||||
| { | ||||
| 	struct samsung_clk_pll *pll = to_clk_pll(clk); | ||||
| 	u32 mdiv, pdiv, sdiv, pll_con3; | ||||
| 	u64 fvco = clk_get_parent_rate(clk); | ||||
|  | ||||
| 	pll_con3 = readl_relaxed(pll->con_reg); | ||||
| 	mdiv = (pll_con3 >> PLL0822X_MDIV_SHIFT) & PLL0822X_MDIV_MASK; | ||||
| 	pdiv = (pll_con3 >> PLL0822X_PDIV_SHIFT) & PLL0822X_PDIV_MASK; | ||||
| 	sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK; | ||||
|  | ||||
| 	fvco *= mdiv; | ||||
| 	do_div(fvco, (pdiv << sdiv)); | ||||
| 	return (unsigned long)fvco; | ||||
| } | ||||
|  | ||||
| static const struct clk_ops samsung_pll0822x_clk_min_ops = { | ||||
| 	.get_rate = samsung_pll0822x_recalc_rate, | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * PLL0831x Clock Type | ||||
|  */ | ||||
|  | ||||
| #define PLL0831X_KDIV_MASK		0xffff | ||||
| #define PLL0831X_MDIV_MASK		0x1ff | ||||
| #define PLL0831X_PDIV_MASK		0x3f | ||||
| #define PLL0831X_SDIV_MASK		0x7 | ||||
| #define PLL0831X_MDIV_SHIFT		16 | ||||
| #define PLL0831X_PDIV_SHIFT		8 | ||||
| #define PLL0831X_SDIV_SHIFT		0 | ||||
| #define PLL0831X_KDIV_SHIFT		0 | ||||
|  | ||||
| static unsigned long samsung_pll0831x_recalc_rate(struct clk *clk) | ||||
| { | ||||
| 	struct samsung_clk_pll *pll = to_clk_pll(clk); | ||||
| 	u32 mdiv, pdiv, sdiv, pll_con3, pll_con5; | ||||
| 	s16 kdiv; | ||||
| 	u64 fvco = clk_get_parent_rate(clk); | ||||
|  | ||||
| 	pll_con3 = readl_relaxed(pll->con_reg); | ||||
| 	pll_con5 = readl_relaxed(pll->con_reg + 8); | ||||
| 	mdiv = (pll_con3 >> PLL0831X_MDIV_SHIFT) & PLL0831X_MDIV_MASK; | ||||
| 	pdiv = (pll_con3 >> PLL0831X_PDIV_SHIFT) & PLL0831X_PDIV_MASK; | ||||
| 	sdiv = (pll_con3 >> PLL0831X_SDIV_SHIFT) & PLL0831X_SDIV_MASK; | ||||
| 	kdiv = (s16)((pll_con5 >> PLL0831X_KDIV_SHIFT) & PLL0831X_KDIV_MASK); | ||||
|  | ||||
| 	fvco *= (mdiv << 16) + kdiv; | ||||
| 	do_div(fvco, (pdiv << sdiv)); | ||||
| 	fvco >>= 16; | ||||
|  | ||||
| 	return (unsigned long)fvco; | ||||
| } | ||||
|  | ||||
| static const struct clk_ops samsung_pll0831x_clk_min_ops = { | ||||
| 	.get_rate = samsung_pll0831x_recalc_rate, | ||||
| }; | ||||
|  | ||||
| static struct clk *_samsung_clk_register_pll(void __iomem *base, | ||||
| 					const struct samsung_pll_clock *pll_clk) | ||||
| { | ||||
| 	struct samsung_clk_pll *pll; | ||||
| 	struct clk *clk; | ||||
| 	const char *drv_name; | ||||
| 	int ret; | ||||
|  | ||||
| 	pll = kzalloc(sizeof(*pll), GFP_KERNEL); | ||||
| 	if (!pll) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
|  | ||||
| 	pll->con_reg = base + pll_clk->con_offset; | ||||
| 	pll->type = pll_clk->type; | ||||
| 	clk = &pll->clk; | ||||
| 	clk->flags = pll_clk->flags; | ||||
|  | ||||
| 	switch (pll_clk->type) { | ||||
| 	case pll_0822x: | ||||
| 		drv_name = UBOOT_DM_CLK_SAMSUNG_PLL0822X; | ||||
| 		break; | ||||
| 	case pll_0831x: | ||||
| 		drv_name = UBOOT_DM_CLK_SAMSUNG_PLL0831X; | ||||
| 		break; | ||||
| 	default: | ||||
| 		kfree(pll); | ||||
| 		return ERR_PTR(-ENODEV); | ||||
| 	} | ||||
|  | ||||
| 	ret = clk_register(clk, drv_name, pll_clk->name, pll_clk->parent_name); | ||||
| 	if (ret) { | ||||
| 		kfree(pll); | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
|  | ||||
| 	return clk; | ||||
| } | ||||
|  | ||||
| void samsung_clk_register_pll(void __iomem *base, | ||||
| 			      const struct samsung_pll_clock *clk_list, | ||||
| 			      unsigned int nr_clk) | ||||
| { | ||||
| 	unsigned int cnt; | ||||
|  | ||||
| 	for (cnt = 0; cnt < nr_clk; cnt++) { | ||||
| 		struct clk *clk; | ||||
| 		const struct samsung_pll_clock *pll_clk; | ||||
|  | ||||
| 		pll_clk = &clk_list[cnt]; | ||||
| 		clk = _samsung_clk_register_pll(base, pll_clk); | ||||
| 		clk_dm(pll_clk->id, clk); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| U_BOOT_DRIVER(samsung_pll0822x_clk) = { | ||||
| 	.name	= UBOOT_DM_CLK_SAMSUNG_PLL0822X, | ||||
| 	.id	= UCLASS_CLK, | ||||
| 	.ops	= &samsung_pll0822x_clk_min_ops, | ||||
| 	.flags	= DM_FLAG_PRE_RELOC, | ||||
| }; | ||||
|  | ||||
| U_BOOT_DRIVER(samsung_pll0831x_clk) = { | ||||
| 	.name	= UBOOT_DM_CLK_SAMSUNG_PLL0831X, | ||||
| 	.id	= UCLASS_CLK, | ||||
| 	.ops	= &samsung_pll0831x_clk_min_ops, | ||||
| 	.flags	= DM_FLAG_PRE_RELOC, | ||||
| }; | ||||
							
								
								
									
										23
									
								
								drivers/clk/exynos/clk-pll.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								drivers/clk/exynos/clk-pll.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
| /* | ||||
|  * Copyright (C) 2016 Samsung Electronics | ||||
|  * Copyright (C) 2023 Linaro Ltd. | ||||
|  * | ||||
|  * Authors: | ||||
|  *   Thomas Abraham <thomas.ab@samsung.com> | ||||
|  *   Sam Protsenko <semen.protsenko@linaro.org> | ||||
|  * | ||||
|  * Common Clock Framework support for all PLL's in Samsung platforms. | ||||
|  */ | ||||
|  | ||||
| #ifndef __EXYNOS_CLK_PLL_H | ||||
| #define __EXYNOS_CLK_PLL_H | ||||
|  | ||||
| #include <linux/clk-provider.h> | ||||
|  | ||||
| enum samsung_pll_type { | ||||
| 	pll_0822x, | ||||
| 	pll_0831x, | ||||
| }; | ||||
|  | ||||
| #endif /* __EXYNOS_CLK_PLL_H */ | ||||
							
								
								
									
										121
									
								
								drivers/clk/exynos/clk.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								drivers/clk/exynos/clk.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only | ||||
| /* | ||||
|  * Copyright (C) 2023 Linaro Ltd. | ||||
|  * Sam Protsenko <semen.protsenko@linaro.org> | ||||
|  * | ||||
|  * This file includes utility functions to register clocks to common | ||||
|  * clock framework for Samsung platforms. | ||||
|  */ | ||||
|  | ||||
| #include <dm.h> | ||||
| #include "clk.h" | ||||
|  | ||||
| void samsung_clk_register_mux(void __iomem *base, | ||||
| 			      const struct samsung_mux_clock *clk_list, | ||||
| 			      unsigned int nr_clk) | ||||
| { | ||||
| 	unsigned int cnt; | ||||
|  | ||||
| 	for (cnt = 0; cnt < nr_clk; cnt++) { | ||||
| 		struct clk *clk; | ||||
| 		const struct samsung_mux_clock *m; | ||||
|  | ||||
| 		m = &clk_list[cnt]; | ||||
| 		clk = clk_register_mux(NULL, m->name, m->parent_names, | ||||
| 			m->num_parents, m->flags, base + m->offset, m->shift, | ||||
| 			m->width, m->mux_flags); | ||||
| 		clk_dm(m->id, clk); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void samsung_clk_register_div(void __iomem *base, | ||||
| 			      const struct samsung_div_clock *clk_list, | ||||
| 			      unsigned int nr_clk) | ||||
| { | ||||
| 	unsigned int cnt; | ||||
|  | ||||
| 	for (cnt = 0; cnt < nr_clk; cnt++) { | ||||
| 		struct clk *clk; | ||||
| 		const struct samsung_div_clock *d; | ||||
|  | ||||
| 		d = &clk_list[cnt]; | ||||
| 		clk = clk_register_divider(NULL, d->name, d->parent_name, | ||||
| 			d->flags, base + d->offset, d->shift, | ||||
| 			d->width, d->div_flags); | ||||
| 		clk_dm(d->id, clk); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void samsung_clk_register_gate(void __iomem *base, | ||||
| 			       const struct samsung_gate_clock *clk_list, | ||||
| 			       unsigned int nr_clk) | ||||
| { | ||||
| 	unsigned int cnt; | ||||
|  | ||||
| 	for (cnt = 0; cnt < nr_clk; cnt++) { | ||||
| 		struct clk *clk; | ||||
| 		const struct samsung_gate_clock *g; | ||||
|  | ||||
| 		g = &clk_list[cnt]; | ||||
| 		clk = clk_register_gate(NULL, g->name, g->parent_name, | ||||
| 			g->flags, base + g->offset, g->bit_idx, | ||||
| 			g->gate_flags, NULL); | ||||
| 		clk_dm(g->id, clk); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| typedef void (*samsung_clk_register_fn)(void __iomem *base, | ||||
| 					const void *clk_list, | ||||
| 					unsigned int nr_clk); | ||||
|  | ||||
| static const samsung_clk_register_fn samsung_clk_register_fns[] = { | ||||
| 	[S_CLK_MUX]	= (samsung_clk_register_fn)samsung_clk_register_mux, | ||||
| 	[S_CLK_DIV]	= (samsung_clk_register_fn)samsung_clk_register_div, | ||||
| 	[S_CLK_GATE]	= (samsung_clk_register_fn)samsung_clk_register_gate, | ||||
| 	[S_CLK_PLL]	= (samsung_clk_register_fn)samsung_clk_register_pll, | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * samsung_cmu_register_clocks() - Register provided clock groups | ||||
|  * @base: Base address of CMU registers | ||||
|  * @clk_groups: list of clock groups | ||||
|  * @nr_groups: count of clock groups in @clk_groups | ||||
|  * | ||||
|  * Having the array of clock groups @clk_groups makes it possible to keep a | ||||
|  * correct clocks registration order. | ||||
|  */ | ||||
| void samsung_cmu_register_clocks(void __iomem *base, | ||||
| 				 const struct samsung_clk_group *clk_groups, | ||||
| 				 unsigned int nr_groups) | ||||
| { | ||||
| 	unsigned int i; | ||||
|  | ||||
| 	for (i = 0; i < nr_groups; i++) { | ||||
| 		const struct samsung_clk_group *g = &clk_groups[i]; | ||||
|  | ||||
| 		samsung_clk_register_fns[g->type](base, g->clk_list, g->nr_clk); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * samsung_cmu_register_one - Register all CMU clocks | ||||
|  * @dev: CMU device | ||||
|  * @clk_groups: list of CMU clock groups | ||||
|  * @nr_groups: count of CMU clock groups in @clk_groups | ||||
|  * | ||||
|  * Return: 0 on success or negative value on error. | ||||
|  */ | ||||
| int samsung_cmu_register_one(struct udevice *dev, | ||||
| 			     const struct samsung_clk_group *clk_groups, | ||||
| 			     unsigned int nr_groups) | ||||
| { | ||||
| 	void __iomem *base; | ||||
|  | ||||
| 	base = dev_read_addr_ptr(dev); | ||||
| 	if (!base) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	samsung_cmu_register_clocks(base, clk_groups, nr_groups); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										228
									
								
								drivers/clk/exynos/clk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								drivers/clk/exynos/clk.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /* | ||||
|  * Copyright (c) 2023 Linaro Ltd. | ||||
|  * Sam Protsenko <semen.protsenko@linaro.org> | ||||
|  * | ||||
|  * Common Clock Framework support for all Samsung platforms. | ||||
|  */ | ||||
|  | ||||
| #ifndef __EXYNOS_CLK_H | ||||
| #define __EXYNOS_CLK_H | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <linux/clk-provider.h> | ||||
| #include "clk-pll.h" | ||||
|  | ||||
| /** | ||||
|  * struct samsung_mux_clock - information about mux clock | ||||
|  * @id: platform specific id of the clock | ||||
|  * @name: name of this mux clock | ||||
|  * @parent_names: array of pointer to parent clock names | ||||
|  * @num_parents: number of parents listed in @parent_names | ||||
|  * @flags: optional flags for basic clock | ||||
|  * @offset: offset of the register for configuring the mux | ||||
|  * @shift: starting bit location of the mux control bit-field in @reg | ||||
|  * @width: width of the mux control bit-field in @reg | ||||
|  * @mux_flags: flags for mux-type clock | ||||
|  */ | ||||
| struct samsung_mux_clock { | ||||
| 	unsigned int		id; | ||||
| 	const char		*name; | ||||
| 	const char		* const *parent_names; | ||||
| 	u8			num_parents; | ||||
| 	unsigned long		flags; | ||||
| 	unsigned long		offset; | ||||
| 	u8			shift; | ||||
| 	u8			width; | ||||
| 	u8			mux_flags; | ||||
| }; | ||||
|  | ||||
| #define PNAME(x) static const char * const x[] | ||||
|  | ||||
| #define __MUX(_id, cname, pnames, o, s, w, f, mf)			\ | ||||
| 	{								\ | ||||
| 		.id		= _id,					\ | ||||
| 		.name		= cname,				\ | ||||
| 		.parent_names	= pnames,				\ | ||||
| 		.num_parents	= ARRAY_SIZE(pnames),			\ | ||||
| 		.flags		= (f) | CLK_SET_RATE_NO_REPARENT,	\ | ||||
| 		.offset		= o,					\ | ||||
| 		.shift		= s,					\ | ||||
| 		.width		= w,					\ | ||||
| 		.mux_flags	= mf,					\ | ||||
| 	} | ||||
|  | ||||
| #define MUX(_id, cname, pnames, o, s, w)				\ | ||||
| 	__MUX(_id, cname, pnames, o, s, w, 0, 0) | ||||
|  | ||||
| #define MUX_F(_id, cname, pnames, o, s, w, f, mf)			\ | ||||
| 	__MUX(_id, cname, pnames, o, s, w, f, mf) | ||||
|  | ||||
| /** | ||||
|  * struct samsung_div_clock - information about div clock | ||||
|  * @id: platform specific id of the clock | ||||
|  * @name: name of this div clock | ||||
|  * @parent_name: name of the parent clock | ||||
|  * @flags: optional flags for basic clock | ||||
|  * @offset: offset of the register for configuring the div | ||||
|  * @shift: starting bit location of the div control bit-field in @reg | ||||
|  * @width: width of the bitfield | ||||
|  * @div_flags: flags for div-type clock | ||||
|  */ | ||||
| struct samsung_div_clock { | ||||
| 	unsigned int		id; | ||||
| 	const char		*name; | ||||
| 	const char		*parent_name; | ||||
| 	unsigned long		flags; | ||||
| 	unsigned long		offset; | ||||
| 	u8			shift; | ||||
| 	u8			width; | ||||
| 	u8			div_flags; | ||||
| }; | ||||
|  | ||||
| #define __DIV(_id, cname, pname, o, s, w, f, df)	\ | ||||
| 	{						\ | ||||
| 		.id		= _id,			\ | ||||
| 		.name		= cname,		\ | ||||
| 		.parent_name	= pname,		\ | ||||
| 		.flags		= f,			\ | ||||
| 		.offset		= o,			\ | ||||
| 		.shift		= s,			\ | ||||
| 		.width		= w,			\ | ||||
| 		.div_flags	= df,			\ | ||||
| 	} | ||||
|  | ||||
| #define DIV(_id, cname, pname, o, s, w)			\ | ||||
| 	__DIV(_id, cname, pname, o, s, w, 0, 0) | ||||
|  | ||||
| #define DIV_F(_id, cname, pname, o, s, w, f, df)	\ | ||||
| 	__DIV(_id, cname, pname, o, s, w, f, df) | ||||
|  | ||||
| /** | ||||
|  * struct samsung_gate_clock - information about gate clock | ||||
|  * @id: platform specific id of the clock | ||||
|  * @name: name of this gate clock | ||||
|  * @parent_name: name of the parent clock | ||||
|  * @flags: optional flags for basic clock | ||||
|  * @offset: offset of the register for configuring the gate | ||||
|  * @bit_idx: bit index of the gate control bit-field in @reg | ||||
|  * @gate_flags: flags for gate-type clock | ||||
|  */ | ||||
| struct samsung_gate_clock { | ||||
| 	unsigned int		id; | ||||
| 	const char		*name; | ||||
| 	const char		*parent_name; | ||||
| 	unsigned long		flags; | ||||
| 	unsigned long		offset; | ||||
| 	u8			bit_idx; | ||||
| 	u8			gate_flags; | ||||
| }; | ||||
|  | ||||
| #define __GATE(_id, cname, pname, o, b, f, gf)			\ | ||||
| 	{							\ | ||||
| 		.id		= _id,				\ | ||||
| 		.name		= cname,			\ | ||||
| 		.parent_name	= pname,			\ | ||||
| 		.flags		= f,				\ | ||||
| 		.offset		= o,				\ | ||||
| 		.bit_idx	= b,				\ | ||||
| 		.gate_flags	= gf,				\ | ||||
| 	} | ||||
|  | ||||
| #define GATE(_id, cname, pname, o, b, f, gf)			\ | ||||
| 	__GATE(_id, cname, pname, o, b, f, gf) | ||||
|  | ||||
| /** | ||||
|  * struct samsung_pll_clock - information about pll clock | ||||
|  * @id: platform specific id of the clock | ||||
|  * @name: name of this pll clock | ||||
|  * @parent_name: name of the parent clock | ||||
|  * @flags: optional flags for basic clock | ||||
|  * @con_offset: offset of the register for configuring the PLL | ||||
|  * @type: type of PLL to be registered | ||||
|  */ | ||||
| struct samsung_pll_clock { | ||||
| 	unsigned int		id; | ||||
| 	const char		*name; | ||||
| 	const char		*parent_name; | ||||
| 	unsigned long		flags; | ||||
| 	int			con_offset; | ||||
| 	enum samsung_pll_type	type; | ||||
| }; | ||||
|  | ||||
| #define PLL(_typ, _id, _name, _pname, _con)		\ | ||||
| 	{						\ | ||||
| 		.id		= _id,			\ | ||||
| 		.name		= _name,		\ | ||||
| 		.parent_name	= _pname,		\ | ||||
| 		.flags		= CLK_GET_RATE_NOCACHE,	\ | ||||
| 		.con_offset	= _con,			\ | ||||
| 		.type		= _typ,			\ | ||||
| 	} | ||||
|  | ||||
| enum samsung_clock_type { | ||||
| 	S_CLK_MUX, | ||||
| 	S_CLK_DIV, | ||||
| 	S_CLK_GATE, | ||||
| 	S_CLK_PLL, | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * struct samsung_clock_group - contains a list of clocks of one type | ||||
|  * @type: type of clocks this structure contains | ||||
|  * @clk_list: list of clocks | ||||
|  * @nr_clk: count of clocks in @clk_list | ||||
|  */ | ||||
| struct samsung_clk_group { | ||||
| 	enum samsung_clock_type type; | ||||
| 	const void *clk_list; | ||||
| 	unsigned int nr_clk; | ||||
| }; | ||||
|  | ||||
| void samsung_clk_register_mux(void __iomem *base, | ||||
| 			      const struct samsung_mux_clock *clk_list, | ||||
| 			      unsigned int nr_clk); | ||||
| void samsung_clk_register_div(void __iomem *base, | ||||
| 			      const struct samsung_div_clock *clk_list, | ||||
| 			      unsigned int nr_clk); | ||||
| void samsung_clk_register_gate(void __iomem *base, | ||||
| 			       const struct samsung_gate_clock *clk_list, | ||||
| 			       unsigned int nr_clk); | ||||
| void samsung_clk_register_pll(void __iomem *base, | ||||
| 			      const struct samsung_pll_clock *clk_list, | ||||
| 			      unsigned int nr_clk); | ||||
|  | ||||
| void samsung_cmu_register_clocks(void __iomem *base, | ||||
| 				 const struct samsung_clk_group *clk_groups, | ||||
| 				 unsigned int nr_groups); | ||||
| int samsung_cmu_register_one(struct udevice *dev, | ||||
| 			     const struct samsung_clk_group *clk_groups, | ||||
| 			     unsigned int nr_groups); | ||||
|  | ||||
| /** | ||||
|  * samsung_register_cmu - Register CMU clocks ensuring parent CMU is present | ||||
|  * @dev: CMU device | ||||
|  * @clk_groups: list of CMU clock groups | ||||
|  * @parent_drv: name of parent CMU driver | ||||
|  * | ||||
|  * Register provided CMU clocks, but make sure CMU_TOP driver is instantiated | ||||
|  * first. | ||||
|  * | ||||
|  * Return: 0 on success or negative value on error. | ||||
|  */ | ||||
| #define samsung_register_cmu(dev, clk_groups, parent_drv)		\ | ||||
| ({									\ | ||||
| 	struct udevice *__parent;					\ | ||||
| 	int __ret;							\ | ||||
| 									\ | ||||
| 	__ret = uclass_get_device_by_driver(UCLASS_CLK,			\ | ||||
| 		DM_DRIVER_GET(parent_drv), &__parent);			\ | ||||
| 	if (__ret || !__parent)						\ | ||||
| 		__ret = -ENOENT;					\ | ||||
| 	else								\ | ||||
| 		__ret = samsung_cmu_register_one(dev, clk_groups,	\ | ||||
| 			ARRAY_SIZE(clk_groups));			\ | ||||
| 	__ret;								\ | ||||
| }) | ||||
|  | ||||
| #endif /* __EXYNOS_CLK_H */ | ||||
		Reference in New Issue
	
	Block a user