brintos

brintos / linux-shallow public Read only

0
0
Text · 11.7 KiB · 6ae1740 Raw
464 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * JZ4770 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 <dt-bindings/clock/ingenic,jz4770-cgu.h>14 15#include "cgu.h"16#include "pm.h"17 18/*19 * CPM registers offset address definition20 */21#define CGU_REG_CPCCR		0x0022#define CGU_REG_LCR		0x0423#define CGU_REG_CPPCR0		0x1024#define CGU_REG_CLKGR0		0x2025#define CGU_REG_OPCR		0x2426#define CGU_REG_CLKGR1		0x2827#define CGU_REG_CPPCR1		0x3028#define CGU_REG_USBPCR1		0x4829#define CGU_REG_USBCDR		0x5030#define CGU_REG_I2SCDR		0x6031#define CGU_REG_LPCDR		0x6432#define CGU_REG_MSC0CDR		0x6833#define CGU_REG_UHCCDR		0x6c34#define CGU_REG_SSICDR		0x7435#define CGU_REG_CIMCDR		0x7c36#define CGU_REG_GPSCDR		0x8037#define CGU_REG_PCMCDR		0x8438#define CGU_REG_GPUCDR		0x8839#define CGU_REG_MSC1CDR		0xA440#define CGU_REG_MSC2CDR		0xA841#define CGU_REG_BCHCDR		0xAC42 43/* bits within the OPCR register */44#define OPCR_SPENDH		BIT(5)		/* UHC PHY suspend */45 46/* bits within the USBPCR1 register */47#define USBPCR1_UHC_POWER	BIT(5)		/* UHC PHY power down */48 49static struct ingenic_cgu *cgu;50 51static int jz4770_uhc_phy_enable(struct clk_hw *hw)52{53	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;54	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;55 56	writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);57	writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);58	return 0;59}60 61static void jz4770_uhc_phy_disable(struct clk_hw *hw)62{63	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;64	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;65 66	writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);67	writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);68}69 70static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)71{72	void __iomem *reg_opcr		= cgu->base + CGU_REG_OPCR;73	void __iomem *reg_usbpcr1	= cgu->base + CGU_REG_USBPCR1;74 75	return !(readl(reg_opcr) & OPCR_SPENDH) &&76		(readl(reg_usbpcr1) & USBPCR1_UHC_POWER);77}78 79static const struct clk_ops jz4770_uhc_phy_ops = {80	.enable = jz4770_uhc_phy_enable,81	.disable = jz4770_uhc_phy_disable,82	.is_enabled = jz4770_uhc_phy_is_enabled,83};84 85static const s8 pll_od_encoding[8] = {86	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,87};88 89static const u8 jz4770_cgu_cpccr_div_table[] = {90	1, 2, 3, 4, 6, 8, 12,91};92 93static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {94 95	/* External clocks */96 97	[JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },98	[JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },99 100	/* PLLs */101 102	[JZ4770_CLK_PLL0] = {103		"pll0", CGU_CLK_PLL,104		.parents = { JZ4770_CLK_EXT },105		.pll = {106			.reg = CGU_REG_CPPCR0,107			.rate_multiplier = 1,108			.m_shift = 24,109			.m_bits = 7,110			.m_offset = 1,111			.n_shift = 18,112			.n_bits = 5,113			.n_offset = 1,114			.od_shift = 16,115			.od_bits = 2,116			.od_max = 8,117			.od_encoding = pll_od_encoding,118			.bypass_reg = CGU_REG_CPPCR0,119			.bypass_bit = 9,120			.enable_bit = 8,121			.stable_bit = 10,122		},123	},124 125	[JZ4770_CLK_PLL1] = {126		/* TODO: PLL1 can depend on PLL0 */127		"pll1", CGU_CLK_PLL,128		.parents = { JZ4770_CLK_EXT },129		.pll = {130			.reg = CGU_REG_CPPCR1,131			.rate_multiplier = 1,132			.m_shift = 24,133			.m_bits = 7,134			.m_offset = 1,135			.n_shift = 18,136			.n_bits = 5,137			.n_offset = 1,138			.od_shift = 16,139			.od_bits = 2,140			.od_max = 8,141			.od_encoding = pll_od_encoding,142			.bypass_bit = -1,143			.enable_bit = 7,144			.stable_bit = 6,145		},146	},147 148	/* Main clocks */149 150	[JZ4770_CLK_CCLK] = {151		"cclk", CGU_CLK_DIV,152		/*153		 * Disabling the CPU clock or any parent clocks will hang the154		 * system; mark it critical.155		 */156		.flags = CLK_IS_CRITICAL,157		.parents = { JZ4770_CLK_PLL0, },158		.div = {159			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,160			jz4770_cgu_cpccr_div_table,161		},162	},163	[JZ4770_CLK_H0CLK] = {164		"h0clk", CGU_CLK_DIV,165		.parents = { JZ4770_CLK_PLL0, },166		.div = {167			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,168			jz4770_cgu_cpccr_div_table,169		},170	},171	[JZ4770_CLK_H1CLK] = {172		"h1clk", CGU_CLK_DIV | CGU_CLK_GATE,173		.parents = { JZ4770_CLK_PLL0, },174		.div = {175			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,176			jz4770_cgu_cpccr_div_table,177		},178		.gate = { CGU_REG_CLKGR1, 7 },179	},180	[JZ4770_CLK_H2CLK] = {181		"h2clk", CGU_CLK_DIV,182		.parents = { JZ4770_CLK_PLL0, },183		.div = {184			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,185			jz4770_cgu_cpccr_div_table,186		},187	},188	[JZ4770_CLK_C1CLK] = {189		"c1clk", CGU_CLK_DIV | CGU_CLK_GATE,190		.parents = { JZ4770_CLK_PLL0, },191		.div = {192			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,193			jz4770_cgu_cpccr_div_table,194		},195		.gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle196	},197	[JZ4770_CLK_PCLK] = {198		"pclk", CGU_CLK_DIV,199		.parents = { JZ4770_CLK_PLL0, },200		.div = {201			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,202			jz4770_cgu_cpccr_div_table,203		},204	},205 206	/* Those divided clocks can connect to PLL0 or PLL1 */207 208	[JZ4770_CLK_MMC0_MUX] = {209		"mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,210		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },211		.mux = { CGU_REG_MSC0CDR, 30, 1 },212		.div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },213		.gate = { CGU_REG_MSC0CDR, 31 },214	},215	[JZ4770_CLK_MMC1_MUX] = {216		"mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,217		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },218		.mux = { CGU_REG_MSC1CDR, 30, 1 },219		.div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },220		.gate = { CGU_REG_MSC1CDR, 31 },221	},222	[JZ4770_CLK_MMC2_MUX] = {223		"mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,224		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },225		.mux = { CGU_REG_MSC2CDR, 30, 1 },226		.div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },227		.gate = { CGU_REG_MSC2CDR, 31 },228	},229	[JZ4770_CLK_CIM] = {230		"cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,231		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },232		.mux = { CGU_REG_CIMCDR, 31, 1 },233		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },234		.gate = { CGU_REG_CLKGR0, 26 },235	},236	[JZ4770_CLK_UHC] = {237		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,238		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },239		.mux = { CGU_REG_UHCCDR, 29, 1 },240		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },241		.gate = { CGU_REG_CLKGR0, 24 },242	},243	[JZ4770_CLK_GPU] = {244		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,245		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },246		.mux = { CGU_REG_GPUCDR, 31, 1 },247		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },248		.gate = { CGU_REG_CLKGR1, 9 },249	},250	[JZ4770_CLK_BCH] = {251		"bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,252		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },253		.mux = { CGU_REG_BCHCDR, 31, 1 },254		.div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },255		.gate = { CGU_REG_CLKGR0, 1 },256	},257	[JZ4770_CLK_LPCLK_MUX] = {258		"lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,259		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },260		.mux = { CGU_REG_LPCDR, 29, 1 },261		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },262		.gate = { CGU_REG_CLKGR0, 28 },263	},264	[JZ4770_CLK_GPS] = {265		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,266		.parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },267		.mux = { CGU_REG_GPSCDR, 31, 1 },268		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },269		.gate = { CGU_REG_CLKGR0, 22 },270	},271 272	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */273 274	[JZ4770_CLK_SSI_MUX] = {275		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,276		.parents = { JZ4770_CLK_EXT, -1,277			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },278		.mux = { CGU_REG_SSICDR, 30, 2 },279		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },280	},281	[JZ4770_CLK_PCM_MUX] = {282		"pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,283		.parents = { JZ4770_CLK_EXT, -1,284			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },285		.mux = { CGU_REG_PCMCDR, 30, 2 },286		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },287	},288	[JZ4770_CLK_I2S] = {289		"i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,290		.parents = { JZ4770_CLK_EXT, -1,291			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },292		.mux = { CGU_REG_I2SCDR, 30, 2 },293		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },294		.gate = { CGU_REG_CLKGR1, 13 },295	},296	[JZ4770_CLK_OTG] = {297		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,298		.parents = { JZ4770_CLK_EXT, -1,299			JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },300		.mux = { CGU_REG_USBCDR, 30, 2 },301		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },302		.gate = { CGU_REG_CLKGR0, 2 },303	},304 305	/* Gate-only clocks */306 307	[JZ4770_CLK_SSI0] = {308		"ssi0", CGU_CLK_GATE,309		.parents = { JZ4770_CLK_SSI_MUX, },310		.gate = { CGU_REG_CLKGR0, 4 },311	},312	[JZ4770_CLK_SSI1] = {313		"ssi1", CGU_CLK_GATE,314		.parents = { JZ4770_CLK_SSI_MUX, },315		.gate = { CGU_REG_CLKGR0, 19 },316	},317	[JZ4770_CLK_SSI2] = {318		"ssi2", CGU_CLK_GATE,319		.parents = { JZ4770_CLK_SSI_MUX, },320		.gate = { CGU_REG_CLKGR0, 20 },321	},322	[JZ4770_CLK_PCM0] = {323		"pcm0", CGU_CLK_GATE,324		.parents = { JZ4770_CLK_PCM_MUX, },325		.gate = { CGU_REG_CLKGR1, 8 },326	},327	[JZ4770_CLK_PCM1] = {328		"pcm1", CGU_CLK_GATE,329		.parents = { JZ4770_CLK_PCM_MUX, },330		.gate = { CGU_REG_CLKGR1, 10 },331	},332	[JZ4770_CLK_DMA] = {333		"dma", CGU_CLK_GATE,334		.parents = { JZ4770_CLK_H2CLK, },335		.gate = { CGU_REG_CLKGR0, 21 },336	},337	[JZ4770_CLK_BDMA] = {338		"bdma", CGU_CLK_GATE,339		.parents = { JZ4770_CLK_H2CLK, },340		.gate = { CGU_REG_CLKGR1, 0 },341	},342	[JZ4770_CLK_I2C0] = {343		"i2c0", CGU_CLK_GATE,344		.parents = { JZ4770_CLK_EXT, },345		.gate = { CGU_REG_CLKGR0, 5 },346	},347	[JZ4770_CLK_I2C1] = {348		"i2c1", CGU_CLK_GATE,349		.parents = { JZ4770_CLK_EXT, },350		.gate = { CGU_REG_CLKGR0, 6 },351	},352	[JZ4770_CLK_I2C2] = {353		"i2c2", CGU_CLK_GATE,354		.parents = { JZ4770_CLK_EXT, },355		.gate = { CGU_REG_CLKGR1, 15 },356	},357	[JZ4770_CLK_UART0] = {358		"uart0", CGU_CLK_GATE,359		.parents = { JZ4770_CLK_EXT, },360		.gate = { CGU_REG_CLKGR0, 15 },361	},362	[JZ4770_CLK_UART1] = {363		"uart1", CGU_CLK_GATE,364		.parents = { JZ4770_CLK_EXT, },365		.gate = { CGU_REG_CLKGR0, 16 },366	},367	[JZ4770_CLK_UART2] = {368		"uart2", CGU_CLK_GATE,369		.parents = { JZ4770_CLK_EXT, },370		.gate = { CGU_REG_CLKGR0, 17 },371	},372	[JZ4770_CLK_UART3] = {373		"uart3", CGU_CLK_GATE,374		.parents = { JZ4770_CLK_EXT, },375		.gate = { CGU_REG_CLKGR0, 18 },376	},377	[JZ4770_CLK_IPU] = {378		"ipu", CGU_CLK_GATE,379		.parents = { JZ4770_CLK_H0CLK, },380		.gate = { CGU_REG_CLKGR0, 29 },381	},382	[JZ4770_CLK_ADC] = {383		"adc", CGU_CLK_GATE,384		.parents = { JZ4770_CLK_EXT, },385		.gate = { CGU_REG_CLKGR0, 14 },386	},387	[JZ4770_CLK_AIC] = {388		"aic", CGU_CLK_GATE,389		.parents = { JZ4770_CLK_EXT, },390		.gate = { CGU_REG_CLKGR0, 8 },391	},392	[JZ4770_CLK_AUX] = {393		"aux", CGU_CLK_GATE,394		.parents = { JZ4770_CLK_C1CLK, },395		.gate = { CGU_REG_CLKGR1, 14 },396	},397	[JZ4770_CLK_VPU] = {398		"vpu", CGU_CLK_GATE,399		.parents = { JZ4770_CLK_H1CLK, },400		.gate = { CGU_REG_LCR, 30, false, 150 },401	},402	[JZ4770_CLK_MMC0] = {403		"mmc0", CGU_CLK_GATE,404		.parents = { JZ4770_CLK_MMC0_MUX, },405		.gate = { CGU_REG_CLKGR0, 3 },406	},407	[JZ4770_CLK_MMC1] = {408		"mmc1", CGU_CLK_GATE,409		.parents = { JZ4770_CLK_MMC1_MUX, },410		.gate = { CGU_REG_CLKGR0, 11 },411	},412	[JZ4770_CLK_MMC2] = {413		"mmc2", CGU_CLK_GATE,414		.parents = { JZ4770_CLK_MMC2_MUX, },415		.gate = { CGU_REG_CLKGR0, 12 },416	},417	[JZ4770_CLK_OTG_PHY] = {418		"usb_phy", CGU_CLK_GATE,419		.parents = { JZ4770_CLK_OTG },420		.gate = { CGU_REG_OPCR, 7, true, 50 },421	},422 423	/* Custom clocks */424 425	[JZ4770_CLK_UHC_PHY] = {426		"uhc_phy", CGU_CLK_CUSTOM,427		.parents = { JZ4770_CLK_UHC, -1, -1, -1 },428		.custom = { &jz4770_uhc_phy_ops },429	},430 431	[JZ4770_CLK_EXT512] = {432		"ext/512", CGU_CLK_FIXDIV,433		.parents = { JZ4770_CLK_EXT },434		.fixdiv = { 512 },435	},436 437	[JZ4770_CLK_RTC] = {438		"rtc", CGU_CLK_MUX,439		.parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },440		.mux = { CGU_REG_OPCR, 2, 1},441	},442};443 444static void __init jz4770_cgu_init(struct device_node *np)445{446	int retval;447 448	cgu = ingenic_cgu_new(jz4770_cgu_clocks,449			      ARRAY_SIZE(jz4770_cgu_clocks), np);450	if (!cgu) {451		pr_err("%s: failed to initialise CGU\n", __func__);452		return;453	}454 455	retval = ingenic_cgu_register_clocks(cgu);456	if (retval)457		pr_err("%s: failed to register CGU Clocks\n", __func__);458 459	ingenic_cgu_register_syscore_ops(cgu);460}461 462/* We only probe via devicetree, no need for a platform driver */463CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);464