brintos

brintos / linux-shallow public Read only

0
0
Text · 11.3 KiB · 0fd46e5 Raw
473 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * X1830 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 12#include <dt-bindings/clock/ingenic,x1830-cgu.h>13 14#include "cgu.h"15#include "pm.h"16 17/* CGU register offsets */18#define CGU_REG_CPCCR		0x0019#define CGU_REG_CPPCR		0x0c20#define CGU_REG_APLL		0x1021#define CGU_REG_MPLL		0x1422#define CGU_REG_CLKGR0		0x2023#define CGU_REG_OPCR		0x2424#define CGU_REG_CLKGR1		0x2825#define CGU_REG_DDRCDR		0x2c26#define CGU_REG_USBPCR		0x3c27#define CGU_REG_USBRDT		0x4028#define CGU_REG_USBVBFIL	0x4429#define CGU_REG_USBPCR1		0x4830#define CGU_REG_MACCDR		0x5431#define CGU_REG_EPLL		0x5832#define CGU_REG_I2SCDR		0x6033#define CGU_REG_LPCDR		0x6434#define CGU_REG_MSC0CDR		0x6835#define CGU_REG_I2SCDR1		0x7036#define CGU_REG_SSICDR		0x7437#define CGU_REG_CIMCDR		0x7c38#define CGU_REG_MSC1CDR		0xa439#define CGU_REG_CMP_INTR	0xb040#define CGU_REG_CMP_INTRE	0xb441#define CGU_REG_DRCG		0xd042#define CGU_REG_CPCSR		0xd443#define CGU_REG_VPLL		0xe044#define CGU_REG_MACPHYC		0xe845 46/* bits within the OPCR register */47#define OPCR_GATE_USBPHYCLK	BIT(23)48#define OPCR_SPENDN0		BIT(7)49#define OPCR_SPENDN1		BIT(6)50 51/* bits within the USBPCR register */52#define USBPCR_SIDDQ		BIT(21)53#define USBPCR_OTG_DISABLE	BIT(20)54 55static struct ingenic_cgu *cgu;56 57static int x1830_usb_phy_enable(struct clk_hw *hw)58{59	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;60	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;61 62	writel((readl(reg_opcr) | OPCR_SPENDN0) & ~OPCR_GATE_USBPHYCLK, reg_opcr);63	writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);64	return 0;65}66 67static void x1830_usb_phy_disable(struct clk_hw *hw)68{69	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;70	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;71 72	writel((readl(reg_opcr) & ~OPCR_SPENDN0) | OPCR_GATE_USBPHYCLK, reg_opcr);73	writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);74}75 76static int x1830_usb_phy_is_enabled(struct clk_hw *hw)77{78	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;79	void __iomem *reg_usbpcr	= cgu->base + CGU_REG_USBPCR;80 81	return (readl(reg_opcr) & OPCR_SPENDN0) &&82		!(readl(reg_usbpcr) & USBPCR_SIDDQ) &&83		!(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);84}85 86static const struct clk_ops x1830_otg_phy_ops = {87	.enable		= x1830_usb_phy_enable,88	.disable	= x1830_usb_phy_disable,89	.is_enabled	= x1830_usb_phy_is_enabled,90};91 92static const s8 pll_od_encoding[64] = {93	0x0, 0x1,  -1, 0x2,  -1,  -1,  -1, 0x3,94	 -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x4,95	 -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,96	 -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x5,97	 -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,98	 -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,99	 -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,100	 -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x6,101};102 103static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = {104 105	/* External clocks */106 107	[X1830_CLK_EXCLK] = { "ext", CGU_CLK_EXT },108	[X1830_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },109 110	/* PLLs */111 112	[X1830_CLK_APLL] = {113		"apll", CGU_CLK_PLL,114		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },115		.pll = {116			.reg = CGU_REG_APLL,117			.rate_multiplier = 2,118			.m_shift = 20,119			.m_bits = 9,120			.m_offset = 1,121			.n_shift = 14,122			.n_bits = 6,123			.n_offset = 1,124			.od_shift = 11,125			.od_bits = 3,126			.od_max = 64,127			.od_encoding = pll_od_encoding,128			.bypass_reg = CGU_REG_CPPCR,129			.bypass_bit = 30,130			.enable_bit = 0,131			.stable_bit = 3,132		},133	},134 135	[X1830_CLK_MPLL] = {136		"mpll", CGU_CLK_PLL,137		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },138		.pll = {139			.reg = CGU_REG_MPLL,140			.rate_multiplier = 2,141			.m_shift = 20,142			.m_bits = 9,143			.m_offset = 1,144			.n_shift = 14,145			.n_bits = 6,146			.n_offset = 1,147			.od_shift = 11,148			.od_bits = 3,149			.od_max = 64,150			.od_encoding = pll_od_encoding,151			.bypass_reg = CGU_REG_CPPCR,152			.bypass_bit = 28,153			.enable_bit = 0,154			.stable_bit = 3,155		},156	},157 158	[X1830_CLK_EPLL] = {159		"epll", CGU_CLK_PLL,160		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },161		.pll = {162			.reg = CGU_REG_EPLL,163			.rate_multiplier = 2,164			.m_shift = 20,165			.m_bits = 9,166			.m_offset = 1,167			.n_shift = 14,168			.n_bits = 6,169			.n_offset = 1,170			.od_shift = 11,171			.od_bits = 3,172			.od_max = 64,173			.od_encoding = pll_od_encoding,174			.bypass_reg = CGU_REG_CPPCR,175			.bypass_bit = 24,176			.enable_bit = 0,177			.stable_bit = 3,178		},179	},180 181	[X1830_CLK_VPLL] = {182		"vpll", CGU_CLK_PLL,183		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },184		.pll = {185			.reg = CGU_REG_VPLL,186			.rate_multiplier = 2,187			.m_shift = 20,188			.m_bits = 9,189			.m_offset = 1,190			.n_shift = 14,191			.n_bits = 6,192			.n_offset = 1,193			.od_shift = 11,194			.od_bits = 3,195			.od_max = 64,196			.od_encoding = pll_od_encoding,197			.bypass_reg = CGU_REG_CPPCR,198			.bypass_bit = 26,199			.enable_bit = 0,200			.stable_bit = 3,201		},202	},203 204	/* Custom (SoC-specific) OTG PHY */205 206	[X1830_CLK_OTGPHY] = {207		"otg_phy", CGU_CLK_CUSTOM,208		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },209		.custom = { &x1830_otg_phy_ops },210	},211 212	/* Muxes & dividers */213 214	[X1830_CLK_SCLKA] = {215		"sclk_a", CGU_CLK_MUX,216		.parents = { -1, X1830_CLK_EXCLK, X1830_CLK_APLL, -1 },217		.mux = { CGU_REG_CPCCR, 30, 2 },218	},219 220	[X1830_CLK_CPUMUX] = {221		"cpu_mux", CGU_CLK_MUX,222		.parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },223		.mux = { CGU_REG_CPCCR, 28, 2 },224	},225 226	[X1830_CLK_CPU] = {227		"cpu", CGU_CLK_DIV | CGU_CLK_GATE,228		.flags = CLK_IS_CRITICAL,229		.parents = { X1830_CLK_CPUMUX, -1, -1, -1 },230		.div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },231		.gate = { CGU_REG_CLKGR1, 15 },232	},233 234	[X1830_CLK_L2CACHE] = {235		"l2cache", CGU_CLK_DIV,236		/*237		 * The L2 cache clock is critical if caches are enabled and238		 * disabling it or any parent clocks will hang the system.239		 */240		.flags = CLK_IS_CRITICAL,241		.parents = { X1830_CLK_CPUMUX, -1, -1, -1 },242		.div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },243	},244 245	[X1830_CLK_AHB0] = {246		"ahb0", CGU_CLK_MUX | CGU_CLK_DIV,247		.parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },248		.mux = { CGU_REG_CPCCR, 26, 2 },249		.div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },250	},251 252	[X1830_CLK_AHB2PMUX] = {253		"ahb2_apb_mux", CGU_CLK_MUX,254		.parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },255		.mux = { CGU_REG_CPCCR, 24, 2 },256	},257 258	[X1830_CLK_AHB2] = {259		"ahb2", CGU_CLK_DIV,260		.parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },261		.div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },262	},263 264	[X1830_CLK_PCLK] = {265		"pclk", CGU_CLK_DIV | CGU_CLK_GATE,266		.parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },267		.div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },268		.gate = { CGU_REG_CLKGR1, 14 },269	},270 271	[X1830_CLK_DDR] = {272		"ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,273		/*274		 * Disabling DDR clock or its parents will render DRAM275		 * inaccessible; mark it critical.276		 */277		.flags = CLK_IS_CRITICAL,278		.parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },279		.mux = { CGU_REG_DDRCDR, 30, 2 },280		.div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },281		.gate = { CGU_REG_CLKGR0, 31 },282	},283 284	[X1830_CLK_MAC] = {285		"mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,286		.parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,287					 X1830_CLK_VPLL, X1830_CLK_EPLL },288		.mux = { CGU_REG_MACCDR, 30, 2 },289		.div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },290		.gate = { CGU_REG_CLKGR1, 4 },291	},292 293	[X1830_CLK_LCD] = {294		"lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,295		.parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,296					 X1830_CLK_VPLL, X1830_CLK_EPLL },297		.mux = { CGU_REG_LPCDR, 30, 2 },298		.div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },299		.gate = { CGU_REG_CLKGR1, 9 },300	},301 302	[X1830_CLK_MSCMUX] = {303		"msc_mux", CGU_CLK_MUX,304		.parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,305					 X1830_CLK_VPLL, X1830_CLK_EPLL },306		.mux = { CGU_REG_MSC0CDR, 30, 2 },307	},308 309	[X1830_CLK_MSC0] = {310		"msc0", CGU_CLK_DIV | CGU_CLK_GATE,311		.parents = { X1830_CLK_MSCMUX, -1, -1, -1 },312		.div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },313		.gate = { CGU_REG_CLKGR0, 4 },314	},315 316	[X1830_CLK_MSC1] = {317		"msc1", CGU_CLK_DIV | CGU_CLK_GATE,318		.parents = { X1830_CLK_MSCMUX, -1, -1, -1 },319		.div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },320		.gate = { CGU_REG_CLKGR0, 5 },321	},322 323	[X1830_CLK_SSIPLL] = {324		"ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,325		.parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,326					 X1830_CLK_VPLL, X1830_CLK_EPLL },327		.mux = { CGU_REG_SSICDR, 30, 2 },328		.div = { CGU_REG_SSICDR, 0, 1, 8, 28, 27, 26 },329	},330 331	[X1830_CLK_SSIPLL_DIV2] = {332		"ssi_pll_div2", CGU_CLK_FIXDIV,333		.parents = { X1830_CLK_SSIPLL },334		.fixdiv = { 2 },335	},336 337	[X1830_CLK_SSIMUX] = {338		"ssi_mux", CGU_CLK_MUX,339		.parents = { X1830_CLK_EXCLK, X1830_CLK_SSIPLL_DIV2, -1, -1 },340		.mux = { CGU_REG_SSICDR, 29, 1 },341	},342 343	[X1830_CLK_EXCLK_DIV512] = {344		"exclk_div512", CGU_CLK_FIXDIV,345		.parents = { X1830_CLK_EXCLK },346		.fixdiv = { 512 },347	},348 349	[X1830_CLK_RTC] = {350		"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,351		.parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK },352		.mux = { CGU_REG_OPCR, 2, 1},353		.gate = { CGU_REG_CLKGR0, 29 },354	},355 356	/* Gate-only clocks */357 358	[X1830_CLK_EMC] = {359		"emc", CGU_CLK_GATE,360		.parents = { X1830_CLK_AHB2, -1, -1, -1 },361		.gate = { CGU_REG_CLKGR0, 0 },362	},363 364	[X1830_CLK_EFUSE] = {365		"efuse", CGU_CLK_GATE,366		.parents = { X1830_CLK_AHB2, -1, -1, -1 },367		.gate = { CGU_REG_CLKGR0, 1 },368	},369 370	[X1830_CLK_OTG] = {371		"otg", CGU_CLK_GATE,372		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },373		.gate = { CGU_REG_CLKGR0, 3 },374	},375 376	[X1830_CLK_SSI0] = {377		"ssi0", CGU_CLK_GATE,378		.parents = { X1830_CLK_SSIMUX, -1, -1, -1 },379		.gate = { CGU_REG_CLKGR0, 6 },380	},381 382	[X1830_CLK_SMB0] = {383		"smb0", CGU_CLK_GATE,384		.parents = { X1830_CLK_PCLK, -1, -1, -1 },385		.gate = { CGU_REG_CLKGR0, 7 },386	},387 388	[X1830_CLK_SMB1] = {389		"smb1", CGU_CLK_GATE,390		.parents = { X1830_CLK_PCLK, -1, -1, -1 },391		.gate = { CGU_REG_CLKGR0, 8 },392	},393 394	[X1830_CLK_SMB2] = {395		"smb2", CGU_CLK_GATE,396		.parents = { X1830_CLK_PCLK, -1, -1, -1 },397		.gate = { CGU_REG_CLKGR0, 9 },398	},399 400	[X1830_CLK_UART0] = {401		"uart0", CGU_CLK_GATE,402		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },403		.gate = { CGU_REG_CLKGR0, 14 },404	},405 406	[X1830_CLK_UART1] = {407		"uart1", CGU_CLK_GATE,408		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },409		.gate = { CGU_REG_CLKGR0, 15 },410	},411 412	[X1830_CLK_SSI1] = {413		"ssi1", CGU_CLK_GATE,414		.parents = { X1830_CLK_SSIMUX, -1, -1, -1 },415		.gate = { CGU_REG_CLKGR0, 19 },416	},417 418	[X1830_CLK_SFC] = {419		"sfc", CGU_CLK_GATE,420		.parents = { X1830_CLK_SSIPLL, -1, -1, -1 },421		.gate = { CGU_REG_CLKGR0, 20 },422	},423 424	[X1830_CLK_PDMA] = {425		"pdma", CGU_CLK_GATE,426		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },427		.gate = { CGU_REG_CLKGR0, 21 },428	},429 430	[X1830_CLK_TCU] = {431		"tcu", CGU_CLK_GATE,432		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },433		.gate = { CGU_REG_CLKGR0, 30 },434	},435 436	[X1830_CLK_DTRNG] = {437		"dtrng", CGU_CLK_GATE,438		.parents = { X1830_CLK_PCLK, -1, -1, -1 },439		.gate = { CGU_REG_CLKGR1, 1 },440	},441 442	[X1830_CLK_OST] = {443		"ost", CGU_CLK_GATE,444		.parents = { X1830_CLK_EXCLK, -1, -1, -1 },445		.gate = { CGU_REG_CLKGR1, 11 },446	},447};448 449static void __init x1830_cgu_init(struct device_node *np)450{451	int retval;452 453	cgu = ingenic_cgu_new(x1830_cgu_clocks,454			      ARRAY_SIZE(x1830_cgu_clocks), np);455	if (!cgu) {456		pr_err("%s: failed to initialise CGU\n", __func__);457		return;458	}459 460	retval = ingenic_cgu_register_clocks(cgu);461	if (retval) {462		pr_err("%s: failed to register CGU Clocks\n", __func__);463		return;464	}465 466	ingenic_cgu_register_syscore_ops(cgu);467}468/*469 * CGU has some children devices, this is useful for probing children devices470 * in the case where the device node is compatible with "simple-mfd".471 */472CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init);473