brintos

brintos / linux-shallow public Read only

0
0
Text · 26.6 KiB · 002f736 Raw
949 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Bitmain BM1880 SoC clock driver4 *5 * Copyright (c) 2019 Linaro Ltd.6 * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>7 */8 9#include <linux/clk-provider.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/mod_devicetable.h>13#include <linux/module.h>14#include <linux/platform_device.h>15#include <linux/slab.h>16 17#include <dt-bindings/clock/bm1880-clock.h>18 19#define BM1880_CLK_MPLL_CTL	0x0020#define BM1880_CLK_SPLL_CTL	0x0421#define BM1880_CLK_FPLL_CTL	0x0822#define BM1880_CLK_DDRPLL_CTL	0x0c23 24#define BM1880_CLK_ENABLE0	0x0025#define BM1880_CLK_ENABLE1	0x0426#define BM1880_CLK_SELECT	0x2027#define BM1880_CLK_DIV0		0x4028#define BM1880_CLK_DIV1		0x4429#define BM1880_CLK_DIV2		0x4830#define BM1880_CLK_DIV3		0x4c31#define BM1880_CLK_DIV4		0x5032#define BM1880_CLK_DIV5		0x5433#define BM1880_CLK_DIV6		0x5834#define BM1880_CLK_DIV7		0x5c35#define BM1880_CLK_DIV8		0x6036#define BM1880_CLK_DIV9		0x6437#define BM1880_CLK_DIV10	0x6838#define BM1880_CLK_DIV11	0x6c39#define BM1880_CLK_DIV12	0x7040#define BM1880_CLK_DIV13	0x7441#define BM1880_CLK_DIV14	0x7842#define BM1880_CLK_DIV15	0x7c43#define BM1880_CLK_DIV16	0x8044#define BM1880_CLK_DIV17	0x8445#define BM1880_CLK_DIV18	0x8846#define BM1880_CLK_DIV19	0x8c47#define BM1880_CLK_DIV20	0x9048#define BM1880_CLK_DIV21	0x9449#define BM1880_CLK_DIV22	0x9850#define BM1880_CLK_DIV23	0x9c51#define BM1880_CLK_DIV24	0xa052#define BM1880_CLK_DIV25	0xa453#define BM1880_CLK_DIV26	0xa854#define BM1880_CLK_DIV27	0xac55#define BM1880_CLK_DIV28	0xb056 57#define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw)58#define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw)59 60static DEFINE_SPINLOCK(bm1880_clk_lock);61 62struct bm1880_clock_data {63	void __iomem *pll_base;64	void __iomem *sys_base;65	struct clk_hw_onecell_data hw_data;66};67 68struct bm1880_gate_clock {69	unsigned int	id;70	const char	*name;71	const char      *parent;72	u32		gate_reg;73	s8		gate_shift;74	unsigned long	flags;75};76 77struct bm1880_mux_clock {78	unsigned int	id;79	const char	*name;80	const char      * const *parents;81	s8		num_parents;82	u32		reg;83	s8		shift;84	unsigned long	flags;85};86 87struct bm1880_div_clock {88	unsigned int	id;89	const char	*name;90	u32		reg;91	u8		shift;92	u8		width;93	u32		initval;94	const struct clk_div_table *table;95	unsigned long flags;96};97 98struct bm1880_div_hw_clock {99	struct bm1880_div_clock div;100	void __iomem *base;101	spinlock_t *lock;102	struct clk_hw hw;103	struct clk_init_data init;104};105 106struct bm1880_composite_clock {107	unsigned int	id;108	const char	*name;109	const char	*parent;110	const char      * const *parents;111	unsigned int	num_parents;112	unsigned long	flags;113 114	u32		gate_reg;115	u32		mux_reg;116	u32		div_reg;117 118	s8		gate_shift;119	s8		mux_shift;120	s8		div_shift;121	s8		div_width;122	s16		div_initval;123	const struct clk_div_table *table;124};125 126struct bm1880_pll_clock {127	unsigned int	id;128	const char	*name;129	u32		reg;130	unsigned long	flags;131};132 133struct bm1880_pll_hw_clock {134	struct bm1880_pll_clock pll;135	void __iomem *base;136	struct clk_hw hw;137	struct clk_init_data init;138};139 140static const struct clk_ops bm1880_pll_ops;141static const struct clk_ops bm1880_clk_div_ops;142 143#define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,	\144			_div_shift, _div_width, _div_initval, _table,	\145			_flags) {					\146		.id = _id,						\147		.parent = _parent,					\148		.name = _name,						\149		.gate_reg = _gate_reg,					\150		.gate_shift = _gate_shift,				\151		.div_reg = _div_reg,					\152		.div_shift = _div_shift,				\153		.div_width = _div_width,				\154		.div_initval = _div_initval,				\155		.table = _table,					\156		.mux_shift = -1,					\157		.flags = _flags,					\158	}159 160#define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift,		\161			_mux_reg, _mux_shift, _flags) {			\162		.id = _id,						\163		.parents = _parents,					\164		.num_parents = ARRAY_SIZE(_parents),			\165		.name = _name,						\166		.gate_reg = _gate_reg,					\167		.gate_shift = _gate_shift,				\168		.div_shift = -1,					\169		.mux_reg = _mux_reg,					\170		.mux_shift = _mux_shift,				\171		.flags = _flags,					\172	}173 174#define CLK_PLL(_id, _name, _parent, _reg, _flags) {			\175		.pll.id = _id,						\176		.pll.name = _name,					\177		.pll.reg = _reg,					\178		.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent,	\179						    &bm1880_pll_ops,	\180						    _flags),		\181	}182 183#define CLK_DIV(_id, _name, _parent, _reg, _shift, _width, _initval,	\184				_table,	_flags) {			\185		.div.id = _id,						\186		.div.name = _name,					\187		.div.reg = _reg,					\188		.div.shift = _shift,					\189		.div.width = _width,					\190		.div.initval = _initval,				\191		.div.table = _table,					\192		.hw.init = CLK_HW_INIT_HW(_name, _parent,		\193					  &bm1880_clk_div_ops,		\194					  _flags),			\195	}196 197static struct clk_parent_data bm1880_pll_parent[] = {198	{ .fw_name = "osc", .name = "osc" },199};200 201/*202 * All PLL clocks are marked as CRITICAL, hence they are very crucial203 * for the functioning of the SoC204 */205static struct bm1880_pll_hw_clock bm1880_pll_clks[] = {206	CLK_PLL(BM1880_CLK_MPLL, "clk_mpll", bm1880_pll_parent,207		BM1880_CLK_MPLL_CTL, 0),208	CLK_PLL(BM1880_CLK_SPLL, "clk_spll", bm1880_pll_parent,209		BM1880_CLK_SPLL_CTL, 0),210	CLK_PLL(BM1880_CLK_FPLL, "clk_fpll", bm1880_pll_parent,211		BM1880_CLK_FPLL_CTL, 0),212	CLK_PLL(BM1880_CLK_DDRPLL, "clk_ddrpll", bm1880_pll_parent,213		BM1880_CLK_DDRPLL_CTL, 0),214};215 216/*217 * Clocks marked as CRITICAL are needed for the proper functioning218 * of the SoC.219 */220static const struct bm1880_gate_clock bm1880_gate_clks[] = {221	{ BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6",222	  BM1880_CLK_ENABLE0, 2, 0 },223	{ BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1",224	  BM1880_CLK_ENABLE0, 3, 0 },225	/*226	 * Since this clock is sourcing the DDR memory, let's mark it as227	 * critical to avoid gating.228	 */229	{ BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6",230	  BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL },231	{ BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6",232	  BM1880_CLK_ENABLE0, 6, 0 },233	{ BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5",234	  BM1880_CLK_ENABLE0, 7, 0 },235	{ BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5",236	  BM1880_CLK_ENABLE0, 10, 0 },237	{ BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4",238	  BM1880_CLK_ENABLE0, 14, 0 },239	{ BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4",240	  BM1880_CLK_ENABLE0, 16, 0 },241	{ BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1",242	  BM1880_CLK_ENABLE0, 17, 0 },243	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */244	{ BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6",245	  BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED },246	{ BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6",247	  BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED },248	{ BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1",249	  BM1880_CLK_ENABLE0, 21, 0 },250	{ BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6",251	  BM1880_CLK_ENABLE0, 22, 0 },252	/*253	 * Not sure which module this clock is sourcing but gating this clock254	 * prevents the system from booting. So, let's mark it as critical.255	 */256	{ BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5",257	  BM1880_CLK_ENABLE0, 23, CLK_IS_CRITICAL },258	{ BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6",259	  BM1880_CLK_ENABLE0, 25, 0 },260	{ BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6",261	  BM1880_CLK_ENABLE0, 26, 0 },262	{ BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6",263	  BM1880_CLK_ENABLE0, 27, 0 },264	{ BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5",265	  BM1880_CLK_ENABLE0, 29, 0 },266	{ BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6",267	  BM1880_CLK_ENABLE0, 30, 0 },268	{ BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6",269	  BM1880_CLK_ENABLE1, 0, 0 },270	{ BM1880_CLK_RV, "clk_rv", "clk_mux_rv",271	  BM1880_CLK_ENABLE1, 1, 0 },272	{ BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6",273	  BM1880_CLK_ENABLE1, 2, 0 },274	{ BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m",275	  BM1880_CLK_ENABLE1, 4, 0 },276	{ BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6",277	  BM1880_CLK_ENABLE1, 5, 0 },278	{ BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6",279	  BM1880_CLK_ENABLE1, 6, 0 },280	{ BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4",281	  BM1880_CLK_ENABLE1, 7, 0 },282	{ BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6",283	  BM1880_CLK_ENABLE1, 8, 0 },284	{ BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb",285	  BM1880_CLK_ENABLE1, 11, 0 },286	{ BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6",287	  BM1880_CLK_ENABLE1, 12, 0 },288	{ BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6",289	  BM1880_CLK_ENABLE1, 15, 0 },290	{ BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6",291	  BM1880_CLK_ENABLE1, 21, 0 },292};293 294static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" };295static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" };296static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" };297static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" };298 299static const struct bm1880_mux_clock bm1880_mux_clks[] = {300	{ BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2,301	  BM1880_CLK_SELECT, 1, 0 },302	{ BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2,303	  BM1880_CLK_SELECT, 3, 0 },304};305 306static const struct clk_div_table bm1880_div_table_0[] = {307	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },308	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },309	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },310	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },311	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },312	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },313	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },314	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },315	{ 0, 0 }316};317 318static const struct clk_div_table bm1880_div_table_1[] = {319	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },320	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },321	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },322	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },323	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },324	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },325	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },326	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },327	{ 127, 128 }, { 0, 0 }328};329 330static const struct clk_div_table bm1880_div_table_2[] = {331	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },332	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },333	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },334	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },335	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },336	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },337	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },338	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },339	{ 127, 128 }, { 255, 256 }, { 0, 0 }340};341 342static const struct clk_div_table bm1880_div_table_3[] = {343	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },344	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },345	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },346	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },347	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },348	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },349	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },350	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },351	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 }352};353 354static const struct clk_div_table bm1880_div_table_4[] = {355	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },356	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },357	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },358	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },359	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },360	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },361	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },362	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },363	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 },364	{ 0, 0 }365};366 367/*368 * Clocks marked as CRITICAL are needed for the proper functioning369 * of the SoC.370 */371static struct bm1880_div_hw_clock bm1880_div_clks[] = {372	CLK_DIV(BM1880_CLK_DIV_0_RV, "clk_div_0_rv", &bm1880_pll_clks[1].hw,373		BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, 0),374	CLK_DIV(BM1880_CLK_DIV_1_RV, "clk_div_1_rv", &bm1880_pll_clks[2].hw,375		BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, 0),376	CLK_DIV(BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", &bm1880_pll_clks[2].hw,377		BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0),378	CLK_DIV(BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", &bm1880_pll_clks[0].hw,379		BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0,380		0),381	CLK_DIV(BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", &bm1880_pll_clks[2].hw,382		BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0,383		0),384	CLK_DIV(BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", &bm1880_pll_clks[2].hw,385		BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0,386		0),387	CLK_DIV(BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", &bm1880_pll_clks[0].hw,388		BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0,389		0),390	CLK_DIV(BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", &bm1880_pll_clks[2].hw,391		BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0),392};393 394/*395 * Clocks marked as CRITICAL are all needed for the proper functioning396 * of the SoC.397 */398static struct bm1880_composite_clock bm1880_composite_clks[] = {399	/*400	 * Since clk_a53 and clk_50m_a53 clocks are sourcing the CPU core,401	 * let's mark them as critical to avoid gating.402	 */403	GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents,404		 BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0,405		 CLK_IS_CRITICAL),406	GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll",407		 BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30,408		 bm1880_div_table_0, CLK_IS_CRITICAL),409	GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll",410		 BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60,411		 bm1880_div_table_1, 0),412	GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll",413		 BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15,414		 bm1880_div_table_0, 0),415	GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb",416		 BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120,417		 bm1880_div_table_2, 0),418	GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll",419		 BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15,420		 bm1880_div_table_0, 0),421	GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb",422		 BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120,423		 bm1880_div_table_2, 0),424	GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll",425		 BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3,426		 bm1880_div_table_0, 0),427	GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll",428		 BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3,429		 bm1880_div_table_0, 0),430	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */431	GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb",432		 BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120,433		 bm1880_div_table_4, CLK_IGNORE_UNUSED),434	GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll",435		 BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61,436		 bm1880_div_table_1, 0),437	GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll",438		 BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4,439		 bm1880_div_table_0, 0),440	GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll",441		 BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30,442		 bm1880_div_table_0, 0),443	GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll",444		 BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1,445		 bm1880_div_table_0, 0),446	GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll",447		 BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12,448		 bm1880_div_table_0, 0),449	GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb",450		 BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363,451		 bm1880_div_table_3, 0),452	GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll",453		 BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4,454		 bm1880_div_table_0, 0),455	GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll",456		 BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4,457		 bm1880_div_table_0, 0),458	GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents,459		 BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2, 0),460	GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll",461		 BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3,462		 bm1880_div_table_0, 0),463	GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv",464		 BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2,465		 bm1880_div_table_0, 0),466	GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll",467		 BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6,468		 bm1880_div_table_0, 0),469	GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll",470		 BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15,471		 bm1880_div_table_0, 0),472};473 474static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)475{476	u64 numerator;477	u32 fbdiv, refdiv;478	u32 postdiv1, postdiv2, denominator;479 480	fbdiv = (regval >> 16) & 0xfff;481	refdiv = regval & 0x1f;482	postdiv1 = (regval >> 8) & 0x7;483	postdiv2 = (regval >> 12) & 0x7;484 485	numerator = parent_rate * fbdiv;486	denominator = refdiv * postdiv1 * postdiv2;487	do_div(numerator, denominator);488 489	return (unsigned long)numerator;490}491 492static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw,493					    unsigned long parent_rate)494{495	struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);496	unsigned long rate;497	u32 regval;498 499	regval = readl(pll_hw->base + pll_hw->pll.reg);500	rate = bm1880_pll_rate_calc(regval, parent_rate);501 502	return rate;503}504 505static const struct clk_ops bm1880_pll_ops = {506	.recalc_rate	= bm1880_pll_recalc_rate,507};508 509static struct clk_hw *bm1880_clk_register_pll(struct bm1880_pll_hw_clock *pll_clk,510					      void __iomem *sys_base)511{512	struct clk_hw *hw;513	int err;514 515	pll_clk->base = sys_base;516	hw = &pll_clk->hw;517 518	err = clk_hw_register(NULL, hw);519	if (err)520		return ERR_PTR(err);521 522	return hw;523}524 525static int bm1880_clk_register_plls(struct bm1880_pll_hw_clock *clks,526				    int num_clks,527				    struct bm1880_clock_data *data)528{529	struct clk_hw *hw;530	void __iomem *pll_base = data->pll_base;531	int i;532 533	for (i = 0; i < num_clks; i++) {534		struct bm1880_pll_hw_clock *bm1880_clk = &clks[i];535 536		hw = bm1880_clk_register_pll(bm1880_clk, pll_base);537		if (IS_ERR(hw)) {538			pr_err("%s: failed to register clock %s\n",539			       __func__, bm1880_clk->pll.name);540			goto err_clk;541		}542 543		data->hw_data.hws[clks[i].pll.id] = hw;544	}545 546	return 0;547 548err_clk:549	while (i--)550		clk_hw_unregister(data->hw_data.hws[clks[i].pll.id]);551 552	return PTR_ERR(hw);553}554 555static int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,556				   int num_clks,557				   struct bm1880_clock_data *data)558{559	struct clk_hw *hw;560	void __iomem *sys_base = data->sys_base;561	int i;562 563	for (i = 0; i < num_clks; i++) {564		hw = clk_hw_register_mux(NULL, clks[i].name,565					 clks[i].parents,566					 clks[i].num_parents,567					 clks[i].flags,568					 sys_base + clks[i].reg,569					 clks[i].shift, 1, 0,570					 &bm1880_clk_lock);571		if (IS_ERR(hw)) {572			pr_err("%s: failed to register clock %s\n",573			       __func__, clks[i].name);574			goto err_clk;575		}576 577		data->hw_data.hws[clks[i].id] = hw;578	}579 580	return 0;581 582err_clk:583	while (i--)584		clk_hw_unregister_mux(data->hw_data.hws[clks[i].id]);585 586	return PTR_ERR(hw);587}588 589static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,590						unsigned long parent_rate)591{592	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);593	struct bm1880_div_clock *div = &div_hw->div;594	void __iomem *reg_addr = div_hw->base + div->reg;595	unsigned int val;596	unsigned long rate;597 598	if (!(readl(reg_addr) & BIT(3))) {599		val = div->initval;600	} else {601		val = readl(reg_addr) >> div->shift;602		val &= clk_div_mask(div->width);603	}604 605	rate = divider_recalc_rate(hw, parent_rate, val, div->table,606				   div->flags, div->width);607 608	return rate;609}610 611static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,612				      unsigned long *prate)613{614	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);615	struct bm1880_div_clock *div = &div_hw->div;616	void __iomem *reg_addr = div_hw->base + div->reg;617 618	if (div->flags & CLK_DIVIDER_READ_ONLY) {619		u32 val;620 621		val = readl(reg_addr) >> div->shift;622		val &= clk_div_mask(div->width);623 624		return divider_ro_round_rate(hw, rate, prate, div->table,625					     div->width, div->flags,626					     val);627	}628 629	return divider_round_rate(hw, rate, prate, div->table,630				  div->width, div->flags);631}632 633static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,634				   unsigned long parent_rate)635{636	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);637	struct bm1880_div_clock *div = &div_hw->div;638	void __iomem *reg_addr = div_hw->base + div->reg;639	unsigned long flags = 0;640	int value;641	u32 val;642 643	value = divider_get_val(rate, parent_rate, div->table,644				div->width, div_hw->div.flags);645	if (value < 0)646		return value;647 648	if (div_hw->lock)649		spin_lock_irqsave(div_hw->lock, flags);650	else651		__acquire(div_hw->lock);652 653	val = readl(reg_addr);654	val &= ~(clk_div_mask(div->width) << div_hw->div.shift);655	val |= (u32)value << div->shift;656	writel(val, reg_addr);657 658	if (div_hw->lock)659		spin_unlock_irqrestore(div_hw->lock, flags);660	else661		__release(div_hw->lock);662 663	return 0;664}665 666static const struct clk_ops bm1880_clk_div_ops = {667	.recalc_rate = bm1880_clk_div_recalc_rate,668	.round_rate = bm1880_clk_div_round_rate,669	.set_rate = bm1880_clk_div_set_rate,670};671 672static struct clk_hw *bm1880_clk_register_div(struct bm1880_div_hw_clock *div_clk,673					      void __iomem *sys_base)674{675	struct clk_hw *hw;676	int err;677 678	div_clk->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;679	div_clk->base = sys_base;680	div_clk->lock = &bm1880_clk_lock;681 682	hw = &div_clk->hw;683	err = clk_hw_register(NULL, hw);684	if (err)685		return ERR_PTR(err);686 687	return hw;688}689 690static int bm1880_clk_register_divs(struct bm1880_div_hw_clock *clks,691				    int num_clks,692				    struct bm1880_clock_data *data)693{694	struct clk_hw *hw;695	void __iomem *sys_base = data->sys_base;696	unsigned int i, id;697 698	for (i = 0; i < num_clks; i++) {699		struct bm1880_div_hw_clock *bm1880_clk = &clks[i];700 701		hw = bm1880_clk_register_div(bm1880_clk, sys_base);702		if (IS_ERR(hw)) {703			pr_err("%s: failed to register clock %s\n",704			       __func__, bm1880_clk->div.name);705			goto err_clk;706		}707 708		id = clks[i].div.id;709		data->hw_data.hws[id] = hw;710	}711 712	return 0;713 714err_clk:715	while (i--)716		clk_hw_unregister(data->hw_data.hws[clks[i].div.id]);717 718	return PTR_ERR(hw);719}720 721static int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks,722				    int num_clks,723				    struct bm1880_clock_data *data)724{725	struct clk_hw *hw;726	void __iomem *sys_base = data->sys_base;727	int i;728 729	for (i = 0; i < num_clks; i++) {730		hw = clk_hw_register_gate(NULL, clks[i].name,731					  clks[i].parent,732					  clks[i].flags,733					  sys_base + clks[i].gate_reg,734					  clks[i].gate_shift, 0,735					  &bm1880_clk_lock);736		if (IS_ERR(hw)) {737			pr_err("%s: failed to register clock %s\n",738			       __func__, clks[i].name);739			goto err_clk;740		}741 742		data->hw_data.hws[clks[i].id] = hw;743	}744 745	return 0;746 747err_clk:748	while (i--)749		clk_hw_unregister_gate(data->hw_data.hws[clks[i].id]);750 751	return PTR_ERR(hw);752}753 754static struct clk_hw *bm1880_clk_register_composite(struct bm1880_composite_clock *clks,755						    void __iomem *sys_base)756{757	struct clk_hw *hw;758	struct clk_mux *mux = NULL;759	struct clk_gate *gate = NULL;760	struct bm1880_div_hw_clock *div_hws = NULL;761	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;762	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;763	const char * const *parent_names;764	const char *parent;765	int num_parents;766	int ret;767 768	if (clks->mux_shift >= 0) {769		mux = kzalloc(sizeof(*mux), GFP_KERNEL);770		if (!mux)771			return ERR_PTR(-ENOMEM);772 773		mux->reg = sys_base + clks->mux_reg;774		mux->mask = 1;775		mux->shift = clks->mux_shift;776		mux_hw = &mux->hw;777		mux_ops = &clk_mux_ops;778		mux->lock = &bm1880_clk_lock;779 780		parent_names = clks->parents;781		num_parents = clks->num_parents;782	} else {783		parent = clks->parent;784		parent_names = &parent;785		num_parents = 1;786	}787 788	if (clks->gate_shift >= 0) {789		gate = kzalloc(sizeof(*gate), GFP_KERNEL);790		if (!gate) {791			ret = -ENOMEM;792			goto err_out;793		}794 795		gate->reg = sys_base + clks->gate_reg;796		gate->bit_idx = clks->gate_shift;797		gate->lock = &bm1880_clk_lock;798 799		gate_hw = &gate->hw;800		gate_ops = &clk_gate_ops;801	}802 803	if (clks->div_shift >= 0) {804		div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL);805		if (!div_hws) {806			ret = -ENOMEM;807			goto err_out;808		}809 810		div_hws->base = sys_base;811		div_hws->div.reg = clks->div_reg;812		div_hws->div.shift = clks->div_shift;813		div_hws->div.width = clks->div_width;814		div_hws->div.table = clks->table;815		div_hws->div.initval = clks->div_initval;816		div_hws->lock = &bm1880_clk_lock;817		div_hws->div.flags = CLK_DIVIDER_ONE_BASED |818				     CLK_DIVIDER_ALLOW_ZERO;819 820		div_hw = &div_hws->hw;821		div_ops = &bm1880_clk_div_ops;822	}823 824	hw = clk_hw_register_composite(NULL, clks->name, parent_names,825				       num_parents, mux_hw, mux_ops, div_hw,826				       div_ops, gate_hw, gate_ops,827				       clks->flags);828 829	if (IS_ERR(hw)) {830		ret = PTR_ERR(hw);831		goto err_out;832	}833 834	return hw;835 836err_out:837	kfree(div_hws);838	kfree(gate);839	kfree(mux);840 841	return ERR_PTR(ret);842}843 844static int bm1880_clk_register_composites(struct bm1880_composite_clock *clks,845					  int num_clks,846					  struct bm1880_clock_data *data)847{848	struct clk_hw *hw;849	void __iomem *sys_base = data->sys_base;850	int i;851 852	for (i = 0; i < num_clks; i++) {853		struct bm1880_composite_clock *bm1880_clk = &clks[i];854 855		hw = bm1880_clk_register_composite(bm1880_clk, sys_base);856		if (IS_ERR(hw)) {857			pr_err("%s: failed to register clock %s\n",858			       __func__, bm1880_clk->name);859			goto err_clk;860		}861 862		data->hw_data.hws[clks[i].id] = hw;863	}864 865	return 0;866 867err_clk:868	while (i--)869		clk_hw_unregister_composite(data->hw_data.hws[clks[i].id]);870 871	return PTR_ERR(hw);872}873 874static int bm1880_clk_probe(struct platform_device *pdev)875{876	struct bm1880_clock_data *clk_data;877	void __iomem *pll_base, *sys_base;878	struct device *dev = &pdev->dev;879	int num_clks, i;880 881	pll_base = devm_platform_ioremap_resource(pdev, 0);882	if (IS_ERR(pll_base))883		return PTR_ERR(pll_base);884 885	sys_base = devm_platform_ioremap_resource(pdev, 1);886	if (IS_ERR(sys_base))887		return PTR_ERR(sys_base);888 889	num_clks = ARRAY_SIZE(bm1880_pll_clks) +890		   ARRAY_SIZE(bm1880_div_clks) +891		   ARRAY_SIZE(bm1880_mux_clks) +892		   ARRAY_SIZE(bm1880_composite_clks) +893		   ARRAY_SIZE(bm1880_gate_clks);894 895	clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws,896						 num_clks), GFP_KERNEL);897	if (!clk_data)898		return -ENOMEM;899 900	clk_data->pll_base = pll_base;901	clk_data->sys_base = sys_base;902 903	for (i = 0; i < num_clks; i++)904		clk_data->hw_data.hws[i] = ERR_PTR(-ENOENT);905 906	clk_data->hw_data.num = num_clks;907 908	bm1880_clk_register_plls(bm1880_pll_clks,909				 ARRAY_SIZE(bm1880_pll_clks),910				 clk_data);911 912	bm1880_clk_register_divs(bm1880_div_clks,913				 ARRAY_SIZE(bm1880_div_clks),914				 clk_data);915 916	bm1880_clk_register_mux(bm1880_mux_clks,917				ARRAY_SIZE(bm1880_mux_clks),918				clk_data);919 920	bm1880_clk_register_composites(bm1880_composite_clks,921				       ARRAY_SIZE(bm1880_composite_clks),922				       clk_data);923 924	bm1880_clk_register_gate(bm1880_gate_clks,925				 ARRAY_SIZE(bm1880_gate_clks),926				 clk_data);927 928	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,929				      &clk_data->hw_data);930}931 932static const struct of_device_id bm1880_of_match[] = {933	{ .compatible = "bitmain,bm1880-clk", },934	{}935};936MODULE_DEVICE_TABLE(of, bm1880_of_match);937 938static struct platform_driver bm1880_clk_driver = {939	.driver = {940		.name = "bm1880-clk",941		.of_match_table = bm1880_of_match,942	},943	.probe = bm1880_clk_probe,944};945module_platform_driver(bm1880_clk_driver);946 947MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");948MODULE_DESCRIPTION("Clock driver for Bitmain BM1880 SoC");949