mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	clk: Add Allwinner A64 CLK driver
Add initial clock driver for Allwinner A64. Implement USB clock enable and disable functions for OHCI, EHCI, OTG and USBPHY gate and clock registers via ccu clk gate table. Signed-off-by: Jagan Teki <jagan@amarulasolutions.com> Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
This commit is contained in:
		
							
								
								
									
										65
									
								
								arch/arm/include/asm/arch-sunxi/ccu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								arch/arm/include/asm/arch-sunxi/ccu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /* | ||||||
|  |  * Copyright (C) 2018 Amarula Solutions. | ||||||
|  |  * Author: Jagan Teki <jagan@amarulasolutions.com> | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef _ASM_ARCH_CCU_H | ||||||
|  | #define _ASM_ARCH_CCU_H | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * enum ccu_flags - ccu clock flags | ||||||
|  |  * | ||||||
|  |  * @CCU_CLK_F_IS_VALID:		is given clock gate is valid? | ||||||
|  |  */ | ||||||
|  | enum ccu_flags { | ||||||
|  | 	CCU_CLK_F_IS_VALID		= BIT(0), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * struct ccu_clk_gate - ccu clock gate | ||||||
|  |  * @off:	gate offset | ||||||
|  |  * @bit:	gate bit | ||||||
|  |  * @flags:	ccu clock gate flags | ||||||
|  |  */ | ||||||
|  | struct ccu_clk_gate { | ||||||
|  | 	u16 off; | ||||||
|  | 	u32 bit; | ||||||
|  | 	enum ccu_flags flags; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #define GATE(_off, _bit) {			\ | ||||||
|  | 	.off = _off,				\ | ||||||
|  | 	.bit = _bit,				\ | ||||||
|  | 	.flags = CCU_CLK_F_IS_VALID,		\ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * struct ccu_desc - clock control unit descriptor | ||||||
|  |  * | ||||||
|  |  * @gates:	clock gates | ||||||
|  |  */ | ||||||
|  | struct ccu_desc { | ||||||
|  | 	const struct ccu_clk_gate *gates; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * struct ccu_priv - sunxi clock control unit | ||||||
|  |  * | ||||||
|  |  * @base:	base address | ||||||
|  |  * @desc:	ccu descriptor | ||||||
|  |  */ | ||||||
|  | struct ccu_priv { | ||||||
|  | 	void *base; | ||||||
|  | 	const struct ccu_desc *desc; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * sunxi_clk_probe - common sunxi clock probe | ||||||
|  |  * @dev:	clock device | ||||||
|  |  */ | ||||||
|  | int sunxi_clk_probe(struct udevice *dev); | ||||||
|  |  | ||||||
|  | extern struct clk_ops sunxi_clk_ops; | ||||||
|  |  | ||||||
|  | #endif /* _ASM_ARCH_CCU_H */ | ||||||
| @@ -104,6 +104,7 @@ source "drivers/clk/imx/Kconfig" | |||||||
| source "drivers/clk/mvebu/Kconfig" | source "drivers/clk/mvebu/Kconfig" | ||||||
| source "drivers/clk/owl/Kconfig" | source "drivers/clk/owl/Kconfig" | ||||||
| source "drivers/clk/renesas/Kconfig" | source "drivers/clk/renesas/Kconfig" | ||||||
|  | source "drivers/clk/sunxi/Kconfig" | ||||||
| source "drivers/clk/tegra/Kconfig" | source "drivers/clk/tegra/Kconfig" | ||||||
| source "drivers/clk/uniphier/Kconfig" | source "drivers/clk/uniphier/Kconfig" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o | |||||||
| obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o | obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o | ||||||
| obj-$(CONFIG_CLK_OWL) += owl/ | obj-$(CONFIG_CLK_OWL) += owl/ | ||||||
| obj-$(CONFIG_CLK_RENESAS) += renesas/ | obj-$(CONFIG_CLK_RENESAS) += renesas/ | ||||||
|  | obj-$(CONFIG_ARCH_SUNXI) += sunxi/ | ||||||
| obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o | obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o | ||||||
| obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o | obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o | ||||||
| obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ | obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								drivers/clk/sunxi/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								drivers/clk/sunxi/Kconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | config CLK_SUNXI | ||||||
|  | 	bool "Clock support for Allwinner SoCs" | ||||||
|  | 	depends on CLK && ARCH_SUNXI | ||||||
|  | 	default y | ||||||
|  | 	help | ||||||
|  | 	  This enables support for common clock driver API on Allwinner | ||||||
|  | 	  SoCs. | ||||||
|  |  | ||||||
|  | if CLK_SUNXI | ||||||
|  |  | ||||||
|  | config CLK_SUN50I_A64 | ||||||
|  | 	bool "Clock driver for Allwinner A64" | ||||||
|  | 	default MACH_SUN50I | ||||||
|  | 	help | ||||||
|  | 	  This enables common clock driver support for platforms based | ||||||
|  | 	  on Allwinner A64 SoC. | ||||||
|  |  | ||||||
|  | endif # CLK_SUNXI | ||||||
							
								
								
									
										9
									
								
								drivers/clk/sunxi/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/clk/sunxi/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | # | ||||||
|  | # Copyright (C) 2018 Amarula Solutions. | ||||||
|  | # | ||||||
|  | # SPDX-License-Identifier:      GPL-2.0+ | ||||||
|  | # | ||||||
|  |  | ||||||
|  | obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o | ||||||
|  |  | ||||||
|  | obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o | ||||||
							
								
								
									
										46
									
								
								drivers/clk/sunxi/clk_a64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								drivers/clk/sunxi/clk_a64.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /* | ||||||
|  |  * Copyright (C) 2018 Amarula Solutions. | ||||||
|  |  * Author: Jagan Teki <jagan@amarulasolutions.com> | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <common.h> | ||||||
|  | #include <clk-uclass.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <asm/arch/ccu.h> | ||||||
|  | #include <dt-bindings/clock/sun50i-a64-ccu.h> | ||||||
|  |  | ||||||
|  | static const struct ccu_clk_gate a64_gates[] = { | ||||||
|  | 	[CLK_BUS_OTG]		= GATE(0x060, BIT(23)), | ||||||
|  | 	[CLK_BUS_EHCI0]		= GATE(0x060, BIT(24)), | ||||||
|  | 	[CLK_BUS_EHCI1]		= GATE(0x060, BIT(25)), | ||||||
|  | 	[CLK_BUS_OHCI0]		= GATE(0x060, BIT(28)), | ||||||
|  | 	[CLK_BUS_OHCI1]		= GATE(0x060, BIT(29)), | ||||||
|  |  | ||||||
|  | 	[CLK_USB_PHY0]		= GATE(0x0cc, BIT(8)), | ||||||
|  | 	[CLK_USB_PHY1]		= GATE(0x0cc, BIT(9)), | ||||||
|  | 	[CLK_USB_HSIC]		= GATE(0x0cc, BIT(10)), | ||||||
|  | 	[CLK_USB_HSIC_12M]	= GATE(0x0cc, BIT(11)), | ||||||
|  | 	[CLK_USB_OHCI0]		= GATE(0x0cc, BIT(16)), | ||||||
|  | 	[CLK_USB_OHCI1]		= GATE(0x0cc, BIT(17)), | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct ccu_desc a64_ccu_desc = { | ||||||
|  | 	.gates = a64_gates, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const struct udevice_id a64_ccu_ids[] = { | ||||||
|  | 	{ .compatible = "allwinner,sun50i-a64-ccu", | ||||||
|  | 	  .data = (ulong)&a64_ccu_desc }, | ||||||
|  | 	{ } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | U_BOOT_DRIVER(clk_sun50i_a64) = { | ||||||
|  | 	.name		= "sun50i_a64_ccu", | ||||||
|  | 	.id		= UCLASS_CLK, | ||||||
|  | 	.of_match	= a64_ccu_ids, | ||||||
|  | 	.priv_auto_alloc_size	= sizeof(struct ccu_priv), | ||||||
|  | 	.ops		= &sunxi_clk_ops, | ||||||
|  | 	.probe		= sunxi_clk_probe, | ||||||
|  | }; | ||||||
							
								
								
									
										74
									
								
								drivers/clk/sunxi/clk_sunxi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								drivers/clk/sunxi/clk_sunxi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0+ | ||||||
|  | /* | ||||||
|  |  * Copyright (C) 2018 Amarula Solutions. | ||||||
|  |  * Author: Jagan Teki <jagan@amarulasolutions.com> | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include <common.h> | ||||||
|  | #include <clk-uclass.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <asm/io.h> | ||||||
|  | #include <asm/arch/ccu.h> | ||||||
|  | #include <linux/log2.h> | ||||||
|  |  | ||||||
|  | static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv, | ||||||
|  | 					       unsigned long id) | ||||||
|  | { | ||||||
|  | 	return &priv->desc->gates[id]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int sunxi_set_gate(struct clk *clk, bool on) | ||||||
|  | { | ||||||
|  | 	struct ccu_priv *priv = dev_get_priv(clk->dev); | ||||||
|  | 	const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id); | ||||||
|  | 	u32 reg; | ||||||
|  |  | ||||||
|  | 	if (!(gate->flags & CCU_CLK_F_IS_VALID)) { | ||||||
|  | 		printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id); | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__, | ||||||
|  | 	      clk->id, gate->off, ilog2(gate->bit)); | ||||||
|  |  | ||||||
|  | 	reg = readl(priv->base + gate->off); | ||||||
|  | 	if (on) | ||||||
|  | 		reg |= gate->bit; | ||||||
|  | 	else | ||||||
|  | 		reg &= ~gate->bit; | ||||||
|  |  | ||||||
|  | 	writel(reg, priv->base + gate->off); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int sunxi_clk_enable(struct clk *clk) | ||||||
|  | { | ||||||
|  | 	return sunxi_set_gate(clk, true); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int sunxi_clk_disable(struct clk *clk) | ||||||
|  | { | ||||||
|  | 	return sunxi_set_gate(clk, false); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct clk_ops sunxi_clk_ops = { | ||||||
|  | 	.enable = sunxi_clk_enable, | ||||||
|  | 	.disable = sunxi_clk_disable, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int sunxi_clk_probe(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct ccu_priv *priv = dev_get_priv(dev); | ||||||
|  |  | ||||||
|  | 	priv->base = dev_read_addr_ptr(dev); | ||||||
|  | 	if (!priv->base) | ||||||
|  | 		return -ENOMEM; | ||||||
|  |  | ||||||
|  | 	priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev); | ||||||
|  | 	if (!priv->desc) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user