brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · e407f00 Raw
447 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * JZ4760 SoC CGU driver4 * Copyright 2018, Paul Cercueil <paul@crapouillou.net>5 */6 7#include <linux/bitops.h>8#include <linux/clk-provider.h>9#include <linux/delay.h>10#include <linux/io.h>11#include <linux/of.h>12 13#include <linux/clk.h>14 15#include <dt-bindings/clock/ingenic,jz4760-cgu.h>16 17#include "cgu.h"18#include "pm.h"19 20#define MHZ (1000 * 1000)21 22/*23 * CPM registers offset address definition24 */25#define CGU_REG_CPCCR		0x0026#define CGU_REG_LCR		0x0427#define CGU_REG_CPPCR0		0x1028#define CGU_REG_CLKGR0		0x2029#define CGU_REG_OPCR		0x2430#define CGU_REG_CLKGR1		0x2831#define CGU_REG_CPPCR1		0x3032#define CGU_REG_USBPCR		0x3c33#define CGU_REG_USBCDR		0x5034#define CGU_REG_I2SCDR		0x6035#define CGU_REG_LPCDR		0x6436#define CGU_REG_MSCCDR		0x6837#define CGU_REG_UHCCDR		0x6c38#define CGU_REG_SSICDR		0x7439#define CGU_REG_CIMCDR		0x7c40#define CGU_REG_GPSCDR		0x8041#define CGU_REG_PCMCDR		0x8442#define CGU_REG_GPUCDR		0x8843 44static const s8 pll_od_encoding[8] = {45	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,46};47 48static const u8 jz4760_cgu_cpccr_div_table[] = {49	1, 2, 3, 4, 6, 8,50};51 52static const u8 jz4760_cgu_pll_half_div_table[] = {53	2, 1,54};55 56static void57jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,58		       unsigned long rate, unsigned long parent_rate,59		       unsigned int *pm, unsigned int *pn, unsigned int *pod)60{61	unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1;62 63	/* The frequency after the N divider must be between 1 and 50 MHz. */64	n = parent_rate / (1 * MHZ);65 66	/* The N divider must be >= 2. */67	n = clamp_val(n, 2, 1 << pll_info->n_bits);68 69	rate /= MHZ;70	parent_rate /= MHZ;71 72	for (m = m_max; m >= m_max && n >= 2; n--) {73		m = rate * n / parent_rate;74		od = m & 1;75		m <<= od;76	}77 78	*pm = m;79	*pn = n + 1;80	*pod = 1 << od;81}82 83static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {84 85	/* External clocks */86 87	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },88	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },89 90	/* PLLs */91 92	[JZ4760_CLK_PLL0] = {93		"pll0", CGU_CLK_PLL,94		.parents = { JZ4760_CLK_EXT },95		.pll = {96			.reg = CGU_REG_CPPCR0,97			.rate_multiplier = 1,98			.m_shift = 23,99			.m_bits = 8,100			.m_offset = 0,101			.n_shift = 18,102			.n_bits = 4,103			.n_offset = 0,104			.od_shift = 16,105			.od_bits = 2,106			.od_max = 8,107			.od_encoding = pll_od_encoding,108			.bypass_reg = CGU_REG_CPPCR0,109			.bypass_bit = 9,110			.enable_bit = 8,111			.stable_bit = 10,112			.calc_m_n_od = jz4760_cgu_calc_m_n_od,113		},114	},115 116	[JZ4760_CLK_PLL1] = {117		/* TODO: PLL1 can depend on PLL0 */118		"pll1", CGU_CLK_PLL,119		.parents = { JZ4760_CLK_EXT },120		.pll = {121			.reg = CGU_REG_CPPCR1,122			.rate_multiplier = 1,123			.m_shift = 23,124			.m_bits = 8,125			.m_offset = 0,126			.n_shift = 18,127			.n_bits = 4,128			.n_offset = 0,129			.od_shift = 16,130			.od_bits = 2,131			.od_max = 8,132			.od_encoding = pll_od_encoding,133			.bypass_bit = -1,134			.enable_bit = 7,135			.stable_bit = 6,136			.calc_m_n_od = jz4760_cgu_calc_m_n_od,137		},138	},139 140	/* Main clocks */141 142	[JZ4760_CLK_CCLK] = {143		"cclk", CGU_CLK_DIV,144		/*145		 * Disabling the CPU clock or any parent clocks will hang the146		 * system; mark it critical.147		 */148		.flags = CLK_IS_CRITICAL,149		.parents = { JZ4760_CLK_PLL0, },150		.div = {151			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,152			jz4760_cgu_cpccr_div_table,153		},154	},155	[JZ4760_CLK_HCLK] = {156		"hclk", CGU_CLK_DIV,157		.parents = { JZ4760_CLK_PLL0, },158		.div = {159			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,160			jz4760_cgu_cpccr_div_table,161		},162	},163	[JZ4760_CLK_SCLK] = {164		"sclk", CGU_CLK_DIV,165		.parents = { JZ4760_CLK_PLL0, },166		.div = {167			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,168			jz4760_cgu_cpccr_div_table,169		},170	},171	[JZ4760_CLK_H2CLK] = {172		"h2clk", CGU_CLK_DIV,173		.parents = { JZ4760_CLK_PLL0, },174		.div = {175			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,176			jz4760_cgu_cpccr_div_table,177		},178	},179	[JZ4760_CLK_MCLK] = {180		"mclk", CGU_CLK_DIV,181		/*182		 * Disabling MCLK or its parents will render DRAM183		 * inaccessible; mark it critical.184		 */185		.flags = CLK_IS_CRITICAL,186		.parents = { JZ4760_CLK_PLL0, },187		.div = {188			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,189			jz4760_cgu_cpccr_div_table,190		},191	},192	[JZ4760_CLK_PCLK] = {193		"pclk", CGU_CLK_DIV,194		.parents = { JZ4760_CLK_PLL0, },195		.div = {196			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,197			jz4760_cgu_cpccr_div_table,198		},199	},200 201	/* Divided clocks */202 203	[JZ4760_CLK_PLL0_HALF] = {204		"pll0_half", CGU_CLK_DIV,205		.parents = { JZ4760_CLK_PLL0 },206		.div = {207			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,208			jz4760_cgu_pll_half_div_table,209		},210	},211 212	/* Those divided clocks can connect to PLL0 or PLL1 */213 214	[JZ4760_CLK_UHC] = {215		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,216		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },217		.mux = { CGU_REG_UHCCDR, 31, 1 },218		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },219		.gate = { CGU_REG_CLKGR0, 24 },220	},221	[JZ4760_CLK_GPU] = {222		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,223		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },224		.mux = { CGU_REG_GPUCDR, 31, 1 },225		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },226		.gate = { CGU_REG_CLKGR1, 9 },227	},228	[JZ4760_CLK_LPCLK_DIV] = {229		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,230		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },231		.mux = { CGU_REG_LPCDR, 29, 1 },232		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },233	},234	[JZ4760_CLK_TVE] = {235		"tve", CGU_CLK_GATE | CGU_CLK_MUX,236		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },237		.mux = { CGU_REG_LPCDR, 31, 1 },238		.gate = { CGU_REG_CLKGR0, 27 },239	},240	[JZ4760_CLK_LPCLK] = {241		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,242		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },243		.mux = { CGU_REG_LPCDR, 30, 1 },244		.gate = { CGU_REG_CLKGR0, 28 },245	},246	[JZ4760_CLK_GPS] = {247		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,248		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },249		.mux = { CGU_REG_GPSCDR, 31, 1 },250		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },251		.gate = { CGU_REG_CLKGR0, 22 },252	},253 254	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */255 256	[JZ4760_CLK_PCM] = {257		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,258		.parents = { JZ4760_CLK_EXT, -1,259			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },260		.mux = { CGU_REG_PCMCDR, 30, 2 },261		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },262		.gate = { CGU_REG_CLKGR1, 8 },263	},264	[JZ4760_CLK_I2S] = {265		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,266		.parents = { JZ4760_CLK_EXT, -1,267			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },268		.mux = { CGU_REG_I2SCDR, 30, 2 },269		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },270	},271	[JZ4760_CLK_OTG] = {272		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,273		.parents = { JZ4760_CLK_EXT, -1,274			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },275		.mux = { CGU_REG_USBCDR, 30, 2 },276		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },277		.gate = { CGU_REG_CLKGR0, 2 },278	},279 280	/* Those divided clocks can connect to EXT or PLL0 */281	[JZ4760_CLK_MMC_MUX] = {282		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,283		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },284		.mux = { CGU_REG_MSCCDR, 31, 1 },285		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },286	},287	[JZ4760_CLK_SSI_MUX] = {288		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,289		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },290		.mux = { CGU_REG_SSICDR, 31, 1 },291		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },292	},293 294	/* These divided clock can connect to PLL0 only */295	[JZ4760_CLK_CIM] = {296		"cim", CGU_CLK_DIV | CGU_CLK_GATE,297		.parents = { JZ4760_CLK_PLL0_HALF },298		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },299		.gate = { CGU_REG_CLKGR0, 26 },300	},301 302	/* Gate-only clocks */303 304	[JZ4760_CLK_SSI0] = {305		"ssi0", CGU_CLK_GATE,306		.parents = { JZ4760_CLK_SSI_MUX, },307		.gate = { CGU_REG_CLKGR0, 4 },308	},309	[JZ4760_CLK_SSI1] = {310		"ssi1", CGU_CLK_GATE,311		.parents = { JZ4760_CLK_SSI_MUX, },312		.gate = { CGU_REG_CLKGR0, 19 },313	},314	[JZ4760_CLK_SSI2] = {315		"ssi2", CGU_CLK_GATE,316		.parents = { JZ4760_CLK_SSI_MUX, },317		.gate = { CGU_REG_CLKGR0, 20 },318	},319	[JZ4760_CLK_DMA] = {320		"dma", CGU_CLK_GATE,321		.parents = { JZ4760_CLK_H2CLK, },322		.gate = { CGU_REG_CLKGR0, 21 },323	},324	[JZ4760_CLK_MDMA] = {325		"mdma", CGU_CLK_GATE,326		.parents = { JZ4760_CLK_HCLK, },327		.gate = { CGU_REG_CLKGR0, 25 },328	},329	[JZ4760_CLK_BDMA] = {330		"bdma", CGU_CLK_GATE,331		.parents = { JZ4760_CLK_HCLK, },332		.gate = { CGU_REG_CLKGR1, 0 },333	},334	[JZ4760_CLK_I2C0] = {335		"i2c0", CGU_CLK_GATE,336		.parents = { JZ4760_CLK_EXT, },337		.gate = { CGU_REG_CLKGR0, 5 },338	},339	[JZ4760_CLK_I2C1] = {340		"i2c1", CGU_CLK_GATE,341		.parents = { JZ4760_CLK_EXT, },342		.gate = { CGU_REG_CLKGR0, 6 },343	},344	[JZ4760_CLK_UART0] = {345		"uart0", CGU_CLK_GATE,346		.parents = { JZ4760_CLK_EXT, },347		.gate = { CGU_REG_CLKGR0, 15 },348	},349	[JZ4760_CLK_UART1] = {350		"uart1", CGU_CLK_GATE,351		.parents = { JZ4760_CLK_EXT, },352		.gate = { CGU_REG_CLKGR0, 16 },353	},354	[JZ4760_CLK_UART2] = {355		"uart2", CGU_CLK_GATE,356		.parents = { JZ4760_CLK_EXT, },357		.gate = { CGU_REG_CLKGR0, 17 },358	},359	[JZ4760_CLK_UART3] = {360		"uart3", CGU_CLK_GATE,361		.parents = { JZ4760_CLK_EXT, },362		.gate = { CGU_REG_CLKGR0, 18 },363	},364	[JZ4760_CLK_IPU] = {365		"ipu", CGU_CLK_GATE,366		.parents = { JZ4760_CLK_HCLK, },367		.gate = { CGU_REG_CLKGR0, 29 },368	},369	[JZ4760_CLK_ADC] = {370		"adc", CGU_CLK_GATE,371		.parents = { JZ4760_CLK_EXT, },372		.gate = { CGU_REG_CLKGR0, 14 },373	},374	[JZ4760_CLK_AIC] = {375		"aic", CGU_CLK_GATE,376		.parents = { JZ4760_CLK_EXT, },377		.gate = { CGU_REG_CLKGR0, 8 },378	},379	[JZ4760_CLK_VPU] = {380		"vpu", CGU_CLK_GATE,381		.parents = { JZ4760_CLK_HCLK, },382		.gate = { CGU_REG_LCR, 30, false, 150 },383	},384	[JZ4760_CLK_MMC0] = {385		"mmc0", CGU_CLK_GATE,386		.parents = { JZ4760_CLK_MMC_MUX, },387		.gate = { CGU_REG_CLKGR0, 3 },388	},389	[JZ4760_CLK_MMC1] = {390		"mmc1", CGU_CLK_GATE,391		.parents = { JZ4760_CLK_MMC_MUX, },392		.gate = { CGU_REG_CLKGR0, 11 },393	},394	[JZ4760_CLK_MMC2] = {395		"mmc2", CGU_CLK_GATE,396		.parents = { JZ4760_CLK_MMC_MUX, },397		.gate = { CGU_REG_CLKGR0, 12 },398	},399	[JZ4760_CLK_UHC_PHY] = {400		"uhc_phy", CGU_CLK_GATE,401		.parents = { JZ4760_CLK_UHC, },402		.gate = { CGU_REG_OPCR, 5 },403	},404	[JZ4760_CLK_OTG_PHY] = {405		"usb_phy", CGU_CLK_GATE,406		.parents = { JZ4760_CLK_OTG },407		.gate = { CGU_REG_OPCR, 7, true, 50 },408	},409 410	/* Custom clocks */411	[JZ4760_CLK_EXT512] = {412		"ext/512", CGU_CLK_FIXDIV,413		.parents = { JZ4760_CLK_EXT },414		.fixdiv = { 512 },415	},416	[JZ4760_CLK_RTC] = {417		"rtc", CGU_CLK_MUX,418		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },419		.mux = { CGU_REG_OPCR, 2, 1},420	},421};422 423static void __init jz4760_cgu_init(struct device_node *np)424{425	struct ingenic_cgu *cgu;426	int retval;427 428	cgu = ingenic_cgu_new(jz4760_cgu_clocks,429			      ARRAY_SIZE(jz4760_cgu_clocks), np);430	if (!cgu) {431		pr_err("%s: failed to initialise CGU\n", __func__);432		return;433	}434 435	retval = ingenic_cgu_register_clocks(cgu);436	if (retval)437		pr_err("%s: failed to register CGU Clocks\n", __func__);438 439	ingenic_cgu_register_syscore_ops(cgu);440}441 442/* We only probe via devicetree, no need for a platform driver */443CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);444 445/* JZ4760B has some small differences, but we don't implement them. */446CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);447