brintos

brintos / linux-shallow public Read only

0
0
Text · 13.3 KiB · feb03ee Raw
565 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * X1000 SoC CGU driver4 * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>5 */6 7#include <linux/clk-provider.h>8#include <linux/delay.h>9#include <linux/io.h>10#include <linux/of.h>11#include <linux/rational.h>12 13#include <dt-bindings/clock/ingenic,x1000-cgu.h>14 15#include "cgu.h"16#include "pm.h"17 18/* CGU register offsets */19#define CGU_REG_CPCCR		0x0020#define CGU_REG_APLL		0x1021#define CGU_REG_MPLL		0x1422#define CGU_REG_CLKGR		0x2023#define CGU_REG_OPCR		0x2424#define CGU_REG_DDRCDR		0x2c25#define CGU_REG_USBPCR		0x3c26#define CGU_REG_USBPCR1		0x4827#define CGU_REG_USBCDR		0x5028#define CGU_REG_MACCDR		0x5429#define CGU_REG_I2SCDR		0x6030#define CGU_REG_LPCDR		0x6431#define CGU_REG_MSC0CDR		0x6832#define CGU_REG_I2SCDR1		0x7033#define CGU_REG_SSICDR		0x7434#define CGU_REG_CIMCDR		0x7c35#define CGU_REG_PCMCDR		0x8436#define CGU_REG_MSC1CDR		0xa437#define CGU_REG_CMP_INTR	0xb038#define CGU_REG_CMP_INTRE	0xb439#define CGU_REG_DRCG		0xd040#define CGU_REG_CPCSR		0xd441#define CGU_REG_PCMCDR1		0xe042#define CGU_REG_MACPHYC		0xe843 44/* bits within the OPCR register */45#define OPCR_SPENDN0		BIT(7)46#define OPCR_SPENDN1		BIT(6)47 48/* bits within the USBPCR register */49#define USBPCR_SIDDQ		BIT(21)50#define USBPCR_OTG_DISABLE	BIT(20)51 52/* bits within the USBPCR1 register */53#define USBPCR1_REFCLKSEL_SHIFT	2654#define USBPCR1_REFCLKSEL_MASK	(0x3 << USBPCR1_REFCLKSEL_SHIFT)55#define USBPCR1_REFCLKSEL_CORE	(0x2 << USBPCR1_REFCLKSEL_SHIFT)56#define USBPCR1_REFCLKDIV_SHIFT	2457#define USBPCR1_REFCLKDIV_MASK	(0x3 << USBPCR1_REFCLKDIV_SHIFT)58#define USBPCR1_REFCLKDIV_48	(0x2 << USBPCR1_REFCLKDIV_SHIFT)59#define USBPCR1_REFCLKDIV_24	(0x1 << USBPCR1_REFCLKDIV_SHIFT)60#define USBPCR1_REFCLKDIV_12	(0x0 << USBPCR1_REFCLKDIV_SHIFT)61 62static struct ingenic_cgu *cgu;63 64static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,65						unsigned long parent_rate)66{67	u32 usbpcr1;68	unsigned refclk_div;69 70	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);71	refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;72 73	switch (refclk_div) {74	case USBPCR1_REFCLKDIV_12:75		return 12000000;76 77	case USBPCR1_REFCLKDIV_24:78		return 24000000;79 80	case USBPCR1_REFCLKDIV_48:81		return 48000000;82	}83 84	return parent_rate;85}86 87static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,88				      unsigned long *parent_rate)89{90	if (req_rate < 18000000)91		return 12000000;92 93	if (req_rate < 36000000)94		return 24000000;95 96	return 48000000;97}98 99static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,100				   unsigned long parent_rate)101{102	unsigned long flags;103	u32 usbpcr1, div_bits;104 105	switch (req_rate) {106	case 12000000:107		div_bits = USBPCR1_REFCLKDIV_12;108		break;109 110	case 24000000:111		div_bits = USBPCR1_REFCLKDIV_24;112		break;113 114	case 48000000:115		div_bits = USBPCR1_REFCLKDIV_48;116		break;117 118	default:119		return -EINVAL;120	}121 122	spin_lock_irqsave(&cgu->lock, flags);123 124	usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);125	usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;126	usbpcr1 |= div_bits;127	writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);128 129	spin_unlock_irqrestore(&cgu->lock, flags);130	return 0;131}132 133static int x1000_usb_phy_enable(struct clk_hw *hw)134{135	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;136	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;137 138	writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);139	writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);140	return 0;141}142 143static void x1000_usb_phy_disable(struct clk_hw *hw)144{145	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;146	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;147 148	writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);149	writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);150}151 152static int x1000_usb_phy_is_enabled(struct clk_hw *hw)153{154	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;155	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;156 157	return (readl(reg_opcr) & OPCR_SPENDN0) &&158		!(readl(reg_usbpcr) & USBPCR_SIDDQ) &&159		!(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);160}161 162static const struct clk_ops x1000_otg_phy_ops = {163	.recalc_rate = x1000_otg_phy_recalc_rate,164	.round_rate = x1000_otg_phy_round_rate,165	.set_rate = x1000_otg_phy_set_rate,166 167	.enable		= x1000_usb_phy_enable,168	.disable	= x1000_usb_phy_disable,169	.is_enabled	= x1000_usb_phy_is_enabled,170};171 172static void173x1000_i2spll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,174			 unsigned long rate, unsigned long parent_rate,175			 unsigned int *pm, unsigned int *pn, unsigned int *pod)176{177	const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0);178	const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0);179	unsigned long m, n;180 181	rational_best_approximation(rate, parent_rate, m_max, n_max, &m, &n);182 183	/* n should not be less than 2*m */184	if (n < 2 * m)185		n = 2 * m;186 187	*pm = m;188	*pn = n;189	*pod = 1;190}191 192static void193x1000_i2spll_set_rate_hook(const struct ingenic_cgu_pll_info *pll_info,194			   unsigned long rate, unsigned long parent_rate)195{196	/*197	 * Writing 0 causes I2SCDR1.I2SDIV_D to be automatically recalculated198	 * based on the current value of I2SCDR.I2SDIV_N, which is needed for199	 * the divider to function correctly.200	 */201	writel(0, cgu->base + CGU_REG_I2SCDR1);202}203 204static const s8 pll_od_encoding[8] = {205	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,206};207 208static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {209 210	/* External clocks */211 212	[X1000_CLK_EXCLK] = { "ext", CGU_CLK_EXT },213	[X1000_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },214 215	/* PLLs */216 217	[X1000_CLK_APLL] = {218		"apll", CGU_CLK_PLL,219		.parents = { X1000_CLK_EXCLK },220		.pll = {221			.reg = CGU_REG_APLL,222			.rate_multiplier = 1,223			.m_shift = 24,224			.m_bits = 7,225			.m_offset = 1,226			.n_shift = 18,227			.n_bits = 5,228			.n_offset = 1,229			.od_shift = 16,230			.od_bits = 2,231			.od_max = 8,232			.od_encoding = pll_od_encoding,233			.bypass_reg = CGU_REG_APLL,234			.bypass_bit = 9,235			.enable_bit = 8,236			.stable_bit = 10,237		},238	},239 240	[X1000_CLK_MPLL] = {241		"mpll", CGU_CLK_PLL,242		.parents = { X1000_CLK_EXCLK },243		.pll = {244			.reg = CGU_REG_MPLL,245			.rate_multiplier = 1,246			.m_shift = 24,247			.m_bits = 7,248			.m_offset = 1,249			.n_shift = 18,250			.n_bits = 5,251			.n_offset = 1,252			.od_shift = 16,253			.od_bits = 2,254			.od_max = 8,255			.od_encoding = pll_od_encoding,256			.bypass_reg = CGU_REG_MPLL,257			.bypass_bit = 6,258			.enable_bit = 7,259			.stable_bit = 0,260		},261	},262 263	/* Custom (SoC-specific) OTG PHY */264 265	[X1000_CLK_OTGPHY] = {266		"otg_phy", CGU_CLK_CUSTOM,267		.parents = { -1, -1, X1000_CLK_EXCLK, -1 },268		.custom = { &x1000_otg_phy_ops },269	},270 271	/* Muxes & dividers */272 273	[X1000_CLK_SCLKA] = {274		"sclk_a", CGU_CLK_MUX,275		.parents = { -1, X1000_CLK_EXCLK, X1000_CLK_APLL, -1 },276		.mux = { CGU_REG_CPCCR, 30, 2 },277	},278 279	[X1000_CLK_CPUMUX] = {280		"cpu_mux", CGU_CLK_MUX,281		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },282		.mux = { CGU_REG_CPCCR, 28, 2 },283	},284 285	[X1000_CLK_CPU] = {286		"cpu", CGU_CLK_DIV | CGU_CLK_GATE,287		/*288		 * Disabling the CPU clock or any parent clocks will hang the289		 * system; mark it critical.290		 */291		.flags = CLK_IS_CRITICAL,292		.parents = { X1000_CLK_CPUMUX },293		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },294		.gate = { CGU_REG_CLKGR, 30 },295	},296 297	[X1000_CLK_L2CACHE] = {298		"l2cache", CGU_CLK_DIV,299		/*300		 * The L2 cache clock is critical if caches are enabled and301		 * disabling it or any parent clocks will hang the system.302		 */303		.flags = CLK_IS_CRITICAL,304		.parents = { X1000_CLK_CPUMUX },305		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },306	},307 308	[X1000_CLK_AHB0] = {309		"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,310		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },311		.mux = { CGU_REG_CPCCR, 26, 2 },312		.div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },313	},314 315	[X1000_CLK_AHB2PMUX] = {316		"ahb2_apb_mux", CGU_CLK_MUX,317		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },318		.mux = { CGU_REG_CPCCR, 24, 2 },319	},320 321	[X1000_CLK_AHB2] = {322		"ahb2", CGU_CLK_DIV,323		.parents = { X1000_CLK_AHB2PMUX },324		.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },325	},326 327	[X1000_CLK_PCLK] = {328		"pclk", CGU_CLK_DIV | CGU_CLK_GATE,329		.parents = { X1000_CLK_AHB2PMUX },330		.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },331		.gate = { CGU_REG_CLKGR, 28 },332	},333 334	[X1000_CLK_DDR] = {335		"ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,336		/*337		 * Disabling DDR clock or its parents will render DRAM338		 * inaccessible; mark it critical.339		 */340		.flags = CLK_IS_CRITICAL,341		.parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },342		.mux = { CGU_REG_DDRCDR, 30, 2 },343		.div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },344		.gate = { CGU_REG_CLKGR, 31 },345	},346 347	[X1000_CLK_MAC] = {348		"mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,349		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },350		.mux = { CGU_REG_MACCDR, 31, 1 },351		.div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },352		.gate = { CGU_REG_CLKGR, 25 },353	},354 355	[X1000_CLK_I2SPLLMUX] = {356		"i2s_pll_mux", CGU_CLK_MUX,357		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },358		.mux = { CGU_REG_I2SCDR, 31, 1 },359	},360 361	[X1000_CLK_I2SPLL] = {362		"i2s_pll", CGU_CLK_PLL,363		.parents = { X1000_CLK_I2SPLLMUX },364		.pll = {365			.reg = CGU_REG_I2SCDR,366			.rate_multiplier = 1,367			.m_shift = 13,368			.m_bits = 9,369			.n_shift = 0,370			.n_bits = 13,371			.calc_m_n_od = x1000_i2spll_calc_m_n_od,372			.set_rate_hook = x1000_i2spll_set_rate_hook,373		},374	},375 376	[X1000_CLK_I2S] = {377		"i2s", CGU_CLK_MUX,378		.parents = { X1000_CLK_EXCLK, -1, -1, X1000_CLK_I2SPLL },379		/*380		 * NOTE: the mux is at bit 30; bit 29 enables the M/N divider.381		 * Therefore, the divider is disabled when EXCLK is selected.382		 */383		.mux = { CGU_REG_I2SCDR, 29, 2 },384	},385 386	[X1000_CLK_LCD] = {387		"lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,388		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },389		.mux = { CGU_REG_LPCDR, 31, 1 },390		.div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },391		.gate = { CGU_REG_CLKGR, 23 },392	},393 394	[X1000_CLK_MSCMUX] = {395		"msc_mux", CGU_CLK_MUX,396		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },397		.mux = { CGU_REG_MSC0CDR, 31, 1 },398	},399 400	[X1000_CLK_MSC0] = {401		"msc0", CGU_CLK_DIV | CGU_CLK_GATE,402		.parents = { X1000_CLK_MSCMUX },403		.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },404		.gate = { CGU_REG_CLKGR, 4 },405	},406 407	[X1000_CLK_MSC1] = {408		"msc1", CGU_CLK_DIV | CGU_CLK_GATE,409		.parents = { X1000_CLK_MSCMUX, -1, -1, -1 },410		.div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },411		.gate = { CGU_REG_CLKGR, 5 },412	},413 414	[X1000_CLK_OTG] = {415		"otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,416		.parents = { X1000_CLK_EXCLK, -1, X1000_CLK_APLL, X1000_CLK_MPLL },417		.mux = { CGU_REG_USBCDR, 30, 2 },418		.div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 },419		.gate = { CGU_REG_CLKGR, 3 },420	},421 422	[X1000_CLK_SSIPLL] = {423		"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,424		.parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },425		.mux = { CGU_REG_SSICDR, 31, 1 },426		.div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },427	},428 429	[X1000_CLK_SSIPLL_DIV2] = {430		"ssi_pll_div2", CGU_CLK_FIXDIV,431		.parents = { X1000_CLK_SSIPLL },432		.fixdiv = { 2 },433	},434 435	[X1000_CLK_SSIMUX] = {436		"ssi_mux", CGU_CLK_MUX,437		.parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2 },438		.mux = { CGU_REG_SSICDR, 30, 1 },439	},440 441	[X1000_CLK_EXCLK_DIV512] = {442		"exclk_div512", CGU_CLK_FIXDIV,443		.parents = { X1000_CLK_EXCLK },444		.fixdiv = { 512 },445	},446 447	[X1000_CLK_RTC] = {448		"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,449		.parents = { X1000_CLK_EXCLK_DIV512, X1000_CLK_RTCLK },450		.mux = { CGU_REG_OPCR, 2, 1},451		.gate = { CGU_REG_CLKGR, 27 },452	},453 454	/* Gate-only clocks */455 456	[X1000_CLK_EMC] = {457		"emc", CGU_CLK_GATE,458		.parents = { X1000_CLK_AHB2 },459		.gate = { CGU_REG_CLKGR, 0 },460	},461 462	[X1000_CLK_EFUSE] = {463		"efuse", CGU_CLK_GATE,464		.parents = { X1000_CLK_AHB2 },465		.gate = { CGU_REG_CLKGR, 1 },466	},467 468	[X1000_CLK_SFC] = {469		"sfc", CGU_CLK_GATE,470		.parents = { X1000_CLK_SSIPLL },471		.gate = { CGU_REG_CLKGR, 2 },472	},473 474	[X1000_CLK_I2C0] = {475		"i2c0", CGU_CLK_GATE,476		.parents = { X1000_CLK_PCLK },477		.gate = { CGU_REG_CLKGR, 7 },478	},479 480	[X1000_CLK_I2C1] = {481		"i2c1", CGU_CLK_GATE,482		.parents = { X1000_CLK_PCLK },483		.gate = { CGU_REG_CLKGR, 8 },484	},485 486	[X1000_CLK_I2C2] = {487		"i2c2", CGU_CLK_GATE,488		.parents = { X1000_CLK_PCLK },489		.gate = { CGU_REG_CLKGR, 9 },490	},491 492	[X1000_CLK_AIC] = {493		"aic", CGU_CLK_GATE,494		.parents = { X1000_CLK_EXCLK },495		.gate = { CGU_REG_CLKGR, 11 },496	},497 498	[X1000_CLK_UART0] = {499		"uart0", CGU_CLK_GATE,500		.parents = { X1000_CLK_EXCLK },501		.gate = { CGU_REG_CLKGR, 14 },502	},503 504	[X1000_CLK_UART1] = {505		"uart1", CGU_CLK_GATE,506		.parents = { X1000_CLK_EXCLK},507		.gate = { CGU_REG_CLKGR, 15 },508	},509 510	[X1000_CLK_UART2] = {511		"uart2", CGU_CLK_GATE,512		.parents = { X1000_CLK_EXCLK },513		.gate = { CGU_REG_CLKGR, 16 },514	},515 516	[X1000_CLK_TCU] = {517		"tcu", CGU_CLK_GATE,518		.parents = { X1000_CLK_EXCLK },519		.gate = { CGU_REG_CLKGR, 18 },520	},521 522	[X1000_CLK_SSI] = {523		"ssi", CGU_CLK_GATE,524		.parents = { X1000_CLK_SSIMUX },525		.gate = { CGU_REG_CLKGR, 19 },526	},527 528	[X1000_CLK_OST] = {529		"ost", CGU_CLK_GATE,530		.parents = { X1000_CLK_EXCLK },531		.gate = { CGU_REG_CLKGR, 20 },532	},533 534	[X1000_CLK_PDMA] = {535		"pdma", CGU_CLK_GATE,536		.parents = { X1000_CLK_EXCLK },537		.gate = { CGU_REG_CLKGR, 21 },538	},539};540 541static void __init x1000_cgu_init(struct device_node *np)542{543	int retval;544 545	cgu = ingenic_cgu_new(x1000_cgu_clocks,546			      ARRAY_SIZE(x1000_cgu_clocks), np);547	if (!cgu) {548		pr_err("%s: failed to initialise CGU\n", __func__);549		return;550	}551 552	retval = ingenic_cgu_register_clocks(cgu);553	if (retval) {554		pr_err("%s: failed to register CGU Clocks\n", __func__);555		return;556	}557 558	ingenic_cgu_register_syscore_ops(cgu);559}560/*561 * CGU has some children devices, this is useful for probing children devices562 * in the case where the device node is compatible with "simple-mfd".563 */564CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-cgu", x1000_cgu_init);565