diff options
Diffstat (limited to 'drivers/clk')
53 files changed, 5967 insertions, 1848 deletions
| diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 0357ac44638b..51380d655d1a 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -42,7 +42,7 @@ config COMMON_CLK_WM831X  config COMMON_CLK_VERSATILE  	bool "Clock driver for ARM Reference designs" -	depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS +	depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64  	---help---            Supports clocking on ARM Reference designs:  	  - Integrator/AP and Integrator/CP @@ -58,7 +58,6 @@ config COMMON_CLK_MAX77686  config COMMON_CLK_SI5351  	tristate "Clock driver for SiLabs 5351A/B/C"  	depends on I2C -	depends on OF  	select REGMAP_I2C  	select RATIONAL  	---help--- @@ -81,6 +80,13 @@ config COMMON_CLK_AXI_CLKGEN  	  Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx  	  FPGAs. It is commonly used in Analog Devices' reference designs. +config CLK_PPC_CORENET +	bool "Clock driver for PowerPC corenet platforms" +	depends on PPC_E500MC && OF +	---help--- +	  This adds the clock driver support for Freescale PowerPC corenet +	  platforms using common clock framework. +  endmenu  source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 137d3e730f86..4038c2bdf334 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -13,21 +13,23 @@ obj-$(CONFIG_COMMON_CLK)	+= clk-composite.o  obj-$(CONFIG_ARCH_BCM2835)	+= clk-bcm2835.o  obj-$(CONFIG_ARCH_NOMADIK)	+= clk-nomadik.o  obj-$(CONFIG_ARCH_HIGHBANK)	+= clk-highbank.o +obj-$(CONFIG_ARCH_NSPIRE)	+= clk-nspire.o  obj-$(CONFIG_ARCH_MXS)		+= mxs/  obj-$(CONFIG_ARCH_SOCFPGA)	+= socfpga/  obj-$(CONFIG_PLAT_SPEAR)	+= spear/  obj-$(CONFIG_ARCH_U300)		+= clk-u300.o  obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ -obj-$(CONFIG_ARCH_PRIMA2)	+= clk-prima2.o +obj-$(CONFIG_ARCH_SIRF)		+= clk-prima2.o  obj-$(CONFIG_PLAT_ORION)	+= mvebu/  ifeq ($(CONFIG_COMMON_CLK), y)  obj-$(CONFIG_ARCH_MMP)		+= mmp/  endif  obj-$(CONFIG_MACH_LOONGSON1)	+= clk-ls1x.o +obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/  obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/  obj-$(CONFIG_ARCH_U8500)	+= ux500/  obj-$(CONFIG_ARCH_VT8500)	+= clk-vt8500.o -obj-$(CONFIG_ARCH_ZYNQ)		+= clk-zynq.o +obj-$(CONFIG_ARCH_ZYNQ)		+= zynq/  obj-$(CONFIG_ARCH_TEGRA)	+= tegra/  obj-$(CONFIG_PLAT_SAMSUNG)	+= samsung/ @@ -39,3 +41,4 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o  obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o  obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o  obj-$(CONFIG_CLK_TWL6040)	+= clk-twl6040.o +obj-$(CONFIG_CLK_PPC_CORENET)	+= clk-ppc-corenet.o diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 6d9674160430..6d55eb2cb959 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,  	struct clk_divider *divider = to_clk_divider(hw);  	int i, bestdiv = 0;  	unsigned long parent_rate, best = 0, now, maxdiv; +	unsigned long parent_rate_saved = *best_parent_rate;  	if (!rate)  		rate = 1; @@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,  	for (i = 1; i <= maxdiv; i++) {  		if (!_is_valid_div(divider, i))  			continue; +		if (rate * i == parent_rate_saved) { +			/* +			 * It's the most ideal case if the requested rate can be +			 * divided from parent clock without needing to change +			 * parent rate, so return the divider immediately. +			 */ +			*best_parent_rate = parent_rate_saved; +			return i; +		}  		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),  				MULT_ROUND_UP(rate, i));  		now = parent_rate / i; @@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,  	if (divider->lock)  		spin_lock_irqsave(divider->lock, flags); -	val = readl(divider->reg); -	val &= ~(div_mask(divider) << divider->shift); +	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { +		val = div_mask(divider) << (divider->shift + 16); +	} else { +		val = readl(divider->reg); +		val &= ~(div_mask(divider) << divider->shift); +	}  	val |= value << divider->shift;  	writel(val, divider->reg); @@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,  	struct clk *clk;  	struct clk_init_data init; +	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { +		if (width + shift > 16) { +			pr_warn("divider value exceeds LOWORD field\n"); +			return ERR_PTR(-EINVAL); +		} +	} +  	/* allocate the divider */  	div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);  	if (!div) { diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 15114febfd92..790306e921c8 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -53,12 +53,18 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)  	if (gate->lock)  		spin_lock_irqsave(gate->lock, flags); -	reg = readl(gate->reg); - -	if (set) -		reg |= BIT(gate->bit_idx); -	else -		reg &= ~BIT(gate->bit_idx); +	if (gate->flags & CLK_GATE_HIWORD_MASK) { +		reg = BIT(gate->bit_idx + 16); +		if (set) +			reg |= BIT(gate->bit_idx); +	} else { +		reg = readl(gate->reg); + +		if (set) +			reg |= BIT(gate->bit_idx); +		else +			reg &= ~BIT(gate->bit_idx); +	}  	writel(reg, gate->reg); @@ -121,6 +127,13 @@ struct clk *clk_register_gate(struct device *dev, const char *name,  	struct clk *clk;  	struct clk_init_data init; +	if (clk_gate_flags & CLK_GATE_HIWORD_MASK) { +		if (bit_idx > 16) { +			pr_err("gate bit exceeds LOWORD field\n"); +			return ERR_PTR(-EINVAL); +		} +	} +  	/* allocate the gate */  	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);  	if (!gate) { diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 25b1734560d0..614444ca40cd 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -86,8 +86,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)  	if (mux->lock)  		spin_lock_irqsave(mux->lock, flags); -	val = readl(mux->reg); -	val &= ~(mux->mask << mux->shift); +	if (mux->flags & CLK_MUX_HIWORD_MASK) { +		val = mux->mask << (mux->shift + 16); +	} else { +		val = readl(mux->reg); +		val &= ~(mux->mask << mux->shift); +	}  	val |= index << mux->shift;  	writel(val, mux->reg); @@ -111,6 +115,15 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,  	struct clk_mux *mux;  	struct clk *clk;  	struct clk_init_data init; +	u8 width = 0; + +	if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { +		width = fls(mask) - ffs(mask) + 1; +		if (width + shift > 16) { +			pr_err("mux value exceeds LOWORD field\n"); +			return ERR_PTR(-EINVAL); +		} +	}  	/* allocate the mux */  	mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index 6b4c70f7d23d..6d819a37f647 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -1,48 +1,566 @@ +/* + * Nomadik clock implementation + * Copyright (C) 2013 ST-Ericsson AB + * License terms: GNU General Public License (GPL) version 2 + * Author: Linus Walleij <[email protected]> + */ + +#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt + +#include <linux/bitops.h>  #include <linux/clk.h>  #include <linux/clkdev.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> +#include <linux/reboot.h>  /*   * The Nomadik clock tree is described in the STN8815A12 DB V4.2   * reference manual for the chip, page 94 ff. + * Clock IDs are in the STn8815 Reference Manual table 3, page 27.   */ -void __init nomadik_clk_init(void) +#define SRC_CR			0x00U +#define SRC_XTALCR		0x0CU +#define SRC_XTALCR_XTALTIMEN	BIT(20) +#define SRC_XTALCR_SXTALDIS	BIT(19) +#define SRC_XTALCR_MXTALSTAT	BIT(2) +#define SRC_XTALCR_MXTALEN	BIT(1) +#define SRC_XTALCR_MXTALOVER	BIT(0) +#define SRC_PLLCR		0x10U +#define SRC_PLLCR_PLLTIMEN	BIT(29) +#define SRC_PLLCR_PLL2EN	BIT(28) +#define SRC_PLLCR_PLL1STAT	BIT(2) +#define SRC_PLLCR_PLL1EN	BIT(1) +#define SRC_PLLCR_PLL1OVER	BIT(0) +#define SRC_PLLFR		0x14U +#define SRC_PCKEN0		0x24U +#define SRC_PCKDIS0		0x28U +#define SRC_PCKENSR0		0x2CU +#define SRC_PCKSR0		0x30U +#define SRC_PCKEN1		0x34U +#define SRC_PCKDIS1		0x38U +#define SRC_PCKENSR1		0x3CU +#define SRC_PCKSR1		0x40U + +/* Lock protecting the SRC_CR register */ +static DEFINE_SPINLOCK(src_lock); +/* Base address of the SRC */ +static void __iomem *src_base; + +/** + * struct clk_pll1 - Nomadik PLL1 clock + * @hw: corresponding clock hardware entry + * @id: PLL instance: 1 or 2 + */ +struct clk_pll { +	struct clk_hw hw; +	int id; +}; + +/** + * struct clk_src - Nomadik src clock + * @hw: corresponding clock hardware entry + * @id: the clock ID + * @group1: true if the clock is in group1, else it is in group0 + * @clkbit: bit 0...31 corresponding to the clock in each clock register + */ +struct clk_src { +	struct clk_hw hw; +	int id; +	bool group1; +	u32 clkbit; +}; + +#define to_pll(_hw) container_of(_hw, struct clk_pll, hw) +#define to_src(_hw) container_of(_hw, struct clk_src, hw) + +static int pll_clk_enable(struct clk_hw *hw) +{ +	struct clk_pll *pll = to_pll(hw); +	u32 val; + +	spin_lock(&src_lock); +	val = readl(src_base + SRC_PLLCR); +	if (pll->id == 1) { +		if (val & SRC_PLLCR_PLL1OVER) { +			val |= SRC_PLLCR_PLL1EN; +			writel(val, src_base + SRC_PLLCR); +		} +	} else if (pll->id == 2) { +		val |= SRC_PLLCR_PLL2EN; +		writel(val, src_base + SRC_PLLCR); +	} +	spin_unlock(&src_lock); +	return 0; +} + +static void pll_clk_disable(struct clk_hw *hw) +{ +	struct clk_pll *pll = to_pll(hw); +	u32 val; + +	spin_lock(&src_lock); +	val = readl(src_base + SRC_PLLCR); +	if (pll->id == 1) { +		if (val & SRC_PLLCR_PLL1OVER) { +			val &= ~SRC_PLLCR_PLL1EN; +			writel(val, src_base + SRC_PLLCR); +		} +	} else if (pll->id == 2) { +		val &= ~SRC_PLLCR_PLL2EN; +		writel(val, src_base + SRC_PLLCR); +	} +	spin_unlock(&src_lock); +} + +static int pll_clk_is_enabled(struct clk_hw *hw) +{ +	struct clk_pll *pll = to_pll(hw); +	u32 val; + +	val = readl(src_base + SRC_PLLCR); +	if (pll->id == 1) { +		if (val & SRC_PLLCR_PLL1OVER) +			return !!(val & SRC_PLLCR_PLL1EN); +	} else if (pll->id == 2) { +		return !!(val & SRC_PLLCR_PLL2EN); +	} +	return 1; +} + +static unsigned long pll_clk_recalc_rate(struct clk_hw *hw, +					  unsigned long parent_rate) +{ +	struct clk_pll *pll = to_pll(hw); +	u32 val; + +	val = readl(src_base + SRC_PLLFR); + +	if (pll->id == 1) { +		u8 mul; +		u8 div; + +		mul = (val >> 8) & 0x3FU; +		mul += 2; +		div = val & 0x07U; +		return (parent_rate * mul) >> div; +	} + +	if (pll->id == 2) { +		u8 mul; + +		mul = (val >> 24) & 0x3FU; +		mul += 2; +		return (parent_rate * mul); +	} + +	/* Unknown PLL */ +	return 0; +} + + +static const struct clk_ops pll_clk_ops = { +	.enable = pll_clk_enable, +	.disable = pll_clk_disable, +	.is_enabled = pll_clk_is_enabled, +	.recalc_rate = pll_clk_recalc_rate, +}; + +static struct clk * __init +pll_clk_register(struct device *dev, const char *name, +		 const char *parent_name, u32 id)  {  	struct clk *clk; +	struct clk_pll *pll; +	struct clk_init_data init; -	clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); -	clk_register_clkdev(clk, "apb_pclk", NULL); -	clk_register_clkdev(clk, NULL, "gpio.0"); -	clk_register_clkdev(clk, NULL, "gpio.1"); -	clk_register_clkdev(clk, NULL, "gpio.2"); -	clk_register_clkdev(clk, NULL, "gpio.3"); -	clk_register_clkdev(clk, NULL, "rng"); -	clk_register_clkdev(clk, NULL, "fsmc-nand"); +	if (id != 1 && id != 2) { +		pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__); +		return ERR_PTR(-EINVAL); +	} -	/* -	 * The 2.4 MHz TIMCLK reference clock is active at boot time, this is -	 * actually the MXTALCLK @19.2 MHz divided by 8. This clock is used -	 * by the timers and watchdog. See page 105 ff. -	 */ -	clk = clk_register_fixed_rate(NULL, "TIMCLK", NULL, CLK_IS_ROOT, -				      2400000); -	clk_register_clkdev(clk, NULL, "mtu0"); -	clk_register_clkdev(clk, NULL, "mtu1"); +	pll = kzalloc(sizeof(*pll), GFP_KERNEL); +	if (!pll) { +		pr_err("%s: could not allocate PLL clk\n", __func__); +		return ERR_PTR(-ENOMEM); +	} + +	init.name = name; +	init.ops = &pll_clk_ops; +	init.parent_names = (parent_name ? &parent_name : NULL); +	init.num_parents = (parent_name ? 1 : 0); +	pll->hw.init = &init; +	pll->id = id; + +	pr_debug("register PLL1 clock \"%s\"\n", name); + +	clk = clk_register(dev, &pll->hw); +	if (IS_ERR(clk)) +		kfree(pll); + +	return clk; +} + +/* + * The Nomadik SRC clocks are gated, but not in the sense that + * you read-modify-write a register. Instead there are separate + * clock enable and clock disable registers. Writing a '1' bit in + * the enable register for a certain clock ungates that clock without + * affecting the other clocks. The disable register works the opposite + * way. + */ + +static int src_clk_enable(struct clk_hw *hw) +{ +	struct clk_src *sclk = to_src(hw); +	u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0; +	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0; + +	writel(sclk->clkbit, src_base + enreg); +	/* spin until enabled */ +	while (!(readl(src_base + sreg) & sclk->clkbit)) +		cpu_relax(); +	return 0; +} + +static void src_clk_disable(struct clk_hw *hw) +{ +	struct clk_src *sclk = to_src(hw); +	u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0; +	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0; + +	writel(sclk->clkbit, src_base + disreg); +	/* spin until disabled */ +	while (readl(src_base + sreg) & sclk->clkbit) +		cpu_relax(); +} + +static int src_clk_is_enabled(struct clk_hw *hw) +{ +	struct clk_src *sclk = to_src(hw); +	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0; +	u32 val = readl(src_base + sreg); +	return !!(val & sclk->clkbit); +} + +static unsigned long +src_clk_recalc_rate(struct clk_hw *hw, +		    unsigned long parent_rate) +{ +	return parent_rate; +} + +static const struct clk_ops src_clk_ops = { +	.enable = src_clk_enable, +	.disable = src_clk_disable, +	.is_enabled = src_clk_is_enabled, +	.recalc_rate = src_clk_recalc_rate, +}; + +static struct clk * __init +src_clk_register(struct device *dev, const char *name, +		 const char *parent_name, u8 id) +{ +	struct clk *clk; +	struct clk_src *sclk; +	struct clk_init_data init; + +	sclk = kzalloc(sizeof(*sclk), GFP_KERNEL); +	if (!sclk) { +		pr_err("could not allocate SRC clock %s\n", +			name); +		return ERR_PTR(-ENOMEM); +	} +	init.name = name; +	init.ops = &src_clk_ops; +	/* Do not force-disable the static SDRAM controller */ +	if (id == 2) +		init.flags = CLK_IGNORE_UNUSED; +	else +		init.flags = 0; +	init.parent_names = (parent_name ? &parent_name : NULL); +	init.num_parents = (parent_name ? 1 : 0); +	sclk->hw.init = &init; +	sclk->id = id; +	sclk->group1 = (id > 31); +	sclk->clkbit = BIT(id & 0x1f); + +	pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n", +		 name, id, sclk->group1, sclk->clkbit); + +	clk = clk_register(dev, &sclk->hw); +	if (IS_ERR(clk)) +		kfree(sclk); + +	return clk; +} + +#ifdef CONFIG_DEBUG_FS + +static u32 src_pcksr0_boot; +static u32 src_pcksr1_boot; + +static const char * const src_clk_names[] = { +	"HCLKDMA0  ", +	"HCLKSMC   ", +	"HCLKSDRAM ", +	"HCLKDMA1  ", +	"HCLKCLCD  ", +	"PCLKIRDA  ", +	"PCLKSSP   ", +	"PCLKUART0 ", +	"PCLKSDI   ", +	"PCLKI2C0  ", +	"PCLKI2C1  ", +	"PCLKUART1 ", +	"PCLMSP0   ", +	"HCLKUSB   ", +	"HCLKDIF   ", +	"HCLKSAA   ", +	"HCLKSVA   ", +	"PCLKHSI   ", +	"PCLKXTI   ", +	"PCLKUART2 ", +	"PCLKMSP1  ", +	"PCLKMSP2  ", +	"PCLKOWM   ", +	"HCLKHPI   ", +	"PCLKSKE   ", +	"PCLKHSEM  ", +	"HCLK3D    ", +	"HCLKHASH  ", +	"HCLKCRYP  ", +	"PCLKMSHC  ", +	"HCLKUSBM  ", +	"HCLKRNG   ", +	"RESERVED  ", +	"RESERVED  ", +	"RESERVED  ", +	"RESERVED  ", +	"CLDCLK    ", +	"IRDACLK   ", +	"SSPICLK   ", +	"UART0CLK  ", +	"SDICLK    ", +	"I2C0CLK   ", +	"I2C1CLK   ", +	"UART1CLK  ", +	"MSPCLK0   ", +	"USBCLK    ", +	"DIFCLK    ", +	"IPI2CCLK  ", +	"IPBMCCLK  ", +	"HSICLKRX  ", +	"HSICLKTX  ", +	"UART2CLK  ", +	"MSPCLK1   ", +	"MSPCLK2   ", +	"OWMCLK    ", +	"RESERVED  ", +	"SKECLK    ", +	"RESERVED  ", +	"3DCLK     ", +	"PCLKMSP3  ", +	"MSPCLK3   ", +	"MSHCCLK   ", +	"USBMCLK   ", +	"RNGCCLK   ", +}; + +static int nomadik_src_clk_show(struct seq_file *s, void *what) +{ +	int i; +	u32 src_pcksr0 = readl(src_base + SRC_PCKSR0); +	u32 src_pcksr1 = readl(src_base + SRC_PCKSR1); +	u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0); +	u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1); + +	seq_printf(s, "Clock:      Boot:   Now:    Request: ASKED:\n"); +	for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) { +		u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot; +		u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1; +		u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1; +		u32 mask = BIT(i & 0x1f); + +		seq_printf(s, "%s  %s     %s     %s\n", +			   src_clk_names[i], +			   (pcksrb & mask) ? "on " : "off", +			   (pcksr & mask) ? "on " : "off", +			   (pckreq & mask) ? "on " : "off"); +	} +	return 0; +} + +static int nomadik_src_clk_open(struct inode *inode, struct file *file) +{ +	return single_open(file, nomadik_src_clk_show, NULL); +} + +static const struct file_operations nomadik_src_clk_debugfs_ops = { +	.open           = nomadik_src_clk_open, +	.read           = seq_read, +        .llseek         = seq_lseek, +	.release        = single_release, +}; + +static int __init nomadik_src_clk_init_debugfs(void) +{ +	src_pcksr0_boot = readl(src_base + SRC_PCKSR0); +	src_pcksr1_boot = readl(src_base + SRC_PCKSR1); +	debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO, +			    NULL, NULL, &nomadik_src_clk_debugfs_ops); +	return 0; +} + +module_init(nomadik_src_clk_init_debugfs); + +#endif + +static void __init of_nomadik_pll_setup(struct device_node *np) +{ +	struct clk *clk = ERR_PTR(-EINVAL); +	const char *clk_name = np->name; +	const char *parent_name; +	u32 pll_id; + +	if (of_property_read_u32(np, "pll-id", &pll_id)) { +		pr_err("%s: PLL \"%s\" missing pll-id property\n", +			__func__, clk_name); +		return; +	} +	parent_name = of_clk_get_parent_name(np, 0); +	clk = pll_clk_register(NULL, clk_name, parent_name, pll_id); +	if (!IS_ERR(clk)) +		of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +static void __init of_nomadik_hclk_setup(struct device_node *np) +{ +	struct clk *clk = ERR_PTR(-EINVAL); +	const char *clk_name = np->name; +	const char *parent_name; + +	parent_name = of_clk_get_parent_name(np, 0);  	/* -	 * At boot time, PLL2 is set to generate a set of fixed clocks, -	 * one of them is CLK48, the 48 MHz clock, routed to the UART, MMC/SD -	 * I2C, IrDA, USB and SSP blocks. +	 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.  	 */ -	clk = clk_register_fixed_rate(NULL, "CLK48", NULL, CLK_IS_ROOT, -				      48000000); -	clk_register_clkdev(clk, NULL, "uart0"); -	clk_register_clkdev(clk, NULL, "uart1"); -	clk_register_clkdev(clk, NULL, "mmci"); -	clk_register_clkdev(clk, NULL, "ssp"); -	clk_register_clkdev(clk, NULL, "nmk-i2c.0"); -	clk_register_clkdev(clk, NULL, "nmk-i2c.1"); +	clk = clk_register_divider(NULL, clk_name, parent_name, +			   0, src_base + SRC_CR, +			   13, 2, +			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			   &src_lock); +	if (!IS_ERR(clk)) +		of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +static void __init of_nomadik_src_clk_setup(struct device_node *np) +{ +	struct clk *clk = ERR_PTR(-EINVAL); +	const char *clk_name = np->name; +	const char *parent_name; +	u32 clk_id; + +	if (of_property_read_u32(np, "clock-id", &clk_id)) { +		pr_err("%s: SRC clock \"%s\" missing clock-id property\n", +			__func__, clk_name); +		return; +	} +	parent_name = of_clk_get_parent_name(np, 0); +	clk = src_clk_register(NULL, clk_name, parent_name, clk_id); +	if (!IS_ERR(clk)) +		of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +static const __initconst struct of_device_id nomadik_src_match[] = { +	{ .compatible = "stericsson,nomadik-src" }, +	{ /* sentinel */ } +}; + +static const __initconst struct of_device_id nomadik_src_clk_match[] = { +	{ +		.compatible = "fixed-clock", +		.data = of_fixed_clk_setup, +	}, +	{ +		.compatible = "fixed-factor-clock", +		.data = of_fixed_factor_clk_setup, +	}, +	{ +		.compatible = "st,nomadik-pll-clock", +		.data = of_nomadik_pll_setup, +	}, +	{ +		.compatible = "st,nomadik-hclk-clock", +		.data = of_nomadik_hclk_setup, +	}, +	{ +		.compatible = "st,nomadik-src-clock", +		.data = of_nomadik_src_clk_setup, +	}, +	{ /* sentinel */ } +}; + +static int nomadik_clk_reboot_handler(struct notifier_block *this, +				unsigned long code, +				void *unused) +{ +	u32 val; + +	/* The main chrystal need to be enabled for reboot to work */ +	val = readl(src_base + SRC_XTALCR); +	val &= ~SRC_XTALCR_MXTALOVER; +	val |= SRC_XTALCR_MXTALEN; +	pr_crit("force-enabling MXTALO\n"); +	writel(val, src_base + SRC_XTALCR); +	return NOTIFY_OK; +} + +static struct notifier_block nomadik_clk_reboot_notifier = { +	.notifier_call = nomadik_clk_reboot_handler, +}; + +void __init nomadik_clk_init(void) +{ +	struct device_node *np; +	u32 val; + +	np = of_find_matching_node(NULL, nomadik_src_match); +	if (!np) { +		pr_crit("no matching node for SRC, aborting clock init\n"); +		return; +	} +	src_base = of_iomap(np, 0); +	if (!src_base) { +		pr_err("%s: must have src parent node with REGS (%s)\n", +		       __func__, np->name); +		return; +	} +	val = readl(src_base + SRC_XTALCR); +	pr_info("SXTALO is %s\n", +		(val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled"); +	pr_info("MXTAL is %s\n", +		(val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled"); +	if (of_property_read_bool(np, "disable-sxtalo")) { +		/* The machine uses an external oscillator circuit */ +		val |= SRC_XTALCR_SXTALDIS; +		pr_info("disabling SXTALO\n"); +	} +	if (of_property_read_bool(np, "disable-mxtalo")) { +		/* Disable this too: also run by external oscillator */ +		val |= SRC_XTALCR_MXTALOVER; +		val &= ~SRC_XTALCR_MXTALEN; +		pr_info("disabling MXTALO\n"); +	} +	writel(val, src_base + SRC_XTALCR); +	register_reboot_notifier(&nomadik_clk_reboot_notifier); + +	of_clk_init(nomadik_src_clk_match);  } diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c new file mode 100644 index 000000000000..a378db7b2382 --- /dev/null +++ b/drivers/clk/clk-nspire.c @@ -0,0 +1,153 @@ +/* + * + *  Copyright (C) 2013 Daniel Tang <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#define MHZ (1000 * 1000) + +#define BASE_CPU_SHIFT		1 +#define BASE_CPU_MASK		0x7F + +#define CPU_AHB_SHIFT		12 +#define CPU_AHB_MASK		0x07 + +#define FIXED_BASE_SHIFT	8 +#define FIXED_BASE_MASK		0x01 + +#define CLASSIC_BASE_SHIFT	16 +#define CLASSIC_BASE_MASK	0x1F + +#define CX_BASE_SHIFT		15 +#define CX_BASE_MASK		0x3F + +#define CX_UNKNOWN_SHIFT	21 +#define CX_UNKNOWN_MASK		0x03 + +struct nspire_clk_info { +	u32 base_clock; +	u16 base_cpu_ratio; +	u16 base_ahb_ratio; +}; + + +#define EXTRACT(var, prop) (((var)>>prop##_SHIFT) & prop##_MASK) +static void nspire_clkinfo_cx(u32 val, struct nspire_clk_info *clk) +{ +	if (EXTRACT(val, FIXED_BASE)) +		clk->base_clock = 48 * MHZ; +	else +		clk->base_clock = 6 * EXTRACT(val, CX_BASE) * MHZ; + +	clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * EXTRACT(val, CX_UNKNOWN); +	clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1); +} + +static void nspire_clkinfo_classic(u32 val, struct nspire_clk_info *clk) +{ +	if (EXTRACT(val, FIXED_BASE)) +		clk->base_clock = 27 * MHZ; +	else +		clk->base_clock = (300 - 6 * EXTRACT(val, CLASSIC_BASE)) * MHZ; + +	clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * 2; +	clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1); +} + +static void __init nspire_ahbdiv_setup(struct device_node *node, +		void (*get_clkinfo)(u32, struct nspire_clk_info *)) +{ +	u32 val; +	void __iomem *io; +	struct clk *clk; +	const char *clk_name = node->name; +	const char *parent_name; +	struct nspire_clk_info info; + +	io = of_iomap(node, 0); +	if (!io) +		return; +	val = readl(io); +	iounmap(io); + +	get_clkinfo(val, &info); + +	of_property_read_string(node, "clock-output-names", &clk_name); +	parent_name = of_clk_get_parent_name(node, 0); + +	clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0, +					1, info.base_ahb_ratio); +	if (!IS_ERR(clk)) +		of_clk_add_provider(node, of_clk_src_simple_get, clk); +} + +static void __init nspire_ahbdiv_setup_cx(struct device_node *node) +{ +	nspire_ahbdiv_setup(node, nspire_clkinfo_cx); +} + +static void __init nspire_ahbdiv_setup_classic(struct device_node *node) +{ +	nspire_ahbdiv_setup(node, nspire_clkinfo_classic); +} + +CLK_OF_DECLARE(nspire_ahbdiv_cx, "lsi,nspire-cx-ahb-divider", +		nspire_ahbdiv_setup_cx); +CLK_OF_DECLARE(nspire_ahbdiv_classic, "lsi,nspire-classic-ahb-divider", +		nspire_ahbdiv_setup_classic); + +static void __init nspire_clk_setup(struct device_node *node, +		void (*get_clkinfo)(u32, struct nspire_clk_info *)) +{ +	u32 val; +	void __iomem *io; +	struct clk *clk; +	const char *clk_name = node->name; +	struct nspire_clk_info info; + +	io = of_iomap(node, 0); +	if (!io) +		return; +	val = readl(io); +	iounmap(io); + +	get_clkinfo(val, &info); + +	of_property_read_string(node, "clock-output-names", &clk_name); + +	clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, +			info.base_clock); +	if (!IS_ERR(clk)) +		of_clk_add_provider(node, of_clk_src_simple_get, clk); +	else +		return; + +	pr_info("TI-NSPIRE Base: %uMHz CPU: %uMHz AHB: %uMHz\n", +		info.base_clock / MHZ, +		info.base_clock / info.base_cpu_ratio / MHZ, +		info.base_clock / info.base_ahb_ratio / MHZ); +} + +static void __init nspire_clk_setup_cx(struct device_node *node) +{ +	nspire_clk_setup(node, nspire_clkinfo_cx); +} + +static void __init nspire_clk_setup_classic(struct device_node *node) +{ +	nspire_clk_setup(node, nspire_clkinfo_classic); +} + +CLK_OF_DECLARE(nspire_clk_cx, "lsi,nspire-cx-clock", nspire_clk_setup_cx); +CLK_OF_DECLARE(nspire_clk_classic, "lsi,nspire-classic-clock", +		nspire_clk_setup_classic); diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c new file mode 100644 index 000000000000..e9587073bd32 --- /dev/null +++ b/drivers/clk/clk-ppc-corenet.c @@ -0,0 +1,280 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * clock driver for Freescale PowerPC corenet SoCs. + */ +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of.h> +#include <linux/slab.h> + +struct cmux_clk { +	struct clk_hw hw; +	void __iomem *reg; +	u32 flags; +}; + +#define PLL_KILL			BIT(31) +#define	CLKSEL_SHIFT		27 +#define CLKSEL_ADJUST		BIT(0) +#define to_cmux_clk(p)		container_of(p, struct cmux_clk, hw) + +static void __iomem *base; +static unsigned int clocks_per_pll; + +static int cmux_set_parent(struct clk_hw *hw, u8 idx) +{ +	struct cmux_clk *clk = to_cmux_clk(hw); +	u32 clksel; + +	clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll; +	if (clk->flags & CLKSEL_ADJUST) +		clksel += 8; +	clksel = (clksel & 0xf) << CLKSEL_SHIFT; +	iowrite32be(clksel, clk->reg); + +	return 0; +} + +static u8 cmux_get_parent(struct clk_hw *hw) +{ +	struct cmux_clk *clk = to_cmux_clk(hw); +	u32 clksel; + +	clksel = ioread32be(clk->reg); +	clksel = (clksel >> CLKSEL_SHIFT) & 0xf; +	if (clk->flags & CLKSEL_ADJUST) +		clksel -= 8; +	clksel = (clksel >> 2) * clocks_per_pll + clksel % 4; + +	return clksel; +} + +const struct clk_ops cmux_ops = { +	.get_parent = cmux_get_parent, +	.set_parent = cmux_set_parent, +}; + +static void __init core_mux_init(struct device_node *np) +{ +	struct clk *clk; +	struct clk_init_data init; +	struct cmux_clk *cmux_clk; +	struct device_node *node; +	int rc, count, i; +	u32	offset; +	const char *clk_name; +	const char **parent_names; + +	rc = of_property_read_u32(np, "reg", &offset); +	if (rc) { +		pr_err("%s: could not get reg property\n", np->name); +		return; +	} + +	/* get the input clock source count */ +	count = of_property_count_strings(np, "clock-names"); +	if (count < 0) { +		pr_err("%s: get clock count error\n", np->name); +		return; +	} +	parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL); +	if (!parent_names) { +		pr_err("%s: could not allocate parent_names\n", __func__); +		return; +	} + +	for (i = 0; i < count; i++) +		parent_names[i] = of_clk_get_parent_name(np, i); + +	cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL); +	if (!cmux_clk) { +		pr_err("%s: could not allocate cmux_clk\n", __func__); +		goto err_name; +	} +	cmux_clk->reg = base + offset; + +	node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen"); +	if (node && (offset >= 0x80)) +		cmux_clk->flags = CLKSEL_ADJUST; + +	rc = of_property_read_string_index(np, "clock-output-names", +			0, &clk_name); +	if (rc) { +		pr_err("%s: read clock names error\n", np->name); +		goto err_clk; +	} + +	init.name = clk_name; +	init.ops = &cmux_ops; +	init.parent_names = parent_names; +	init.num_parents = count; +	init.flags = 0; +	cmux_clk->hw.init = &init; + +	clk = clk_register(NULL, &cmux_clk->hw); +	if (IS_ERR(clk)) { +		pr_err("%s: could not register clock\n", clk_name); +		goto err_clk; +	} + +	rc = of_clk_add_provider(np, of_clk_src_simple_get, clk); +	if (rc) { +		pr_err("Could not register clock provider for node:%s\n", +			 np->name); +		goto err_clk; +	} +	goto err_name; + +err_clk: +	kfree(cmux_clk); +err_name: +	/* free *_names because they are reallocated when registered */ +	kfree(parent_names); +} + +static void __init core_pll_init(struct device_node *np) +{ +	u32 offset, mult; +	int i, rc, count; +	const char *clk_name, *parent_name; +	struct clk_onecell_data *onecell_data; +	struct clk      **subclks; + +	rc = of_property_read_u32(np, "reg", &offset); +	if (rc) { +		pr_err("%s: could not get reg property\n", np->name); +		return; +	} + +	/* get the multiple of PLL */ +	mult = ioread32be(base + offset); + +	/* check if this PLL is disabled */ +	if (mult & PLL_KILL) { +		pr_debug("PLL:%s is disabled\n", np->name); +		return; +	} +	mult = (mult >> 1) & 0x3f; + +	parent_name = of_clk_get_parent_name(np, 0); +	if (!parent_name) { +		pr_err("PLL: %s must have a parent\n", np->name); +		return; +	} + +	count = of_property_count_strings(np, "clock-output-names"); +	if (count < 0 || count > 4) { +		pr_err("%s: clock is not supported\n", np->name); +		return; +	} + +	/* output clock number per PLL */ +	clocks_per_pll = count; + +	subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL); +	if (!subclks) { +		pr_err("%s: could not allocate subclks\n", __func__); +		return; +	} + +	onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); +	if (!onecell_data) { +		pr_err("%s: could not allocate onecell_data\n", __func__); +		goto err_clks; +	} + +	for (i = 0; i < count; i++) { +		rc = of_property_read_string_index(np, "clock-output-names", +				i, &clk_name); +		if (rc) { +			pr_err("%s: could not get clock names\n", np->name); +			goto err_cell; +		} + +		/* +		 * when count == 4, there are 4 output clocks: +		 * /1, /2, /3, /4 respectively +		 * when count < 4, there are at least 2 output clocks: +		 * /1, /2, (/4, if count == 3) respectively. +		 */ +		if (count == 4) +			subclks[i] = clk_register_fixed_factor(NULL, clk_name, +					parent_name, 0, mult, 1 + i); +		else + +			subclks[i] = clk_register_fixed_factor(NULL, clk_name, +					parent_name, 0, mult, 1 << i); + +		if (IS_ERR(subclks[i])) { +			pr_err("%s: could not register clock\n", clk_name); +			goto err_cell; +		} +	} + +	onecell_data->clks = subclks; +	onecell_data->clk_num = count; + +	rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data); +	if (rc) { +		pr_err("Could not register clk provider for node:%s\n", +			 np->name); +		goto err_cell; +	} + +	return; +err_cell: +	kfree(onecell_data); +err_clks: +	kfree(subclks); +} + +static const struct of_device_id clk_match[] __initconst = { +	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, +	{ .compatible = "fsl,core-pll-clock", .data = core_pll_init, }, +	{ .compatible = "fsl,core-mux-clock", .data = core_mux_init, }, +	{} +}; + +static int __init ppc_corenet_clk_probe(struct platform_device *pdev) +{ +	struct device_node *np; + +	np = pdev->dev.of_node; +	base = of_iomap(np, 0); +	if (!base) { +		dev_err(&pdev->dev, "iomap error\n"); +		return -ENOMEM; +	} +	of_clk_init(clk_match); + +	return 0; +} + +static const struct of_device_id ppc_clk_ids[] __initconst = { +	{ .compatible = "fsl,qoriq-clockgen-1.0", }, +	{ .compatible = "fsl,qoriq-clockgen-2.0", }, +	{} +}; + +static struct platform_driver ppc_corenet_clk_driver = { +	.driver = { +		.name = "ppc_corenet_clock", +		.owner = THIS_MODULE, +		.of_match_table = ppc_clk_ids, +	}, +	.probe = ppc_corenet_clk_probe, +}; + +static int __init ppc_corenet_clk_init(void) +{ +	return platform_driver_register(&ppc_corenet_clk_driver); +} +subsys_initcall(ppc_corenet_clk_init); diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 24f553673b72..c50e83744b0a 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -851,6 +851,41 @@ static int _si5351_clkout_set_drive_strength(  	return 0;  } +static int _si5351_clkout_set_disable_state( +	struct si5351_driver_data *drvdata, int num, +	enum si5351_disable_state state) +{ +	u8 reg = (num < 4) ? SI5351_CLK3_0_DISABLE_STATE : +		SI5351_CLK7_4_DISABLE_STATE; +	u8 shift = (num < 4) ? (2 * num) : (2 * (num-4)); +	u8 mask = SI5351_CLK_DISABLE_STATE_MASK << shift; +	u8 val; + +	if (num > 8) +		return -EINVAL; + +	switch (state) { +	case SI5351_DISABLE_LOW: +		val = SI5351_CLK_DISABLE_STATE_LOW; +		break; +	case SI5351_DISABLE_HIGH: +		val = SI5351_CLK_DISABLE_STATE_HIGH; +		break; +	case SI5351_DISABLE_FLOATING: +		val = SI5351_CLK_DISABLE_STATE_FLOAT; +		break; +	case SI5351_DISABLE_NEVER: +		val = SI5351_CLK_DISABLE_STATE_NEVER; +		break; +	default: +		return 0; +	} + +	si5351_set_bits(drvdata, reg, mask, val << shift); + +	return 0; +} +  static int si5351_clkout_prepare(struct clk_hw *hw)  {  	struct si5351_hw_data *hwdata = @@ -1225,6 +1260,33 @@ static int si5351_dt_parse(struct i2c_client *client)  			}  		} +		if (!of_property_read_u32(child, "silabs,disable-state", +					  &val)) { +			switch (val) { +			case 0: +				pdata->clkout[num].disable_state = +					SI5351_DISABLE_LOW; +				break; +			case 1: +				pdata->clkout[num].disable_state = +					SI5351_DISABLE_HIGH; +				break; +			case 2: +				pdata->clkout[num].disable_state = +					SI5351_DISABLE_FLOATING; +				break; +			case 3: +				pdata->clkout[num].disable_state = +					SI5351_DISABLE_NEVER; +				break; +			default: +				dev_err(&client->dev, +					"invalid disable state %d for clkout %d\n", +					val, num); +				return -EINVAL; +			} +		} +  		if (!of_property_read_u32(child, "clock-frequency", &val))  			pdata->clkout[num].rate = val; @@ -1281,9 +1343,6 @@ static int si5351_i2c_probe(struct i2c_client *client,  	/* Disable interrupts */  	si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0); -	/* Set disabled output drivers to drive low */ -	si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00); -	si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);  	/* Ensure pll select is on XTAL for Si5351A/B */  	if (drvdata->variant != SI5351_VARIANT_C)  		si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE, @@ -1327,6 +1386,15 @@ static int si5351_i2c_probe(struct i2c_client *client,  				n, pdata->clkout[n].drive);  			return ret;  		} + +		ret = _si5351_clkout_set_disable_state(drvdata, n, +						pdata->clkout[n].disable_state); +		if (ret) { +			dev_err(&client->dev, +				"failed set disable state of clkout%d to %d\n", +				n, pdata->clkout[n].disable_state); +			return ret; +		}  	}  	/* register xtal input clock gate */ @@ -1500,7 +1568,10 @@ static int si5351_i2c_probe(struct i2c_client *client,  }  static const struct i2c_device_id si5351_i2c_ids[] = { -	{ "silabs,si5351", 0 }, +	{ "si5351a", 0 }, +	{ "si5351a-msop", 0 }, +	{ "si5351b", 0 }, +	{ "si5351c", 0 },  	{ }  };  MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids); diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h index af41b5080f43..c0dbf2676872 100644 --- a/drivers/clk/clk-si5351.h +++ b/drivers/clk/clk-si5351.h @@ -81,6 +81,7 @@  #define SI5351_CLK3_0_DISABLE_STATE		24  #define SI5351_CLK7_4_DISABLE_STATE		25 +#define  SI5351_CLK_DISABLE_STATE_MASK		3  #define  SI5351_CLK_DISABLE_STATE_LOW		0  #define  SI5351_CLK_DISABLE_STATE_HIGH		1  #define  SI5351_CLK_DISABLE_STATE_FLOAT		2 diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 3af729b1b89d..1ada79a28052 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -95,14 +95,14 @@ static int twl6040_clk_probe(struct platform_device *pdev)  	if (IS_ERR(clkdata->clk))  		return PTR_ERR(clkdata->clk); -	dev_set_drvdata(&pdev->dev, clkdata); +	platform_set_drvdata(pdev, clkdata);  	return 0;  }  static int twl6040_clk_remove(struct platform_device *pdev)  { -	struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev); +	struct twl6040_clk *clkdata = platform_get_drvdata(pdev);  	clk_unregister(clkdata->clk); diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c index a15f7928fb11..8774e058cb6c 100644 --- a/drivers/clk/clk-u300.c +++ b/drivers/clk/clk-u300.c @@ -11,7 +11,349 @@  #include <linux/io.h>  #include <linux/clk-provider.h>  #include <linux/spinlock.h> -#include <mach/syscon.h> +#include <linux/of.h> + +/* APP side SYSCON registers */ +/* CLK Control Register 16bit (R/W) */ +#define U300_SYSCON_CCR						(0x0000) +#define U300_SYSCON_CCR_I2S1_USE_VCXO				(0x0040) +#define U300_SYSCON_CCR_I2S0_USE_VCXO				(0x0020) +#define U300_SYSCON_CCR_TURN_VCXO_ON				(0x0008) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK			(0x0007) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER		(0x04) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW			(0x03) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE		(0x02) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH			(0x01) +#define U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST			(0x00) +/* CLK Status Register 16bit (R/W) */ +#define U300_SYSCON_CSR						(0x0004) +#define U300_SYSCON_CSR_PLL208_LOCK_IND				(0x0002) +#define U300_SYSCON_CSR_PLL13_LOCK_IND				(0x0001) +/* Reset lines for SLOW devices 16bit (R/W) */ +#define U300_SYSCON_RSR						(0x0014) +#define U300_SYSCON_RSR_PPM_RESET_EN				(0x0200) +#define U300_SYSCON_RSR_ACC_TMR_RESET_EN			(0x0100) +#define U300_SYSCON_RSR_APP_TMR_RESET_EN			(0x0080) +#define U300_SYSCON_RSR_RTC_RESET_EN				(0x0040) +#define U300_SYSCON_RSR_KEYPAD_RESET_EN				(0x0020) +#define U300_SYSCON_RSR_GPIO_RESET_EN				(0x0010) +#define U300_SYSCON_RSR_EH_RESET_EN				(0x0008) +#define U300_SYSCON_RSR_BTR_RESET_EN				(0x0004) +#define U300_SYSCON_RSR_UART_RESET_EN				(0x0002) +#define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN			(0x0001) +/* Reset lines for FAST devices 16bit (R/W) */ +#define U300_SYSCON_RFR						(0x0018) +#define U300_SYSCON_RFR_UART1_RESET_ENABLE			(0x0080) +#define U300_SYSCON_RFR_SPI_RESET_ENABLE			(0x0040) +#define U300_SYSCON_RFR_MMC_RESET_ENABLE			(0x0020) +#define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE			(0x0010) +#define U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE			(0x0008) +#define U300_SYSCON_RFR_I2C1_RESET_ENABLE			(0x0004) +#define U300_SYSCON_RFR_I2C0_RESET_ENABLE			(0x0002) +#define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE		(0x0001) +/* Reset lines for the rest of the peripherals 16bit (R/W) */ +#define U300_SYSCON_RRR						(0x001c) +#define U300_SYSCON_RRR_CDS_RESET_EN				(0x4000) +#define U300_SYSCON_RRR_ISP_RESET_EN				(0x2000) +#define U300_SYSCON_RRR_INTCON_RESET_EN				(0x1000) +#define U300_SYSCON_RRR_MSPRO_RESET_EN				(0x0800) +#define U300_SYSCON_RRR_XGAM_RESET_EN				(0x0100) +#define U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN			(0x0080) +#define U300_SYSCON_RRR_NANDIF_RESET_EN				(0x0040) +#define U300_SYSCON_RRR_EMIF_RESET_EN				(0x0020) +#define U300_SYSCON_RRR_DMAC_RESET_EN				(0x0010) +#define U300_SYSCON_RRR_CPU_RESET_EN				(0x0008) +#define U300_SYSCON_RRR_APEX_RESET_EN				(0x0004) +#define U300_SYSCON_RRR_AHB_RESET_EN				(0x0002) +#define U300_SYSCON_RRR_AAIF_RESET_EN				(0x0001) +/* Clock enable for SLOW peripherals 16bit (R/W) */ +#define U300_SYSCON_CESR					(0x0020) +#define U300_SYSCON_CESR_PPM_CLK_EN				(0x0200) +#define U300_SYSCON_CESR_ACC_TMR_CLK_EN				(0x0100) +#define U300_SYSCON_CESR_APP_TMR_CLK_EN				(0x0080) +#define U300_SYSCON_CESR_KEYPAD_CLK_EN				(0x0040) +#define U300_SYSCON_CESR_GPIO_CLK_EN				(0x0010) +#define U300_SYSCON_CESR_EH_CLK_EN				(0x0008) +#define U300_SYSCON_CESR_BTR_CLK_EN				(0x0004) +#define U300_SYSCON_CESR_UART_CLK_EN				(0x0002) +#define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN			(0x0001) +/* Clock enable for FAST peripherals 16bit (R/W) */ +#define U300_SYSCON_CEFR					(0x0024) +#define U300_SYSCON_CEFR_UART1_CLK_EN				(0x0200) +#define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN			(0x0100) +#define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN			(0x0080) +#define U300_SYSCON_CEFR_SPI_CLK_EN				(0x0040) +#define U300_SYSCON_CEFR_MMC_CLK_EN				(0x0020) +#define U300_SYSCON_CEFR_I2S1_CLK_EN				(0x0010) +#define U300_SYSCON_CEFR_I2S0_CLK_EN				(0x0008) +#define U300_SYSCON_CEFR_I2C1_CLK_EN				(0x0004) +#define U300_SYSCON_CEFR_I2C0_CLK_EN				(0x0002) +#define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN			(0x0001) +/* Clock enable for the rest of the peripherals 16bit (R/W) */ +#define U300_SYSCON_CERR					(0x0028) +#define U300_SYSCON_CERR_CDS_CLK_EN				(0x2000) +#define U300_SYSCON_CERR_ISP_CLK_EN				(0x1000) +#define U300_SYSCON_CERR_MSPRO_CLK_EN				(0x0800) +#define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN		(0x0400) +#define U300_SYSCON_CERR_SEMI_CLK_EN				(0x0200) +#define U300_SYSCON_CERR_XGAM_CLK_EN				(0x0100) +#define U300_SYSCON_CERR_VIDEO_ENC_CLK_EN			(0x0080) +#define U300_SYSCON_CERR_NANDIF_CLK_EN				(0x0040) +#define U300_SYSCON_CERR_EMIF_CLK_EN				(0x0020) +#define U300_SYSCON_CERR_DMAC_CLK_EN				(0x0010) +#define U300_SYSCON_CERR_CPU_CLK_EN				(0x0008) +#define U300_SYSCON_CERR_APEX_CLK_EN				(0x0004) +#define U300_SYSCON_CERR_AHB_CLK_EN				(0x0002) +#define U300_SYSCON_CERR_AAIF_CLK_EN				(0x0001) +/* Single block clock enable 16bit (-/W) */ +#define U300_SYSCON_SBCER					(0x002c) +#define U300_SYSCON_SBCER_PPM_CLK_EN				(0x0009) +#define U300_SYSCON_SBCER_ACC_TMR_CLK_EN			(0x0008) +#define U300_SYSCON_SBCER_APP_TMR_CLK_EN			(0x0007) +#define U300_SYSCON_SBCER_KEYPAD_CLK_EN				(0x0006) +#define U300_SYSCON_SBCER_GPIO_CLK_EN				(0x0004) +#define U300_SYSCON_SBCER_EH_CLK_EN				(0x0003) +#define U300_SYSCON_SBCER_BTR_CLK_EN				(0x0002) +#define U300_SYSCON_SBCER_UART_CLK_EN				(0x0001) +#define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN			(0x0000) +#define U300_SYSCON_SBCER_UART1_CLK_EN				(0x0019) +#define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN			(0x0018) +#define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN			(0x0017) +#define U300_SYSCON_SBCER_SPI_CLK_EN				(0x0016) +#define U300_SYSCON_SBCER_MMC_CLK_EN				(0x0015) +#define U300_SYSCON_SBCER_I2S1_CLK_EN				(0x0014) +#define U300_SYSCON_SBCER_I2S0_CLK_EN				(0x0013) +#define U300_SYSCON_SBCER_I2C1_CLK_EN				(0x0012) +#define U300_SYSCON_SBCER_I2C0_CLK_EN				(0x0011) +#define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN			(0x0010) +#define U300_SYSCON_SBCER_CDS_CLK_EN				(0x002D) +#define U300_SYSCON_SBCER_ISP_CLK_EN				(0x002C) +#define U300_SYSCON_SBCER_MSPRO_CLK_EN				(0x002B) +#define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN		(0x002A) +#define U300_SYSCON_SBCER_SEMI_CLK_EN				(0x0029) +#define U300_SYSCON_SBCER_XGAM_CLK_EN				(0x0028) +#define U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN			(0x0027) +#define U300_SYSCON_SBCER_NANDIF_CLK_EN				(0x0026) +#define U300_SYSCON_SBCER_EMIF_CLK_EN				(0x0025) +#define U300_SYSCON_SBCER_DMAC_CLK_EN				(0x0024) +#define U300_SYSCON_SBCER_CPU_CLK_EN				(0x0023) +#define U300_SYSCON_SBCER_APEX_CLK_EN				(0x0022) +#define U300_SYSCON_SBCER_AHB_CLK_EN				(0x0021) +#define U300_SYSCON_SBCER_AAIF_CLK_EN				(0x0020) +/* Single block clock disable 16bit (-/W) */ +#define U300_SYSCON_SBCDR					(0x0030) +/* Same values as above for SBCER */ +/* Clock force SLOW peripherals 16bit (R/W) */ +#define U300_SYSCON_CFSR					(0x003c) +#define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN			(0x0200) +#define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN			(0x0100) +#define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN			(0x0080) +#define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN			(0x0020) +#define U300_SYSCON_CFSR_GPIO_CLK_FORCE_EN			(0x0010) +#define U300_SYSCON_CFSR_EH_CLK_FORCE_EN			(0x0008) +#define U300_SYSCON_CFSR_BTR_CLK_FORCE_EN			(0x0004) +#define U300_SYSCON_CFSR_UART_CLK_FORCE_EN			(0x0002) +#define U300_SYSCON_CFSR_SLOW_BRIDGE_CLK_FORCE_EN		(0x0001) +/* Clock force FAST peripherals 16bit (R/W) */ +#define U300_SYSCON_CFFR					(0x40) +/* Values not defined. Define if you want to use them. */ +/* Clock force the rest of the peripherals 16bit (R/W) */ +#define U300_SYSCON_CFRR					(0x44) +#define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN			(0x2000) +#define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN			(0x1000) +#define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN			(0x0800) +#define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN		(0x0400) +#define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN			(0x0200) +#define U300_SYSCON_CFRR_XGAM_CLK_FORCE_EN			(0x0100) +#define U300_SYSCON_CFRR_VIDEO_ENC_CLK_FORCE_EN			(0x0080) +#define U300_SYSCON_CFRR_NANDIF_CLK_FORCE_EN			(0x0040) +#define U300_SYSCON_CFRR_EMIF_CLK_FORCE_EN			(0x0020) +#define U300_SYSCON_CFRR_DMAC_CLK_FORCE_EN			(0x0010) +#define U300_SYSCON_CFRR_CPU_CLK_FORCE_EN			(0x0008) +#define U300_SYSCON_CFRR_APEX_CLK_FORCE_EN			(0x0004) +#define U300_SYSCON_CFRR_AHB_CLK_FORCE_EN			(0x0002) +#define U300_SYSCON_CFRR_AAIF_CLK_FORCE_EN			(0x0001) +/* PLL208 Frequency Control 16bit (R/W) */ +#define U300_SYSCON_PFCR					(0x48) +#define U300_SYSCON_PFCR_DPLL_MULT_NUM				(0x000F) +/* Power Management Control 16bit (R/W) */ +#define U300_SYSCON_PMCR					(0x50) +#define U300_SYSCON_PMCR_DCON_ENABLE				(0x0002) +#define U300_SYSCON_PMCR_PWR_MGNT_ENABLE			(0x0001) +/* Reset Out 16bit (R/W) */ +#define U300_SYSCON_RCR						(0x6c) +#define U300_SYSCON_RCR_RESOUT0_RST_N_DISABLE			(0x0001) +/* EMIF Slew Rate Control 16bit (R/W) */ +#define U300_SYSCON_SRCLR					(0x70) +#define U300_SYSCON_SRCLR_MASK					(0x03FF) +#define U300_SYSCON_SRCLR_VALUE					(0x03FF) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_B			(0x0200) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_5_A			(0x0100) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_B			(0x0080) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_4_A			(0x0040) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_B			(0x0020) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_3_A			(0x0010) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_B			(0x0008) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_2_A			(0x0004) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_B			(0x0002) +#define U300_SYSCON_SRCLR_EMIF_1_SLRC_1_A			(0x0001) +/* EMIF Clock Control Register 16bit (R/W) */ +#define U300_SYSCON_ECCR					(0x0078) +#define U300_SYSCON_ECCR_MASK					(0x000F) +#define U300_SYSCON_ECCR_EMIF_1_STATIC_CLK_EN_N_DISABLE		(0x0008) +#define U300_SYSCON_ECCR_EMIF_1_RET_OUT_CLK_EN_N_DISABLE	(0x0004) +#define U300_SYSCON_ECCR_EMIF_MEMCLK_RET_EN_N_DISABLE		(0x0002) +#define U300_SYSCON_ECCR_EMIF_SDRCLK_RET_EN_N_DISABLE		(0x0001) +/* MMC/MSPRO frequency divider register 0 16bit (R/W) */ +#define U300_SYSCON_MMF0R					(0x90) +#define U300_SYSCON_MMF0R_MASK					(0x00FF) +#define U300_SYSCON_MMF0R_FREQ_0_HIGH_MASK			(0x00F0) +#define U300_SYSCON_MMF0R_FREQ_0_LOW_MASK			(0x000F) +/* MMC/MSPRO frequency divider register 1 16bit (R/W) */ +#define U300_SYSCON_MMF1R					(0x94) +#define U300_SYSCON_MMF1R_MASK					(0x00FF) +#define U300_SYSCON_MMF1R_FREQ_1_HIGH_MASK			(0x00F0) +#define U300_SYSCON_MMF1R_FREQ_1_LOW_MASK			(0x000F) +/* Clock control for the MMC and MSPRO blocks 16bit (R/W) */ +#define U300_SYSCON_MMCR					(0x9C) +#define U300_SYSCON_MMCR_MASK					(0x0003) +#define U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE			(0x0002) +#define U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE			(0x0001) +/* SYS_0_CLK_CONTROL first clock control 16bit (R/W) */ +#define U300_SYSCON_S0CCR					(0x120) +#define U300_SYSCON_S0CCR_FIELD_MASK				(0x43FF) +#define U300_SYSCON_S0CCR_CLOCK_REQ				(0x4000) +#define U300_SYSCON_S0CCR_CLOCK_REQ_MONITOR			(0x2000) +#define U300_SYSCON_S0CCR_CLOCK_INV				(0x0200) +#define U300_SYSCON_S0CCR_CLOCK_FREQ_MASK			(0x01E0) +#define U300_SYSCON_S0CCR_CLOCK_SELECT_MASK			(0x001E) +#define U300_SYSCON_S0CCR_CLOCK_ENABLE				(0x0001) +#define U300_SYSCON_S0CCR_SEL_MCLK				(0x8<<1) +#define U300_SYSCON_S0CCR_SEL_ACC_FSM_CLK			(0xA<<1) +#define U300_SYSCON_S0CCR_SEL_PLL60_48_CLK			(0xC<<1) +#define U300_SYSCON_S0CCR_SEL_PLL60_60_CLK			(0xD<<1) +#define U300_SYSCON_S0CCR_SEL_ACC_PLL208_CLK			(0xE<<1) +#define U300_SYSCON_S0CCR_SEL_APP_PLL13_CLK			(0x0<<1) +#define U300_SYSCON_S0CCR_SEL_APP_FSM_CLK			(0x2<<1) +#define U300_SYSCON_S0CCR_SEL_RTC_CLK				(0x4<<1) +#define U300_SYSCON_S0CCR_SEL_APP_PLL208_CLK			(0x6<<1) +/* SYS_1_CLK_CONTROL second clock control 16 bit (R/W) */ +#define U300_SYSCON_S1CCR					(0x124) +#define U300_SYSCON_S1CCR_FIELD_MASK				(0x43FF) +#define U300_SYSCON_S1CCR_CLOCK_REQ				(0x4000) +#define U300_SYSCON_S1CCR_CLOCK_REQ_MONITOR			(0x2000) +#define U300_SYSCON_S1CCR_CLOCK_INV				(0x0200) +#define U300_SYSCON_S1CCR_CLOCK_FREQ_MASK			(0x01E0) +#define U300_SYSCON_S1CCR_CLOCK_SELECT_MASK			(0x001E) +#define U300_SYSCON_S1CCR_CLOCK_ENABLE				(0x0001) +#define U300_SYSCON_S1CCR_SEL_MCLK				(0x8<<1) +#define U300_SYSCON_S1CCR_SEL_ACC_FSM_CLK			(0xA<<1) +#define U300_SYSCON_S1CCR_SEL_PLL60_48_CLK			(0xC<<1) +#define U300_SYSCON_S1CCR_SEL_PLL60_60_CLK			(0xD<<1) +#define U300_SYSCON_S1CCR_SEL_ACC_PLL208_CLK			(0xE<<1) +#define U300_SYSCON_S1CCR_SEL_ACC_PLL13_CLK			(0x0<<1) +#define U300_SYSCON_S1CCR_SEL_APP_FSM_CLK			(0x2<<1) +#define U300_SYSCON_S1CCR_SEL_RTC_CLK				(0x4<<1) +#define U300_SYSCON_S1CCR_SEL_APP_PLL208_CLK			(0x6<<1) +/* SYS_2_CLK_CONTROL third clock contol 16 bit (R/W) */ +#define U300_SYSCON_S2CCR					(0x128) +#define U300_SYSCON_S2CCR_FIELD_MASK				(0xC3FF) +#define U300_SYSCON_S2CCR_CLK_STEAL				(0x8000) +#define U300_SYSCON_S2CCR_CLOCK_REQ				(0x4000) +#define U300_SYSCON_S2CCR_CLOCK_REQ_MONITOR			(0x2000) +#define U300_SYSCON_S2CCR_CLOCK_INV				(0x0200) +#define U300_SYSCON_S2CCR_CLOCK_FREQ_MASK			(0x01E0) +#define U300_SYSCON_S2CCR_CLOCK_SELECT_MASK			(0x001E) +#define U300_SYSCON_S2CCR_CLOCK_ENABLE				(0x0001) +#define U300_SYSCON_S2CCR_SEL_MCLK				(0x8<<1) +#define U300_SYSCON_S2CCR_SEL_ACC_FSM_CLK			(0xA<<1) +#define U300_SYSCON_S2CCR_SEL_PLL60_48_CLK			(0xC<<1) +#define U300_SYSCON_S2CCR_SEL_PLL60_60_CLK			(0xD<<1) +#define U300_SYSCON_S2CCR_SEL_ACC_PLL208_CLK			(0xE<<1) +#define U300_SYSCON_S2CCR_SEL_ACC_PLL13_CLK			(0x0<<1) +#define U300_SYSCON_S2CCR_SEL_APP_FSM_CLK			(0x2<<1) +#define U300_SYSCON_S2CCR_SEL_RTC_CLK				(0x4<<1) +#define U300_SYSCON_S2CCR_SEL_APP_PLL208_CLK			(0x6<<1) +/* SC_PLL_IRQ_CONTROL 16bit (R/W) */ +#define U300_SYSCON_PICR					(0x0130) +#define U300_SYSCON_PICR_MASK					(0x00FF) +#define U300_SYSCON_PICR_FORCE_PLL208_LOCK_LOW_ENABLE		(0x0080) +#define U300_SYSCON_PICR_FORCE_PLL208_LOCK_HIGH_ENABLE		(0x0040) +#define U300_SYSCON_PICR_FORCE_PLL13_LOCK_LOW_ENABLE		(0x0020) +#define U300_SYSCON_PICR_FORCE_PLL13_LOCK_HIGH_ENABLE		(0x0010) +#define U300_SYSCON_PICR_IRQMASK_PLL13_UNLOCK_ENABLE		(0x0008) +#define U300_SYSCON_PICR_IRQMASK_PLL13_LOCK_ENABLE		(0x0004) +#define U300_SYSCON_PICR_IRQMASK_PLL208_UNLOCK_ENABLE		(0x0002) +#define U300_SYSCON_PICR_IRQMASK_PLL208_LOCK_ENABLE		(0x0001) +/* SC_PLL_IRQ_STATUS 16 bit (R/-) */ +#define U300_SYSCON_PISR					(0x0134) +#define U300_SYSCON_PISR_MASK					(0x000F) +#define U300_SYSCON_PISR_PLL13_UNLOCK_IND			(0x0008) +#define U300_SYSCON_PISR_PLL13_LOCK_IND				(0x0004) +#define U300_SYSCON_PISR_PLL208_UNLOCK_IND			(0x0002) +#define U300_SYSCON_PISR_PLL208_LOCK_IND			(0x0001) +/* SC_PLL_IRQ_CLEAR 16 bit (-/W) */ +#define U300_SYSCON_PICLR					(0x0138) +#define U300_SYSCON_PICLR_MASK					(0x000F) +#define U300_SYSCON_PICLR_RWMASK				(0x0000) +#define U300_SYSCON_PICLR_PLL13_UNLOCK_SC			(0x0008) +#define U300_SYSCON_PICLR_PLL13_LOCK_SC				(0x0004) +#define U300_SYSCON_PICLR_PLL208_UNLOCK_SC			(0x0002) +#define U300_SYSCON_PICLR_PLL208_LOCK_SC			(0x0001) +/* Clock activity observability register 0 */ +#define U300_SYSCON_C0OAR					(0x140) +#define U300_SYSCON_C0OAR_MASK					(0xFFFF) +#define U300_SYSCON_C0OAR_VALUE					(0xFFFF) +#define U300_SYSCON_C0OAR_BT_H_CLK				(0x8000) +#define U300_SYSCON_C0OAR_ASPB_P_CLK				(0x4000) +#define U300_SYSCON_C0OAR_APP_SEMI_H_CLK			(0x2000) +#define U300_SYSCON_C0OAR_APP_SEMI_CLK				(0x1000) +#define U300_SYSCON_C0OAR_APP_MMC_MSPRO_CLK			(0x0800) +#define U300_SYSCON_C0OAR_APP_I2S1_CLK				(0x0400) +#define U300_SYSCON_C0OAR_APP_I2S0_CLK				(0x0200) +#define U300_SYSCON_C0OAR_APP_CPU_CLK				(0x0100) +#define U300_SYSCON_C0OAR_APP_52_CLK				(0x0080) +#define U300_SYSCON_C0OAR_APP_208_CLK				(0x0040) +#define U300_SYSCON_C0OAR_APP_104_CLK				(0x0020) +#define U300_SYSCON_C0OAR_APEX_CLK				(0x0010) +#define U300_SYSCON_C0OAR_AHPB_M_H_CLK				(0x0008) +#define U300_SYSCON_C0OAR_AHB_CLK				(0x0004) +#define U300_SYSCON_C0OAR_AFPB_P_CLK				(0x0002) +#define U300_SYSCON_C0OAR_AAIF_CLK				(0x0001) +/* Clock activity observability register 1 */ +#define U300_SYSCON_C1OAR					(0x144) +#define U300_SYSCON_C1OAR_MASK					(0x3FFE) +#define U300_SYSCON_C1OAR_VALUE					(0x3FFE) +#define U300_SYSCON_C1OAR_NFIF_F_CLK				(0x2000) +#define U300_SYSCON_C1OAR_MSPRO_CLK				(0x1000) +#define U300_SYSCON_C1OAR_MMC_P_CLK				(0x0800) +#define U300_SYSCON_C1OAR_MMC_CLK				(0x0400) +#define U300_SYSCON_C1OAR_KP_P_CLK				(0x0200) +#define U300_SYSCON_C1OAR_I2C1_P_CLK				(0x0100) +#define U300_SYSCON_C1OAR_I2C0_P_CLK				(0x0080) +#define U300_SYSCON_C1OAR_GPIO_CLK				(0x0040) +#define U300_SYSCON_C1OAR_EMIF_MPMC_CLK				(0x0020) +#define U300_SYSCON_C1OAR_EMIF_H_CLK				(0x0010) +#define U300_SYSCON_C1OAR_EVHIST_CLK				(0x0008) +#define U300_SYSCON_C1OAR_PPM_CLK				(0x0004) +#define U300_SYSCON_C1OAR_DMA_CLK				(0x0002) +/* Clock activity observability register 2 */ +#define U300_SYSCON_C2OAR					(0x148) +#define U300_SYSCON_C2OAR_MASK					(0x0FFF) +#define U300_SYSCON_C2OAR_VALUE					(0x0FFF) +#define U300_SYSCON_C2OAR_XGAM_CDI_CLK				(0x0800) +#define U300_SYSCON_C2OAR_XGAM_CLK				(0x0400) +#define U300_SYSCON_C2OAR_VC_H_CLK				(0x0200) +#define U300_SYSCON_C2OAR_VC_CLK				(0x0100) +#define U300_SYSCON_C2OAR_UA_P_CLK				(0x0080) +#define U300_SYSCON_C2OAR_TMR1_CLK				(0x0040) +#define U300_SYSCON_C2OAR_TMR0_CLK				(0x0020) +#define U300_SYSCON_C2OAR_SPI_P_CLK				(0x0010) +#define U300_SYSCON_C2OAR_PCM_I2S1_CORE_CLK			(0x0008) +#define U300_SYSCON_C2OAR_PCM_I2S1_CLK				(0x0004) +#define U300_SYSCON_C2OAR_PCM_I2S0_CORE_CLK			(0x0002) +#define U300_SYSCON_C2OAR_PCM_I2S0_CLK				(0x0001) +  /*   * The clocking hierarchy currently looks like this. @@ -386,6 +728,213 @@ syscon_clk_register(struct device *dev, const char *name,  	return clk;  } +#define U300_CLK_TYPE_SLOW 0 +#define U300_CLK_TYPE_FAST 1 +#define U300_CLK_TYPE_REST 2 + +/** + * struct u300_clock - defines the bits and pieces for a certain clock + * @type: the clock type, slow fast or rest + * @id: the bit in the slow/fast/rest register for this clock + * @hw_ctrld: whether the clock is hardware controlled + * @clk_val: a value to poke in the one-write enable/disable registers + */ +struct u300_clock { +	u8 type; +	u8 id; +	bool hw_ctrld; +	u16 clk_val; +}; + +struct u300_clock const __initconst u300_clk_lookup[] = { +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 3, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_CPU_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 4, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_DMAC_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 5, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_EMIF_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 6, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_NANDIF_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 8, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_XGAM_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 9, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_SEMI_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 10, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_REST, +		.id = 12, +		.hw_ctrld = false, +		/* INTCON: cannot be enabled, just taken out of reset */ +		.clk_val = 0xFFFFU, +	}, +	{ +		.type = U300_CLK_TYPE_FAST, +		.id = 0, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_FAST, +		.id = 1, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_I2C0_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_FAST, +		.id = 2, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_I2C1_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_FAST, +		.id = 5, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_MMC_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_FAST, +		.id = 6, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_SPI_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 0, +		.hw_ctrld = true, +		.clk_val = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 1, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_UART_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 4, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_GPIO_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 6, +		.hw_ctrld = true, +		/* No clock enable register bit */ +		.clk_val = 0xFFFFU, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 7, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_APP_TMR_CLK_EN, +	}, +	{ +		.type = U300_CLK_TYPE_SLOW, +		.id = 8, +		.hw_ctrld = false, +		.clk_val = U300_SYSCON_SBCER_ACC_TMR_CLK_EN, +	}, +}; + +static void __init of_u300_syscon_clk_init(struct device_node *np) +{ +	struct clk *clk = ERR_PTR(-EINVAL); +	const char *clk_name = np->name; +	const char *parent_name; +	void __iomem *res_reg; +	void __iomem *en_reg; +	u32 clk_type; +	u32 clk_id; +	int i; + +	if (of_property_read_u32(np, "clock-type", &clk_type)) { +		pr_err("%s: syscon clock \"%s\" missing clock-type property\n", +		       __func__, clk_name); +		return; +	} +	if (of_property_read_u32(np, "clock-id", &clk_id)) { +		pr_err("%s: syscon clock \"%s\" missing clock-id property\n", +		       __func__, clk_name); +		return; +	} +	parent_name = of_clk_get_parent_name(np, 0); + +	switch (clk_type) { +	case U300_CLK_TYPE_SLOW: +		res_reg = syscon_vbase + U300_SYSCON_RSR; +		en_reg = syscon_vbase + U300_SYSCON_CESR; +		break; +	case U300_CLK_TYPE_FAST: +		res_reg = syscon_vbase + U300_SYSCON_RFR; +		en_reg = syscon_vbase + U300_SYSCON_CEFR; +		break; +	case U300_CLK_TYPE_REST: +		res_reg = syscon_vbase + U300_SYSCON_RRR; +		en_reg = syscon_vbase + U300_SYSCON_CERR; +		break; +	default: +		pr_err("unknown clock type %x specified\n", clk_type); +		return; +	} + +	for (i = 0; i < ARRAY_SIZE(u300_clk_lookup); i++) { +		const struct u300_clock *u3clk = &u300_clk_lookup[i]; + +		if (u3clk->type == clk_type && u3clk->id == clk_id) +			clk = syscon_clk_register(NULL, +						  clk_name, parent_name, +						  0, u3clk->hw_ctrld, +						  res_reg, u3clk->id, +						  en_reg, u3clk->id, +						  u3clk->clk_val); +	} + +	if (!IS_ERR(clk)) { +		of_clk_add_provider(np, of_clk_src_simple_get, clk); + +		/* +		 * Some few system clocks - device tree does not +		 * represent clocks without a corresponding device node. +		 * for now we add these three clocks here. +		 */ +		if (clk_type == U300_CLK_TYPE_REST && clk_id == 5) +			clk_register_clkdev(clk, NULL, "pl172"); +		if (clk_type == U300_CLK_TYPE_REST && clk_id == 9) +			clk_register_clkdev(clk, NULL, "semi"); +		if (clk_type == U300_CLK_TYPE_REST && clk_id == 12) +			clk_register_clkdev(clk, NULL, "intcon"); +	} +} +  /**   * struct clk_mclk - U300 MCLK clock (MMC/SD clock)   * @hw: corresponding clock hardware entry @@ -590,10 +1139,41 @@ mclk_clk_register(struct device *dev, const char *name,  	return clk;  } +static void __init of_u300_syscon_mclk_init(struct device_node *np) +{ +	struct clk *clk = ERR_PTR(-EINVAL); +	const char *clk_name = np->name; +	const char *parent_name; + +	parent_name = of_clk_get_parent_name(np, 0); +	clk = mclk_clk_register(NULL, clk_name, parent_name, false); +	if (!IS_ERR(clk)) +		of_clk_add_provider(np, of_clk_src_simple_get, clk); +} + +static const __initconst struct of_device_id u300_clk_match[] = { +	{ +		.compatible = "fixed-clock", +		.data = of_fixed_clk_setup, +	}, +	{ +		.compatible = "fixed-factor-clock", +		.data = of_fixed_factor_clk_setup, +	}, +	{ +		.compatible = "stericsson,u300-syscon-clk", +		.data = of_u300_syscon_clk_init, +	}, +	{ +		.compatible = "stericsson,u300-syscon-mclk", +		.data = of_u300_syscon_mclk_init, +	}, +}; + +  void __init u300_clk_init(void __iomem *base)  {  	u16 val; -	struct clk *clk;  	syscon_vbase = base; @@ -610,137 +1190,5 @@ void __init u300_clk_init(void __iomem *base)  	val |= U300_SYSCON_PMCR_PWR_MGNT_ENABLE;  	writew(val, syscon_vbase + U300_SYSCON_PMCR); -	/* These are always available (RTC and PLL13) */ -	clk = clk_register_fixed_rate(NULL, "app_32_clk", NULL, -				      CLK_IS_ROOT, 32768); -	/* The watchdog sits directly on the 32 kHz clock */ -	clk_register_clkdev(clk, NULL, "coh901327_wdog"); -	clk = clk_register_fixed_rate(NULL, "pll13", NULL, -				      CLK_IS_ROOT, 13000000); - -	/* These derive from PLL208 */ -	clk = clk_register_fixed_rate(NULL, "pll208", NULL, -				      CLK_IS_ROOT, 208000000); -	clk = clk_register_fixed_factor(NULL, "app_208_clk", "pll208", -					0, 1, 1); -	clk = clk_register_fixed_factor(NULL, "app_104_clk", "pll208", -					0, 1, 2); -	clk = clk_register_fixed_factor(NULL, "app_52_clk", "pll208", -					0, 1, 4); -	/* The 52 MHz is divided down to 26 MHz */ -	clk = clk_register_fixed_factor(NULL, "app_26_clk", "app_52_clk", -					0, 1, 2); - -	/* Directly on the AMBA interconnect */ -	clk = syscon_clk_register(NULL, "cpu_clk", "app_208_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RRR, 3, -				  syscon_vbase + U300_SYSCON_CERR, 3, -				  U300_SYSCON_SBCER_CPU_CLK_EN); -	clk = syscon_clk_register(NULL, "dmac_clk", "app_52_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RRR, 4, -				  syscon_vbase + U300_SYSCON_CERR, 4, -				  U300_SYSCON_SBCER_DMAC_CLK_EN); -	clk_register_clkdev(clk, NULL, "dma"); -	clk = syscon_clk_register(NULL, "fsmc_clk", "app_52_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RRR, 6, -				  syscon_vbase + U300_SYSCON_CERR, 6, -				  U300_SYSCON_SBCER_NANDIF_CLK_EN); -	clk_register_clkdev(clk, NULL, "fsmc-nand"); -	clk = syscon_clk_register(NULL, "xgam_clk", "app_52_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RRR, 8, -				  syscon_vbase + U300_SYSCON_CERR, 8, -				  U300_SYSCON_SBCER_XGAM_CLK_EN); -	clk_register_clkdev(clk, NULL, "xgam"); -	clk = syscon_clk_register(NULL, "semi_clk", "app_104_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RRR, 9, -				  syscon_vbase + U300_SYSCON_CERR, 9, -				  U300_SYSCON_SBCER_SEMI_CLK_EN); -	clk_register_clkdev(clk, NULL, "semi"); - -	/* AHB bridge clocks */ -	clk = syscon_clk_register(NULL, "ahb_subsys_clk", "app_52_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RRR, 10, -				  syscon_vbase + U300_SYSCON_CERR, 10, -				  U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN); -	clk = syscon_clk_register(NULL, "intcon_clk", "ahb_subsys_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RRR, 12, -				  syscon_vbase + U300_SYSCON_CERR, 12, -				  /* Cannot be enabled, just taken out of reset */ -				  0xFFFFU); -	clk_register_clkdev(clk, NULL, "intcon"); -	clk = syscon_clk_register(NULL, "emif_clk", "ahb_subsys_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RRR, 5, -				  syscon_vbase + U300_SYSCON_CERR, 5, -				  U300_SYSCON_SBCER_EMIF_CLK_EN); -	clk_register_clkdev(clk, NULL, "pl172"); - -	/* FAST bridge clocks */ -	clk = syscon_clk_register(NULL, "fast_clk", "app_26_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RFR, 0, -				  syscon_vbase + U300_SYSCON_CEFR, 0, -				  U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN); -	clk = syscon_clk_register(NULL, "i2c0_p_clk", "fast_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RFR, 1, -				  syscon_vbase + U300_SYSCON_CEFR, 1, -				  U300_SYSCON_SBCER_I2C0_CLK_EN); -	clk_register_clkdev(clk, NULL, "stu300.0"); -	clk = syscon_clk_register(NULL, "i2c1_p_clk", "fast_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RFR, 2, -				  syscon_vbase + U300_SYSCON_CEFR, 2, -				  U300_SYSCON_SBCER_I2C1_CLK_EN); -	clk_register_clkdev(clk, NULL, "stu300.1"); -	clk = syscon_clk_register(NULL, "mmc_p_clk", "fast_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RFR, 5, -				  syscon_vbase + U300_SYSCON_CEFR, 5, -				  U300_SYSCON_SBCER_MMC_CLK_EN); -	clk_register_clkdev(clk, "apb_pclk", "mmci"); -	clk = syscon_clk_register(NULL, "spi_p_clk", "fast_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RFR, 6, -				  syscon_vbase + U300_SYSCON_CEFR, 6, -				  U300_SYSCON_SBCER_SPI_CLK_EN); -	/* The SPI has no external clock for the outward bus, uses the pclk */ -	clk_register_clkdev(clk, NULL, "pl022"); -	clk_register_clkdev(clk, "apb_pclk", "pl022"); - -	/* SLOW bridge clocks */ -	clk = syscon_clk_register(NULL, "slow_clk", "pll13", 0, true, -				  syscon_vbase + U300_SYSCON_RSR, 0, -				  syscon_vbase + U300_SYSCON_CESR, 0, -				  U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN); -	clk = syscon_clk_register(NULL, "uart0_clk", "slow_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RSR, 1, -				  syscon_vbase + U300_SYSCON_CESR, 1, -				  U300_SYSCON_SBCER_UART_CLK_EN); -	/* Same clock is used for APB and outward bus */ -	clk_register_clkdev(clk, NULL, "uart0"); -	clk_register_clkdev(clk, "apb_pclk", "uart0"); -	clk = syscon_clk_register(NULL, "gpio_clk", "slow_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RSR, 4, -				  syscon_vbase + U300_SYSCON_CESR, 4, -				  U300_SYSCON_SBCER_GPIO_CLK_EN); -	clk_register_clkdev(clk, NULL, "u300-gpio"); -	clk = syscon_clk_register(NULL, "keypad_clk", "slow_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RSR, 5, -				  syscon_vbase + U300_SYSCON_CESR, 6, -				  U300_SYSCON_SBCER_KEYPAD_CLK_EN); -	clk_register_clkdev(clk, NULL, "coh901461-keypad"); -	clk = syscon_clk_register(NULL, "rtc_clk", "slow_clk", 0, true, -				  syscon_vbase + U300_SYSCON_RSR, 6, -				  /* No clock enable register bit */ -				  NULL, 0, 0xFFFFU); -	clk_register_clkdev(clk, NULL, "rtc-coh901331"); -	clk = syscon_clk_register(NULL, "app_tmr_clk", "slow_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RSR, 7, -				  syscon_vbase + U300_SYSCON_CESR, 7, -				  U300_SYSCON_SBCER_APP_TMR_CLK_EN); -	clk_register_clkdev(clk, NULL, "apptimer"); -	clk = syscon_clk_register(NULL, "acc_tmr_clk", "slow_clk", 0, false, -				  syscon_vbase + U300_SYSCON_RSR, 8, -				  syscon_vbase + U300_SYSCON_CESR, 8, -				  U300_SYSCON_SBCER_ACC_TMR_CLK_EN); -	clk_register_clkdev(clk, NULL, "timer"); - -	/* Then this special MMC/SD clock */ -	clk = mclk_clk_register(NULL, "mmc_clk", "mmc_p_clk", false); -	clk_register_clkdev(clk, NULL, "mmci"); +	of_clk_init(u300_clk_match);  } diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 553ac35bcc91..82306f5fb9c2 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -42,6 +42,7 @@ struct clk_device {  #define PLL_TYPE_VT8500		0  #define PLL_TYPE_WM8650		1  #define PLL_TYPE_WM8750		2 +#define PLL_TYPE_WM8850		3  struct clk_pll {  	struct clk_hw	hw; @@ -156,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,  	divisor =  parent_rate / rate; -	/* If prate / rate would be decimal, incr the divisor */ -	if (rate * divisor < parent_rate) -		divisor++; -  	if (divisor == cdev->div_mask + 1)  		divisor = 0; @@ -327,6 +324,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);  #define WM8750_BITS_TO_VAL(f, m, d1, d2)				\  		((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2) +/* Helper macros for PLL_WM8850 */ +#define WM8850_PLL_MUL(x)	((((x >> 16) & 0x7F) + 1) * 2) +#define WM8850_PLL_DIV(x)	((((x >> 8) & 1) + 1) * (1 << (x & 3))) + +#define WM8850_BITS_TO_FREQ(r, m, d1, d2)				\ +				(r * ((m + 1) * 2) / ((d1+1) * (1 << d2))) + +#define WM8850_BITS_TO_VAL(m, d1, d2)					\ +		((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2)  static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,  				u32 *multiplier, u32 *prediv) @@ -466,6 +472,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,  	*divisor2 = best_div2;  } +static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, +				u32 *multiplier, u32 *divisor1, u32 *divisor2) +{ +	u32 mul, div1, div2; +	u32 best_mul, best_div1, best_div2; +	unsigned long tclk, rate_err, best_err; + +	best_err = (unsigned long)-1; + +	/* Find the closest match (lower or equal to requested) */ +	for (div1 = 1; div1 >= 0; div1--) +		for (div2 = 3; div2 >= 0; div2--) +			for (mul = 0; mul <= 127; mul++) { +				tclk = parent_rate * ((mul + 1) * 2) / +						((div1 + 1) * (1 << div2)); +				if (tclk > rate) +					continue; +				/* error will always be +ve */ +				rate_err = rate - tclk; +				if (rate_err == 0) { +					*multiplier = mul; +					*divisor1 = div1; +					*divisor2 = div2; +					return; +				} + +				if (rate_err < best_err) { +					best_err = rate_err; +					best_mul = mul; +					best_div1 = div1; +					best_div2 = div2; +				} +			} + +	/* if we got here, it wasn't an exact match */ +	pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, +							rate - best_err); + +	*multiplier = best_mul; +	*divisor1 = best_div1; +	*divisor2 = best_div2; +} +  static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,  				unsigned long parent_rate)  { @@ -489,6 +538,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,  		wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);  		pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);  		break; +	case PLL_TYPE_WM8850: +		wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); +		pll_val = WM8850_BITS_TO_VAL(mul, div1, div2); +		break;  	default:  		pr_err("%s: invalid pll type\n", __func__);  		return 0; @@ -525,6 +578,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,  		wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);  		round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);  		break; +	case PLL_TYPE_WM8850: +		wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2); +		round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2); +		break;  	default:  		round_rate = 0;  	} @@ -552,6 +609,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,  		pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);  		pll_freq /= WM8750_PLL_DIV(pll_val);  		break; +	case PLL_TYPE_WM8850: +		pll_freq = parent_rate * WM8850_PLL_MUL(pll_val); +		pll_freq /= WM8850_PLL_DIV(pll_val); +		break;  	default:  		pll_freq = 0;  	} @@ -628,6 +689,12 @@ static void __init wm8750_pll_init(struct device_node *node)  }  CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init); +static void __init wm8850_pll_init(struct device_node *node) +{ +	vtwm_pll_clk_init(node, PLL_TYPE_WM8850); +} +CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init); +  void __init vtwm_clk_init(void __iomem *base)  {  	if (!base) diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 16ed06808554..1b3f8c9b98cc 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -97,7 +97,7 @@ static int wm831x_fll_prepare(struct clk_hw *hw)  	struct wm831x *wm831x = clkdata->wm831x;  	int ret; -	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, +	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1,  			      WM831X_FLL_ENA, WM831X_FLL_ENA);  	if (ret != 0)  		dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret); @@ -114,9 +114,9 @@ static void wm831x_fll_unprepare(struct clk_hw *hw)  	struct wm831x *wm831x = clkdata->wm831x;  	int ret; -	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0); +	ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);  	if (ret != 0) -		dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret); +		dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);  }  static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw, @@ -299,8 +299,8 @@ static void wm831x_clkout_unprepare(struct clk_hw *hw)  }  static const char *wm831x_clkout_parents[] = { -	"xtal",  	"fll", +	"xtal",  };  static u8 wm831x_clkout_get_parent(struct clk_hw *hw) @@ -318,9 +318,9 @@ static u8 wm831x_clkout_get_parent(struct clk_hw *hw)  	}  	if (ret & WM831X_CLKOUT_SRC) -		return 0; -	else  		return 1; +	else +		return 0;  }  static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent) @@ -384,7 +384,7 @@ static int wm831x_clk_probe(struct platform_device *pdev)  	if (IS_ERR(clkdata->clkout))  		return PTR_ERR(clkdata->clkout); -	dev_set_drvdata(&pdev->dev, clkdata); +	platform_set_drvdata(pdev, clkdata);  	return 0;  } diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c deleted file mode 100644 index 32062977f453..000000000000 --- a/drivers/clk/clk-zynq.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2012 National Instruments - * - * Josh Cartwright <[email protected]> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program.  If not, see <http://www.gnu.org/licenses/>. - */ -#include <linux/io.h> -#include <linux/of.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/clk-provider.h> -#include <linux/clk/zynq.h> - -static void __iomem *slcr_base; - -struct zynq_pll_clk { -	struct clk_hw	hw; -	void __iomem	*pll_ctrl; -	void __iomem	*pll_cfg; -}; - -#define to_zynq_pll_clk(hw)	container_of(hw, struct zynq_pll_clk, hw) - -#define CTRL_PLL_FDIV(x)	((x) >> 12) - -static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, -					  unsigned long parent_rate) -{ -	struct zynq_pll_clk *pll = to_zynq_pll_clk(hw); -	return parent_rate * CTRL_PLL_FDIV(ioread32(pll->pll_ctrl)); -} - -static const struct clk_ops zynq_pll_clk_ops = { -	.recalc_rate	= zynq_pll_recalc_rate, -}; - -static void __init zynq_pll_clk_setup(struct device_node *np) -{ -	struct clk_init_data init; -	struct zynq_pll_clk *pll; -	const char *parent_name; -	struct clk *clk; -	u32 regs[2]; -	int ret; - -	ret = of_property_read_u32_array(np, "reg", regs, ARRAY_SIZE(regs)); -	if (WARN_ON(ret)) -		return; - -	pll = kzalloc(sizeof(*pll), GFP_KERNEL); -	if (WARN_ON(!pll)) -		return; - -	pll->pll_ctrl = slcr_base + regs[0]; -	pll->pll_cfg  = slcr_base + regs[1]; - -	of_property_read_string(np, "clock-output-names", &init.name); - -	init.ops = &zynq_pll_clk_ops; -	parent_name = of_clk_get_parent_name(np, 0); -	init.parent_names = &parent_name; -	init.num_parents = 1; - -	pll->hw.init = &init; - -	clk = clk_register(NULL, &pll->hw); -	if (WARN_ON(IS_ERR(clk))) -		return; - -	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); -	if (WARN_ON(ret)) -		return; -} -CLK_OF_DECLARE(zynq_pll, "xlnx,zynq-pll", zynq_pll_clk_setup); - -struct zynq_periph_clk { -	struct clk_hw		hw; -	struct clk_onecell_data	onecell_data; -	struct clk		*gates[2]; -	void __iomem		*clk_ctrl; -	spinlock_t		clkact_lock; -}; - -#define to_zynq_periph_clk(hw)	container_of(hw, struct zynq_periph_clk, hw) - -static const u8 periph_clk_parent_map[] = { -	0, 0, 1, 2 -}; -#define PERIPH_CLK_CTRL_SRC(x)	(periph_clk_parent_map[((x) & 0x30) >> 4]) -#define PERIPH_CLK_CTRL_DIV(x)	(((x) & 0x3F00) >> 8) - -static unsigned long zynq_periph_recalc_rate(struct clk_hw *hw, -					     unsigned long parent_rate) -{ -	struct zynq_periph_clk *periph = to_zynq_periph_clk(hw); -	return parent_rate / PERIPH_CLK_CTRL_DIV(ioread32(periph->clk_ctrl)); -} - -static u8 zynq_periph_get_parent(struct clk_hw *hw) -{ -	struct zynq_periph_clk *periph = to_zynq_periph_clk(hw); -	return PERIPH_CLK_CTRL_SRC(ioread32(periph->clk_ctrl)); -} - -static const struct clk_ops zynq_periph_clk_ops = { -	.recalc_rate	= zynq_periph_recalc_rate, -	.get_parent	= zynq_periph_get_parent, -}; - -static void __init zynq_periph_clk_setup(struct device_node *np) -{ -	struct zynq_periph_clk *periph; -	const char *parent_names[3]; -	struct clk_init_data init; -	int clk_num = 0, err; -	const char *name; -	struct clk *clk; -	u32 reg; -	int i; - -	err = of_property_read_u32(np, "reg", ®); -	if (WARN_ON(err)) -		return; - -	periph = kzalloc(sizeof(*periph), GFP_KERNEL); -	if (WARN_ON(!periph)) -		return; - -	periph->clk_ctrl = slcr_base + reg; -	spin_lock_init(&periph->clkact_lock); - -	init.name = np->name; -	init.ops = &zynq_periph_clk_ops; -	for (i = 0; i < ARRAY_SIZE(parent_names); i++) -		parent_names[i] = of_clk_get_parent_name(np, i); -	init.parent_names = parent_names; -	init.num_parents = ARRAY_SIZE(parent_names); - -	periph->hw.init = &init; - -	clk = clk_register(NULL, &periph->hw); -	if (WARN_ON(IS_ERR(clk))) -		return; - -	err = of_clk_add_provider(np, of_clk_src_simple_get, clk); -	if (WARN_ON(err)) -		return; - -	err = of_property_read_string_index(np, "clock-output-names", 0, -					    &name); -	if (WARN_ON(err)) -		return; - -	periph->gates[0] = clk_register_gate(NULL, name, np->name, 0, -					     periph->clk_ctrl, 0, 0, -					     &periph->clkact_lock); -	if (WARN_ON(IS_ERR(periph->gates[0]))) -		return; -	clk_num++; - -	/* some periph clks have 2 downstream gates */ -	err = of_property_read_string_index(np, "clock-output-names", 1, -					    &name); -	if (err != -ENODATA) { -		periph->gates[1] = clk_register_gate(NULL, name, np->name, 0, -						     periph->clk_ctrl, 1, 0, -						     &periph->clkact_lock); -		if (WARN_ON(IS_ERR(periph->gates[1]))) -			return; -		clk_num++; -	} - -	periph->onecell_data.clks = periph->gates; -	periph->onecell_data.clk_num = clk_num; - -	err = of_clk_add_provider(np, of_clk_src_onecell_get, -				  &periph->onecell_data); -	if (WARN_ON(err)) -		return; -} -CLK_OF_DECLARE(zynq_periph, "xlnx,zynq-periph-clock", zynq_periph_clk_setup); - -/* CPU Clock domain is modelled as a mux with 4 children subclks, whose - * derivative rates depend on CLK_621_TRUE - */ - -struct zynq_cpu_clk { -	struct clk_hw		hw; -	struct clk_onecell_data	onecell_data; -	struct clk		*subclks[4]; -	void __iomem		*clk_ctrl; -	spinlock_t		clkact_lock; -}; - -#define to_zynq_cpu_clk(hw)	container_of(hw, struct zynq_cpu_clk, hw) - -static const u8 zynq_cpu_clk_parent_map[] = { -	1, 1, 2, 0 -}; -#define CPU_CLK_SRCSEL(x)	(zynq_cpu_clk_parent_map[(((x) & 0x30) >> 4)]) -#define CPU_CLK_CTRL_DIV(x)	(((x) & 0x3F00) >> 8) - -static u8 zynq_cpu_clk_get_parent(struct clk_hw *hw) -{ -	struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw); -	return CPU_CLK_SRCSEL(ioread32(cpuclk->clk_ctrl)); -} - -static unsigned long zynq_cpu_clk_recalc_rate(struct clk_hw *hw, -					      unsigned long parent_rate) -{ -	struct zynq_cpu_clk *cpuclk = to_zynq_cpu_clk(hw); -	return parent_rate / CPU_CLK_CTRL_DIV(ioread32(cpuclk->clk_ctrl)); -} - -static const struct clk_ops zynq_cpu_clk_ops = { -	.get_parent	= zynq_cpu_clk_get_parent, -	.recalc_rate	= zynq_cpu_clk_recalc_rate, -}; - -struct zynq_cpu_subclk { -	struct clk_hw	hw; -	void __iomem	*clk_621; -	enum { -		CPU_SUBCLK_6X4X, -		CPU_SUBCLK_3X2X, -		CPU_SUBCLK_2X, -		CPU_SUBCLK_1X, -	} which; -}; - -#define CLK_621_TRUE(x)	((x) & 1) - -#define to_zynq_cpu_subclk(hw)	container_of(hw, struct zynq_cpu_subclk, hw); - -static unsigned long zynq_cpu_subclk_recalc_rate(struct clk_hw *hw, -						 unsigned long parent_rate) -{ -	unsigned long uninitialized_var(rate); -	struct zynq_cpu_subclk *subclk; -	bool is_621; - -	subclk = to_zynq_cpu_subclk(hw) -	is_621 = CLK_621_TRUE(ioread32(subclk->clk_621)); - -	switch (subclk->which) { -	case CPU_SUBCLK_6X4X: -		rate = parent_rate; -		break; -	case CPU_SUBCLK_3X2X: -		rate = parent_rate / 2; -		break; -	case CPU_SUBCLK_2X: -		rate = parent_rate / (is_621 ? 3 : 2); -		break; -	case CPU_SUBCLK_1X: -		rate = parent_rate / (is_621 ? 6 : 4); -		break; -	}; - -	return rate; -} - -static const struct clk_ops zynq_cpu_subclk_ops = { -	.recalc_rate	= zynq_cpu_subclk_recalc_rate, -}; - -static struct clk *zynq_cpu_subclk_setup(struct device_node *np, u8 which, -					 void __iomem *clk_621) -{ -	struct zynq_cpu_subclk *subclk; -	struct clk_init_data init; -	struct clk *clk; -	int err; - -	err = of_property_read_string_index(np, "clock-output-names", -					    which, &init.name); -	if (WARN_ON(err)) -		goto err_read_output_name; - -	subclk = kzalloc(sizeof(*subclk), GFP_KERNEL); -	if (!subclk) -		goto err_subclk_alloc; - -	subclk->clk_621 = clk_621; -	subclk->which = which; - -	init.ops = &zynq_cpu_subclk_ops; -	init.parent_names = &np->name; -	init.num_parents = 1; - -	subclk->hw.init = &init; - -	clk = clk_register(NULL, &subclk->hw); -	if (WARN_ON(IS_ERR(clk))) -		goto err_clk_register; - -	return clk; - -err_clk_register: -	kfree(subclk); -err_subclk_alloc: -err_read_output_name: -	return ERR_PTR(-EINVAL); -} - -static void __init zynq_cpu_clk_setup(struct device_node *np) -{ -	struct zynq_cpu_clk *cpuclk; -	const char *parent_names[3]; -	struct clk_init_data init; -	void __iomem *clk_621; -	struct clk *clk; -	u32 reg[2]; -	int err; -	int i; - -	err = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg)); -	if (WARN_ON(err)) -		return; - -	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL); -	if (WARN_ON(!cpuclk)) -		return; - -	cpuclk->clk_ctrl = slcr_base + reg[0]; -	clk_621 = slcr_base + reg[1]; -	spin_lock_init(&cpuclk->clkact_lock); - -	init.name = np->name; -	init.ops = &zynq_cpu_clk_ops; -	for (i = 0; i < ARRAY_SIZE(parent_names); i++) -		parent_names[i] = of_clk_get_parent_name(np, i); -	init.parent_names = parent_names; -	init.num_parents = ARRAY_SIZE(parent_names); - -	cpuclk->hw.init = &init; - -	clk = clk_register(NULL, &cpuclk->hw); -	if (WARN_ON(IS_ERR(clk))) -		return; - -	err = of_clk_add_provider(np, of_clk_src_simple_get, clk); -	if (WARN_ON(err)) -		return; - -	for (i = 0; i < 4; i++) { -		cpuclk->subclks[i] = zynq_cpu_subclk_setup(np, i, clk_621); -		if (WARN_ON(IS_ERR(cpuclk->subclks[i]))) -			return; -	} - -	cpuclk->onecell_data.clks = cpuclk->subclks; -	cpuclk->onecell_data.clk_num = i; - -	err = of_clk_add_provider(np, of_clk_src_onecell_get, -				  &cpuclk->onecell_data); -	if (WARN_ON(err)) -		return; -} -CLK_OF_DECLARE(zynq_cpu, "xlnx,zynq-cpu-clock", zynq_cpu_clk_setup); - -void __init xilinx_zynq_clocks_init(void __iomem *slcr) -{ -	slcr_base = slcr; -	of_clk_init(NULL); -} diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1144e8c7579d..54a191c5bbf0 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -107,7 +107,7 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)  	seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",  		   level * 3 + 1, "",  		   30 - level * 3, c->name, -		   c->enable_count, c->prepare_count, c->rate); +		   c->enable_count, c->prepare_count, clk_get_rate(c));  	seq_printf(s, "\n");  } @@ -166,7 +166,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)  	seq_printf(s, "\"%s\": { ", c->name);  	seq_printf(s, "\"enable_count\": %d,", c->enable_count);  	seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); -	seq_printf(s, "\"rate\": %lu", c->rate); +	seq_printf(s, "\"rate\": %lu", clk_get_rate(c));  }  static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) @@ -534,7 +534,7 @@ static int clk_disable_unused(void)  	return 0;  } -late_initcall(clk_disable_unused); +late_initcall_sync(clk_disable_unused);  /***    helper functions   ***/ @@ -1216,7 +1216,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)  	clk_prepare_lock();  	/* bail early if nothing to do */ -	if (rate == clk->rate) +	if (rate == clk_get_rate(clk))  		goto out;  	if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) { @@ -1377,23 +1377,33 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)  	unsigned long flags;  	int ret = 0;  	struct clk *old_parent = clk->parent; -	bool migrated_enable = false; -	/* migrate prepare */ -	if (clk->prepare_count) +	/* +	 * Migrate prepare state between parents and prevent race with +	 * clk_enable(). +	 * +	 * If the clock is not prepared, then a race with +	 * clk_enable/disable() is impossible since we already have the +	 * prepare lock (future calls to clk_enable() need to be preceded by +	 * a clk_prepare()). +	 * +	 * If the clock is prepared, migrate the prepared state to the new +	 * parent and also protect against a race with clk_enable() by +	 * forcing the clock and the new parent on.  This ensures that all +	 * future calls to clk_enable() are practically NOPs with respect to +	 * hardware and software states. +	 * +	 * See also: Comment for clk_set_parent() below. +	 */ +	if (clk->prepare_count) {  		__clk_prepare(parent); - -	flags = clk_enable_lock(); - -	/* migrate enable */ -	if (clk->enable_count) { -		__clk_enable(parent); -		migrated_enable = true; +		clk_enable(parent); +		clk_enable(clk);  	}  	/* update the clk tree topology */ +	flags = clk_enable_lock();  	clk_reparent(clk, parent); -  	clk_enable_unlock(flags);  	/* change clock input source */ @@ -1401,43 +1411,27 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)  		ret = clk->ops->set_parent(clk->hw, p_index);  	if (ret) { -		/* -		 * The error handling is tricky due to that we need to release -		 * the spinlock while issuing the .set_parent callback. This -		 * means the new parent might have been enabled/disabled in -		 * between, which must be considered when doing rollback. -		 */  		flags = clk_enable_lock(); -  		clk_reparent(clk, old_parent); - -		if (migrated_enable && clk->enable_count) { -			__clk_disable(parent); -		} else if (migrated_enable && (clk->enable_count == 0)) { -			__clk_disable(old_parent); -		} else if (!migrated_enable && clk->enable_count) { -			__clk_disable(parent); -			__clk_enable(old_parent); -		} -  		clk_enable_unlock(flags); -		if (clk->prepare_count) +		if (clk->prepare_count) { +			clk_disable(clk); +			clk_disable(parent);  			__clk_unprepare(parent); - +		}  		return ret;  	} -	/* clean up enable for old parent if migration was done */ -	if (migrated_enable) { -		flags = clk_enable_lock(); -		__clk_disable(old_parent); -		clk_enable_unlock(flags); -	} - -	/* clean up prepare for old parent if migration was done */ -	if (clk->prepare_count) +	/* +	 * Finish the migration of prepare state and undo the changes done +	 * for preventing a race with clk_enable(). +	 */ +	if (clk->prepare_count) { +		clk_disable(clk); +		clk_disable(old_parent);  		__clk_unprepare(old_parent); +	}  	/* update debugfs with new clk tree topology */  	clk_debug_reparent(clk, parent); @@ -1449,12 +1443,17 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)   * @clk: the mux clk whose input we are switching   * @parent: the new input to clk   * - * Re-parent clk to use parent as it's new input source.  If clk has the - * CLK_SET_PARENT_GATE flag set then clk must be gated for this - * operation to succeed.  After successfully changing clk's parent - * clk_set_parent will update the clk topology, sysfs topology and - * propagate rate recalculation via __clk_recalc_rates.  Returns 0 on - * success, -EERROR otherwise. + * Re-parent clk to use parent as its new input source.  If clk is in + * prepared state, the clk will get enabled for the duration of this call. If + * that's not acceptable for a specific clk (Eg: the consumer can't handle + * that, the reparenting is glitchy in hardware, etc), use the + * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared. + * + * After successfully changing clk's parent clk_set_parent will update the + * clk topology, sysfs topology and propagate rate recalculation via + * __clk_recalc_rates. + * + * Returns 0 on success, -EERROR otherwise.   */  int clk_set_parent(struct clk *clk, struct clk *parent)  { @@ -1494,8 +1493,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)  	}  	/* propagate PRE_RATE_CHANGE notifications */ -	if (clk->notifier_count) -		ret = __clk_speculate_rates(clk, p_rate); +	ret = __clk_speculate_rates(clk, p_rate);  	/* abort if a driver objects */  	if (ret & NOTIFY_STOP_MASK) diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig index 57323fd15ec9..0b0f3e729cf7 100644 --- a/drivers/clk/mvebu/Kconfig +++ b/drivers/clk/mvebu/Kconfig @@ -1,8 +1,23 @@ -config MVEBU_CLK_CORE -       bool +config MVEBU_CLK_COMMON +	bool  config MVEBU_CLK_CPU -       bool +	bool -config MVEBU_CLK_GATING -       bool +config ARMADA_370_CLK +	bool +	select MVEBU_CLK_COMMON +	select MVEBU_CLK_CPU + +config ARMADA_XP_CLK +	bool +	select MVEBU_CLK_COMMON +	select MVEBU_CLK_CPU + +config DOVE_CLK +	bool +	select MVEBU_CLK_COMMON + +config KIRKWOOD_CLK +	bool +	select MVEBU_CLK_COMMON diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 58df3dc49363..1c7e70c63fb2 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -1,3 +1,7 @@ -obj-$(CONFIG_MVEBU_CLK_CORE) 	+= clk.o clk-core.o +obj-$(CONFIG_MVEBU_CLK_COMMON)	+= common.o  obj-$(CONFIG_MVEBU_CLK_CPU) 	+= clk-cpu.o -obj-$(CONFIG_MVEBU_CLK_GATING) 	+= clk-gating-ctrl.o + +obj-$(CONFIG_ARMADA_370_CLK)	+= armada-370.o +obj-$(CONFIG_ARMADA_XP_CLK)	+= armada-xp.o +obj-$(CONFIG_DOVE_CLK)		+= dove.o +obj-$(CONFIG_KIRKWOOD_CLK)	+= kirkwood.o diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c new file mode 100644 index 000000000000..079960e7c304 --- /dev/null +++ b/drivers/clk/mvebu/armada-370.c @@ -0,0 +1,176 @@ +/* + * Marvell Armada 370 SoC clocks + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * Core Clocks + */ + +#define SARL				0	/* Low part [0:31] */ +#define	 SARL_A370_PCLK_FREQ_OPT	11 +#define	 SARL_A370_PCLK_FREQ_OPT_MASK	0xF +#define	 SARL_A370_FAB_FREQ_OPT		15 +#define	 SARL_A370_FAB_FREQ_OPT_MASK	0x1F +#define	 SARL_A370_TCLK_FREQ_OPT	20 +#define	 SARL_A370_TCLK_FREQ_OPT_MASK	0x1 + +enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK }; + +static const struct coreclk_ratio __initconst a370_coreclk_ratios[] = { +	{ .id = A370_CPU_TO_NBCLK, .name = "nbclk" }, +	{ .id = A370_CPU_TO_HCLK, .name = "hclk" }, +	{ .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" }, +}; + +static const u32 __initconst a370_tclk_freqs[] = { +	16600000, +	20000000, +}; + +static u32 __init a370_get_tclk_freq(void __iomem *sar) +{ +	u8 tclk_freq_select = 0; + +	tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) & +			    SARL_A370_TCLK_FREQ_OPT_MASK); +	return a370_tclk_freqs[tclk_freq_select]; +} + +static const u32 __initconst a370_cpu_freqs[] = { +	400000000, +	533000000, +	667000000, +	800000000, +	1000000000, +	1067000000, +	1200000000, +}; + +static u32 __init a370_get_cpu_freq(void __iomem *sar) +{ +	u32 cpu_freq; +	u8 cpu_freq_select = 0; + +	cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) & +			   SARL_A370_PCLK_FREQ_OPT_MASK); +	if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) { +		pr_err("CPU freq select unsupported %d\n", cpu_freq_select); +		cpu_freq = 0; +	} else +		cpu_freq = a370_cpu_freqs[cpu_freq_select]; + +	return cpu_freq; +} + +static const int __initconst a370_nbclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 2}, {2, 2}, +	{1, 2}, {1, 2}, {1, 1}, {2, 3}, +	{0, 1}, {1, 2}, {2, 4}, {0, 1}, +	{1, 2}, {0, 1}, {0, 1}, {2, 2}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{2, 3}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int __initconst a370_hclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 6}, {2, 3}, +	{1, 3}, {1, 4}, {1, 2}, {2, 6}, +	{0, 1}, {1, 6}, {2, 10}, {0, 1}, +	{1, 4}, {0, 1}, {0, 1}, {2, 5}, +	{0, 1}, {0, 1}, {0, 1}, {1, 2}, +	{2, 6}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int __initconst a370_dramclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 3}, {2, 3}, +	{1, 3}, {1, 2}, {1, 2}, {2, 6}, +	{0, 1}, {1, 3}, {2, 5}, {0, 1}, +	{1, 4}, {0, 1}, {0, 1}, {2, 5}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{2, 3}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static void __init a370_get_clk_ratio( +	void __iomem *sar, int id, int *mult, int *div) +{ +	u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) & +		SARL_A370_FAB_FREQ_OPT_MASK); + +	switch (id) { +	case A370_CPU_TO_NBCLK: +		*mult = a370_nbclk_ratios[opt][0]; +		*div = a370_nbclk_ratios[opt][1]; +		break; +	case A370_CPU_TO_HCLK: +		*mult = a370_hclk_ratios[opt][0]; +		*div = a370_hclk_ratios[opt][1]; +		break; +	case A370_CPU_TO_DRAMCLK: +		*mult = a370_dramclk_ratios[opt][0]; +		*div = a370_dramclk_ratios[opt][1]; +		break; +	} +} + +static const struct coreclk_soc_desc a370_coreclks = { +	.get_tclk_freq = a370_get_tclk_freq, +	.get_cpu_freq = a370_get_cpu_freq, +	.get_clk_ratio = a370_get_clk_ratio, +	.ratios = a370_coreclk_ratios, +	.num_ratios = ARRAY_SIZE(a370_coreclk_ratios), +}; + +static void __init a370_coreclk_init(struct device_node *np) +{ +	mvebu_coreclk_setup(np, &a370_coreclks); +} +CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock", +	       a370_coreclk_init); + +/* + * Clock Gating Control + */ + +static const struct clk_gating_soc_desc __initconst a370_gating_desc[] = { +	{ "audio", NULL, 0, 0 }, +	{ "pex0_en", NULL, 1, 0 }, +	{ "pex1_en", NULL,  2, 0 }, +	{ "ge1", NULL, 3, 0 }, +	{ "ge0", NULL, 4, 0 }, +	{ "pex0", "pex0_en", 5, 0 }, +	{ "pex1", "pex1_en", 9, 0 }, +	{ "sata0", NULL, 15, 0 }, +	{ "sdio", NULL, 17, 0 }, +	{ "tdm", NULL, 25, 0 }, +	{ "ddr", NULL, 28, CLK_IGNORE_UNUSED }, +	{ "sata1", NULL, 30, 0 }, +	{ } +}; + +static void __init a370_clk_gating_init(struct device_node *np) +{ +	mvebu_clk_gating_setup(np, a370_gating_desc); +} +CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock", +	       a370_clk_gating_init); diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c new file mode 100644 index 000000000000..13b62ceb3407 --- /dev/null +++ b/drivers/clk/mvebu/armada-xp.c @@ -0,0 +1,210 @@ +/* + * Marvell Armada XP SoC clocks + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * Core Clocks + * + * Armada XP Sample At Reset is a 64 bit bitfiled split in two + * register of 32 bits + */ + +#define SARL				0	/* Low part [0:31] */ +#define	 SARL_AXP_PCLK_FREQ_OPT		21 +#define	 SARL_AXP_PCLK_FREQ_OPT_MASK	0x7 +#define	 SARL_AXP_FAB_FREQ_OPT		24 +#define	 SARL_AXP_FAB_FREQ_OPT_MASK	0xF +#define SARH				4	/* High part [32:63] */ +#define	 SARH_AXP_PCLK_FREQ_OPT		(52-32) +#define	 SARH_AXP_PCLK_FREQ_OPT_MASK	0x1 +#define	 SARH_AXP_PCLK_FREQ_OPT_SHIFT	3 +#define	 SARH_AXP_FAB_FREQ_OPT		(51-32) +#define	 SARH_AXP_FAB_FREQ_OPT_MASK	0x1 +#define	 SARH_AXP_FAB_FREQ_OPT_SHIFT	4 + +enum { AXP_CPU_TO_NBCLK, AXP_CPU_TO_HCLK, AXP_CPU_TO_DRAMCLK }; + +static const struct coreclk_ratio __initconst axp_coreclk_ratios[] = { +	{ .id = AXP_CPU_TO_NBCLK, .name = "nbclk" }, +	{ .id = AXP_CPU_TO_HCLK, .name = "hclk" }, +	{ .id = AXP_CPU_TO_DRAMCLK, .name = "dramclk" }, +}; + +/* Armada XP TCLK frequency is fixed to 250MHz */ +static u32 __init axp_get_tclk_freq(void __iomem *sar) +{ +	return 250000000; +} + +static const u32 __initconst axp_cpu_freqs[] = { +	1000000000, +	1066000000, +	1200000000, +	1333000000, +	1500000000, +	1666000000, +	1800000000, +	2000000000, +	667000000, +	0, +	800000000, +	1600000000, +}; + +static u32 __init axp_get_cpu_freq(void __iomem *sar) +{ +	u32 cpu_freq; +	u8 cpu_freq_select = 0; + +	cpu_freq_select = ((readl(sar + SARL) >> SARL_AXP_PCLK_FREQ_OPT) & +			   SARL_AXP_PCLK_FREQ_OPT_MASK); +	/* +	 * The upper bit is not contiguous to the other ones and +	 * located in the high part of the SAR registers +	 */ +	cpu_freq_select |= (((readl(sar + SARH) >> SARH_AXP_PCLK_FREQ_OPT) & +	     SARH_AXP_PCLK_FREQ_OPT_MASK) << SARH_AXP_PCLK_FREQ_OPT_SHIFT); +	if (cpu_freq_select >= ARRAY_SIZE(axp_cpu_freqs)) { +		pr_err("CPU freq select unsupported: %d\n", cpu_freq_select); +		cpu_freq = 0; +	} else +		cpu_freq = axp_cpu_freqs[cpu_freq_select]; + +	return cpu_freq; +} + +static const int __initconst axp_nbclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 2}, {2, 2}, +	{1, 2}, {1, 2}, {1, 1}, {2, 3}, +	{0, 1}, {1, 2}, {2, 4}, {0, 1}, +	{1, 2}, {0, 1}, {0, 1}, {2, 2}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{2, 3}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int __initconst axp_hclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 6}, {2, 3}, +	{1, 3}, {1, 4}, {1, 2}, {2, 6}, +	{0, 1}, {1, 6}, {2, 10}, {0, 1}, +	{1, 4}, {0, 1}, {0, 1}, {2, 5}, +	{0, 1}, {0, 1}, {0, 1}, {1, 2}, +	{2, 6}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static const int __initconst axp_dramclk_ratios[32][2] = { +	{0, 1}, {1, 2}, {2, 3}, {2, 3}, +	{1, 3}, {1, 2}, {1, 2}, {2, 6}, +	{0, 1}, {1, 3}, {2, 5}, {0, 1}, +	{1, 4}, {0, 1}, {0, 1}, {2, 5}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{2, 3}, {0, 1}, {0, 1}, {0, 1}, +	{0, 1}, {0, 1}, {0, 1}, {1, 1}, +	{0, 1}, {0, 1}, {0, 1}, {0, 1}, +}; + +static void __init axp_get_clk_ratio( +	void __iomem *sar, int id, int *mult, int *div) +{ +	u32 opt = ((readl(sar + SARL) >> SARL_AXP_FAB_FREQ_OPT) & +	      SARL_AXP_FAB_FREQ_OPT_MASK); +	/* +	 * The upper bit is not contiguous to the other ones and +	 * located in the high part of the SAR registers +	 */ +	opt |= (((readl(sar + SARH) >> SARH_AXP_FAB_FREQ_OPT) & +		 SARH_AXP_FAB_FREQ_OPT_MASK) << SARH_AXP_FAB_FREQ_OPT_SHIFT); + +	switch (id) { +	case AXP_CPU_TO_NBCLK: +		*mult = axp_nbclk_ratios[opt][0]; +		*div = axp_nbclk_ratios[opt][1]; +		break; +	case AXP_CPU_TO_HCLK: +		*mult = axp_hclk_ratios[opt][0]; +		*div = axp_hclk_ratios[opt][1]; +		break; +	case AXP_CPU_TO_DRAMCLK: +		*mult = axp_dramclk_ratios[opt][0]; +		*div = axp_dramclk_ratios[opt][1]; +		break; +	} +} + +static const struct coreclk_soc_desc axp_coreclks = { +	.get_tclk_freq = axp_get_tclk_freq, +	.get_cpu_freq = axp_get_cpu_freq, +	.get_clk_ratio = axp_get_clk_ratio, +	.ratios = axp_coreclk_ratios, +	.num_ratios = ARRAY_SIZE(axp_coreclk_ratios), +}; + +static void __init axp_coreclk_init(struct device_node *np) +{ +	mvebu_coreclk_setup(np, &axp_coreclks); +} +CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock", +	       axp_coreclk_init); + +/* + * Clock Gating Control + */ + +static const struct clk_gating_soc_desc __initconst axp_gating_desc[] = { +	{ "audio", NULL, 0, 0 }, +	{ "ge3", NULL, 1, 0 }, +	{ "ge2", NULL,  2, 0 }, +	{ "ge1", NULL, 3, 0 }, +	{ "ge0", NULL, 4, 0 }, +	{ "pex00", NULL, 5, 0 }, +	{ "pex01", NULL, 6, 0 }, +	{ "pex02", NULL, 7, 0 }, +	{ "pex03", NULL, 8, 0 }, +	{ "pex10", NULL, 9, 0 }, +	{ "pex11", NULL, 10, 0 }, +	{ "pex12", NULL, 11, 0 }, +	{ "pex13", NULL, 12, 0 }, +	{ "bp", NULL, 13, 0 }, +	{ "sata0lnk", NULL, 14, 0 }, +	{ "sata0", "sata0lnk", 15, 0 }, +	{ "lcd", NULL, 16, 0 }, +	{ "sdio", NULL, 17, 0 }, +	{ "usb0", NULL, 18, 0 }, +	{ "usb1", NULL, 19, 0 }, +	{ "usb2", NULL, 20, 0 }, +	{ "xor0", NULL, 22, 0 }, +	{ "crypto", NULL, 23, 0 }, +	{ "tdm", NULL, 25, 0 }, +	{ "pex20", NULL, 26, 0 }, +	{ "pex30", NULL, 27, 0 }, +	{ "xor1", NULL, 28, 0 }, +	{ "sata1lnk", NULL, 29, 0 }, +	{ "sata1", "sata1lnk", 30, 0 }, +	{ } +}; + +static void __init axp_clk_gating_init(struct device_node *np) +{ +	mvebu_clk_gating_setup(np, axp_gating_desc); +} +CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock", +	       axp_clk_gating_init); diff --git a/drivers/clk/mvebu/clk-core.c b/drivers/clk/mvebu/clk-core.c deleted file mode 100644 index 0a53edbae8b8..000000000000 --- a/drivers/clk/mvebu/clk-core.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Marvell EBU clock core handling defined at reset - * - * Copyright (C) 2012 Marvell - * - * Gregory CLEMENT <[email protected]> - * Sebastian Hesselbarth <[email protected]> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/clk-provider.h> -#include <linux/of_address.h> -#include <linux/io.h> -#include <linux/of.h> -#include "clk-core.h" - -struct core_ratio { -	int id; -	const char *name; -}; - -struct core_clocks { -	u32 (*get_tclk_freq)(void __iomem *sar); -	u32 (*get_cpu_freq)(void __iomem *sar); -	void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); -	const struct core_ratio *ratios; -	int num_ratios; -}; - -static struct clk_onecell_data clk_data; - -static void __init mvebu_clk_core_setup(struct device_node *np, -				 struct core_clocks *coreclk) -{ -	const char *tclk_name = "tclk"; -	const char *cpuclk_name = "cpuclk"; -	void __iomem *base; -	unsigned long rate; -	int n; - -	base = of_iomap(np, 0); -	if (WARN_ON(!base)) -		return; - -	/* -	 * Allocate struct for TCLK, cpu clk, and core ratio clocks -	 */ -	clk_data.clk_num = 2 + coreclk->num_ratios; -	clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *), -				GFP_KERNEL); -	if (WARN_ON(!clk_data.clks)) -		return; - -	/* -	 * Register TCLK -	 */ -	of_property_read_string_index(np, "clock-output-names", 0, -				      &tclk_name); -	rate = coreclk->get_tclk_freq(base); -	clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL, -						   CLK_IS_ROOT, rate); -	WARN_ON(IS_ERR(clk_data.clks[0])); - -	/* -	 * Register CPU clock -	 */ -	of_property_read_string_index(np, "clock-output-names", 1, -				      &cpuclk_name); -	rate = coreclk->get_cpu_freq(base); -	clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, -						   CLK_IS_ROOT, rate); -	WARN_ON(IS_ERR(clk_data.clks[1])); - -	/* -	 * Register fixed-factor clocks derived from CPU clock -	 */ -	for (n = 0; n < coreclk->num_ratios; n++) { -		const char *rclk_name = coreclk->ratios[n].name; -		int mult, div; - -		of_property_read_string_index(np, "clock-output-names", -					      2+n, &rclk_name); -		coreclk->get_clk_ratio(base, coreclk->ratios[n].id, -				       &mult, &div); -		clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name, -				       cpuclk_name, 0, mult, div); -		WARN_ON(IS_ERR(clk_data.clks[2+n])); -	}; - -	/* -	 * SAR register isn't needed anymore -	 */ -	iounmap(base); - -	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); -} - -#ifdef CONFIG_MACH_ARMADA_370_XP -/* - * Armada 370/XP Sample At Reset is a 64 bit bitfiled split in two - * register of 32 bits - */ - -#define SARL				    0	/* Low part [0:31] */ -#define	    SARL_AXP_PCLK_FREQ_OPT	    21 -#define	    SARL_AXP_PCLK_FREQ_OPT_MASK	    0x7 -#define	    SARL_A370_PCLK_FREQ_OPT	    11 -#define	    SARL_A370_PCLK_FREQ_OPT_MASK    0xF -#define	    SARL_AXP_FAB_FREQ_OPT	    24 -#define	    SARL_AXP_FAB_FREQ_OPT_MASK	    0xF -#define	    SARL_A370_FAB_FREQ_OPT	    15 -#define	    SARL_A370_FAB_FREQ_OPT_MASK	    0x1F -#define	    SARL_A370_TCLK_FREQ_OPT	    20 -#define	    SARL_A370_TCLK_FREQ_OPT_MASK    0x1 -#define SARH				    4	/* High part [32:63] */ -#define	    SARH_AXP_PCLK_FREQ_OPT	    (52-32) -#define	    SARH_AXP_PCLK_FREQ_OPT_MASK	    0x1 -#define	    SARH_AXP_PCLK_FREQ_OPT_SHIFT    3 -#define	    SARH_AXP_FAB_FREQ_OPT	    (51-32) -#define	    SARH_AXP_FAB_FREQ_OPT_MASK	    0x1 -#define	    SARH_AXP_FAB_FREQ_OPT_SHIFT	    4 - -static const u32 __initconst armada_370_tclk_frequencies[] = { -	16600000, -	20000000, -}; - -static u32 __init armada_370_get_tclk_freq(void __iomem *sar) -{ -	u8 tclk_freq_select = 0; - -	tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) & -			    SARL_A370_TCLK_FREQ_OPT_MASK); -	return armada_370_tclk_frequencies[tclk_freq_select]; -} - -static const u32 __initconst armada_370_cpu_frequencies[] = { -	400000000, -	533000000, -	667000000, -	800000000, -	1000000000, -	1067000000, -	1200000000, -}; - -static u32 __init armada_370_get_cpu_freq(void __iomem *sar) -{ -	u32 cpu_freq; -	u8 cpu_freq_select = 0; - -	cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) & -			   SARL_A370_PCLK_FREQ_OPT_MASK); -	if (cpu_freq_select >= ARRAY_SIZE(armada_370_cpu_frequencies)) { -		pr_err("CPU freq select unsupported %d\n", cpu_freq_select); -		cpu_freq = 0; -	} else -		cpu_freq = armada_370_cpu_frequencies[cpu_freq_select]; - -	return cpu_freq; -} - -enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK }; - -static const struct core_ratio __initconst armada_370_xp_core_ratios[] = { -	{ .id = A370_XP_NBCLK,	 .name = "nbclk" }, -	{ .id = A370_XP_HCLK,	 .name = "hclk" }, -	{ .id = A370_XP_DRAMCLK, .name = "dramclk" }, -}; - -static const int __initconst armada_370_xp_nbclk_ratios[32][2] = { -	{0, 1}, {1, 2}, {2, 2}, {2, 2}, -	{1, 2}, {1, 2}, {1, 1}, {2, 3}, -	{0, 1}, {1, 2}, {2, 4}, {0, 1}, -	{1, 2}, {0, 1}, {0, 1}, {2, 2}, -	{0, 1}, {0, 1}, {0, 1}, {1, 1}, -	{2, 3}, {0, 1}, {0, 1}, {0, 1}, -	{0, 1}, {0, 1}, {0, 1}, {1, 1}, -	{0, 1}, {0, 1}, {0, 1}, {0, 1}, -}; - -static const int __initconst armada_370_xp_hclk_ratios[32][2] = { -	{0, 1}, {1, 2}, {2, 6}, {2, 3}, -	{1, 3}, {1, 4}, {1, 2}, {2, 6}, -	{0, 1}, {1, 6}, {2, 10}, {0, 1}, -	{1, 4}, {0, 1}, {0, 1}, {2, 5}, -	{0, 1}, {0, 1}, {0, 1}, {1, 2}, -	{2, 6}, {0, 1}, {0, 1}, {0, 1}, -	{0, 1}, {0, 1}, {0, 1}, {1, 1}, -	{0, 1}, {0, 1}, {0, 1}, {0, 1}, -}; - -static const int __initconst armada_370_xp_dramclk_ratios[32][2] = { -	{0, 1}, {1, 2}, {2, 3}, {2, 3}, -	{1, 3}, {1, 2}, {1, 2}, {2, 6}, -	{0, 1}, {1, 3}, {2, 5}, {0, 1}, -	{1, 4}, {0, 1}, {0, 1}, {2, 5}, -	{0, 1}, {0, 1}, {0, 1}, {1, 1}, -	{2, 3}, {0, 1}, {0, 1}, {0, 1}, -	{0, 1}, {0, 1}, {0, 1}, {1, 1}, -	{0, 1}, {0, 1}, {0, 1}, {0, 1}, -}; - -static void __init armada_370_xp_get_clk_ratio(u32 opt, -	void __iomem *sar, int id, int *mult, int *div) -{ -	switch (id) { -	case A370_XP_NBCLK: -		*mult = armada_370_xp_nbclk_ratios[opt][0]; -		*div = armada_370_xp_nbclk_ratios[opt][1]; -		break; -	case A370_XP_HCLK: -		*mult = armada_370_xp_hclk_ratios[opt][0]; -		*div = armada_370_xp_hclk_ratios[opt][1]; -		break; -	case A370_XP_DRAMCLK: -		*mult = armada_370_xp_dramclk_ratios[opt][0]; -		*div = armada_370_xp_dramclk_ratios[opt][1]; -		break; -	} -} - -static void __init armada_370_get_clk_ratio( -	void __iomem *sar, int id, int *mult, int *div) -{ -	u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) & -		SARL_A370_FAB_FREQ_OPT_MASK); - -	armada_370_xp_get_clk_ratio(opt, sar, id, mult, div); -} - - -static const struct core_clocks armada_370_core_clocks = { -	.get_tclk_freq = armada_370_get_tclk_freq, -	.get_cpu_freq = armada_370_get_cpu_freq, -	.get_clk_ratio = armada_370_get_clk_ratio, -	.ratios = armada_370_xp_core_ratios, -	.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios), -}; - -static const u32 __initconst armada_xp_cpu_frequencies[] = { -	1000000000, -	1066000000, -	1200000000, -	1333000000, -	1500000000, -	1666000000, -	1800000000, -	2000000000, -	667000000, -	0, -	800000000, -	1600000000, -}; - -/* For Armada XP TCLK frequency is fix: 250MHz */ -static u32 __init armada_xp_get_tclk_freq(void __iomem *sar) -{ -	return 250 * 1000 * 1000; -} - -static u32 __init armada_xp_get_cpu_freq(void __iomem *sar) -{ -	u32 cpu_freq; -	u8 cpu_freq_select = 0; - -	cpu_freq_select = ((readl(sar) >> SARL_AXP_PCLK_FREQ_OPT) & -			   SARL_AXP_PCLK_FREQ_OPT_MASK); -	/* -	 * The upper bit is not contiguous to the other ones and -	 * located in the high part of the SAR registers -	 */ -	cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) & -			     SARH_AXP_PCLK_FREQ_OPT_MASK) -			    << SARH_AXP_PCLK_FREQ_OPT_SHIFT); -	if (cpu_freq_select >= ARRAY_SIZE(armada_xp_cpu_frequencies)) { -		pr_err("CPU freq select unsupported: %d\n", cpu_freq_select); -		cpu_freq = 0; -	} else -		cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select]; - -	return cpu_freq; -} - -static void __init armada_xp_get_clk_ratio( -	void __iomem *sar, int id, int *mult, int *div) -{ - -	u32 opt = ((readl(sar) >> SARL_AXP_FAB_FREQ_OPT) & -	      SARL_AXP_FAB_FREQ_OPT_MASK); -	/* -	 * The upper bit is not contiguous to the other ones and -	 * located in the high part of the SAR registers -	 */ -	opt |= (((readl(sar+4) >> SARH_AXP_FAB_FREQ_OPT) & -		SARH_AXP_FAB_FREQ_OPT_MASK) -	       << SARH_AXP_FAB_FREQ_OPT_SHIFT); - -	armada_370_xp_get_clk_ratio(opt, sar, id, mult, div); -} - -static const struct core_clocks armada_xp_core_clocks = { -	.get_tclk_freq = armada_xp_get_tclk_freq, -	.get_cpu_freq = armada_xp_get_cpu_freq, -	.get_clk_ratio = armada_xp_get_clk_ratio, -	.ratios = armada_370_xp_core_ratios, -	.num_ratios = ARRAY_SIZE(armada_370_xp_core_ratios), -}; - -#endif /* CONFIG_MACH_ARMADA_370_XP */ - -/* - * Dove PLL sample-at-reset configuration - * - * SAR0[8:5]   : CPU frequency - *		 5  = 1000 MHz - *		 6  =  933 MHz - *		 7  =  933 MHz - *		 8  =  800 MHz - *		 9  =  800 MHz - *		 10 =  800 MHz - *		 11 = 1067 MHz - *		 12 =  667 MHz - *		 13 =  533 MHz - *		 14 =  400 MHz - *		 15 =  333 MHz - *		 others reserved. - * - * SAR0[11:9]  : CPU to L2 Clock divider ratio - *		 0 = (1/1) * CPU - *		 2 = (1/2) * CPU - *		 4 = (1/3) * CPU - *		 6 = (1/4) * CPU - *		 others reserved. - * - * SAR0[15:12] : CPU to DDR DRAM Clock divider ratio - *		 0  = (1/1) * CPU - *		 2  = (1/2) * CPU - *		 3  = (2/5) * CPU - *		 4  = (1/3) * CPU - *		 6  = (1/4) * CPU - *		 8  = (1/5) * CPU - *		 10 = (1/6) * CPU - *		 12 = (1/7) * CPU - *		 14 = (1/8) * CPU - *		 15 = (1/10) * CPU - *		 others reserved. - * - * SAR0[24:23] : TCLK frequency - *		 0 = 166 MHz - *		 1 = 125 MHz - *		 others reserved. - */ -#ifdef CONFIG_ARCH_DOVE -#define SAR_DOVE_CPU_FREQ		5 -#define SAR_DOVE_CPU_FREQ_MASK		0xf -#define SAR_DOVE_L2_RATIO		9 -#define SAR_DOVE_L2_RATIO_MASK		0x7 -#define SAR_DOVE_DDR_RATIO		12 -#define SAR_DOVE_DDR_RATIO_MASK		0xf -#define SAR_DOVE_TCLK_FREQ		23 -#define SAR_DOVE_TCLK_FREQ_MASK		0x3 - -static const u32 __initconst dove_tclk_frequencies[] = { -	166666667, -	125000000, -	0, 0 -}; - -static u32 __init dove_get_tclk_freq(void __iomem *sar) -{ -	u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) & -		SAR_DOVE_TCLK_FREQ_MASK; -	return dove_tclk_frequencies[opt]; -} - -static const u32 __initconst dove_cpu_frequencies[] = { -	0, 0, 0, 0, 0, -	1000000000, -	933333333, 933333333, -	800000000, 800000000, 800000000, -	1066666667, -	666666667, -	533333333, -	400000000, -	333333333 -}; - -static u32 __init dove_get_cpu_freq(void __iomem *sar) -{ -	u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) & -		SAR_DOVE_CPU_FREQ_MASK; -	return dove_cpu_frequencies[opt]; -} - -enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR }; - -static const struct core_ratio __initconst dove_core_ratios[] = { -	{ .id = DOVE_CPU_TO_L2, .name = "l2clk", }, -	{ .id = DOVE_CPU_TO_DDR, .name = "ddrclk", } -}; - -static const int __initconst dove_cpu_l2_ratios[8][2] = { -	{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, -	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 } -}; - -static const int __initconst dove_cpu_ddr_ratios[16][2] = { -	{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 }, -	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }, -	{ 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 }, -	{ 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 } -}; - -static void __init dove_get_clk_ratio( -	void __iomem *sar, int id, int *mult, int *div) -{ -	switch (id) { -	case DOVE_CPU_TO_L2: -	{ -		u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) & -			SAR_DOVE_L2_RATIO_MASK; -		*mult = dove_cpu_l2_ratios[opt][0]; -		*div = dove_cpu_l2_ratios[opt][1]; -		break; -	} -	case DOVE_CPU_TO_DDR: -	{ -		u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) & -			SAR_DOVE_DDR_RATIO_MASK; -		*mult = dove_cpu_ddr_ratios[opt][0]; -		*div = dove_cpu_ddr_ratios[opt][1]; -		break; -	} -	} -} - -static const struct core_clocks dove_core_clocks = { -	.get_tclk_freq = dove_get_tclk_freq, -	.get_cpu_freq = dove_get_cpu_freq, -	.get_clk_ratio = dove_get_clk_ratio, -	.ratios = dove_core_ratios, -	.num_ratios = ARRAY_SIZE(dove_core_ratios), -}; -#endif /* CONFIG_ARCH_DOVE */ - -/* - * Kirkwood PLL sample-at-reset configuration - * (6180 has different SAR layout than other Kirkwood SoCs) - * - * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282) - *	4  =  600 MHz - *	6  =  800 MHz - *	7  = 1000 MHz - *	9  = 1200 MHz - *	12 = 1500 MHz - *	13 = 1600 MHz - *	14 = 1800 MHz - *	15 = 2000 MHz - *	others reserved. - * - * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282) - *	1 = (1/2) * CPU - *	3 = (1/3) * CPU - *	5 = (1/4) * CPU - *	others reserved. - * - * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282) - *	2 = (1/2) * CPU - *	4 = (1/3) * CPU - *	6 = (1/4) * CPU - *	7 = (2/9) * CPU - *	8 = (1/5) * CPU - *	9 = (1/6) * CPU - *	others reserved. - * - * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only) - *	5 = [CPU =  600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU] - *	6 = [CPU =  800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU] - *	7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU] - *	others reserved. - * - * SAR0[21] : TCLK frequency - *	0 = 200 MHz - *	1 = 166 MHz - *	others reserved. - */ -#ifdef CONFIG_ARCH_KIRKWOOD -#define SAR_KIRKWOOD_CPU_FREQ(x)	\ -	(((x & (1 <<  1)) >>  1) |	\ -	 ((x & (1 << 22)) >> 21) |	\ -	 ((x & (3 <<  3)) >>  1)) -#define SAR_KIRKWOOD_L2_RATIO(x)	\ -	(((x & (3 <<  9)) >> 9) |	\ -	 (((x & (1 << 19)) >> 17))) -#define SAR_KIRKWOOD_DDR_RATIO		5 -#define SAR_KIRKWOOD_DDR_RATIO_MASK	0xf -#define SAR_MV88F6180_CLK		2 -#define SAR_MV88F6180_CLK_MASK		0x7 -#define SAR_KIRKWOOD_TCLK_FREQ		21 -#define SAR_KIRKWOOD_TCLK_FREQ_MASK	0x1 - -enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR }; - -static const struct core_ratio __initconst kirkwood_core_ratios[] = { -	{ .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", }, -	{ .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", } -}; - -static u32 __init kirkwood_get_tclk_freq(void __iomem *sar) -{ -	u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) & -		SAR_KIRKWOOD_TCLK_FREQ_MASK; -	return (opt) ? 166666667 : 200000000; -} - -static const u32 __initconst kirkwood_cpu_frequencies[] = { -	0, 0, 0, 0, -	600000000, -	0, -	800000000, -	1000000000, -	0, -	1200000000, -	0, 0, -	1500000000, -	1600000000, -	1800000000, -	2000000000 -}; - -static u32 __init kirkwood_get_cpu_freq(void __iomem *sar) -{ -	u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar)); -	return kirkwood_cpu_frequencies[opt]; -} - -static const int __initconst kirkwood_cpu_l2_ratios[8][2] = { -	{ 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, -	{ 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 } -}; - -static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = { -	{ 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, -	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 }, -	{ 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 }, -	{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 } -}; - -static void __init kirkwood_get_clk_ratio( -	void __iomem *sar, int id, int *mult, int *div) -{ -	switch (id) { -	case KIRKWOOD_CPU_TO_L2: -	{ -		u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar)); -		*mult = kirkwood_cpu_l2_ratios[opt][0]; -		*div = kirkwood_cpu_l2_ratios[opt][1]; -		break; -	} -	case KIRKWOOD_CPU_TO_DDR: -	{ -		u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) & -			SAR_KIRKWOOD_DDR_RATIO_MASK; -		*mult = kirkwood_cpu_ddr_ratios[opt][0]; -		*div = kirkwood_cpu_ddr_ratios[opt][1]; -		break; -	} -	} -} - -static const struct core_clocks kirkwood_core_clocks = { -	.get_tclk_freq = kirkwood_get_tclk_freq, -	.get_cpu_freq = kirkwood_get_cpu_freq, -	.get_clk_ratio = kirkwood_get_clk_ratio, -	.ratios = kirkwood_core_ratios, -	.num_ratios = ARRAY_SIZE(kirkwood_core_ratios), -}; - -static const u32 __initconst mv88f6180_cpu_frequencies[] = { -	0, 0, 0, 0, 0, -	600000000, -	800000000, -	1000000000 -}; - -static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar) -{ -	u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK; -	return mv88f6180_cpu_frequencies[opt]; -} - -static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = { -	{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, -	{ 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 } -}; - -static void __init mv88f6180_get_clk_ratio( -	void __iomem *sar, int id, int *mult, int *div) -{ -	switch (id) { -	case KIRKWOOD_CPU_TO_L2: -	{ -		/* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */ -		*mult = 1; -		*div = 2; -		break; -	} -	case KIRKWOOD_CPU_TO_DDR: -	{ -		u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & -			SAR_MV88F6180_CLK_MASK; -		*mult = mv88f6180_cpu_ddr_ratios[opt][0]; -		*div = mv88f6180_cpu_ddr_ratios[opt][1]; -		break; -	} -	} -} - -static const struct core_clocks mv88f6180_core_clocks = { -	.get_tclk_freq = kirkwood_get_tclk_freq, -	.get_cpu_freq = mv88f6180_get_cpu_freq, -	.get_clk_ratio = mv88f6180_get_clk_ratio, -	.ratios = kirkwood_core_ratios, -	.num_ratios = ARRAY_SIZE(kirkwood_core_ratios), -}; -#endif /* CONFIG_ARCH_KIRKWOOD */ - -static const __initdata struct of_device_id clk_core_match[] = { -#ifdef CONFIG_MACH_ARMADA_370_XP -	{ -		.compatible = "marvell,armada-370-core-clock", -		.data = &armada_370_core_clocks, -	}, -	{ -		.compatible = "marvell,armada-xp-core-clock", -		.data = &armada_xp_core_clocks, -	}, -#endif -#ifdef CONFIG_ARCH_DOVE -	{ -		.compatible = "marvell,dove-core-clock", -		.data = &dove_core_clocks, -	}, -#endif - -#ifdef CONFIG_ARCH_KIRKWOOD -	{ -		.compatible = "marvell,kirkwood-core-clock", -		.data = &kirkwood_core_clocks, -	}, -	{ -		.compatible = "marvell,mv88f6180-core-clock", -		.data = &mv88f6180_core_clocks, -	}, -#endif - -	{ } -}; - -void __init mvebu_core_clk_init(void) -{ -	struct device_node *np; - -	for_each_matching_node(np, clk_core_match) { -		const struct of_device_id *match = -			of_match_node(clk_core_match, np); -		mvebu_clk_core_setup(np, (struct core_clocks *)match->data); -	} -} diff --git a/drivers/clk/mvebu/clk-core.h b/drivers/clk/mvebu/clk-core.h deleted file mode 100644 index 28b5e02e9885..000000000000 --- a/drivers/clk/mvebu/clk-core.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - *  * Marvell EBU clock core handling defined at reset - * - * Copyright (C) 2012 Marvell - * - * Gregory CLEMENT <[email protected]> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __MVEBU_CLK_CORE_H -#define __MVEBU_CLK_CORE_H - -void __init mvebu_core_clk_init(void); - -#endif diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c deleted file mode 100644 index ebf141d4374b..000000000000 --- a/drivers/clk/mvebu/clk-gating-ctrl.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Marvell MVEBU clock gating control. - * - * Sebastian Hesselbarth <[email protected]> - * Andrew Lunn <[email protected]> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <linux/kernel.h> -#include <linux/bitops.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/clk-provider.h> -#include <linux/clk/mvebu.h> -#include <linux/of.h> -#include <linux/of_address.h> - -struct mvebu_gating_ctrl { -	spinlock_t lock; -	struct clk **gates; -	int num_gates; -}; - -struct mvebu_soc_descr { -	const char *name; -	const char *parent; -	int bit_idx; -}; - -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) - -static struct clk *mvebu_clk_gating_get_src( -	struct of_phandle_args *clkspec, void *data) -{ -	struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data; -	int n; - -	if (clkspec->args_count < 1) -		return ERR_PTR(-EINVAL); - -	for (n = 0; n < ctrl->num_gates; n++) { -		struct clk_gate *gate = -			to_clk_gate(__clk_get_hw(ctrl->gates[n])); -		if (clkspec->args[0] == gate->bit_idx) -			return ctrl->gates[n]; -	} -	return ERR_PTR(-ENODEV); -} - -static void __init mvebu_clk_gating_setup( -	struct device_node *np, const struct mvebu_soc_descr *descr) -{ -	struct mvebu_gating_ctrl *ctrl; -	struct clk *clk; -	void __iomem *base; -	const char *default_parent = NULL; -	int n; - -	base = of_iomap(np, 0); - -	clk = of_clk_get(np, 0); -	if (!IS_ERR(clk)) { -		default_parent = __clk_get_name(clk); -		clk_put(clk); -	} - -	ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL); -	if (WARN_ON(!ctrl)) -		return; - -	spin_lock_init(&ctrl->lock); - -	/* -	 * Count, allocate, and register clock gates -	 */ -	for (n = 0; descr[n].name;) -		n++; - -	ctrl->num_gates = n; -	ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *), -			      GFP_KERNEL); -	if (WARN_ON(!ctrl->gates)) { -		kfree(ctrl); -		return; -	} - -	for (n = 0; n < ctrl->num_gates; n++) { -		u8 flags = 0; -		const char *parent = -			(descr[n].parent) ? descr[n].parent : default_parent; - -		/* -		 * On Armada 370, the DDR clock is a special case: it -		 * isn't taken by any driver, but should anyway be -		 * kept enabled, so we mark it as IGNORE_UNUSED for -		 * now. -		 */ -		if (!strcmp(descr[n].name, "ddr")) -			flags |= CLK_IGNORE_UNUSED; - -		ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent, -				   flags, base, descr[n].bit_idx, 0, &ctrl->lock); -		WARN_ON(IS_ERR(ctrl->gates[n])); -	} -	of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl); -} - -/* - * SoC specific clock gating control - */ - -#ifdef CONFIG_MACH_ARMADA_370 -static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = { -	{ "audio", NULL, 0 }, -	{ "pex0_en", NULL, 1 }, -	{ "pex1_en", NULL,  2 }, -	{ "ge1", NULL, 3 }, -	{ "ge0", NULL, 4 }, -	{ "pex0", NULL, 5 }, -	{ "pex1", NULL, 9 }, -	{ "sata0", NULL, 15 }, -	{ "sdio", NULL, 17 }, -	{ "tdm", NULL, 25 }, -	{ "ddr", NULL, 28 }, -	{ "sata1", NULL, 30 }, -	{ } -}; -#endif - -#ifdef CONFIG_MACH_ARMADA_XP -static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = { -	{ "audio", NULL, 0 }, -	{ "ge3", NULL, 1 }, -	{ "ge2", NULL,  2 }, -	{ "ge1", NULL, 3 }, -	{ "ge0", NULL, 4 }, -	{ "pex0", NULL, 5 }, -	{ "pex1", NULL, 6 }, -	{ "pex2", NULL, 7 }, -	{ "pex3", NULL, 8 }, -	{ "bp", NULL, 13 }, -	{ "sata0lnk", NULL, 14 }, -	{ "sata0", "sata0lnk", 15 }, -	{ "lcd", NULL, 16 }, -	{ "sdio", NULL, 17 }, -	{ "usb0", NULL, 18 }, -	{ "usb1", NULL, 19 }, -	{ "usb2", NULL, 20 }, -	{ "xor0", NULL, 22 }, -	{ "crypto", NULL, 23 }, -	{ "tdm", NULL, 25 }, -	{ "xor1", NULL, 28 }, -	{ "sata1lnk", NULL, 29 }, -	{ "sata1", "sata1lnk", 30 }, -	{ } -}; -#endif - -#ifdef CONFIG_ARCH_DOVE -static const struct mvebu_soc_descr __initconst dove_gating_descr[] = { -	{ "usb0", NULL, 0 }, -	{ "usb1", NULL, 1 }, -	{ "ge", "gephy", 2 }, -	{ "sata", NULL, 3 }, -	{ "pex0", NULL, 4 }, -	{ "pex1", NULL, 5 }, -	{ "sdio0", NULL, 8 }, -	{ "sdio1", NULL, 9 }, -	{ "nand", NULL, 10 }, -	{ "camera", NULL, 11 }, -	{ "i2s0", NULL, 12 }, -	{ "i2s1", NULL, 13 }, -	{ "crypto", NULL, 15 }, -	{ "ac97", NULL, 21 }, -	{ "pdma", NULL, 22 }, -	{ "xor0", NULL, 23 }, -	{ "xor1", NULL, 24 }, -	{ "gephy", NULL, 30 }, -	{ } -}; -#endif - -#ifdef CONFIG_ARCH_KIRKWOOD -static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = { -	{ "ge0", NULL, 0 }, -	{ "pex0", NULL, 2 }, -	{ "usb0", NULL, 3 }, -	{ "sdio", NULL, 4 }, -	{ "tsu", NULL, 5 }, -	{ "runit", NULL, 7 }, -	{ "xor0", NULL, 8 }, -	{ "audio", NULL, 9 }, -	{ "powersave", "cpuclk", 11 }, -	{ "sata0", NULL, 14 }, -	{ "sata1", NULL, 15 }, -	{ "xor1", NULL, 16 }, -	{ "crypto", NULL, 17 }, -	{ "pex1", NULL, 18 }, -	{ "ge1", NULL, 19 }, -	{ "tdm", NULL, 20 }, -	{ } -}; -#endif - -static const __initdata struct of_device_id clk_gating_match[] = { -#ifdef CONFIG_MACH_ARMADA_370 -	{ -		.compatible = "marvell,armada-370-gating-clock", -		.data = armada_370_gating_descr, -	}, -#endif - -#ifdef CONFIG_MACH_ARMADA_XP -	{ -		.compatible = "marvell,armada-xp-gating-clock", -		.data = armada_xp_gating_descr, -	}, -#endif - -#ifdef CONFIG_ARCH_DOVE -	{ -		.compatible = "marvell,dove-gating-clock", -		.data = dove_gating_descr, -	}, -#endif - -#ifdef CONFIG_ARCH_KIRKWOOD -	{ -		.compatible = "marvell,kirkwood-gating-clock", -		.data = kirkwood_gating_descr, -	}, -#endif - -	{ } -}; - -void __init mvebu_gating_clk_init(void) -{ -	struct device_node *np; - -	for_each_matching_node(np, clk_gating_match) { -		const struct of_device_id *match = -			of_match_node(clk_gating_match, np); -		mvebu_clk_gating_setup(np, -		       (const struct mvebu_soc_descr *)match->data); -	} -} diff --git a/drivers/clk/mvebu/clk-gating-ctrl.h b/drivers/clk/mvebu/clk-gating-ctrl.h deleted file mode 100644 index 9275d1e51f1b..000000000000 --- a/drivers/clk/mvebu/clk-gating-ctrl.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Marvell EBU gating clock handling - * - * Copyright (C) 2012 Marvell - * - * Thomas Petazzoni <[email protected]> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __MVEBU_CLK_GATING_H -#define __MVEBU_CLK_GATING_H - -#ifdef CONFIG_MVEBU_CLK_GATING -void __init mvebu_gating_clk_init(void); -#else -void mvebu_gating_clk_init(void) {} -#endif - -#endif diff --git a/drivers/clk/mvebu/clk.c b/drivers/clk/mvebu/clk.c deleted file mode 100644 index 29f10fb3006c..000000000000 --- a/drivers/clk/mvebu/clk.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Marvell EBU SoC clock handling. - * - * Copyright (C) 2012 Marvell - * - * Gregory CLEMENT <[email protected]> - * - * This file is licensed under the terms of the GNU General Public - * License version 2.  This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <linux/kernel.h> -#include <linux/clk-provider.h> -#include <linux/of.h> -#include "clk-core.h" -#include "clk-gating-ctrl.h" - -void __init mvebu_clocks_init(void) -{ -	mvebu_core_clk_init(); -	mvebu_gating_clk_init(); -	of_clk_init(NULL); -} diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c new file mode 100644 index 000000000000..adaa4a1821b8 --- /dev/null +++ b/drivers/clk/mvebu/common.c @@ -0,0 +1,163 @@ +/* + * Marvell EBU SoC common clock handling + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "common.h" + +/* + * Core Clocks + */ + +static struct clk_onecell_data clk_data; + +void __init mvebu_coreclk_setup(struct device_node *np, +				const struct coreclk_soc_desc *desc) +{ +	const char *tclk_name = "tclk"; +	const char *cpuclk_name = "cpuclk"; +	void __iomem *base; +	unsigned long rate; +	int n; + +	base = of_iomap(np, 0); +	if (WARN_ON(!base)) +		return; + +	/* Allocate struct for TCLK, cpu clk, and core ratio clocks */ +	clk_data.clk_num = 2 + desc->num_ratios; +	clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *), +				GFP_KERNEL); +	if (WARN_ON(!clk_data.clks)) +		return; + +	/* Register TCLK */ +	of_property_read_string_index(np, "clock-output-names", 0, +				      &tclk_name); +	rate = desc->get_tclk_freq(base); +	clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL, +						   CLK_IS_ROOT, rate); +	WARN_ON(IS_ERR(clk_data.clks[0])); + +	/* Register CPU clock */ +	of_property_read_string_index(np, "clock-output-names", 1, +				      &cpuclk_name); +	rate = desc->get_cpu_freq(base); +	clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL, +						   CLK_IS_ROOT, rate); +	WARN_ON(IS_ERR(clk_data.clks[1])); + +	/* Register fixed-factor clocks derived from CPU clock */ +	for (n = 0; n < desc->num_ratios; n++) { +		const char *rclk_name = desc->ratios[n].name; +		int mult, div; + +		of_property_read_string_index(np, "clock-output-names", +					      2+n, &rclk_name); +		desc->get_clk_ratio(base, desc->ratios[n].id, &mult, &div); +		clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name, +				       cpuclk_name, 0, mult, div); +		WARN_ON(IS_ERR(clk_data.clks[2+n])); +	}; + +	/* SAR register isn't needed anymore */ +	iounmap(base); + +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +/* + * Clock Gating Control + */ + +struct clk_gating_ctrl { +	spinlock_t lock; +	struct clk **gates; +	int num_gates; +}; + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static struct clk *clk_gating_get_src( +	struct of_phandle_args *clkspec, void *data) +{ +	struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data; +	int n; + +	if (clkspec->args_count < 1) +		return ERR_PTR(-EINVAL); + +	for (n = 0; n < ctrl->num_gates; n++) { +		struct clk_gate *gate = +			to_clk_gate(__clk_get_hw(ctrl->gates[n])); +		if (clkspec->args[0] == gate->bit_idx) +			return ctrl->gates[n]; +	} +	return ERR_PTR(-ENODEV); +} + +void __init mvebu_clk_gating_setup(struct device_node *np, +				   const struct clk_gating_soc_desc *desc) +{ +	struct clk_gating_ctrl *ctrl; +	struct clk *clk; +	void __iomem *base; +	const char *default_parent = NULL; +	int n; + +	base = of_iomap(np, 0); +	if (WARN_ON(!base)) +		return; + +	clk = of_clk_get(np, 0); +	if (!IS_ERR(clk)) { +		default_parent = __clk_get_name(clk); +		clk_put(clk); +	} + +	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); +	if (WARN_ON(!ctrl)) +		return; + +	spin_lock_init(&ctrl->lock); + +	/* Count, allocate, and register clock gates */ +	for (n = 0; desc[n].name;) +		n++; + +	ctrl->num_gates = n; +	ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *), +			      GFP_KERNEL); +	if (WARN_ON(!ctrl->gates)) { +		kfree(ctrl); +		return; +	} + +	for (n = 0; n < ctrl->num_gates; n++) { +		const char *parent = +			(desc[n].parent) ? desc[n].parent : default_parent; +		ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent, +					desc[n].flags, base, desc[n].bit_idx, +					0, &ctrl->lock); +		WARN_ON(IS_ERR(ctrl->gates[n])); +	} + +	of_clk_add_provider(np, clk_gating_get_src, ctrl); +} diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h new file mode 100644 index 000000000000..f968b4d9df92 --- /dev/null +++ b/drivers/clk/mvebu/common.h @@ -0,0 +1,48 @@ +/* + * Marvell EBU SoC common clock handling + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __CLK_MVEBU_COMMON_H_ +#define __CLK_MVEBU_COMMON_H_ + +#include <linux/kernel.h> + +struct device_node; + +struct coreclk_ratio { +	int id; +	const char *name; +}; + +struct coreclk_soc_desc { +	u32 (*get_tclk_freq)(void __iomem *sar); +	u32 (*get_cpu_freq)(void __iomem *sar); +	void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div); +	const struct coreclk_ratio *ratios; +	int num_ratios; +}; + +struct clk_gating_soc_desc { +	const char *name; +	const char *parent; +	int bit_idx; +	unsigned long flags; +}; + +void __init mvebu_coreclk_setup(struct device_node *np, +				const struct coreclk_soc_desc *desc); + +void __init mvebu_clk_gating_setup(struct device_node *np, +				   const struct clk_gating_soc_desc *desc); + +#endif diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c new file mode 100644 index 000000000000..79d7aedf03fb --- /dev/null +++ b/drivers/clk/mvebu/dove.c @@ -0,0 +1,194 @@ +/* + * Marvell Dove SoC clocks + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * Core Clocks + * + * Dove PLL sample-at-reset configuration + * + * SAR0[8:5]   : CPU frequency + *		 5  = 1000 MHz + *		 6  =  933 MHz + *		 7  =  933 MHz + *		 8  =  800 MHz + *		 9  =  800 MHz + *		 10 =  800 MHz + *		 11 = 1067 MHz + *		 12 =  667 MHz + *		 13 =  533 MHz + *		 14 =  400 MHz + *		 15 =  333 MHz + *		 others reserved. + * + * SAR0[11:9]  : CPU to L2 Clock divider ratio + *		 0 = (1/1) * CPU + *		 2 = (1/2) * CPU + *		 4 = (1/3) * CPU + *		 6 = (1/4) * CPU + *		 others reserved. + * + * SAR0[15:12] : CPU to DDR DRAM Clock divider ratio + *		 0  = (1/1) * CPU + *		 2  = (1/2) * CPU + *		 3  = (2/5) * CPU + *		 4  = (1/3) * CPU + *		 6  = (1/4) * CPU + *		 8  = (1/5) * CPU + *		 10 = (1/6) * CPU + *		 12 = (1/7) * CPU + *		 14 = (1/8) * CPU + *		 15 = (1/10) * CPU + *		 others reserved. + * + * SAR0[24:23] : TCLK frequency + *		 0 = 166 MHz + *		 1 = 125 MHz + *		 others reserved. + */ + +#define SAR_DOVE_CPU_FREQ		5 +#define SAR_DOVE_CPU_FREQ_MASK		0xf +#define SAR_DOVE_L2_RATIO		9 +#define SAR_DOVE_L2_RATIO_MASK		0x7 +#define SAR_DOVE_DDR_RATIO		12 +#define SAR_DOVE_DDR_RATIO_MASK		0xf +#define SAR_DOVE_TCLK_FREQ		23 +#define SAR_DOVE_TCLK_FREQ_MASK		0x3 + +enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR }; + +static const struct coreclk_ratio __initconst dove_coreclk_ratios[] = { +	{ .id = DOVE_CPU_TO_L2, .name = "l2clk", }, +	{ .id = DOVE_CPU_TO_DDR, .name = "ddrclk", } +}; + +static const u32 __initconst dove_tclk_freqs[] = { +	166666667, +	125000000, +	0, 0 +}; + +static u32 __init dove_get_tclk_freq(void __iomem *sar) +{ +	u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) & +		SAR_DOVE_TCLK_FREQ_MASK; +	return dove_tclk_freqs[opt]; +} + +static const u32 __initconst dove_cpu_freqs[] = { +	0, 0, 0, 0, 0, +	1000000000, +	933333333, 933333333, +	800000000, 800000000, 800000000, +	1066666667, +	666666667, +	533333333, +	400000000, +	333333333 +}; + +static u32 __init dove_get_cpu_freq(void __iomem *sar) +{ +	u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) & +		SAR_DOVE_CPU_FREQ_MASK; +	return dove_cpu_freqs[opt]; +} + +static const int __initconst dove_cpu_l2_ratios[8][2] = { +	{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, +	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 } +}; + +static const int __initconst dove_cpu_ddr_ratios[16][2] = { +	{ 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 }, +	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }, +	{ 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 }, +	{ 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 } +}; + +static void __init dove_get_clk_ratio( +	void __iomem *sar, int id, int *mult, int *div) +{ +	switch (id) { +	case DOVE_CPU_TO_L2: +	{ +		u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) & +			SAR_DOVE_L2_RATIO_MASK; +		*mult = dove_cpu_l2_ratios[opt][0]; +		*div = dove_cpu_l2_ratios[opt][1]; +		break; +	} +	case DOVE_CPU_TO_DDR: +	{ +		u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) & +			SAR_DOVE_DDR_RATIO_MASK; +		*mult = dove_cpu_ddr_ratios[opt][0]; +		*div = dove_cpu_ddr_ratios[opt][1]; +		break; +	} +	} +} + +static const struct coreclk_soc_desc dove_coreclks = { +	.get_tclk_freq = dove_get_tclk_freq, +	.get_cpu_freq = dove_get_cpu_freq, +	.get_clk_ratio = dove_get_clk_ratio, +	.ratios = dove_coreclk_ratios, +	.num_ratios = ARRAY_SIZE(dove_coreclk_ratios), +}; + +static void __init dove_coreclk_init(struct device_node *np) +{ +	mvebu_coreclk_setup(np, &dove_coreclks); +} +CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init); + +/* + * Clock Gating Control + */ + +static const struct clk_gating_soc_desc __initconst dove_gating_desc[] = { +	{ "usb0", NULL, 0, 0 }, +	{ "usb1", NULL, 1, 0 }, +	{ "ge",	"gephy", 2, 0 }, +	{ "sata", NULL, 3, 0 }, +	{ "pex0", NULL, 4, 0 }, +	{ "pex1", NULL, 5, 0 }, +	{ "sdio0", NULL, 8, 0 }, +	{ "sdio1", NULL, 9, 0 }, +	{ "nand", NULL, 10, 0 }, +	{ "camera", NULL, 11, 0 }, +	{ "i2s0", NULL, 12, 0 }, +	{ "i2s1", NULL, 13, 0 }, +	{ "crypto", NULL, 15, 0 }, +	{ "ac97", NULL, 21, 0 }, +	{ "pdma", NULL, 22, 0 }, +	{ "xor0", NULL, 23, 0 }, +	{ "xor1", NULL, 24, 0 }, +	{ "gephy", NULL, 30, 0 }, +	{ } +}; + +static void __init dove_clk_gating_init(struct device_node *np) +{ +	mvebu_clk_gating_setup(np, dove_gating_desc); +} +CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock", +	       dove_clk_gating_init); diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c new file mode 100644 index 000000000000..71d24619ccdb --- /dev/null +++ b/drivers/clk/mvebu/kirkwood.c @@ -0,0 +1,247 @@ +/* + * Marvell Kirkwood SoC clocks + * + * Copyright (C) 2012 Marvell + * + * Gregory CLEMENT <[email protected]> + * Sebastian Hesselbarth <[email protected]> + * Andrew Lunn <[email protected]> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/of.h> +#include "common.h" + +/* + * Core Clocks + * + * Kirkwood PLL sample-at-reset configuration + * (6180 has different SAR layout than other Kirkwood SoCs) + * + * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282) + *	4  =  600 MHz + *	6  =  800 MHz + *	7  = 1000 MHz + *	9  = 1200 MHz + *	12 = 1500 MHz + *	13 = 1600 MHz + *	14 = 1800 MHz + *	15 = 2000 MHz + *	others reserved. + * + * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282) + *	1 = (1/2) * CPU + *	3 = (1/3) * CPU + *	5 = (1/4) * CPU + *	others reserved. + * + * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282) + *	2 = (1/2) * CPU + *	4 = (1/3) * CPU + *	6 = (1/4) * CPU + *	7 = (2/9) * CPU + *	8 = (1/5) * CPU + *	9 = (1/6) * CPU + *	others reserved. + * + * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only) + *	5 = [CPU =  600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU] + *	6 = [CPU =  800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU] + *	7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU] + *	others reserved. + * + * SAR0[21] : TCLK frequency + *	0 = 200 MHz + *	1 = 166 MHz + *	others reserved. + */ + +#define SAR_KIRKWOOD_CPU_FREQ(x)	\ +	(((x & (1 <<  1)) >>  1) |	\ +	 ((x & (1 << 22)) >> 21) |	\ +	 ((x & (3 <<  3)) >>  1)) +#define SAR_KIRKWOOD_L2_RATIO(x)	\ +	(((x & (3 <<  9)) >> 9) |	\ +	 (((x & (1 << 19)) >> 17))) +#define SAR_KIRKWOOD_DDR_RATIO		5 +#define SAR_KIRKWOOD_DDR_RATIO_MASK	0xf +#define SAR_MV88F6180_CLK		2 +#define SAR_MV88F6180_CLK_MASK		0x7 +#define SAR_KIRKWOOD_TCLK_FREQ		21 +#define SAR_KIRKWOOD_TCLK_FREQ_MASK	0x1 + +enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR }; + +static const struct coreclk_ratio __initconst kirkwood_coreclk_ratios[] = { +	{ .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", }, +	{ .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", } +}; + +static u32 __init kirkwood_get_tclk_freq(void __iomem *sar) +{ +	u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) & +		SAR_KIRKWOOD_TCLK_FREQ_MASK; +	return (opt) ? 166666667 : 200000000; +} + +static const u32 __initconst kirkwood_cpu_freqs[] = { +	0, 0, 0, 0, +	600000000, +	0, +	800000000, +	1000000000, +	0, +	1200000000, +	0, 0, +	1500000000, +	1600000000, +	1800000000, +	2000000000 +}; + +static u32 __init kirkwood_get_cpu_freq(void __iomem *sar) +{ +	u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar)); +	return kirkwood_cpu_freqs[opt]; +} + +static const int __initconst kirkwood_cpu_l2_ratios[8][2] = { +	{ 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 }, +	{ 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 } +}; + +static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = { +	{ 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 }, +	{ 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 }, +	{ 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 }, +	{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 } +}; + +static void __init kirkwood_get_clk_ratio( +	void __iomem *sar, int id, int *mult, int *div) +{ +	switch (id) { +	case KIRKWOOD_CPU_TO_L2: +	{ +		u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar)); +		*mult = kirkwood_cpu_l2_ratios[opt][0]; +		*div = kirkwood_cpu_l2_ratios[opt][1]; +		break; +	} +	case KIRKWOOD_CPU_TO_DDR: +	{ +		u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) & +			SAR_KIRKWOOD_DDR_RATIO_MASK; +		*mult = kirkwood_cpu_ddr_ratios[opt][0]; +		*div = kirkwood_cpu_ddr_ratios[opt][1]; +		break; +	} +	} +} + +static const u32 __initconst mv88f6180_cpu_freqs[] = { +	0, 0, 0, 0, 0, +	600000000, +	800000000, +	1000000000 +}; + +static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar) +{ +	u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK; +	return mv88f6180_cpu_freqs[opt]; +} + +static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = { +	{ 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }, +	{ 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 } +}; + +static void __init mv88f6180_get_clk_ratio( +	void __iomem *sar, int id, int *mult, int *div) +{ +	switch (id) { +	case KIRKWOOD_CPU_TO_L2: +	{ +		/* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */ +		*mult = 1; +		*div = 2; +		break; +	} +	case KIRKWOOD_CPU_TO_DDR: +	{ +		u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & +			SAR_MV88F6180_CLK_MASK; +		*mult = mv88f6180_cpu_ddr_ratios[opt][0]; +		*div = mv88f6180_cpu_ddr_ratios[opt][1]; +		break; +	} +	} +} + +static const struct coreclk_soc_desc kirkwood_coreclks = { +	.get_tclk_freq = kirkwood_get_tclk_freq, +	.get_cpu_freq = kirkwood_get_cpu_freq, +	.get_clk_ratio = kirkwood_get_clk_ratio, +	.ratios = kirkwood_coreclk_ratios, +	.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), +}; + +static void __init kirkwood_coreclk_init(struct device_node *np) +{ +	mvebu_coreclk_setup(np, &kirkwood_coreclks); +} +CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock", +	       kirkwood_coreclk_init); + +static const struct coreclk_soc_desc mv88f6180_coreclks = { +	.get_tclk_freq = kirkwood_get_tclk_freq, +	.get_cpu_freq = mv88f6180_get_cpu_freq, +	.get_clk_ratio = mv88f6180_get_clk_ratio, +	.ratios = kirkwood_coreclk_ratios, +	.num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), +}; + +static void __init mv88f6180_coreclk_init(struct device_node *np) +{ +	mvebu_coreclk_setup(np, &mv88f6180_coreclks); +} +CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock", +	       mv88f6180_coreclk_init); + +/* + * Clock Gating Control + */ + +static const struct clk_gating_soc_desc __initconst kirkwood_gating_desc[] = { +	{ "ge0", NULL, 0, 0 }, +	{ "pex0", NULL, 2, 0 }, +	{ "usb0", NULL, 3, 0 }, +	{ "sdio", NULL, 4, 0 }, +	{ "tsu", NULL, 5, 0 }, +	{ "runit", NULL, 7, 0 }, +	{ "xor0", NULL, 8, 0 }, +	{ "audio", NULL, 9, 0 }, +	{ "powersave", "cpuclk", 11, 0 }, +	{ "sata0", NULL, 14, 0 }, +	{ "sata1", NULL, 15, 0 }, +	{ "xor1", NULL, 16, 0 }, +	{ "crypto", NULL, 17, 0 }, +	{ "pex1", NULL, 18, 0 }, +	{ "ge1", NULL, 19, 0 }, +	{ "tdm", NULL, 20, 0 }, +	{ } +}; + +static void __init kirkwood_clk_gating_init(struct device_node *np) +{ +	mvebu_clk_gating_setup(np, kirkwood_gating_desc); +} +CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock", +	       kirkwood_clk_gating_init); diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile new file mode 100644 index 000000000000..8d3aefad2e73 --- /dev/null +++ b/drivers/clk/rockchip/Makefile @@ -0,0 +1,5 @@ +# +# Rockchip Clock specific Makefile +# + +obj-y	+= clk-rockchip.o diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c new file mode 100644 index 000000000000..967c141b1a20 --- /dev/null +++ b/drivers/clk/rockchip/clk-rockchip.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013 MundoReader S.L. + * Author: Heiko Stuebner <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> + +static DEFINE_SPINLOCK(clk_lock); + +/* + * Gate clocks + */ + +static void __init rk2928_gate_clk_init(struct device_node *node, +					 void *data) +{ +	struct clk_onecell_data *clk_data; +	const char *clk_parent; +	const char *clk_name; +	void __iomem *reg; +	void __iomem *reg_idx; +	int flags; +	int qty; +	int reg_bit; +	int clkflags = CLK_SET_RATE_PARENT; +	int i; + +	qty = of_property_count_strings(node, "clock-output-names"); +	if (qty < 0) { +		pr_err("%s: error in clock-output-names %d\n", __func__, qty); +		return; +	} + +	if (qty == 0) { +		pr_info("%s: nothing to do\n", __func__); +		return; +	} + +	reg = of_iomap(node, 0); + +	clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); +	if (!clk_data) +		return; + +	clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL); +	if (!clk_data->clks) { +		kfree(clk_data); +		return; +	} + +	flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE; + +	for (i = 0; i < qty; i++) { +		of_property_read_string_index(node, "clock-output-names", +					      i, &clk_name); + +		/* ignore empty slots */ +		if (!strcmp("reserved", clk_name)) +			continue; + +		clk_parent = of_clk_get_parent_name(node, i); + +		/* keep all gates untouched for now */ +		clkflags |= CLK_IGNORE_UNUSED; + +		reg_idx = reg + (4 * (i / 16)); +		reg_bit = (i % 16); + +		clk_data->clks[i] = clk_register_gate(NULL, clk_name, +						      clk_parent, clkflags, +						      reg_idx, reg_bit, +						      flags, +						      &clk_lock); +		WARN_ON(IS_ERR(clk_data->clks[i])); +	} + +	clk_data->clk_num = qty; + +	of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} +CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init); diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index b7c232e67425..5d4d432cc4ac 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -5,4 +5,6 @@  obj-$(CONFIG_COMMON_CLK)	+= clk.o clk-pll.o  obj-$(CONFIG_ARCH_EXYNOS4)	+= clk-exynos4.o  obj-$(CONFIG_SOC_EXYNOS5250)	+= clk-exynos5250.o +obj-$(CONFIG_SOC_EXYNOS5420)	+= clk-exynos5420.o  obj-$(CONFIG_SOC_EXYNOS5440)	+= clk-exynos5440.o +obj-$(CONFIG_ARCH_EXYNOS)	+= clk-exynos-audss.o diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c new file mode 100644 index 000000000000..9b1bbd52fd1f --- /dev/null +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Author: Padmavathi Venna <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Common Clock Framework support for Audio Subsystem Clock Controller. +*/ + +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <linux/syscore_ops.h> + +#include <dt-bindings/clk/exynos-audss-clk.h> + +static DEFINE_SPINLOCK(lock); +static struct clk **clk_table; +static void __iomem *reg_base; +static struct clk_onecell_data clk_data; + +#define ASS_CLK_SRC 0x0 +#define ASS_CLK_DIV 0x4 +#define ASS_CLK_GATE 0x8 + +static unsigned long reg_save[][2] = { +	{ASS_CLK_SRC,  0}, +	{ASS_CLK_DIV,  0}, +	{ASS_CLK_GATE, 0}, +}; + +/* list of all parent clock list */ +static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; +static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; + +#ifdef CONFIG_PM_SLEEP +static int exynos_audss_clk_suspend(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(reg_save); i++) +		reg_save[i][1] = readl(reg_base + reg_save[i][0]); + +	return 0; +} + +static void exynos_audss_clk_resume(void) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(reg_save); i++) +		writel(reg_save[i][1], reg_base + reg_save[i][0]); +} + +static struct syscore_ops exynos_audss_clk_syscore_ops = { +	.suspend	= exynos_audss_clk_suspend, +	.resume		= exynos_audss_clk_resume, +}; +#endif /* CONFIG_PM_SLEEP */ + +/* register exynos_audss clocks */ +void __init exynos_audss_clk_init(struct device_node *np) +{ +	reg_base = of_iomap(np, 0); +	if (!reg_base) { +		pr_err("%s: failed to map audss registers\n", __func__); +		return; +	} + +	clk_table = kzalloc(sizeof(struct clk *) * EXYNOS_AUDSS_MAX_CLKS, +				GFP_KERNEL); +	if (!clk_table) { +		pr_err("%s: could not allocate clk lookup table\n", __func__); +		return; +	} + +	clk_data.clks = clk_table; +	clk_data.clk_num = EXYNOS_AUDSS_MAX_CLKS; +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + +	clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss", +				mout_audss_p, ARRAY_SIZE(mout_audss_p), 0, +				reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); + +	clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s", +				mout_i2s_p, ARRAY_SIZE(mout_i2s_p), 0, +				reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); + +	clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp", +				"mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4, +				0, &lock); + +	clk_table[EXYNOS_DOUT_AUD_BUS] = clk_register_divider(NULL, +				"dout_aud_bus", "dout_srp", 0, +				reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); + +	clk_table[EXYNOS_DOUT_I2S] = clk_register_divider(NULL, "dout_i2s", +				"mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0, +				&lock); + +	clk_table[EXYNOS_SRP_CLK] = clk_register_gate(NULL, "srp_clk", +				"dout_srp", CLK_SET_RATE_PARENT, +				reg_base + ASS_CLK_GATE, 0, 0, &lock); + +	clk_table[EXYNOS_I2S_BUS] = clk_register_gate(NULL, "i2s_bus", +				"dout_aud_bus", CLK_SET_RATE_PARENT, +				reg_base + ASS_CLK_GATE, 2, 0, &lock); + +	clk_table[EXYNOS_SCLK_I2S] = clk_register_gate(NULL, "sclk_i2s", +				"dout_i2s", CLK_SET_RATE_PARENT, +				reg_base + ASS_CLK_GATE, 3, 0, &lock); + +	clk_table[EXYNOS_PCM_BUS] = clk_register_gate(NULL, "pcm_bus", +				 "sclk_pcm", CLK_SET_RATE_PARENT, +				reg_base + ASS_CLK_GATE, 4, 0, &lock); + +	clk_table[EXYNOS_SCLK_PCM] = clk_register_gate(NULL, "sclk_pcm", +				"div_pcm0", CLK_SET_RATE_PARENT, +				reg_base + ASS_CLK_GATE, 5, 0, &lock); + +#ifdef CONFIG_PM_SLEEP +	register_syscore_ops(&exynos_audss_clk_syscore_ops); +#endif + +	pr_info("Exynos: Audss: clock setup completed\n"); +} +CLK_OF_DECLARE(exynos4210_audss_clk, "samsung,exynos4210-audss-clock", +		exynos_audss_clk_init); +CLK_OF_DECLARE(exynos5250_audss_clk, "samsung,exynos5250-audss-clock", +		exynos_audss_clk_init); diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 3c1f88868f29..1bdb882c845b 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -151,7 +151,7 @@ enum exynos4_clks {  	sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2,  	sclk_slimbus, sclk_fimd1, sclk_mipi1, sclk_pcm1, sclk_pcm2, sclk_i2s1,  	sclk_i2s2, sclk_mipihsi, sclk_mfc, sclk_pcm0, sclk_g3d, sclk_pwm_isp, -	sclk_spi0_isp, sclk_spi1_isp, sclk_uart_isp, +	sclk_spi0_isp, sclk_spi1_isp, sclk_uart_isp, sclk_fimg2d,  	/* gate clocks */  	fimc0 = 256, fimc1, fimc2, fimc3, csis0, csis1, jpeg, smmu_fimc0, @@ -356,8 +356,8 @@ struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {  /* list of mux clocks supported in all exynos4 soc's */  struct samsung_mux_clock exynos4_mux_clks[] __initdata = { -	MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, -			CLK_SET_RATE_PARENT, 0), +	MUX_FA(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, +			CLK_SET_RATE_PARENT, 0, "mout_apll"),  	MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),  	MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),  	MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), @@ -385,9 +385,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {  	MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),  	MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),  	MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4), -	MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"), +	MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "mout_mpll"),  	MUX_A(mout_core, "mout_core", mout_core_p4210, -			SRC_CPU, 16, 1, "mout_core"), +			SRC_CPU, 16, 1, "moutcore"),  	MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,  			SRC_TOP0, 8, 1, "sclk_vpll"),  	MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4), @@ -424,8 +424,8 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {  /* list of mux clocks supported in exynos4x12 soc */  struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = { -	MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12, -			SRC_CPU, 24, 1), +	MUX_A(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12, +			SRC_CPU, 24, 1, "mout_mpll"),  	MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),  	MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),  	MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12, @@ -449,7 +449,8 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {  			SRC_DMC, 12, 1, "sclk_mpll"),  	MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,  			SRC_TOP0, 8, 1, "sclk_vpll"), -	MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1), +	MUX_A(mout_core, "mout_core", mout_core_p4x12, +			SRC_CPU, 16, 1, "moutcore"),  	MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),  	MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),  	MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4), @@ -484,6 +485,9 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {  	MUX(none, "mout_spi0_isp", group1_p4x12, E4X12_SRC_ISP, 4, 4),  	MUX(none, "mout_spi1_isp", group1_p4x12, E4X12_SRC_ISP, 8, 4),  	MUX(none, "mout_uart_isp", group1_p4x12, E4X12_SRC_ISP, 12, 4), +	MUX(none, "mout_g2d0", sclk_ampll_p4210, SRC_DMC, 20, 1), +	MUX(none, "mout_g2d1", sclk_evpll_p, SRC_DMC, 24, 1), +	MUX(none, "mout_g2d", mout_g2d_p, SRC_DMC, 28, 1),  };  /* list of divider clocks supported in all exynos4 soc's */ @@ -534,7 +538,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {  	DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),  	DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),  	DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4), -	DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"), +	DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "armclk"),  	DIV_A(sclk_apll, "sclk_apll", "mout_apll",  			DIV_CPU0, 24, 3, "sclk_apll"),  	DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4, @@ -552,7 +556,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {  /* list of divider clocks supported in exynos4210 soc */  struct samsung_div_clock exynos4210_div_clks[] __initdata = {  	DIV(aclk200, "aclk200", "mout_aclk200", DIV_TOP, 0, 3), -	DIV(none, "div_g2d", "mout_g2d", DIV_IMAGE, 0, 4), +	DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_IMAGE, 0, 4),  	DIV(none, "div_fimd1", "mout_fimd1", E4210_DIV_LCD1, 0, 4),  	DIV(none, "div_mipi1", "mout_mipi1", E4210_DIV_LCD1, 16, 4),  	DIV(none, "div_sata", "mout_sata", DIV_FSYS0, 20, 4), @@ -582,6 +586,7 @@ struct samsung_div_clock exynos4x12_div_clks[] __initdata = {  	DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),  	DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3),  	DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3), +	DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),  };  /* list of gate clocks supported in all exynos4 soc's */ @@ -909,6 +914,7 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {  			CLK_IGNORE_UNUSED, 0),  	GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,  			CLK_IGNORE_UNUSED, 0), +	GATE(g2d, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),  };  /* @@ -1065,9 +1071,9 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so  	pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"  		"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",  		exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", -		_get_rate("sclk_apll"),	_get_rate("sclk_mpll"), +		_get_rate("sclk_apll"),	_get_rate("mout_mpll"),  		_get_rate("sclk_epll"), _get_rate("sclk_vpll"), -		_get_rate("arm_clk")); +		_get_rate("armclk"));  } diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 22d7699e7ced..6f767c515ec7 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -87,6 +87,7 @@ enum exynos5250_clks {  	sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_sata, sclk_usb3,  	sclk_jpeg, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_pwm,  	sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2, +	div_i2s1, div_i2s2,  	/* gate clocks */  	gscl0 = 256, gscl1, gscl2, gscl3, gscl_wa, gscl_wb, smmu_gscl0, @@ -291,8 +292,8 @@ struct samsung_div_clock exynos5250_div_clks[] __initdata = {  	DIV(none, "div_pcm1", "sclk_audio1", DIV_PERIC4, 4, 8),  	DIV(none, "div_audio2", "mout_audio2", DIV_PERIC4, 16, 4),  	DIV(none, "div_pcm2", "sclk_audio2", DIV_PERIC4, 20, 8), -	DIV(none, "div_i2s1", "sclk_audio1", DIV_PERIC5, 0, 6), -	DIV(none, "div_i2s2", "sclk_audio2", DIV_PERIC5, 8, 6), +	DIV(div_i2s1, "div_i2s1", "sclk_audio1", DIV_PERIC5, 0, 6), +	DIV(div_i2s2, "div_i2s2", "sclk_audio2", DIV_PERIC5, 8, 6),  	DIV(sclk_pixel, "div_hdmi_pixel", "sclk_vpll", DIV_DISP1_0, 28, 4),  	DIV_A(none, "armclk", "div_arm", DIV_CPU0, 28, 3, "armclk"),  	DIV_F(none, "div_mipi1_pre", "div_mipi1", diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c new file mode 100644 index 000000000000..68a96cbd4936 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Authors: Thomas Abraham <[email protected]> + *	    Chander Kashyap <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Common Clock Framework support for Exynos5420 SoC. +*/ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "clk.h" +#include "clk-pll.h" + +#define SRC_CPU			0x200 +#define DIV_CPU0		0x500 +#define DIV_CPU1		0x504 +#define GATE_BUS_CPU		0x700 +#define GATE_SCLK_CPU		0x800 +#define SRC_TOP0		0x10200 +#define SRC_TOP1		0x10204 +#define SRC_TOP2		0x10208 +#define SRC_TOP3		0x1020c +#define SRC_TOP4		0x10210 +#define SRC_TOP5		0x10214 +#define SRC_TOP6		0x10218 +#define SRC_TOP7		0x1021c +#define SRC_DISP10		0x1022c +#define SRC_MAU			0x10240 +#define SRC_FSYS		0x10244 +#define SRC_PERIC0		0x10250 +#define SRC_PERIC1		0x10254 +#define SRC_TOP10		0x10280 +#define SRC_TOP11		0x10284 +#define SRC_TOP12		0x10288 +#define	SRC_MASK_DISP10		0x1032c +#define SRC_MASK_FSYS		0x10340 +#define SRC_MASK_PERIC0		0x10350 +#define SRC_MASK_PERIC1		0x10354 +#define DIV_TOP0		0x10500 +#define DIV_TOP1		0x10504 +#define DIV_TOP2		0x10508 +#define DIV_DISP10		0x1052c +#define DIV_MAU			0x10544 +#define DIV_FSYS0		0x10548 +#define DIV_FSYS1		0x1054c +#define DIV_FSYS2		0x10550 +#define DIV_PERIC0		0x10558 +#define DIV_PERIC1		0x1055c +#define DIV_PERIC2		0x10560 +#define DIV_PERIC3		0x10564 +#define DIV_PERIC4		0x10568 +#define GATE_BUS_TOP		0x10700 +#define GATE_BUS_FSYS0		0x10740 +#define GATE_BUS_PERIC		0x10750 +#define GATE_BUS_PERIC1		0x10754 +#define GATE_BUS_PERIS0		0x10760 +#define GATE_BUS_PERIS1		0x10764 +#define GATE_IP_GSCL0		0x10910 +#define GATE_IP_GSCL1		0x10920 +#define GATE_IP_MFC		0x1092c +#define GATE_IP_DISP1		0x10928 +#define GATE_IP_G3D		0x10930 +#define GATE_IP_GEN		0x10934 +#define GATE_IP_MSCL		0x10970 +#define GATE_TOP_SCLK_GSCL	0x10820 +#define GATE_TOP_SCLK_DISP1	0x10828 +#define GATE_TOP_SCLK_MAU	0x1083c +#define GATE_TOP_SCLK_FSYS	0x10840 +#define GATE_TOP_SCLK_PERIC	0x10850 +#define SRC_CDREX		0x20200 +#define SRC_KFC			0x28200 +#define DIV_KFC0		0x28500 + +enum exynos5420_clks { +	none, + +	/* core clocks */ +	fin_pll, + +	/* gate for special clocks (sclk) */ +	sclk_uart0 = 128, sclk_uart1, sclk_uart2, sclk_uart3, sclk_mmc0, +	sclk_mmc1, sclk_mmc2, sclk_spi0, sclk_spi1, sclk_spi2, sclk_i2s1, +	sclk_i2s2, sclk_pcm1, sclk_pcm2, sclk_spdif, sclk_hdmi, sclk_pixel, +	sclk_dp1, sclk_mipi1, sclk_fimd1, sclk_maudio0, sclk_maupcm0, +	sclk_usbd300, sclk_usbd301, sclk_usbphy300, sclk_usbphy301, sclk_unipro, +	sclk_pwm, sclk_gscl_wa, sclk_gscl_wb, + +	/* gate clocks */ +	aclk66_peric = 256, uart0, uart1, uart2, uart3, i2c0, i2c1, i2c2, i2c3, +	i2c4, i2c5, i2c6, i2c7, i2c_hdmi, tsadc, spi0, spi1, spi2, keyif, i2s1, +	i2s2, pcm1, pcm2, pwm, spdif, i2c8, i2c9, i2c10, aclk66_psgen = 300, +	chipid, sysreg, tzpc0, tzpc1, tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, +	tzpc8, tzpc9, hdmi_cec, seckey, mct, wdt, rtc, tmu, tmu_gpu, +	pclk66_gpio = 330, aclk200_fsys2 = 350, mmc0, mmc1, mmc2, sromc, ufs, +	aclk200_fsys = 360, tsi, pdma0, pdma1, rtic, usbh20, usbd300, usbd301, +	aclk400_mscl = 380, mscl0, mscl1, mscl2, smmu_mscl0, smmu_mscl1, +	smmu_mscl2, aclk333 = 400, mfc, smmu_mfcl, smmu_mfcr, +	aclk200_disp1 = 410, dsim1, dp1, hdmi, aclk300_disp1 = 420, fimd1, +	smmu_fimd1, aclk166 = 430, mixer, aclk266 = 440, rotator, mdma1, +	smmu_rotator, smmu_mdma1, aclk300_jpeg = 450, jpeg, jpeg2, smmu_jpeg, +	aclk300_gscl = 460, smmu_gscl0, smmu_gscl1, gscl_wa, gscl_wb, gscl0, +	gscl1, clk_3aa, aclk266_g2d = 470, sss, slim_sss, mdma0, +	aclk333_g2d = 480, g2d, aclk333_432_gscl = 490, smmu_3aa, smmu_fimcl0, +	smmu_fimcl1, smmu_fimcl3, fimc_lite3, aclk_g3d = 500, g3d, + +	nr_clks, +}; + +/* + * list of controller registers to be saved and restored during a + * suspend/resume cycle. + */ +static __initdata unsigned long exynos5420_clk_regs[] = { +	SRC_CPU, +	DIV_CPU0, +	DIV_CPU1, +	GATE_BUS_CPU, +	GATE_SCLK_CPU, +	SRC_TOP0, +	SRC_TOP1, +	SRC_TOP2, +	SRC_TOP3, +	SRC_TOP4, +	SRC_TOP5, +	SRC_TOP6, +	SRC_TOP7, +	SRC_DISP10, +	SRC_MAU, +	SRC_FSYS, +	SRC_PERIC0, +	SRC_PERIC1, +	SRC_TOP10, +	SRC_TOP11, +	SRC_TOP12, +	SRC_MASK_DISP10, +	SRC_MASK_FSYS, +	SRC_MASK_PERIC0, +	SRC_MASK_PERIC1, +	DIV_TOP0, +	DIV_TOP1, +	DIV_TOP2, +	DIV_DISP10, +	DIV_MAU, +	DIV_FSYS0, +	DIV_FSYS1, +	DIV_FSYS2, +	DIV_PERIC0, +	DIV_PERIC1, +	DIV_PERIC2, +	DIV_PERIC3, +	DIV_PERIC4, +	GATE_BUS_TOP, +	GATE_BUS_FSYS0, +	GATE_BUS_PERIC, +	GATE_BUS_PERIC1, +	GATE_BUS_PERIS0, +	GATE_BUS_PERIS1, +	GATE_IP_GSCL0, +	GATE_IP_GSCL1, +	GATE_IP_MFC, +	GATE_IP_DISP1, +	GATE_IP_G3D, +	GATE_IP_GEN, +	GATE_IP_MSCL, +	GATE_TOP_SCLK_GSCL, +	GATE_TOP_SCLK_DISP1, +	GATE_TOP_SCLK_MAU, +	GATE_TOP_SCLK_FSYS, +	GATE_TOP_SCLK_PERIC, +	SRC_CDREX, +	SRC_KFC, +	DIV_KFC0, +}; + +/* list of all parent clocks */ +PNAME(mspll_cpu_p)	= { "sclk_cpll", "sclk_dpll", +				"sclk_mpll", "sclk_spll" }; +PNAME(cpu_p)		= { "mout_apll" , "mout_mspll_cpu" }; +PNAME(kfc_p)		= { "mout_kpll" , "mout_mspll_kfc" }; +PNAME(apll_p)		= { "fin_pll", "fout_apll", }; +PNAME(bpll_p)		= { "fin_pll", "fout_bpll", }; +PNAME(cpll_p)		= { "fin_pll", "fout_cpll", }; +PNAME(dpll_p)		= { "fin_pll", "fout_dpll", }; +PNAME(epll_p)		= { "fin_pll", "fout_epll", }; +PNAME(ipll_p)		= { "fin_pll", "fout_ipll", }; +PNAME(kpll_p)		= { "fin_pll", "fout_kpll", }; +PNAME(mpll_p)		= { "fin_pll", "fout_mpll", }; +PNAME(rpll_p)		= { "fin_pll", "fout_rpll", }; +PNAME(spll_p)		= { "fin_pll", "fout_spll", }; +PNAME(vpll_p)		= { "fin_pll", "fout_vpll", }; + +PNAME(group1_p)		= { "sclk_cpll", "sclk_dpll", "sclk_mpll" }; +PNAME(group2_p)		= { "fin_pll", "sclk_cpll", "sclk_dpll", "sclk_mpll", +			  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" }; +PNAME(group3_p)		= { "sclk_rpll", "sclk_spll" }; +PNAME(group4_p)		= { "sclk_ipll", "sclk_dpll", "sclk_mpll" }; +PNAME(group5_p)		= { "sclk_vpll", "sclk_dpll" }; + +PNAME(sw_aclk66_p)	= { "dout_aclk66", "sclk_spll" }; +PNAME(aclk66_peric_p)	= { "fin_pll", "mout_sw_aclk66" }; + +PNAME(sw_aclk200_fsys_p) = { "dout_aclk200_fsys", "sclk_spll"}; +PNAME(user_aclk200_fsys_p)	= { "fin_pll", "mout_sw_aclk200_fsys" }; + +PNAME(sw_aclk200_fsys2_p) = { "dout_aclk200_fsys2", "sclk_spll"}; +PNAME(user_aclk200_fsys2_p)	= { "fin_pll", "mout_sw_aclk200_fsys2" }; + +PNAME(sw_aclk200_p) = { "dout_aclk200", "sclk_spll"}; +PNAME(aclk200_disp1_p)	= { "fin_pll", "mout_sw_aclk200" }; + +PNAME(sw_aclk400_mscl_p) = { "dout_aclk400_mscl", "sclk_spll"}; +PNAME(user_aclk400_mscl_p)	= { "fin_pll", "mout_sw_aclk400_mscl" }; + +PNAME(sw_aclk333_p) = { "dout_aclk333", "sclk_spll"}; +PNAME(user_aclk333_p)	= { "fin_pll", "mout_sw_aclk333" }; + +PNAME(sw_aclk166_p) = { "dout_aclk166", "sclk_spll"}; +PNAME(user_aclk166_p)	= { "fin_pll", "mout_sw_aclk166" }; + +PNAME(sw_aclk266_p) = { "dout_aclk266", "sclk_spll"}; +PNAME(user_aclk266_p)	= { "fin_pll", "mout_sw_aclk266" }; + +PNAME(sw_aclk333_432_gscl_p) = { "dout_aclk333_432_gscl", "sclk_spll"}; +PNAME(user_aclk333_432_gscl_p)	= { "fin_pll", "mout_sw_aclk333_432_gscl" }; + +PNAME(sw_aclk300_gscl_p) = { "dout_aclk300_gscl", "sclk_spll"}; +PNAME(user_aclk300_gscl_p)	= { "fin_pll", "mout_sw_aclk300_gscl" }; + +PNAME(sw_aclk300_disp1_p) = { "dout_aclk300_disp1", "sclk_spll"}; +PNAME(user_aclk300_disp1_p)	= { "fin_pll", "mout_sw_aclk300_disp1" }; + +PNAME(sw_aclk300_jpeg_p) = { "dout_aclk300_jpeg", "sclk_spll"}; +PNAME(user_aclk300_jpeg_p)	= { "fin_pll", "mout_sw_aclk300_jpeg" }; + +PNAME(sw_aclk_g3d_p) = { "dout_aclk_g3d", "sclk_spll"}; +PNAME(user_aclk_g3d_p)	= { "fin_pll", "mout_sw_aclk_g3d" }; + +PNAME(sw_aclk266_g2d_p) = { "dout_aclk266_g2d", "sclk_spll"}; +PNAME(user_aclk266_g2d_p)	= { "fin_pll", "mout_sw_aclk266_g2d" }; + +PNAME(sw_aclk333_g2d_p) = { "dout_aclk333_g2d", "sclk_spll"}; +PNAME(user_aclk333_g2d_p)	= { "fin_pll", "mout_sw_aclk333_g2d" }; + +PNAME(audio0_p)	= { "fin_pll", "cdclk0", "sclk_dpll", "sclk_mpll", +		  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" }; +PNAME(audio1_p)	= { "fin_pll", "cdclk1", "sclk_dpll", "sclk_mpll", +		  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" }; +PNAME(audio2_p)	= { "fin_pll", "cdclk2", "sclk_dpll", "sclk_mpll", +		  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" }; +PNAME(spdif_p)	= { "fin_pll", "dout_audio0", "dout_audio1", "dout_audio2", +		  "spdif_extclk", "sclk_ipll", "sclk_epll", "sclk_rpll" }; +PNAME(hdmi_p)	= { "sclk_hdmiphy", "dout_hdmi_pixel" }; +PNAME(maudio0_p)	= { "fin_pll", "maudio_clk", "sclk_dpll", "sclk_mpll", +			  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" }; + +/* fixed rate clocks generated outside the soc */ +struct samsung_fixed_rate_clock exynos5420_fixed_rate_ext_clks[] __initdata = { +	FRATE(fin_pll, "fin_pll", NULL, CLK_IS_ROOT, 0), +}; + +/* fixed rate clocks generated inside the soc */ +struct samsung_fixed_rate_clock exynos5420_fixed_rate_clks[] __initdata = { +	FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000), +	FRATE(none, "sclk_pwi", NULL, CLK_IS_ROOT, 24000000), +	FRATE(none, "sclk_usbh20", NULL, CLK_IS_ROOT, 48000000), +	FRATE(none, "mphy_refclk_ixtal24", NULL, CLK_IS_ROOT, 48000000), +	FRATE(none, "sclk_usbh20_scan_clk", NULL, CLK_IS_ROOT, 480000000), +}; + +struct samsung_fixed_factor_clock exynos5420_fixed_factor_clks[] __initdata = { +	FFACTOR(none, "sclk_hsic_12m", "fin_pll", 1, 2, 0), +}; + +struct samsung_mux_clock exynos5420_mux_clks[] __initdata = { +	MUX(none, "mout_mspll_kfc", mspll_cpu_p, SRC_TOP7, 8, 2), +	MUX(none, "mout_mspll_cpu", mspll_cpu_p, SRC_TOP7, 12, 2), +	MUX(none, "mout_apll", apll_p, SRC_CPU, 0, 1), +	MUX(none, "mout_cpu", cpu_p, SRC_CPU, 16, 1), +	MUX(none, "mout_kpll", kpll_p, SRC_KFC, 0, 1), +	MUX(none, "mout_cpu_kfc", kfc_p, SRC_KFC, 16, 1), + +	MUX(none, "sclk_bpll", bpll_p, SRC_CDREX, 0, 1), + +	MUX_A(none, "mout_aclk400_mscl", group1_p, +			SRC_TOP0, 4, 2, "aclk400_mscl"), +	MUX(none, "mout_aclk200", group1_p, SRC_TOP0, 8, 2), +	MUX(none, "mout_aclk200_fsys2", group1_p, SRC_TOP0, 12, 2), +	MUX(none, "mout_aclk200_fsys", group1_p, SRC_TOP0, 28, 2), + +	MUX(none, "mout_aclk333_432_gscl", group4_p, SRC_TOP1, 0, 2), +	MUX(none, "mout_aclk66", group1_p, SRC_TOP1, 8, 2), +	MUX(none, "mout_aclk266", group1_p, SRC_TOP1, 20, 2), +	MUX(none, "mout_aclk166", group1_p, SRC_TOP1, 24, 2), +	MUX(none, "mout_aclk333", group1_p, SRC_TOP1, 28, 2), + +	MUX(none, "mout_aclk333_g2d", group1_p, SRC_TOP2, 8, 2), +	MUX(none, "mout_aclk266_g2d", group1_p, SRC_TOP2, 12, 2), +	MUX(none, "mout_aclk_g3d", group5_p, SRC_TOP2, 16, 1), +	MUX(none, "mout_aclk300_jpeg", group1_p, SRC_TOP2, 20, 2), +	MUX(none, "mout_aclk300_disp1", group1_p, SRC_TOP2, 24, 2), +	MUX(none, "mout_aclk300_gscl", group1_p, SRC_TOP2, 28, 2), + +	MUX(none, "mout_user_aclk400_mscl", user_aclk400_mscl_p, +			SRC_TOP3, 4, 1), +	MUX_A(none, "mout_aclk200_disp1", aclk200_disp1_p, +			SRC_TOP3, 8, 1, "aclk200_disp1"), +	MUX(none, "mout_user_aclk200_fsys2", user_aclk200_fsys2_p, +			SRC_TOP3, 12, 1), +	MUX(none, "mout_user_aclk200_fsys", user_aclk200_fsys_p, +			SRC_TOP3, 28, 1), + +	MUX(none, "mout_user_aclk333_432_gscl", user_aclk333_432_gscl_p, +			SRC_TOP4, 0, 1), +	MUX(none, "mout_aclk66_peric", aclk66_peric_p, SRC_TOP4, 8, 1), +	MUX(none, "mout_user_aclk266", user_aclk266_p, SRC_TOP4, 20, 1), +	MUX(none, "mout_user_aclk166", user_aclk166_p, SRC_TOP4, 24, 1), +	MUX(none, "mout_user_aclk333", user_aclk333_p, SRC_TOP4, 28, 1), + +	MUX(none, "mout_aclk66_psgen", aclk66_peric_p, SRC_TOP5, 4, 1), +	MUX(none, "mout_user_aclk333_g2d", user_aclk333_g2d_p, SRC_TOP5, 8, 1), +	MUX(none, "mout_user_aclk266_g2d", user_aclk266_g2d_p, SRC_TOP5, 12, 1), +	MUX_A(none, "mout_user_aclk_g3d", user_aclk_g3d_p, +			SRC_TOP5, 16, 1, "aclkg3d"), +	MUX(none, "mout_user_aclk300_jpeg", user_aclk300_jpeg_p, +			SRC_TOP5, 20, 1), +	MUX(none, "mout_user_aclk300_disp1", user_aclk300_disp1_p, +			SRC_TOP5, 24, 1), +	MUX(none, "mout_user_aclk300_gscl", user_aclk300_gscl_p, +			SRC_TOP5, 28, 1), + +	MUX(none, "sclk_mpll", mpll_p, SRC_TOP6, 0, 1), +	MUX(none, "sclk_vpll", vpll_p, SRC_TOP6, 4, 1), +	MUX(none, "sclk_spll", spll_p, SRC_TOP6, 8, 1), +	MUX(none, "sclk_ipll", ipll_p, SRC_TOP6, 12, 1), +	MUX(none, "sclk_rpll", rpll_p, SRC_TOP6, 16, 1), +	MUX(none, "sclk_epll", epll_p, SRC_TOP6, 20, 1), +	MUX(none, "sclk_dpll", dpll_p, SRC_TOP6, 24, 1), +	MUX(none, "sclk_cpll", cpll_p, SRC_TOP6, 28, 1), + +	MUX(none, "mout_sw_aclk400_mscl", sw_aclk400_mscl_p, SRC_TOP10, 4, 1), +	MUX(none, "mout_sw_aclk200", sw_aclk200_p, SRC_TOP10, 8, 1), +	MUX(none, "mout_sw_aclk200_fsys2", sw_aclk200_fsys2_p, +			SRC_TOP10, 12, 1), +	MUX(none, "mout_sw_aclk200_fsys", sw_aclk200_fsys_p, SRC_TOP10, 28, 1), + +	MUX(none, "mout_sw_aclk333_432_gscl", sw_aclk333_432_gscl_p, +			SRC_TOP11, 0, 1), +	MUX(none, "mout_sw_aclk66", sw_aclk66_p, SRC_TOP11, 8, 1), +	MUX(none, "mout_sw_aclk266", sw_aclk266_p, SRC_TOP11, 20, 1), +	MUX(none, "mout_sw_aclk166", sw_aclk166_p, SRC_TOP11, 24, 1), +	MUX(none, "mout_sw_aclk333", sw_aclk333_p, SRC_TOP11, 28, 1), + +	MUX(none, "mout_sw_aclk333_g2d", sw_aclk333_g2d_p, SRC_TOP12, 8, 1), +	MUX(none, "mout_sw_aclk266_g2d", sw_aclk266_g2d_p, SRC_TOP12, 12, 1), +	MUX(none, "mout_sw_aclk_g3d", sw_aclk_g3d_p, SRC_TOP12, 16, 1), +	MUX(none, "mout_sw_aclk300_jpeg", sw_aclk300_jpeg_p, SRC_TOP12, 20, 1), +	MUX(none, "mout_sw_aclk300_disp1", sw_aclk300_disp1_p, +			SRC_TOP12, 24, 1), +	MUX(none, "mout_sw_aclk300_gscl", sw_aclk300_gscl_p, SRC_TOP12, 28, 1), + +	/* DISP1 Block */ +	MUX(none, "mout_fimd1", group3_p, SRC_DISP10, 4, 1), +	MUX(none, "mout_mipi1", group2_p, SRC_DISP10, 16, 3), +	MUX(none, "mout_dp1", group2_p, SRC_DISP10, 20, 3), +	MUX(none, "mout_pixel", group2_p, SRC_DISP10, 24, 3), +	MUX(none, "mout_hdmi", hdmi_p, SRC_DISP10, 28, 1), + +	/* MAU Block */ +	MUX(none, "mout_maudio0", maudio0_p, SRC_MAU, 28, 3), + +	/* FSYS Block */ +	MUX(none, "mout_usbd301", group2_p, SRC_FSYS, 4, 3), +	MUX(none, "mout_mmc0", group2_p, SRC_FSYS, 8, 3), +	MUX(none, "mout_mmc1", group2_p, SRC_FSYS, 12, 3), +	MUX(none, "mout_mmc2", group2_p, SRC_FSYS, 16, 3), +	MUX(none, "mout_usbd300", group2_p, SRC_FSYS, 20, 3), +	MUX(none, "mout_unipro", group2_p, SRC_FSYS, 24, 3), + +	/* PERIC Block */ +	MUX(none, "mout_uart0", group2_p, SRC_PERIC0, 4, 3), +	MUX(none, "mout_uart1", group2_p, SRC_PERIC0, 8, 3), +	MUX(none, "mout_uart2", group2_p, SRC_PERIC0, 12, 3), +	MUX(none, "mout_uart3", group2_p, SRC_PERIC0, 16, 3), +	MUX(none, "mout_pwm", group2_p, SRC_PERIC0, 24, 3), +	MUX(none, "mout_spdif", spdif_p, SRC_PERIC0, 28, 3), +	MUX(none, "mout_audio0", audio0_p, SRC_PERIC1, 8, 3), +	MUX(none, "mout_audio1", audio1_p, SRC_PERIC1, 12, 3), +	MUX(none, "mout_audio2", audio2_p, SRC_PERIC1, 16, 3), +	MUX(none, "mout_spi0", group2_p, SRC_PERIC1, 20, 3), +	MUX(none, "mout_spi1", group2_p, SRC_PERIC1, 24, 3), +	MUX(none, "mout_spi2", group2_p, SRC_PERIC1, 28, 3), +}; + +struct samsung_div_clock exynos5420_div_clks[] __initdata = { +	DIV(none, "div_arm", "mout_cpu", DIV_CPU0, 0, 3), +	DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3), +	DIV(none, "armclk2", "div_arm", DIV_CPU0, 28, 3), +	DIV(none, "div_kfc", "mout_cpu_kfc", DIV_KFC0, 0, 3), +	DIV(none, "sclk_kpll", "mout_kpll", DIV_KFC0, 24, 3), + +	DIV(none, "dout_aclk400_mscl", "mout_aclk400_mscl", DIV_TOP0, 4, 3), +	DIV(none, "dout_aclk200", "mout_aclk200", DIV_TOP0, 8, 3), +	DIV(none, "dout_aclk200_fsys2", "mout_aclk200_fsys2", DIV_TOP0, 12, 3), +	DIV(none, "dout_pclk200_fsys", "mout_pclk200_fsys", DIV_TOP0, 24, 3), +	DIV(none, "dout_aclk200_fsys", "mout_aclk200_fsys", DIV_TOP0, 28, 3), + +	DIV(none, "dout_aclk333_432_gscl", "mout_aclk333_432_gscl", +			DIV_TOP1, 0, 3), +	DIV(none, "dout_aclk66", "mout_aclk66", DIV_TOP1, 8, 6), +	DIV(none, "dout_aclk266", "mout_aclk266", DIV_TOP1, 20, 3), +	DIV(none, "dout_aclk166", "mout_aclk166", DIV_TOP1, 24, 3), +	DIV(none, "dout_aclk333", "mout_aclk333", DIV_TOP1, 28, 3), + +	DIV(none, "dout_aclk333_g2d", "mout_aclk333_g2d", DIV_TOP2, 8, 3), +	DIV(none, "dout_aclk266_g2d", "mout_aclk266_g2d", DIV_TOP2, 12, 3), +	DIV(none, "dout_aclk_g3d", "mout_aclk_g3d", DIV_TOP2, 16, 3), +	DIV(none, "dout_aclk300_jpeg", "mout_aclk300_jpeg", DIV_TOP2, 20, 3), +	DIV_A(none, "dout_aclk300_disp1", "mout_aclk300_disp1", +			DIV_TOP2, 24, 3, "aclk300_disp1"), +	DIV(none, "dout_aclk300_gscl", "mout_aclk300_gscl", DIV_TOP2, 28, 3), + +	/* DISP1 Block */ +	DIV(none, "dout_fimd1", "mout_fimd1", DIV_DISP10, 0, 4), +	DIV(none, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8), +	DIV(none, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4), +	DIV(none, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4), + +	/* Audio Block */ +	DIV(none, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4), +	DIV(none, "dout_maupcm0", "dout_maudio0", DIV_MAU, 24, 8), + +	/* USB3.0 */ +	DIV(none, "dout_usbphy301", "mout_usbd301", DIV_FSYS0, 12, 4), +	DIV(none, "dout_usbphy300", "mout_usbd300", DIV_FSYS0, 16, 4), +	DIV(none, "dout_usbd301", "mout_usbd301", DIV_FSYS0, 20, 4), +	DIV(none, "dout_usbd300", "mout_usbd300", DIV_FSYS0, 24, 4), + +	/* MMC */ +	DIV(none, "dout_mmc0", "mout_mmc0", DIV_FSYS1, 0, 10), +	DIV(none, "dout_mmc1", "mout_mmc1", DIV_FSYS1, 10, 10), +	DIV(none, "dout_mmc2", "mout_mmc2", DIV_FSYS1, 20, 10), + +	DIV(none, "dout_unipro", "mout_unipro", DIV_FSYS2, 24, 8), + +	/* UART and PWM */ +	DIV(none, "dout_uart0", "mout_uart0", DIV_PERIC0, 8, 4), +	DIV(none, "dout_uart1", "mout_uart1", DIV_PERIC0, 12, 4), +	DIV(none, "dout_uart2", "mout_uart2", DIV_PERIC0, 16, 4), +	DIV(none, "dout_uart3", "mout_uart3", DIV_PERIC0, 20, 4), +	DIV(none, "dout_pwm", "mout_pwm", DIV_PERIC0, 28, 4), + +	/* SPI */ +	DIV(none, "dout_spi0", "mout_spi0", DIV_PERIC1, 20, 4), +	DIV(none, "dout_spi1", "mout_spi1", DIV_PERIC1, 24, 4), +	DIV(none, "dout_spi2", "mout_spi2", DIV_PERIC1, 28, 4), + +	/* PCM */ +	DIV(none, "dout_pcm1", "dout_audio1", DIV_PERIC2, 16, 8), +	DIV(none, "dout_pcm2", "dout_audio2", DIV_PERIC2, 24, 8), + +	/* Audio - I2S */ +	DIV(none, "dout_i2s1", "dout_audio1", DIV_PERIC3, 6, 6), +	DIV(none, "dout_i2s2", "dout_audio2", DIV_PERIC3, 12, 6), +	DIV(none, "dout_audio0", "mout_audio0", DIV_PERIC3, 20, 4), +	DIV(none, "dout_audio1", "mout_audio1", DIV_PERIC3, 24, 4), +	DIV(none, "dout_audio2", "mout_audio2", DIV_PERIC3, 28, 4), + +	/* SPI Pre-Ratio */ +	DIV(none, "dout_pre_spi0", "dout_spi0", DIV_PERIC4, 8, 8), +	DIV(none, "dout_pre_spi1", "dout_spi1", DIV_PERIC4, 16, 8), +	DIV(none, "dout_pre_spi2", "dout_spi2", DIV_PERIC4, 24, 8), +}; + +struct samsung_gate_clock exynos5420_gate_clks[] __initdata = { +	/* TODO: Re-verify the CG bits for all the gate clocks */ +	GATE_A(mct, "pclk_st", "aclk66_psgen", GATE_BUS_PERIS1, 2, 0, 0, "mct"), + +	GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys", +			GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2", +			GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0), + +	GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d", +			GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d", +			GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg", +			GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl", +			GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl", +			GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0), +	GATE(0, "pclk66_gpio", "mout_sw_aclk66", +			GATE_BUS_TOP, 9, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk66_psgen", "mout_aclk66_psgen", +			GATE_BUS_TOP, 10, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk66_peric", "mout_aclk66_peric", +			GATE_BUS_TOP, 11, 0, 0), +	GATE(0, "aclk166", "mout_user_aclk166", +			GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0), +	GATE(0, "aclk333", "mout_aclk333", +			GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0), + +	/* sclk */ +	GATE(sclk_uart0, "sclk_uart0", "dout_uart0", +		GATE_TOP_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_uart1, "sclk_uart1", "dout_uart1", +		GATE_TOP_SCLK_PERIC, 1, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_uart2, "sclk_uart2", "dout_uart2", +		GATE_TOP_SCLK_PERIC, 2, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_uart3, "sclk_uart3", "dout_uart3", +		GATE_TOP_SCLK_PERIC, 3, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_spi0, "sclk_spi0", "dout_pre_spi0", +		GATE_TOP_SCLK_PERIC, 6, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_spi1, "sclk_spi1", "dout_pre_spi1", +		GATE_TOP_SCLK_PERIC, 7, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_spi2, "sclk_spi2", "dout_pre_spi2", +		GATE_TOP_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_spdif, "sclk_spdif", "mout_spdif", +		GATE_TOP_SCLK_PERIC, 9, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_pwm, "sclk_pwm", "dout_pwm", +		GATE_TOP_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_pcm1, "sclk_pcm1", "dout_pcm1", +		GATE_TOP_SCLK_PERIC, 15, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_pcm2, "sclk_pcm2", "dout_pcm2", +		GATE_TOP_SCLK_PERIC, 16, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_i2s1, "sclk_i2s1", "dout_i2s1", +		GATE_TOP_SCLK_PERIC, 17, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_i2s2, "sclk_i2s2", "dout_i2s2", +		GATE_TOP_SCLK_PERIC, 18, CLK_SET_RATE_PARENT, 0), + +	GATE(sclk_mmc0, "sclk_mmc0", "dout_mmc0", +		GATE_TOP_SCLK_FSYS, 0, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_mmc1, "sclk_mmc1", "dout_mmc1", +		GATE_TOP_SCLK_FSYS, 1, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_mmc2, "sclk_mmc2", "dout_mmc2", +		GATE_TOP_SCLK_FSYS, 2, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_usbphy301, "sclk_usbphy301", "dout_usbphy301", +		GATE_TOP_SCLK_FSYS, 7, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_usbphy300, "sclk_usbphy300", "dout_usbphy300", +		GATE_TOP_SCLK_FSYS, 8, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_usbd300, "sclk_usbd300", "dout_usbd300", +		GATE_TOP_SCLK_FSYS, 9, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_usbd301, "sclk_usbd301", "dout_usbd301", +		GATE_TOP_SCLK_FSYS, 10, CLK_SET_RATE_PARENT, 0), + +	GATE(sclk_usbd301, "sclk_unipro", "dout_unipro", +		SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0), + +	GATE(sclk_gscl_wa, "sclk_gscl_wa", "aclK333_432_gscl", +		GATE_TOP_SCLK_GSCL, 6, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_gscl_wb, "sclk_gscl_wb", "aclk333_432_gscl", +		GATE_TOP_SCLK_GSCL, 7, CLK_SET_RATE_PARENT, 0), + +	/* Display */ +	GATE(sclk_fimd1, "sclk_fimd1", "dout_fimd1", +		GATE_TOP_SCLK_DISP1, 0, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_mipi1, "sclk_mipi1", "dout_mipi1", +		GATE_TOP_SCLK_DISP1, 3, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_hdmi, "sclk_hdmi", "mout_hdmi", +		GATE_TOP_SCLK_DISP1, 9, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_pixel, "sclk_pixel", "dout_hdmi_pixel", +		GATE_TOP_SCLK_DISP1, 10, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_dp1, "sclk_dp1", "dout_dp1", +		GATE_TOP_SCLK_DISP1, 20, CLK_SET_RATE_PARENT, 0), + +	/* Maudio Block */ +	GATE(sclk_maudio0, "sclk_maudio0", "dout_maudio0", +		GATE_TOP_SCLK_MAU, 0, CLK_SET_RATE_PARENT, 0), +	GATE(sclk_maupcm0, "sclk_maupcm0", "dout_maupcm0", +		GATE_TOP_SCLK_MAU, 1, CLK_SET_RATE_PARENT, 0), +	/* FSYS */ +	GATE(tsi, "tsi", "aclk200_fsys", GATE_BUS_FSYS0, 0, 0, 0), +	GATE(pdma0, "pdma0", "aclk200_fsys", GATE_BUS_FSYS0, 1, 0, 0), +	GATE(pdma1, "pdma1", "aclk200_fsys", GATE_BUS_FSYS0, 2, 0, 0), +	GATE(ufs, "ufs", "aclk200_fsys2", GATE_BUS_FSYS0, 3, 0, 0), +	GATE(rtic, "rtic", "aclk200_fsys", GATE_BUS_FSYS0, 5, 0, 0), +	GATE(mmc0, "mmc0", "aclk200_fsys2", GATE_BUS_FSYS0, 12, 0, 0), +	GATE(mmc1, "mmc1", "aclk200_fsys2", GATE_BUS_FSYS0, 13, 0, 0), +	GATE(mmc2, "mmc2", "aclk200_fsys2", GATE_BUS_FSYS0, 14, 0, 0), +	GATE(sromc, "sromc", "aclk200_fsys2", +			GATE_BUS_FSYS0, 19, CLK_IGNORE_UNUSED, 0), +	GATE(usbh20, "usbh20", "aclk200_fsys", GATE_BUS_FSYS0, 20, 0, 0), +	GATE(usbd300, "usbd300", "aclk200_fsys", GATE_BUS_FSYS0, 21, 0, 0), +	GATE(usbd301, "usbd301", "aclk200_fsys", GATE_BUS_FSYS0, 28, 0, 0), + +	/* UART */ +	GATE(uart0, "uart0", "aclk66_peric", GATE_BUS_PERIC, 4, 0, 0), +	GATE(uart1, "uart1", "aclk66_peric", GATE_BUS_PERIC, 5, 0, 0), +	GATE_A(uart2, "uart2", "aclk66_peric", +		GATE_BUS_PERIC, 6, CLK_IGNORE_UNUSED, 0, "uart2"), +	GATE(uart3, "uart3", "aclk66_peric", GATE_BUS_PERIC, 7, 0, 0), +	/* I2C */ +	GATE(i2c0, "i2c0", "aclk66_peric", GATE_BUS_PERIC, 9, 0, 0), +	GATE(i2c1, "i2c1", "aclk66_peric", GATE_BUS_PERIC, 10, 0, 0), +	GATE(i2c2, "i2c2", "aclk66_peric", GATE_BUS_PERIC, 11, 0, 0), +	GATE(i2c3, "i2c3", "aclk66_peric", GATE_BUS_PERIC, 12, 0, 0), +	GATE(i2c4, "i2c4", "aclk66_peric", GATE_BUS_PERIC, 13, 0, 0), +	GATE(i2c5, "i2c5", "aclk66_peric", GATE_BUS_PERIC, 14, 0, 0), +	GATE(i2c6, "i2c6", "aclk66_peric", GATE_BUS_PERIC, 15, 0, 0), +	GATE(i2c7, "i2c7", "aclk66_peric", GATE_BUS_PERIC, 16, 0, 0), +	GATE(i2c_hdmi, "i2c_hdmi", "aclk66_peric", GATE_BUS_PERIC, 17, 0, 0), +	GATE(tsadc, "tsadc", "aclk66_peric", GATE_BUS_PERIC, 18, 0, 0), +	/* SPI */ +	GATE(spi0, "spi0", "aclk66_peric", GATE_BUS_PERIC, 19, 0, 0), +	GATE(spi1, "spi1", "aclk66_peric", GATE_BUS_PERIC, 20, 0, 0), +	GATE(spi2, "spi2", "aclk66_peric", GATE_BUS_PERIC, 21, 0, 0), +	GATE(keyif, "keyif", "aclk66_peric", GATE_BUS_PERIC, 22, 0, 0), +	/* I2S */ +	GATE(i2s1, "i2s1", "aclk66_peric", GATE_BUS_PERIC, 23, 0, 0), +	GATE(i2s2, "i2s2", "aclk66_peric", GATE_BUS_PERIC, 24, 0, 0), +	/* PCM */ +	GATE(pcm1, "pcm1", "aclk66_peric", GATE_BUS_PERIC, 25, 0, 0), +	GATE(pcm2, "pcm2", "aclk66_peric", GATE_BUS_PERIC, 26, 0, 0), +	/* PWM */ +	GATE(pwm, "pwm", "aclk66_peric", GATE_BUS_PERIC, 27, 0, 0), +	/* SPDIF */ +	GATE(spdif, "spdif", "aclk66_peric", GATE_BUS_PERIC, 29, 0, 0), + +	GATE(i2c8, "i2c8", "aclk66_peric", GATE_BUS_PERIC1, 0, 0, 0), +	GATE(i2c9, "i2c9", "aclk66_peric", GATE_BUS_PERIC1, 1, 0, 0), +	GATE(i2c10, "i2c10", "aclk66_peric", GATE_BUS_PERIC1, 2, 0, 0), + +	GATE(chipid, "chipid", "aclk66_psgen", +			GATE_BUS_PERIS0, 12, CLK_IGNORE_UNUSED, 0), +	GATE(sysreg, "sysreg", "aclk66_psgen", +			GATE_BUS_PERIS0, 13, CLK_IGNORE_UNUSED, 0), +	GATE(tzpc0, "tzpc0", "aclk66_psgen", GATE_BUS_PERIS0, 18, 0, 0), +	GATE(tzpc1, "tzpc1", "aclk66_psgen", GATE_BUS_PERIS0, 19, 0, 0), +	GATE(tzpc2, "tzpc2", "aclk66_psgen", GATE_BUS_PERIS0, 20, 0, 0), +	GATE(tzpc3, "tzpc3", "aclk66_psgen", GATE_BUS_PERIS0, 21, 0, 0), +	GATE(tzpc4, "tzpc4", "aclk66_psgen", GATE_BUS_PERIS0, 22, 0, 0), +	GATE(tzpc5, "tzpc5", "aclk66_psgen", GATE_BUS_PERIS0, 23, 0, 0), +	GATE(tzpc6, "tzpc6", "aclk66_psgen", GATE_BUS_PERIS0, 24, 0, 0), +	GATE(tzpc7, "tzpc7", "aclk66_psgen", GATE_BUS_PERIS0, 25, 0, 0), +	GATE(tzpc8, "tzpc8", "aclk66_psgen", GATE_BUS_PERIS0, 26, 0, 0), +	GATE(tzpc9, "tzpc9", "aclk66_psgen", GATE_BUS_PERIS0, 27, 0, 0), + +	GATE(hdmi_cec, "hdmi_cec", "aclk66_psgen", GATE_BUS_PERIS1, 0, 0, 0), +	GATE(seckey, "seckey", "aclk66_psgen", GATE_BUS_PERIS1, 1, 0, 0), +	GATE(wdt, "wdt", "aclk66_psgen", GATE_BUS_PERIS1, 3, 0, 0), +	GATE(rtc, "rtc", "aclk66_psgen", GATE_BUS_PERIS1, 4, 0, 0), +	GATE(tmu, "tmu", "aclk66_psgen", GATE_BUS_PERIS1, 5, 0, 0), +	GATE(tmu_gpu, "tmu_gpu", "aclk66_psgen", GATE_BUS_PERIS1, 6, 0, 0), + +	GATE(gscl0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), +	GATE(gscl1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), +	GATE(clk_3aa, "clk_3aa", "aclk300_gscl", GATE_IP_GSCL0, 4, 0, 0), + +	GATE(smmu_3aa, "smmu_3aa", "aclk333_432_gscl", GATE_IP_GSCL1, 2, 0, 0), +	GATE(smmu_fimcl0, "smmu_fimcl0", "aclk333_432_gscl", +			GATE_IP_GSCL1, 3, 0, 0), +	GATE(smmu_fimcl1, "smmu_fimcl1", "aclk333_432_gscl", +			GATE_IP_GSCL1, 4, 0, 0), +	GATE(smmu_gscl0, "smmu_gscl0", "aclk300_gscl", GATE_IP_GSCL1, 6, 0, 0), +	GATE(smmu_gscl1, "smmu_gscl1", "aclk300_gscl", GATE_IP_GSCL1, 7, 0, 0), +	GATE(gscl_wa, "gscl_wa", "aclk300_gscl", GATE_IP_GSCL1, 12, 0, 0), +	GATE(gscl_wb, "gscl_wb", "aclk300_gscl", GATE_IP_GSCL1, 13, 0, 0), +	GATE(smmu_fimcl3, "smmu_fimcl3,", "aclk333_432_gscl", +			GATE_IP_GSCL1, 16, 0, 0), +	GATE(fimc_lite3, "fimc_lite3", "aclk333_432_gscl", +			GATE_IP_GSCL1, 17, 0, 0), + +	GATE(fimd1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), +	GATE(dsim1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), +	GATE(dp1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), +	GATE(mixer, "mixer", "aclk166", GATE_IP_DISP1, 5, 0, 0), +	GATE(hdmi, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), +	GATE(smmu_fimd1, "smmu_fimd1", "aclk300_disp1", GATE_IP_DISP1, 8, 0, 0), + +	GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), +	GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0), +	GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0), + +	GATE(g3d, "g3d", "aclkg3d", GATE_IP_G3D, 9, 0, 0), + +	GATE(rotator, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0), +	GATE(jpeg, "jpeg", "aclk300_jpeg", GATE_IP_GEN, 2, 0, 0), +	GATE(jpeg2, "jpeg2", "aclk300_jpeg", GATE_IP_GEN, 3, 0, 0), +	GATE(mdma1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0), +	GATE(smmu_rotator, "smmu_rotator", "aclk266", GATE_IP_GEN, 6, 0, 0), +	GATE(smmu_jpeg, "smmu_jpeg", "aclk300_jpeg", GATE_IP_GEN, 7, 0, 0), +	GATE(smmu_mdma1, "smmu_mdma1", "aclk266", GATE_IP_GEN, 9, 0, 0), + +	GATE(mscl0, "mscl0", "aclk400_mscl", GATE_IP_MSCL, 0, 0, 0), +	GATE(mscl1, "mscl1", "aclk400_mscl", GATE_IP_MSCL, 1, 0, 0), +	GATE(mscl2, "mscl2", "aclk400_mscl", GATE_IP_MSCL, 2, 0, 0), +	GATE(smmu_mscl0, "smmu_mscl0", "aclk400_mscl", GATE_IP_MSCL, 8, 0, 0), +	GATE(smmu_mscl1, "smmu_mscl1", "aclk400_mscl", GATE_IP_MSCL, 9, 0, 0), +	GATE(smmu_mscl2, "smmu_mscl2", "aclk400_mscl", GATE_IP_MSCL, 10, 0, 0), +}; + +static __initdata struct of_device_id ext_clk_match[] = { +	{ .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, }, +	{ }, +}; + +/* register exynos5420 clocks */ +void __init exynos5420_clk_init(struct device_node *np) +{ +	void __iomem *reg_base; +	struct clk *apll, *bpll, *cpll, *dpll, *epll, *ipll, *kpll, *mpll; +	struct clk *rpll, *spll, *vpll; + +	if (np) { +		reg_base = of_iomap(np, 0); +		if (!reg_base) +			panic("%s: failed to map registers\n", __func__); +	} else { +		panic("%s: unable to determine soc\n", __func__); +	} + +	samsung_clk_init(np, reg_base, nr_clks, +			exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs), +			NULL, 0); +	samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks, +			ARRAY_SIZE(exynos5420_fixed_rate_ext_clks), +			ext_clk_match); + +	apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll", +			reg_base + 0x100); +	bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll", +			reg_base + 0x20110); +	cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll", +			reg_base + 0x10120); +	dpll = samsung_clk_register_pll35xx("fout_dpll", "fin_pll", +			reg_base + 0x10128); +	epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll", +			reg_base + 0x10130); +	ipll = samsung_clk_register_pll35xx("fout_ipll", "fin_pll", +			reg_base + 0x10150); +	kpll = samsung_clk_register_pll35xx("fout_kpll", "fin_pll", +			reg_base + 0x28100); +	mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll", +			reg_base + 0x10180); +	rpll = samsung_clk_register_pll36xx("fout_rpll", "fin_pll", +			reg_base + 0x10140); +	spll = samsung_clk_register_pll35xx("fout_spll", "fin_pll", +			reg_base + 0x10160); +	vpll = samsung_clk_register_pll35xx("fout_vpll", "fin_pll", +			reg_base + 0x10170); + +	samsung_clk_register_fixed_rate(exynos5420_fixed_rate_clks, +			ARRAY_SIZE(exynos5420_fixed_rate_clks)); +	samsung_clk_register_fixed_factor(exynos5420_fixed_factor_clks, +			ARRAY_SIZE(exynos5420_fixed_factor_clks)); +	samsung_clk_register_mux(exynos5420_mux_clks, +			ARRAY_SIZE(exynos5420_mux_clks)); +	samsung_clk_register_div(exynos5420_div_clks, +			ARRAY_SIZE(exynos5420_div_clks)); +	samsung_clk_register_gate(exynos5420_gate_clks, +			ARRAY_SIZE(exynos5420_gate_clks)); +} +CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index e4ad6ea9aa76..2f7dba20ced8 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -144,6 +144,9 @@ struct samsung_mux_clock {  #define MUX_F(_id, cname, pnames, o, s, w, f, mf)		\  	__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL) +#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a)		\ +	__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a) +  /**   * @id: platform specific id of the clock.   * struct samsung_div_clock: information about div clock diff --git a/drivers/clk/socfpga/clk.c b/drivers/clk/socfpga/clk.c index bd11315cf5ab..5bb848cac6ec 100644 --- a/drivers/clk/socfpga/clk.c +++ b/drivers/clk/socfpga/clk.c @@ -24,15 +24,17 @@  #include <linux/of.h>  /* Clock Manager offsets */ -#define CLKMGR_CTRL    0x0 -#define CLKMGR_BYPASS 0x4 +#define CLKMGR_CTRL	0x0 +#define CLKMGR_BYPASS	0x4 +#define CLKMGR_L4SRC	0x70 +#define CLKMGR_PERPLL_SRC	0xAC  /* Clock bypass bits */ -#define MAINPLL_BYPASS (1<<0) -#define SDRAMPLL_BYPASS (1<<1) -#define SDRAMPLL_SRC_BYPASS (1<<2) -#define PERPLL_BYPASS (1<<3) -#define PERPLL_SRC_BYPASS (1<<4) +#define MAINPLL_BYPASS		(1<<0) +#define SDRAMPLL_BYPASS		(1<<1) +#define SDRAMPLL_SRC_BYPASS	(1<<2) +#define PERPLL_BYPASS		(1<<3) +#define PERPLL_SRC_BYPASS	(1<<4)  #define SOCFPGA_PLL_BG_PWRDWN		0  #define SOCFPGA_PLL_EXT_ENA		1 @@ -41,6 +43,17 @@  #define SOCFPGA_PLL_DIVF_SHIFT	3  #define SOCFPGA_PLL_DIVQ_MASK		0x003F0000  #define SOCFPGA_PLL_DIVQ_SHIFT	16 +#define SOCFGPA_MAX_PARENTS	3 + +#define SOCFPGA_L4_MP_CLK		"l4_mp_clk" +#define SOCFPGA_L4_SP_CLK		"l4_sp_clk" +#define SOCFPGA_NAND_CLK		"nand_clk" +#define SOCFPGA_NAND_X_CLK		"nand_x_clk" +#define SOCFPGA_MMC_CLK			"mmc_clk" +#define SOCFPGA_DB_CLK			"gpio_db_clk" + +#define div_mask(width)	((1 << (width)) - 1) +#define streq(a, b) (strcmp((a), (b)) == 0)  extern void __iomem *clk_mgr_base_addr; @@ -49,6 +62,9 @@ struct socfpga_clk {  	char *parent_name;  	char *clk_name;  	u32 fixed_div; +	void __iomem *div_reg; +	u32 width;	/* only valid if div_reg != 0 */ +	u32 shift;	/* only valid if div_reg != 0 */  };  #define to_socfpga_clk(p) container_of(p, struct socfpga_clk, hw.hw) @@ -132,8 +148,9 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,  	socfpga_clk->hw.hw.init = &init; -	if (strcmp(clk_name, "main_pll") || strcmp(clk_name, "periph_pll") || -			strcmp(clk_name, "sdram_pll")) { +	if (streq(clk_name, "main_pll") || +		streq(clk_name, "periph_pll") || +		streq(clk_name, "sdram_pll")) {  		socfpga_clk->hw.bit_idx = SOCFPGA_PLL_EXT_ENA;  		clk_pll_ops.enable = clk_gate_ops.enable;  		clk_pll_ops.disable = clk_gate_ops.disable; @@ -148,6 +165,159 @@ static __init struct clk *socfpga_clk_init(struct device_node *node,  	return clk;  } +static u8 socfpga_clk_get_parent(struct clk_hw *hwclk) +{ +	u32 l4_src; +	u32 perpll_src; + +	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) { +		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC); +		return l4_src &= 0x1; +	} +	if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) { +		l4_src = readl(clk_mgr_base_addr + CLKMGR_L4SRC); +		return !!(l4_src & 2); +	} + +	perpll_src = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC); +	if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) +		return perpll_src &= 0x3; +	if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) || +			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) +			return (perpll_src >> 2) & 3; + +	/* QSPI clock */ +	return (perpll_src >> 4) & 3; + +} + +static int socfpga_clk_set_parent(struct clk_hw *hwclk, u8 parent) +{ +	u32 src_reg; + +	if (streq(hwclk->init->name, SOCFPGA_L4_MP_CLK)) { +		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC); +		src_reg &= ~0x1; +		src_reg |= parent; +		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC); +	} else if (streq(hwclk->init->name, SOCFPGA_L4_SP_CLK)) { +		src_reg = readl(clk_mgr_base_addr + CLKMGR_L4SRC); +		src_reg &= ~0x2; +		src_reg |= (parent << 1); +		writel(src_reg, clk_mgr_base_addr + CLKMGR_L4SRC); +	} else { +		src_reg = readl(clk_mgr_base_addr + CLKMGR_PERPLL_SRC); +		if (streq(hwclk->init->name, SOCFPGA_MMC_CLK)) { +			src_reg &= ~0x3; +			src_reg |= parent; +		} else if (streq(hwclk->init->name, SOCFPGA_NAND_CLK) || +			streq(hwclk->init->name, SOCFPGA_NAND_X_CLK)) { +			src_reg &= ~0xC; +			src_reg |= (parent << 2); +		} else {/* QSPI clock */ +			src_reg &= ~0x30; +			src_reg |= (parent << 4); +		} +		writel(src_reg, clk_mgr_base_addr + CLKMGR_PERPLL_SRC); +	} + +	return 0; +} + +static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk, +	unsigned long parent_rate) +{ +	struct socfpga_clk *socfpgaclk = to_socfpga_clk(hwclk); +	u32 div = 1, val; + +	if (socfpgaclk->fixed_div) +		div = socfpgaclk->fixed_div; +	else if (socfpgaclk->div_reg) { +		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; +		val &= div_mask(socfpgaclk->width); +		if (streq(hwclk->init->name, SOCFPGA_DB_CLK)) +			div = val + 1; +		else +			div = (1 << val); +	} + +	return parent_rate / div; +} + +static struct clk_ops gateclk_ops = { +	.recalc_rate = socfpga_clk_recalc_rate, +	.get_parent = socfpga_clk_get_parent, +	.set_parent = socfpga_clk_set_parent, +}; + +static void __init socfpga_gate_clk_init(struct device_node *node, +	const struct clk_ops *ops) +{ +	u32 clk_gate[2]; +	u32 div_reg[3]; +	u32 fixed_div; +	struct clk *clk; +	struct socfpga_clk *socfpga_clk; +	const char *clk_name = node->name; +	const char *parent_name[SOCFGPA_MAX_PARENTS]; +	struct clk_init_data init; +	int rc; +	int i = 0; + +	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL); +	if (WARN_ON(!socfpga_clk)) +		return; + +	rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2); +	if (rc) +		clk_gate[0] = 0; + +	if (clk_gate[0]) { +		socfpga_clk->hw.reg = clk_mgr_base_addr + clk_gate[0]; +		socfpga_clk->hw.bit_idx = clk_gate[1]; + +		gateclk_ops.enable = clk_gate_ops.enable; +		gateclk_ops.disable = clk_gate_ops.disable; +	} + +	rc = of_property_read_u32(node, "fixed-divider", &fixed_div); +	if (rc) +		socfpga_clk->fixed_div = 0; +	else +		socfpga_clk->fixed_div = fixed_div; + +	rc = of_property_read_u32_array(node, "div-reg", div_reg, 3); +	if (!rc) { +		socfpga_clk->div_reg = clk_mgr_base_addr + div_reg[0]; +		socfpga_clk->shift = div_reg[1]; +		socfpga_clk->width = div_reg[2]; +	} else { +		socfpga_clk->div_reg = 0; +	} + +	of_property_read_string(node, "clock-output-names", &clk_name); + +	init.name = clk_name; +	init.ops = ops; +	init.flags = 0; +	while (i < SOCFGPA_MAX_PARENTS && (parent_name[i] = +			of_clk_get_parent_name(node, i)) != NULL) +		i++; + +	init.parent_names = parent_name; +	init.num_parents = i; +	socfpga_clk->hw.hw.init = &init; + +	clk = clk_register(NULL, &socfpga_clk->hw.hw); +	if (WARN_ON(IS_ERR(clk))) { +		kfree(socfpga_clk); +		return; +	} +	rc = of_clk_add_provider(node, of_clk_src_simple_get, clk); +	if (WARN_ON(rc)) +		return; +} +  static void __init socfpga_pll_init(struct device_node *node)  {  	socfpga_clk_init(node, &clk_pll_ops); @@ -160,6 +330,12 @@ static void __init socfpga_periph_init(struct device_node *node)  }  CLK_OF_DECLARE(socfpga_periph, "altr,socfpga-perip-clk", socfpga_periph_init); +static void __init socfpga_gate_init(struct device_node *node) +{ +	socfpga_gate_clk_init(node, &gateclk_ops); +} +CLK_OF_DECLARE(socfpga_gate, "altr,socfpga-gate-clk", socfpga_gate_init); +  void __init socfpga_init_clocks(void)  {  	struct clk *clk; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 8492ad1d5360..412912bbba53 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -239,7 +239,7 @@ struct mux_data {  	u8 shift;  }; -static const __initconst struct mux_data cpu_data = { +static const __initconst struct mux_data cpu_mux_data = {  	.shift = 16,  }; @@ -333,22 +333,34 @@ struct gates_data {  	DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);  }; -static const __initconst struct gates_data axi_gates_data = { +static const __initconst struct gates_data sun4i_axi_gates_data = {  	.mask = {1},  }; -static const __initconst struct gates_data ahb_gates_data = { +static const __initconst struct gates_data sun4i_ahb_gates_data = {  	.mask = {0x7F77FFF, 0x14FB3F},  }; -static const __initconst struct gates_data apb0_gates_data = { +static const __initconst struct gates_data sun5i_a13_ahb_gates_data = { +	.mask = {0x107067e7, 0x185111}, +}; + +static const __initconst struct gates_data sun4i_apb0_gates_data = {  	.mask = {0x4EF},  }; -static const __initconst struct gates_data apb1_gates_data = { +static const __initconst struct gates_data sun5i_a13_apb0_gates_data = { +	.mask = {0x61}, +}; + +static const __initconst struct gates_data sun4i_apb1_gates_data = {  	.mask = {0xFF00F7},  }; +static const __initconst struct gates_data sun5i_a13_apb1_gates_data = { +	.mask = {0xa0007}, +}; +  static void __init sunxi_gates_clk_setup(struct device_node *node,  					 struct gates_data *data)  { @@ -421,17 +433,20 @@ static const __initconst struct of_device_id clk_div_match[] = {  /* Matches for mux clocks */  static const __initconst struct of_device_id clk_mux_match[] = { -	{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,}, +	{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,},  	{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},  	{}  };  /* Matches for gate clocks */  static const __initconst struct of_device_id clk_gates_match[] = { -	{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,}, -	{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,}, -	{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,}, -	{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,}, +	{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,}, +	{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, +	{.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, +	{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, +	{.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, +	{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, +	{.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},  	{}  }; diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 17c2cc086eb4..197074a57754 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -117,10 +117,6 @@  #define PLLCX_MISC2_DEFAULT 0x30211200  #define PLLCX_MISC3_DEFAULT 0x200 -#define PMC_PLLM_WB0_OVERRIDE	0x1dc -#define PMC_PLLM_WB0_OVERRIDE_2	0x2b0 -#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27) -  #define PMC_SATA_PWRGT 0x1ac  #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)  #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) @@ -128,38 +124,31 @@  #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)  #define pll_readl_base(p) pll_readl(p->params->base_reg, p)  #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) +#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)  #define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)  #define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)  #define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p) +#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)  #define mask(w) ((1 << (w)) - 1) -#define divm_mask(p) mask(p->divm_width) -#define divn_mask(p) mask(p->divn_width) +#define divm_mask(p) mask(p->params->div_nmp->divm_width) +#define divn_mask(p) mask(p->params->div_nmp->divn_width)  #define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :	\ -		      mask(p->divp_width)) +		      mask(p->params->div_nmp->divp_width))  #define divm_max(p) (divm_mask(p))  #define divn_max(p) (divn_mask(p))  #define divp_max(p) (1 << (divp_mask(p))) - -#ifdef CONFIG_ARCH_TEGRA_114_SOC -/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */ -#define PLLXC_PDIV_MAX			14 - -/* non-monotonic mapping below is not a typo */ -static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = { -	/* PDIV: 0, 1, 2, 3, 4, 5, 6,  7,  8,  9, 10, 11, 12, 13, 14 */ -	/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32 -}; - -#define PLLCX_PDIV_MAX 7 -static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = { -	/* PDIV: 0, 1, 2, 3, 4, 5,  6,  7 */ -	/* p: */ 1, 2, 3, 4, 6, 8, 12, 16 +static struct div_nmp default_nmp = { +	.divn_shift = PLL_BASE_DIVN_SHIFT, +	.divn_width = PLL_BASE_DIVN_WIDTH, +	.divm_shift = PLL_BASE_DIVM_SHIFT, +	.divm_width = PLL_BASE_DIVM_WIDTH, +	.divp_shift = PLL_BASE_DIVP_SHIFT, +	.divp_width = PLL_BASE_DIVP_WIDTH,  }; -#endif  static void clk_pll_enable_lock(struct tegra_clk_pll *pll)  { @@ -297,6 +286,39 @@ static void clk_pll_disable(struct clk_hw *hw)  		spin_unlock_irqrestore(pll->lock, flags);  } +static int _p_div_to_hw(struct clk_hw *hw, u8 p_div) +{ +	struct tegra_clk_pll *pll = to_clk_pll(hw); +	struct pdiv_map *p_tohw = pll->params->pdiv_tohw; + +	if (p_tohw) { +		while (p_tohw->pdiv) { +			if (p_div <= p_tohw->pdiv) +				return p_tohw->hw_val; +			p_tohw++; +		} +		return -EINVAL; +	} +	return -EINVAL; +} + +static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw) +{ +	struct tegra_clk_pll *pll = to_clk_pll(hw); +	struct pdiv_map *p_tohw = pll->params->pdiv_tohw; + +	if (p_tohw) { +		while (p_tohw->pdiv) { +			if (p_div_hw == p_tohw->hw_val) +				return p_tohw->pdiv; +			p_tohw++; +		} +		return -EINVAL; +	} + +	return 1 << p_div_hw; +} +  static int _get_table_rate(struct clk_hw *hw,  			   struct tegra_clk_pll_freq_table *cfg,  			   unsigned long rate, unsigned long parent_rate) @@ -326,9 +348,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,  		      unsigned long rate, unsigned long parent_rate)  {  	struct tegra_clk_pll *pll = to_clk_pll(hw); -	struct pdiv_map *p_tohw = pll->params->pdiv_tohw;  	unsigned long cfreq;  	u32 p_div = 0; +	int ret;  	switch (parent_rate) {  	case 12000000: @@ -369,20 +391,16 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,  	    || cfg->output_rate > pll->params->vco_max) {  		pr_err("%s: Failed to set %s rate %lu\n",  		       __func__, __clk_get_name(hw->clk), rate); +		WARN_ON(1);  		return -EINVAL;  	} -	if (p_tohw) { -		p_div = 1 << p_div; -		while (p_tohw->pdiv) { -			if (p_div <= p_tohw->pdiv) { -				cfg->p = p_tohw->hw_val; -				break; -			} -			p_tohw++; -		} -		if (!p_tohw->pdiv) -			return -EINVAL; +	if (pll->params->pdiv_tohw) { +		ret = _p_div_to_hw(hw, 1 << p_div); +		if (ret < 0) +			return ret; +		else +			cfg->p = ret;  	} else  		cfg->p = p_div; @@ -393,29 +411,61 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,  			    struct tegra_clk_pll_freq_table *cfg)  {  	u32 val; +	struct tegra_clk_pll_params *params = pll->params; +	struct div_nmp *div_nmp = params->div_nmp; + +	if ((pll->flags & TEGRA_PLLM) && +		(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) & +			PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) { +		val = pll_override_readl(params->pmc_divp_reg, pll); +		val &= ~(divp_mask(pll) << div_nmp->override_divp_shift); +		val |= cfg->p << div_nmp->override_divp_shift; +		pll_override_writel(val, params->pmc_divp_reg, pll); + +		val = pll_override_readl(params->pmc_divnm_reg, pll); +		val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) | +			~(divn_mask(pll) << div_nmp->override_divn_shift); +		val |= (cfg->m << div_nmp->override_divm_shift) | +			(cfg->n << div_nmp->override_divn_shift); +		pll_override_writel(val, params->pmc_divnm_reg, pll); +	} else { +		val = pll_readl_base(pll); -	val = pll_readl_base(pll); +		val &= ~((divm_mask(pll) << div_nmp->divm_shift) | +		 (divn_mask(pll) << div_nmp->divn_shift) | +		 (divp_mask(pll) << div_nmp->divp_shift)); -	val &= ~((divm_mask(pll) << pll->divm_shift) | -		 (divn_mask(pll) << pll->divn_shift) | -		 (divp_mask(pll) << pll->divp_shift)); -	val |= ((cfg->m << pll->divm_shift) | -		(cfg->n << pll->divn_shift) | -		(cfg->p << pll->divp_shift)); +		val |= ((cfg->m << div_nmp->divm_shift) | +			(cfg->n << div_nmp->divn_shift) | +			(cfg->p << div_nmp->divp_shift)); -	pll_writel_base(val, pll); +		pll_writel_base(val, pll); +	}  }  static void _get_pll_mnp(struct tegra_clk_pll *pll,  			 struct tegra_clk_pll_freq_table *cfg)  {  	u32 val; +	struct tegra_clk_pll_params *params = pll->params; +	struct div_nmp *div_nmp = params->div_nmp; + +	if ((pll->flags & TEGRA_PLLM) && +		(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) & +			PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) { +		val = pll_override_readl(params->pmc_divp_reg, pll); +		cfg->p = (val >> div_nmp->override_divp_shift) & divp_mask(pll); + +		val = pll_override_readl(params->pmc_divnm_reg, pll); +		cfg->m = (val >> div_nmp->override_divm_shift) & divm_mask(pll); +		cfg->n = (val >> div_nmp->override_divn_shift) & divn_mask(pll); +	}  else { +		val = pll_readl_base(pll); -	val = pll_readl_base(pll); - -	cfg->m = (val >> pll->divm_shift) & (divm_mask(pll)); -	cfg->n = (val >> pll->divn_shift) & (divn_mask(pll)); -	cfg->p = (val >> pll->divp_shift) & (divp_mask(pll)); +		cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll); +		cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll); +		cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll); +	}  }  static void _update_pll_cpcon(struct tegra_clk_pll *pll, @@ -485,9 +535,10 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,  	}  	if (_get_table_rate(hw, &cfg, rate, parent_rate) && -	    _calc_rate(hw, &cfg, rate, parent_rate)) +	    _calc_rate(hw, &cfg, rate, parent_rate)) { +		WARN_ON(1);  		return -EINVAL; - +	}  	if (pll->lock)  		spin_lock_irqsave(pll->lock, flags); @@ -507,7 +558,6 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,  {  	struct tegra_clk_pll *pll = to_clk_pll(hw);  	struct tegra_clk_pll_freq_table cfg; -	u64 output_rate = *prate;  	if (pll->flags & TEGRA_PLL_FIXED)  		return pll->fixed_rate; @@ -517,13 +567,12 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,  		return __clk_get_rate(hw->clk);  	if (_get_table_rate(hw, &cfg, rate, *prate) && -	    _calc_rate(hw, &cfg, rate, *prate)) +	    _calc_rate(hw, &cfg, rate, *prate)) { +		WARN_ON(1);  		return -EINVAL; +	} -	output_rate *= cfg.n; -	do_div(output_rate, cfg.m * (1 << cfg.p)); - -	return output_rate; +	return cfg.output_rate;  }  static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, @@ -531,7 +580,6 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,  {  	struct tegra_clk_pll *pll = to_clk_pll(hw);  	struct tegra_clk_pll_freq_table cfg; -	struct pdiv_map *p_tohw = pll->params->pdiv_tohw;  	u32 val;  	u64 rate = parent_rate;  	int pdiv; @@ -553,21 +601,11 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,  	_get_pll_mnp(pll, &cfg); -	if (p_tohw) { -		while (p_tohw->pdiv) { -			if (cfg.p == p_tohw->hw_val) { -				pdiv = p_tohw->pdiv; -				break; -			} -			p_tohw++; -		} - -		if (!p_tohw->pdiv) { -			WARN_ON(1); -			pdiv = 1; -		} -	} else -		pdiv = 1 << cfg.p; +	pdiv = _hw_to_p_div(hw, cfg.p); +	if (pdiv < 0) { +		WARN_ON(1); +		pdiv = 1; +	}  	cfg.m *= pdiv; @@ -647,9 +685,9 @@ static int clk_plle_enable(struct clk_hw *hw)  		val = pll_readl_base(pll);  		val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));  		val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); -		val |= sel.m << pll->divm_shift; -		val |= sel.n << pll->divn_shift; -		val |= sel.p << pll->divp_shift; +		val |= sel.m << pll->params->div_nmp->divm_shift; +		val |= sel.n << pll->params->div_nmp->divn_shift; +		val |= sel.p << pll->params->div_nmp->divp_shift;  		val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;  		pll_writel_base(val, pll);  	} @@ -680,9 +718,9 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,  	u32 divn = 0, divm = 0, divp = 0;  	u64 rate = parent_rate; -	divp = (val >> pll->divp_shift) & (divp_mask(pll)); -	divn = (val >> pll->divn_shift) & (divn_mask(pll)); -	divm = (val >> pll->divm_shift) & (divm_mask(pll)); +	divp = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll)); +	divn = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll)); +	divm = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));  	divm *= divp;  	rate *= divn; @@ -769,16 +807,22 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw,  {  	struct tegra_clk_pll *pll = to_clk_pll(hw);  	unsigned int p; +	int p_div;  	if (!rate)  		return -EINVAL;  	p = DIV_ROUND_UP(pll->params->vco_min, rate);  	cfg->m = _pll_fixed_mdiv(pll->params, parent_rate); -	cfg->p = p; -	cfg->output_rate = rate * cfg->p; +	cfg->output_rate = rate * p;  	cfg->n = cfg->output_rate * cfg->m / parent_rate; +	p_div = _p_div_to_hw(hw, p); +	if (p_div < 0) +		return p_div; +	else +		cfg->p = p_div; +  	if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)  		return -EINVAL; @@ -790,18 +834,25 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,  			      unsigned long rate, unsigned long parent_rate)  {  	struct tegra_clk_pll *pll = to_clk_pll(hw); -	int err = 0; +	int err = 0, p_div;  	err = _get_table_rate(hw, cfg, rate, parent_rate);  	if (err < 0)  		err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate); -	else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) { +	else { +		if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {  			WARN_ON(1);  			err = -EINVAL;  			goto out; +		} +		p_div = _p_div_to_hw(hw, cfg->p); +		if (p_div < 0) +			return p_div; +		else +			cfg->p = p_div;  	} -	if (!cfg->p || (cfg->p >  pll->params->max_p)) +	if (cfg->p >  pll->params->max_p)  		err = -EINVAL;  out: @@ -815,7 +866,6 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,  	struct tegra_clk_pll_freq_table cfg, old_cfg;  	unsigned long flags = 0;  	int ret = 0; -	u8 old_p;  	ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);  	if (ret < 0) @@ -826,11 +876,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,  	_get_pll_mnp(pll, &old_cfg); -	old_p = pllxc_p[old_cfg.p]; -	if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) { -		cfg.p -= 1; +	if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)  		ret = _program_pll(hw, &cfg, rate); -	}  	if (pll->lock)  		spin_unlock_irqrestore(pll->lock, flags); @@ -842,15 +889,19 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,  				unsigned long *prate)  {  	struct tegra_clk_pll_freq_table cfg; -	int ret = 0; +	int ret = 0, p_div;  	u64 output_rate = *prate;  	ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate);  	if (ret < 0)  		return ret; +	p_div = _hw_to_p_div(hw, cfg.p); +	if (p_div < 0) +		return p_div; +  	output_rate *= cfg.n; -	do_div(output_rate, cfg.m * cfg.p); +	do_div(output_rate, cfg.m * p_div);  	return output_rate;  } @@ -862,7 +913,6 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,  	struct tegra_clk_pll *pll = to_clk_pll(hw);  	unsigned long flags = 0;  	int state, ret = 0; -	u32 val;  	if (pll->lock)  		spin_lock_irqsave(pll->lock, flags); @@ -881,22 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,  	if (ret < 0)  		goto out; -	cfg.p -= 1; - -	val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE); -	if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) { -		val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2); -		val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) : -			(val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK); -		writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2); - -		val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE); -		val &= ~(divn_mask(pll) | divm_mask(pll)); -		val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift); -		writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE); -	} else -		_update_pll_mnp(pll, &cfg); - +	_update_pll_mnp(pll, &cfg);  out:  	if (pll->lock) @@ -1010,13 +1045,10 @@ static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll,  static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,  				unsigned long parent_rate)  { -	struct tegra_clk_pll_freq_table cfg; +	struct tegra_clk_pll_freq_table cfg, old_cfg;  	struct tegra_clk_pll *pll = to_clk_pll(hw);  	unsigned long flags = 0;  	int state, ret = 0; -	u32 val; -	u16 old_m, old_n; -	u8 old_p;  	if (pll->lock)  		spin_lock_irqsave(pll->lock, flags); @@ -1025,21 +1057,16 @@ static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,  	if (ret < 0)  		goto out; -	val = pll_readl_base(pll); -	old_m = (val >> pll->divm_shift) & (divm_mask(pll)); -	old_n = (val >> pll->divn_shift) & (divn_mask(pll)); -	old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))]; +	_get_pll_mnp(pll, &old_cfg); -	if (cfg.m != old_m) { +	if (cfg.m != old_cfg.m) {  		WARN_ON(1);  		goto out;  	} -	if (old_n == cfg.n && old_p == cfg.p) +	if (old_cfg.n == cfg.n && old_cfg.p == cfg.p)  		goto out; -	cfg.p -= 1; -  	state = clk_pll_is_enabled(hw);  	if (state)  		_clk_pllc_disable(hw); @@ -1178,8 +1205,8 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)  	val = pll_readl_base(pll);  	val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));  	val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT); -	val |= sel.m << pll->divm_shift; -	val |= sel.n << pll->divn_shift; +	val |= sel.m << pll->params->div_nmp->divm_shift; +	val |= sel.n << pll->params->div_nmp->divn_shift;  	val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;  	pll_writel_base(val, pll);  	udelay(1); @@ -1240,12 +1267,8 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,  	pll->flags = pll_flags;  	pll->lock = lock; -	pll->divp_shift = PLL_BASE_DIVP_SHIFT; -	pll->divp_width = PLL_BASE_DIVP_WIDTH; -	pll->divn_shift = PLL_BASE_DIVN_SHIFT; -	pll->divn_width = PLL_BASE_DIVN_WIDTH; -	pll->divm_shift = PLL_BASE_DIVM_SHIFT; -	pll->divm_width = PLL_BASE_DIVM_WIDTH; +	if (!pll_params->div_nmp) +		pll_params->div_nmp = &default_nmp;  	return pll;  } @@ -1401,7 +1424,7 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,  	struct tegra_clk_pll *pll;  	struct clk *clk; -	pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; +	pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;  	pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,  			      freq_table, lock);  	if (IS_ERR(pll)) @@ -1428,7 +1451,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,  	val &= ~BIT(29);  	pll_writel_misc(val, pll); -	pll_flags |= TEGRA_PLL_LOCK_MISC;  	clk = _tegra_clk_register_pll(pll, name, parent_name, flags,  				      &tegra_clk_pllre_ops);  	if (IS_ERR(clk)) @@ -1453,6 +1475,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,  	pll_flags |= TEGRA_PLL_BYPASS;  	pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; +	pll_flags |= TEGRA_PLLM;  	pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,  			      freq_table, lock);  	if (IS_ERR(pll)) diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index d78e16ee161c..b6015cb4fc01 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -21,6 +21,7 @@  #include <linux/of.h>  #include <linux/of_address.h>  #include <linux/delay.h> +#include <linux/export.h>  #include <linux/clk/tegra.h>  #include "clk.h" @@ -28,6 +29,7 @@  #define RST_DEVICES_L			0x004  #define RST_DEVICES_H			0x008  #define RST_DEVICES_U			0x00C +#define RST_DFLL_DVCO			0x2F4  #define RST_DEVICES_V			0x358  #define RST_DEVICES_W			0x35C  #define RST_DEVICES_X			0x28C @@ -41,8 +43,36 @@  #define RST_DEVICES_CLR_V		0x434  #define RST_DEVICES_SET_W		0x438  #define RST_DEVICES_CLR_W		0x43c +#define CPU_FINETRIM_SELECT		0x4d4	/* override default prop dlys */ +#define CPU_FINETRIM_DR			0x4d8	/* rise->rise prop dly A */ +#define CPU_FINETRIM_R			0x4e4	/* rise->rise prop dly inc A */  #define RST_DEVICES_NUM			5 +/* RST_DFLL_DVCO bitfields */ +#define DVFS_DFLL_RESET_SHIFT		0 + +/* CPU_FINETRIM_SELECT and CPU_FINETRIM_DR bitfields */ +#define CPU_FINETRIM_1_FCPU_1		BIT(0)	/* fcpu0 */ +#define CPU_FINETRIM_1_FCPU_2		BIT(1)	/* fcpu1 */ +#define CPU_FINETRIM_1_FCPU_3		BIT(2)	/* fcpu2 */ +#define CPU_FINETRIM_1_FCPU_4		BIT(3)	/* fcpu3 */ +#define CPU_FINETRIM_1_FCPU_5		BIT(4)	/* fl2 */ +#define CPU_FINETRIM_1_FCPU_6		BIT(5)	/* ftop */ + +/* CPU_FINETRIM_R bitfields */ +#define CPU_FINETRIM_R_FCPU_1_SHIFT	0		/* fcpu0 */ +#define CPU_FINETRIM_R_FCPU_1_MASK	(0x3 << CPU_FINETRIM_R_FCPU_1_SHIFT) +#define CPU_FINETRIM_R_FCPU_2_SHIFT	2		/* fcpu1 */ +#define CPU_FINETRIM_R_FCPU_2_MASK	(0x3 << CPU_FINETRIM_R_FCPU_2_SHIFT) +#define CPU_FINETRIM_R_FCPU_3_SHIFT	4		/* fcpu2 */ +#define CPU_FINETRIM_R_FCPU_3_MASK	(0x3 << CPU_FINETRIM_R_FCPU_3_SHIFT) +#define CPU_FINETRIM_R_FCPU_4_SHIFT	6		/* fcpu3 */ +#define CPU_FINETRIM_R_FCPU_4_MASK	(0x3 << CPU_FINETRIM_R_FCPU_4_SHIFT) +#define CPU_FINETRIM_R_FCPU_5_SHIFT	8		/* fl2 */ +#define CPU_FINETRIM_R_FCPU_5_MASK	(0x3 << CPU_FINETRIM_R_FCPU_5_SHIFT) +#define CPU_FINETRIM_R_FCPU_6_SHIFT	10		/* ftop */ +#define CPU_FINETRIM_R_FCPU_6_MASK	(0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT) +  #define CLK_OUT_ENB_L			0x010  #define CLK_OUT_ENB_H			0x014  #define CLK_OUT_ENB_U			0x018 @@ -127,6 +157,7 @@  #define PMC_DPD_PADS_ORIDE_BLINK_ENB 20  #define PMC_CTRL 0  #define PMC_CTRL_BLINK_ENB 7 +#define PMC_BLINK_TIMER 0x40  #define OSC_CTRL			0x50  #define OSC_CTRL_OSC_FREQ_SHIFT		28 @@ -242,6 +273,8 @@  #define CLK_SOURCE_I2CSLOW 0x3fc  #define CLK_SOURCE_SE 0x42c  #define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_DFLL_REF 0x62c +#define CLK_SOURCE_DFLL_SOC 0x630  #define CLK_SOURCE_SOC_THERM 0x644  #define CLK_SOURCE_XUSB_HOST_SRC 0x600  #define CLK_SOURCE_XUSB_FALCON_SRC 0x604 @@ -250,6 +283,13 @@  #define CLK_SOURCE_XUSB_DEV_SRC 0x60c  #define CLK_SOURCE_EMC 0x19c +/* PLLM override registers */ +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 + +/* Tegra CPU clock and reset control regs */ +#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS	0x470 +  static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32];  static void __iomem *clk_base; @@ -264,6 +304,15 @@ static DEFINE_SPINLOCK(clk_doubler_lock);  static DEFINE_SPINLOCK(clk_out_lock);  static DEFINE_SPINLOCK(sysrate_lock); +static struct div_nmp pllxc_nmp = { +	.divm_shift = 0, +	.divm_width = 8, +	.divn_shift = 8, +	.divn_width = 8, +	.divp_shift = 20, +	.divp_width = 4, +}; +  static struct pdiv_map pllxc_p[] = {  	{ .pdiv = 1, .hw_val = 0 },  	{ .pdiv = 2, .hw_val = 1 }, @@ -312,6 +361,16 @@ static struct tegra_clk_pll_params pll_c_params = {  	.stepa_shift = 17,  	.stepb_shift = 9,  	.pdiv_tohw = pllxc_p, +	.div_nmp = &pllxc_nmp, +}; + +static struct div_nmp pllcx_nmp = { +	.divm_shift = 0, +	.divm_width = 2, +	.divn_shift = 8, +	.divn_width = 8, +	.divp_shift = 20, +	.divp_width = 3,  };  static struct pdiv_map pllc_p[] = { @@ -345,6 +404,8 @@ static struct tegra_clk_pll_params pll_c2_params = {  	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,  	.lock_delay = 300,  	.pdiv_tohw = pllc_p, +	.div_nmp = &pllcx_nmp, +	.max_p = 7,  	.ext_misc_reg[0] = 0x4f0,  	.ext_misc_reg[1] = 0x4f4,  	.ext_misc_reg[2] = 0x4f8, @@ -363,11 +424,25 @@ static struct tegra_clk_pll_params pll_c3_params = {  	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,  	.lock_delay = 300,  	.pdiv_tohw = pllc_p, +	.div_nmp = &pllcx_nmp, +	.max_p = 7,  	.ext_misc_reg[0] = 0x504,  	.ext_misc_reg[1] = 0x508,  	.ext_misc_reg[2] = 0x50c,  }; +static struct div_nmp pllm_nmp = { +	.divm_shift = 0, +	.divm_width = 8, +	.override_divm_shift = 0, +	.divn_shift = 8, +	.divn_width = 8, +	.override_divn_shift = 8, +	.divp_shift = 20, +	.divp_width = 1, +	.override_divp_shift = 27, +}; +  static struct pdiv_map pllm_p[] = {  	{ .pdiv = 1, .hw_val = 0 },  	{ .pdiv = 2, .hw_val = 1 }, @@ -397,6 +472,18 @@ static struct tegra_clk_pll_params pll_m_params = {  	.lock_delay = 300,  	.max_p = 2,  	.pdiv_tohw = pllm_p, +	.div_nmp = &pllm_nmp, +	.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, +	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2, +}; + +static struct div_nmp pllp_nmp = { +	.divm_shift = 0, +	.divm_width = 5, +	.divn_shift = 8, +	.divn_width = 10, +	.divp_shift = 20, +	.divp_width = 3,  };  static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { @@ -420,6 +507,7 @@ static struct tegra_clk_pll_params pll_p_params = {  	.lock_mask = PLL_BASE_LOCK,  	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,  	.lock_delay = 300, +	.div_nmp = &pllp_nmp,  };  static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { @@ -446,6 +534,7 @@ static struct tegra_clk_pll_params pll_a_params = {  	.lock_mask = PLL_BASE_LOCK,  	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,  	.lock_delay = 300, +	.div_nmp = &pllp_nmp,  };  static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { @@ -481,6 +570,7 @@ static struct tegra_clk_pll_params pll_d_params = {  	.lock_mask = PLL_BASE_LOCK,  	.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,  	.lock_delay = 1000, +	.div_nmp = &pllp_nmp,  };  static struct tegra_clk_pll_params pll_d2_params = { @@ -495,6 +585,7 @@ static struct tegra_clk_pll_params pll_d2_params = {  	.lock_mask = PLL_BASE_LOCK,  	.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,  	.lock_delay = 1000, +	.div_nmp = &pllp_nmp,  };  static struct pdiv_map pllu_p[] = { @@ -503,6 +594,15 @@ static struct pdiv_map pllu_p[] = {  	{ .pdiv = 0, .hw_val = 0 },  }; +static struct div_nmp pllu_nmp = { +	.divm_shift = 0, +	.divm_width = 5, +	.divn_shift = 8, +	.divn_width = 10, +	.divp_shift = 20, +	.divp_width = 1, +}; +  static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {  	{12000000, 480000000, 960, 12, 0, 12},  	{13000000, 480000000, 960, 13, 0, 12}, @@ -525,6 +625,7 @@ static struct tegra_clk_pll_params pll_u_params = {  	.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,  	.lock_delay = 1000,  	.pdiv_tohw = pllu_p, +	.div_nmp = &pllu_nmp,  };  static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { @@ -557,6 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = {  	.stepa_shift = 16,  	.stepb_shift = 24,  	.pdiv_tohw = pllxc_p, +	.div_nmp = &pllxc_nmp,  };  static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { @@ -566,6 +668,15 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {  	{0, 0, 0, 0, 0, 0},  }; +static struct div_nmp plle_nmp = { +	.divm_shift = 0, +	.divm_width = 8, +	.divn_shift = 8, +	.divn_width = 8, +	.divp_shift = 24, +	.divp_width = 4, +}; +  static struct tegra_clk_pll_params pll_e_params = {  	.input_min = 12000000,  	.input_max = 1000000000, @@ -579,6 +690,16 @@ static struct tegra_clk_pll_params pll_e_params = {  	.lock_mask = PLLE_MISC_LOCK,  	.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,  	.lock_delay = 300, +	.div_nmp = &plle_nmp, +}; + +static struct div_nmp pllre_nmp = { +	.divm_shift = 0, +	.divm_width = 8, +	.divn_shift = 8, +	.divn_width = 8, +	.divp_shift = 16, +	.divp_width = 4,  };  static struct tegra_clk_pll_params pll_re_vco_params = { @@ -595,6 +716,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {  	.lock_delay = 300,  	.iddq_reg = PLLRE_MISC,  	.iddq_bit_idx = PLLRE_IDDQ_BIT, +	.div_nmp = &pllre_nmp,  };  /* Peripheral clock registers */ @@ -762,6 +884,7 @@ enum tegra114_clk {  	audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3,  	blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src,  	xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp, +	dfll_ref = 264, dfll_soc,  	/* Mux clocks */ @@ -1199,8 +1322,8 @@ static void __init tegra114_pll_init(void __iomem *clk_base,  	/* PLLP_OUT2 */  	clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",  				clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | -				TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, -				&pll_div_lock); +				TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24, +				8, 1, &pll_div_lock);  	clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",  				clk_base + PLLP_OUTA, 17, 16,  				CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, @@ -1602,7 +1725,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)  	/* clk_out_2 */  	clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, -			       ARRAY_SIZE(clk_out1_parents), 0, +			       ARRAY_SIZE(clk_out2_parents), 0,  			       pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,  			       &clk_out_lock);  	clks[clk_out_2_mux] = clk; @@ -1614,7 +1737,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)  	/* clk_out_3 */  	clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, -			       ARRAY_SIZE(clk_out1_parents), 0, +			       ARRAY_SIZE(clk_out3_parents), 0,  			       pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,  			       &clk_out_lock);  	clks[clk_out_3_mux] = clk; @@ -1625,6 +1748,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)  	clks[clk_out_3] = clk;  	/* blink */ +	/* clear the blink timer register to directly output clk_32k */ +	writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);  	clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,  				pmc_base + PMC_DPD_PADS_ORIDE,  				PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); @@ -1637,7 +1762,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)  }  static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", -			       "pll_p_out3", "pll_p_out2", "unused", +			       "pll_p", "pll_p_out2", "unused",  			       "clk_32k", "pll_m_out1" };  static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", @@ -1747,7 +1872,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {  	TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),  	TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),  	TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), -	TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc), +	TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc),  	TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec),  	TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),  	TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), @@ -1764,6 +1889,8 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {  	TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),  	TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se),  	TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED), +	TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref), +	TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc),  	TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm),  	TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src),  	TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src), @@ -2000,13 +2127,35 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base)  	}  } -static struct tegra_cpu_car_ops tegra114_cpu_car_ops; +/* Tegra114 CPU clock and reset control functions */ +static void tegra114_wait_cpu_in_reset(u32 cpu) +{ +	unsigned int reg; + +	do { +		reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); +		cpu_relax(); +	} while (!(reg & (1 << cpu)));  /* check CPU been reset or not */ +} +static void tegra114_disable_cpu_clock(u32 cpu) +{ +	/* flow controller would take care in the power sequence. */ +} + +static struct tegra_cpu_car_ops tegra114_cpu_car_ops = { +	.wait_for_reset	= tegra114_wait_cpu_in_reset, +	.disable_clock	= tegra114_disable_cpu_clock, +};  static const struct of_device_id pmc_match[] __initconst = {  	{ .compatible = "nvidia,tegra114-pmc" },  	{},  }; +/* + * dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5 + * breaks + */  static __initdata struct tegra_clk_init_table init_table[] = {  	{uarta, pll_p, 408000000, 0},  	{uartb, pll_p, 408000000, 0}, @@ -2022,6 +2171,8 @@ static __initdata struct tegra_clk_init_table init_table[] = {  	{i2s2, pll_a_out0, 11289600, 0},  	{i2s3, pll_a_out0, 11289600, 0},  	{i2s4, pll_a_out0, 11289600, 0}, +	{dfll_soc, pll_p, 51000000, 1}, +	{dfll_ref, pll_p, 51000000, 1},  	{clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */  }; @@ -2030,7 +2181,132 @@ static void __init tegra114_clock_apply_init_table(void)  	tegra_init_from_table(init_table, clks, clk_max);  } -void __init tegra114_clock_init(struct device_node *np) + +/** + * tegra114_car_barrier - wait for pending writes to the CAR to complete + * + * Wait for any outstanding writes to the CAR MMIO space from this CPU + * to complete before continuing execution.  No return value. + */ +static void tegra114_car_barrier(void) +{ +	wmb();		/* probably unnecessary */ +	readl_relaxed(clk_base + CPU_FINETRIM_SELECT); +} + +/** + * tegra114_clock_tune_cpu_trimmers_high - use high-voltage propagation delays + * + * When the CPU rail voltage is in the high-voltage range, use the + * built-in hardwired clock propagation delays in the CPU clock + * shaper.  No return value. + */ +void tegra114_clock_tune_cpu_trimmers_high(void) +{ +	u32 select = 0; + +	/* Use hardwired rise->rise & fall->fall clock propagation delays */ +	select |= ~(CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | +		    CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | +		    CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); +	writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT); + +	tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_high); + +/** + * tegra114_clock_tune_cpu_trimmers_low - use low-voltage propagation delays + * + * When the CPU rail voltage is in the low-voltage range, use the + * extended clock propagation delays set by + * tegra114_clock_tune_cpu_trimmers_init().  The intention is to + * maintain the input clock duty cycle that the FCPU subsystem + * expects.  No return value. + */ +void tegra114_clock_tune_cpu_trimmers_low(void) +{ +	u32 select = 0; + +	/* +	 * Use software-specified rise->rise & fall->fall clock +	 * propagation delays (from +	 * tegra114_clock_tune_cpu_trimmers_init() +	 */ +	select |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | +		   CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | +		   CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); +	writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT); + +	tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_low); + +/** + * tegra114_clock_tune_cpu_trimmers_init - set up and enable clk prop delays + * + * Program extended clock propagation delays into the FCPU clock + * shaper and enable them.  XXX Define the purpose - peak current + * reduction?  No return value. + */ +/* XXX Initial voltage rail state assumption issues? */ +void tegra114_clock_tune_cpu_trimmers_init(void) +{ +	u32 dr = 0, r = 0; + +	/* Increment the rise->rise clock delay by four steps */ +	r |= (CPU_FINETRIM_R_FCPU_1_MASK | CPU_FINETRIM_R_FCPU_2_MASK | +	      CPU_FINETRIM_R_FCPU_3_MASK | CPU_FINETRIM_R_FCPU_4_MASK | +	      CPU_FINETRIM_R_FCPU_5_MASK | CPU_FINETRIM_R_FCPU_6_MASK); +	writel_relaxed(r, clk_base + CPU_FINETRIM_R); + +	/* +	 * Use the rise->rise clock propagation delay specified in the +	 * r field +	 */ +	dr |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 | +	       CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 | +	       CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6); +	writel_relaxed(dr, clk_base + CPU_FINETRIM_DR); + +	tegra114_clock_tune_cpu_trimmers_low(); +} +EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init); + +/** + * tegra114_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset + * + * Assert the reset line of the DFLL's DVCO.  No return value. + */ +void tegra114_clock_assert_dfll_dvco_reset(void) +{ +	u32 v; + +	v = readl_relaxed(clk_base + RST_DFLL_DVCO); +	v |= (1 << DVFS_DFLL_RESET_SHIFT); +	writel_relaxed(v, clk_base + RST_DFLL_DVCO); +	tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset); + +/** + * tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset + * + * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to + * operate.  No return value. + */ +void tegra114_clock_deassert_dfll_dvco_reset(void) +{ +	u32 v; + +	v = readl_relaxed(clk_base + RST_DFLL_DVCO); +	v &= ~(1 << DVFS_DFLL_RESET_SHIFT); +	writel_relaxed(v, clk_base + RST_DFLL_DVCO); +	tegra114_car_barrier(); +} +EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset); + +static void __init tegra114_clock_init(struct device_node *np)  {  	struct device_node *node;  	int i; @@ -2083,3 +2359,4 @@ void __init tegra114_clock_init(struct device_node *np)  	tegra_cpu_car_ops = &tegra114_cpu_car_ops;  } +CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init); diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 075db0c99edb..759ca47be753 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -1287,7 +1287,7 @@ static const struct of_device_id pmc_match[] __initconst = {  	{},  }; -void __init tegra20_clock_init(struct device_node *np) +static void __init tegra20_clock_init(struct device_node *np)  {  	int i;  	struct device_node *node; @@ -1339,3 +1339,4 @@ void __init tegra20_clock_init(struct device_node *np)  	tegra_cpu_car_ops = &tegra20_cpu_car_ops;  } +CLK_OF_DECLARE(tegra20, "nvidia,tegra20-car", tegra20_clock_init); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index ba99e3844106..e2c6ca0431d6 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -252,6 +252,9 @@  #define CLK_RESET_CCLK_RUN_POLICY		2  #define CLK_RESET_CCLK_BURST_POLICY_PLLX	8 +/* PLLM override registers */ +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +  #ifdef CONFIG_PM_SLEEP  static struct cpu_clk_suspend_context {  	u32 pllx_misc; @@ -563,6 +566,18 @@ static struct tegra_clk_pll_params pll_c_params = {  	.lock_delay = 300,  }; +static struct div_nmp pllm_nmp = { +	.divn_shift = 8, +	.divn_width = 10, +	.override_divn_shift = 5, +	.divm_shift = 0, +	.divm_width = 5, +	.override_divm_shift = 0, +	.divp_shift = 20, +	.divp_width = 3, +	.override_divp_shift = 15, +}; +  static struct tegra_clk_pll_params pll_m_params = {  	.input_min = 2000000,  	.input_max = 31000000, @@ -575,6 +590,9 @@ static struct tegra_clk_pll_params pll_m_params = {  	.lock_mask = PLL_BASE_LOCK,  	.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,  	.lock_delay = 300, +	.div_nmp = &pllm_nmp, +	.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, +	.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,  };  static struct tegra_clk_pll_params pll_p_params = { @@ -1223,7 +1241,7 @@ static void __init tegra30_pmc_clk_init(void)  	/* clk_out_2 */  	clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, -			       ARRAY_SIZE(clk_out1_parents), 0, +			       ARRAY_SIZE(clk_out2_parents), 0,  			       pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,  			       &clk_out_lock);  	clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, @@ -1234,7 +1252,7 @@ static void __init tegra30_pmc_clk_init(void)  	/* clk_out_3 */  	clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, -			       ARRAY_SIZE(clk_out1_parents), 0, +			       ARRAY_SIZE(clk_out3_parents), 0,  			       pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,  			       &clk_out_lock);  	clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, @@ -1954,7 +1972,7 @@ static const struct of_device_id pmc_match[] __initconst = {  	{},  }; -void __init tegra30_clock_init(struct device_node *np) +static void __init tegra30_clock_init(struct device_node *np)  {  	struct device_node *node;  	int i; @@ -2005,3 +2023,4 @@ void __init tegra30_clock_init(struct device_node *np)  	tegra_cpu_car_ops = &tegra30_cpu_car_ops;  } +CLK_OF_DECLARE(tegra30, "nvidia,tegra30-car", tegra30_clock_init); diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 923ca7ee4694..86581ac1fd69 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -74,18 +74,6 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,  	}  } -static const struct of_device_id tegra_dt_clk_match[] = { -	{ .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init }, -	{ .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init }, -	{ .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init }, -	{ } -}; - -void __init tegra_clocks_init(void) -{ -	of_clk_init(tegra_dt_clk_match); -} -  tegra_clk_apply_init_table_func tegra_clk_apply_init_table;  void __init tegra_clocks_apply_init_table(void) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index e0565620d68e..07cfacd91686 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -128,6 +128,31 @@ struct pdiv_map {  };  /** + * struct div_nmp - offset and width of m,n and p fields + * + * @divn_shift:	shift to the feedback divider bit field + * @divn_width:	width of the feedback divider bit field + * @divm_shift:	shift to the input divider bit field + * @divm_width:	width of the input divider bit field + * @divp_shift:	shift to the post divider bit field + * @divp_width:	width of the post divider bit field + * @override_divn_shift: shift to the feedback divider bitfield in override reg + * @override_divm_shift: shift to the input divider bitfield in override reg + * @override_divp_shift: shift to the post divider bitfield in override reg + */ +struct div_nmp { +	u8		divn_shift; +	u8		divn_width; +	u8		divm_shift; +	u8		divm_width; +	u8		divp_shift; +	u8		divp_width; +	u8		override_divn_shift; +	u8		override_divm_shift; +	u8		override_divp_shift; +}; + +/**   * struct clk_pll_params - PLL parameters   *   * @input_min:			Minimum input frequency @@ -161,11 +186,14 @@ struct tegra_clk_pll_params {  	u32		aux_reg;  	u32		dyn_ramp_reg;  	u32		ext_misc_reg[3]; +	u32		pmc_divnm_reg; +	u32		pmc_divp_reg;  	int		stepa_shift;  	int		stepb_shift;  	int		lock_delay;  	int		max_p;  	struct pdiv_map *pdiv_tohw; +	struct div_nmp	*div_nmp;  };  /** @@ -179,12 +207,6 @@ struct tegra_clk_pll_params {   * @flags:	PLL flags   * @fixed_rate:	PLL rate if it is fixed   * @lock:	register lock - * @divn_shift:	shift to the feedback divider bit field - * @divn_width:	width of the feedback divider bit field - * @divm_shift:	shift to the input divider bit field - * @divm_width:	width of the input divider bit field - * @divp_shift:	shift to the post divider bit field - * @divp_width:	width of the post divider bit field   *   * Flags:   * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for @@ -214,12 +236,6 @@ struct tegra_clk_pll {  	u32		flags;  	unsigned long	fixed_rate;  	spinlock_t	*lock; -	u8		divn_shift; -	u8		divn_width; -	u8		divm_shift; -	u8		divm_width; -	u8		divp_shift; -	u8		divp_width;  	struct tegra_clk_pll_freq_table	*freq_table;  	struct tegra_clk_pll_params	*params;  }; @@ -571,23 +587,11 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl,  void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,  		struct clk *clks[], int clk_max); -#ifdef CONFIG_ARCH_TEGRA_2x_SOC -void tegra20_clock_init(struct device_node *np); -#else -static inline void tegra20_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA_2x_SOC */ - -#ifdef CONFIG_ARCH_TEGRA_3x_SOC -void tegra30_clock_init(struct device_node *np); -#else -static inline void tegra30_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA_3x_SOC */ - -#ifdef CONFIG_ARCH_TEGRA_114_SOC -void tegra114_clock_init(struct device_node *np); -#else -static inline void tegra114_clock_init(struct device_node *np) {} -#endif /* CONFIG_ARCH_TEGRA114_SOC */ +void tegra114_clock_tune_cpu_trimmers_high(void); +void tegra114_clock_tune_cpu_trimmers_low(void); +void tegra114_clock_tune_cpu_trimmers_init(void); +void tegra114_clock_assert_dfll_dvco_reset(void); +void tegra114_clock_deassert_dfll_dvco_reset(void);  typedef void (*tegra_clk_apply_init_table_func)(void);  extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table; diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c index a0fca004abc1..e7bd62cf60b3 100644 --- a/drivers/clk/ux500/abx500-clk.c +++ b/drivers/clk/ux500/abx500-clk.c @@ -45,7 +45,7 @@ static int ab8500_reg_clks(struct device *dev)  				CLK_IS_ROOT);  	clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");  	clk_register_clkdev(clk, "sysclk", "ab-iddet.0"); -	clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0"); +	clk_register_clkdev(clk, "sysclk", "snd-soc-mop500.0");  	clk_register_clkdev(clk, "sysclk", "shrm_bus");  	/* ab8500_sysclk2 */ @@ -70,19 +70,19 @@ static int ab8500_reg_clks(struct device *dev)  		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,  		AB8500_SYSULPCLKCTRL1_ULPCLKREQ,  		38400000, 9000, CLK_IS_ROOT); -	clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0"); +	clk_register_clkdev(clk, "ulpclk", "snd-soc-mop500.0");  	/* ab8500_intclk */  	clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,  		intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0); -	clk_register_clkdev(clk, "intclk", "ab85xx-codec.0"); +	clk_register_clkdev(clk, "intclk", "snd-soc-mop500.0");  	clk_register_clkdev(clk, NULL, "ab8500-pwm.1");  	/* ab8500_audioclk */  	clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",  		AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,  		AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0); -	clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0"); +	clk_register_clkdev(clk, "audioclk", "ab8500-codec.0");  	return 0;  } diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c index 10adfd2ead21..f26258869deb 100644 --- a/drivers/clk/ux500/u8540_clk.c +++ b/drivers/clk/ux500/u8540_clk.c @@ -12,10 +12,568 @@  #include <linux/clk-provider.h>  #include <linux/mfd/dbx500-prcmu.h>  #include <linux/platform_data/clk-ux500.h> -  #include "clk.h" -void u8540_clk_init(void) +void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base, +		    u32 clkrst5_base, u32 clkrst6_base)  { -	/* register clocks here */ +	struct clk *clk; + +	/* Clock sources. */ +	/* Fixed ClockGen */ +	clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0, +				CLK_IS_ROOT|CLK_IGNORE_UNUSED); +	clk_register_clkdev(clk, "soc0_pll", NULL); + +	clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1, +				CLK_IS_ROOT|CLK_IGNORE_UNUSED); +	clk_register_clkdev(clk, "soc1_pll", NULL); + +	clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR, +				CLK_IS_ROOT|CLK_IGNORE_UNUSED); +	clk_register_clkdev(clk, "ddr_pll", NULL); + +	clk = clk_register_fixed_rate(NULL, "rtc32k", NULL, +				CLK_IS_ROOT|CLK_IGNORE_UNUSED, +				32768); +	clk_register_clkdev(clk, "clk32k", NULL); +	clk_register_clkdev(clk, "apb_pclk", "rtc-pl031"); + +	clk = clk_register_fixed_rate(NULL, "ulp38m4", NULL, +				CLK_IS_ROOT|CLK_IGNORE_UNUSED, +				38400000); + +	clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "UART"); + +	/* msp02clk needs a abx500 clk as parent. Handle by abx500 clk driver */ +	clk = clk_reg_prcmu_gate("msp02clk", "ab9540_sysclk12_b1", +			PRCMU_MSP02CLK, 0); +	clk_register_clkdev(clk, NULL, "MSP02"); + +	clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "MSP1"); + +	clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "I2C"); + +	clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "slim"); + +	clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH1"); + +	clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH2"); + +	clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH3"); + +	clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH5"); + +	clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH6"); + +	clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "PERIPH7"); + +	clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "lcd"); +	clk_register_clkdev(clk, "lcd", "mcde"); + +	clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BML8580CLK, +				CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "bml"); + +	clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); + +	clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); + +	clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "hdmi"); +	clk_register_clkdev(clk, "hdmi", "mcde"); + +	clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "apeat"); + +	clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK, +				CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "apetrace"); + +	clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "mcde"); +	clk_register_clkdev(clk, "mcde", "mcde"); +	clk_register_clkdev(clk, NULL, "dsilink.0"); +	clk_register_clkdev(clk, NULL, "dsilink.1"); +	clk_register_clkdev(clk, NULL, "dsilink.2"); + +	clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK, +				CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "ipi2"); + +	clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK, +				CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "dsialt"); + +	clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "dma40.0"); + +	clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "b2r2"); +	clk_register_clkdev(clk, NULL, "b2r2_core"); +	clk_register_clkdev(clk, NULL, "U8500-B2R2.0"); +	clk_register_clkdev(clk, NULL, "b2r2_1_core"); + +	clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "tv"); +	clk_register_clkdev(clk, "tv", "mcde"); + +	clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "SSP"); + +	clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "rngclk"); + +	clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "uicc"); + +	clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "mtu0"); +	clk_register_clkdev(clk, NULL, "mtu1"); + +	clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, +					PRCMU_SDMMCCLK, 100000000, +					CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdmmc"); + +	clk = clk_reg_prcmu_opp_volt_scalable("sdmmchclk", NULL, +					PRCMU_SDMMCHCLK, 400000000, +					CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdmmchclk"); + +	clk = clk_reg_prcmu_gate("hvaclk", NULL, PRCMU_HVACLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "hva"); + +	clk = clk_reg_prcmu_gate("g1clk", NULL, PRCMU_G1CLK, CLK_IS_ROOT); +	clk_register_clkdev(clk, NULL, "g1"); + +	clk = clk_reg_prcmu_scalable("spare1clk", NULL, PRCMU_SPARE1CLK, 0, +				CLK_IS_ROOT|CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsilcd", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", +				PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsihs2", "mcde"); +	clk_register_clkdev(clk, "hs_clk", "dsilink.2"); + +	clk = clk_reg_prcmu_scalable("dsilcd_pll", "spare1clk", +				PRCMU_PLLDSI_LCD, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsilcd_pll", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll", +				PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsihs0", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi0lcdclk", "dsilcd_pll", +				PRCMU_DSI0CLK_LCD, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsihs0", "mcde"); +	clk_register_clkdev(clk, "hs_clk", "dsilink.0"); + +	clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll", +				PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsihs1", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi1lcdclk", "dsilcd_pll", +				PRCMU_DSI1CLK_LCD, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "dsihs1", "mcde"); +	clk_register_clkdev(clk, "hs_clk", "dsilink.1"); + +	clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk", +				PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "lp_clk", "dsilink.0"); +	clk_register_clkdev(clk, "dsilp0", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk", +				PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "lp_clk", "dsilink.1"); +	clk_register_clkdev(clk, "dsilp1", "mcde"); + +	clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk", +				PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, "lp_clk", "dsilink.2"); +	clk_register_clkdev(clk, "dsilp2", "mcde"); + +	clk = clk_reg_prcmu_scalable_rate("armss", NULL, +				PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED); +	clk_register_clkdev(clk, "armss", NULL); + +	clk = clk_register_fixed_factor(NULL, "smp_twd", "armss", +				CLK_IGNORE_UNUSED, 1, 2); +	clk_register_clkdev(clk, NULL, "smp_twd"); + +	/* PRCC P-clocks */ +	/* Peripheral 1 : PRCC P-clocks */ +	clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base, +				BIT(0), 0); +	clk_register_clkdev(clk, "apb_pclk", "uart0"); + +	clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base, +				BIT(1), 0); +	clk_register_clkdev(clk, "apb_pclk", "uart1"); + +	clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base, +				BIT(2), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1"); + +	clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base, +				BIT(3), 0); +	clk_register_clkdev(clk, "apb_pclk", "msp0"); +	clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0"); + +	clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base, +				BIT(4), 0); +	clk_register_clkdev(clk, "apb_pclk", "msp1"); +	clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1"); + +	clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base, +				BIT(5), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi0"); + +	clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base, +				BIT(6), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2"); + +	clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base, +				BIT(7), 0); +	clk_register_clkdev(clk, NULL, "spi3"); + +	clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base, +				BIT(8), 0); +	clk_register_clkdev(clk, "apb_pclk", "slimbus0"); + +	clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base, +				BIT(9), 0); +	clk_register_clkdev(clk, NULL, "gpio.0"); +	clk_register_clkdev(clk, NULL, "gpio.1"); +	clk_register_clkdev(clk, NULL, "gpioblock0"); +	clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0"); + +	clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base, +				BIT(10), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4"); + +	clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base, +				BIT(11), 0); +	clk_register_clkdev(clk, "apb_pclk", "msp3"); +	clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3"); + +	/* Peripheral 2 : PRCC P-clocks */ +	clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base, +				BIT(0), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3"); + +	clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base, +				BIT(1), 0); +	clk_register_clkdev(clk, NULL, "spi2"); + +	clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base, +				BIT(2), 0); +	clk_register_clkdev(clk, NULL, "spi1"); + +	clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base, +				BIT(3), 0); +	clk_register_clkdev(clk, NULL, "pwl"); + +	clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base, +				BIT(4), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi4"); + +	clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base, +				BIT(5), 0); +	clk_register_clkdev(clk, "apb_pclk", "msp2"); +	clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2"); + +	clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base, +				BIT(6), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi1"); + +	clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base, +				BIT(7), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi3"); + +	clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base, +				BIT(8), 0); +	clk_register_clkdev(clk, NULL, "spi0"); + +	clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base, +				BIT(9), 0); +	clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0"); + +	clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base, +				BIT(10), 0); +	clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0"); + +	clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base, +				BIT(11), 0); +	clk_register_clkdev(clk, NULL, "gpio.6"); +	clk_register_clkdev(clk, NULL, "gpio.7"); +	clk_register_clkdev(clk, NULL, "gpioblock1"); + +	clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base, +				BIT(12), 0); +	clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0"); + +	/* Peripheral 3 : PRCC P-clocks */ +	clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base, +				BIT(0), 0); +	clk_register_clkdev(clk, NULL, "fsmc"); + +	clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base, +				BIT(1), 0); +	clk_register_clkdev(clk, "apb_pclk", "ssp0"); + +	clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base, +				BIT(2), 0); +	clk_register_clkdev(clk, "apb_pclk", "ssp1"); + +	clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base, +				BIT(3), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0"); + +	clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base, +				BIT(4), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi2"); + +	clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base, +				BIT(5), 0); +	clk_register_clkdev(clk, "apb_pclk", "ske"); +	clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad"); + +	clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base, +				BIT(6), 0); +	clk_register_clkdev(clk, "apb_pclk", "uart2"); + +	clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base, +				BIT(7), 0); +	clk_register_clkdev(clk, "apb_pclk", "sdi5"); + +	clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base, +				BIT(8), 0); +	clk_register_clkdev(clk, NULL, "gpio.2"); +	clk_register_clkdev(clk, NULL, "gpio.3"); +	clk_register_clkdev(clk, NULL, "gpio.4"); +	clk_register_clkdev(clk, NULL, "gpio.5"); +	clk_register_clkdev(clk, NULL, "gpioblock2"); + +	clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", clkrst3_base, +				BIT(9), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5"); + +	clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", clkrst3_base, +				BIT(10), 0); +	clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6"); + +	clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", clkrst3_base, +				BIT(11), 0); +	clk_register_clkdev(clk, "apb_pclk", "uart3"); + +	clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", clkrst3_base, +				BIT(12), 0); +	clk_register_clkdev(clk, "apb_pclk", "uart4"); + +	/* Peripheral 5 : PRCC P-clocks */ +	clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base, +				BIT(0), 0); +	clk_register_clkdev(clk, "usb", "musb-ux500.0"); +	clk_register_clkdev(clk, "usbclk", "ab-iddet.0"); + +	clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base, +				BIT(1), 0); +	clk_register_clkdev(clk, NULL, "gpio.8"); +	clk_register_clkdev(clk, NULL, "gpioblock3"); + +	/* Peripheral 6 : PRCC P-clocks */ +	clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base, +				BIT(0), 0); +	clk_register_clkdev(clk, "apb_pclk", "rng"); + +	clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base, +				BIT(1), 0); +	clk_register_clkdev(clk, NULL, "cryp0"); +	clk_register_clkdev(clk, NULL, "cryp1"); + +	clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base, +				BIT(2), 0); +	clk_register_clkdev(clk, NULL, "hash0"); + +	clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base, +				BIT(3), 0); +	clk_register_clkdev(clk, NULL, "pka"); + +	clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base, +				BIT(4), 0); +	clk_register_clkdev(clk, NULL, "db8540-hash1"); + +	clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base, +				BIT(5), 0); +	clk_register_clkdev(clk, NULL, "cfgreg"); + +	clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base, +				BIT(6), 0); +	clk_register_clkdev(clk, "apb_pclk", "mtu0"); + +	clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base, +				BIT(7), 0); +	clk_register_clkdev(clk, "apb_pclk", "mtu1"); + +	/* +	 * PRCC K-clocks  ==> see table PRCC_PCKEN/PRCC_KCKEN +	 * This differs from the internal implementation: +	 * We don't use the PERPIH[n| clock as parent, since those _should_ +	 * only be used as parents for the P-clocks. +	 * TODO: "parentjoin" with corresponding P-clocks for all K-clocks. +	 */ + +	/* Peripheral 1 : PRCC K-clocks */ +	clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk", +			clkrst1_base, BIT(0), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "uart0"); + +	clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk", +			clkrst1_base, BIT(1), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "uart1"); + +	clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk", +			clkrst1_base, BIT(2), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.1"); + +	clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk", +			clkrst1_base, BIT(3), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "msp0"); +	clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0"); + +	clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk", +			clkrst1_base, BIT(4), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "msp1"); +	clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1"); + +	clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk", +			clkrst1_base, BIT(5), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi0"); + +	clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk", +			clkrst1_base, BIT(6), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.2"); + +	clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk", +			clkrst1_base, BIT(8), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "slimbus0"); + +	clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk", +			clkrst1_base, BIT(9), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.4"); + +	clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk", +			clkrst1_base, BIT(10), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "msp3"); +	clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3"); + +	/* Peripheral 2 : PRCC K-clocks */ +	clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk", +			clkrst2_base, BIT(0), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.3"); + +	clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k", +			clkrst2_base, BIT(1), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "pwl"); + +	clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk", +			clkrst2_base, BIT(2), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi4"); + +	clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk", +			clkrst2_base, BIT(3), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "msp2"); +	clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2"); + +	clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk", +			clkrst2_base, BIT(4), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi1"); + +	clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk", +			clkrst2_base, BIT(5), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi3"); + +	clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk", +			clkrst2_base, BIT(6), +			CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); +	clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0"); + +	clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk", +			clkrst2_base, BIT(7), +			CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT); +	clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0"); + +	/* Should only be 9540, but might be added for 85xx as well */ +	clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk", +			clkrst2_base, BIT(9), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "msp4"); +	clk_register_clkdev(clk, "msp4", "ab85xx-codec.0"); + +	/* Peripheral 3 : PRCC K-clocks */ +	clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk", +			clkrst3_base, BIT(1), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "ssp0"); + +	clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk", +			clkrst3_base, BIT(2), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "ssp1"); + +	clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk", +			clkrst3_base, BIT(3), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.0"); + +	clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk", +			clkrst3_base, BIT(4), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi2"); + +	clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", +			clkrst3_base, BIT(5), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "ske"); +	clk_register_clkdev(clk, NULL, "nmk-ske-keypad"); + +	clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", +			clkrst3_base, BIT(6), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "uart2"); + +	clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk", +			clkrst3_base, BIT(7), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "sdi5"); + +	clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk", +			clkrst3_base, BIT(8), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.5"); + +	clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk", +			clkrst3_base, BIT(9), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "nmk-i2c.6"); + +	clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk", +			clkrst3_base, BIT(10), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "uart3"); + +	clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk", +			clkrst3_base, BIT(11), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "uart4"); + +	/* Peripheral 6 : PRCC K-clocks */ +	clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk", +			clkrst6_base, BIT(0), CLK_SET_RATE_GATE); +	clk_register_clkdev(clk, NULL, "rng");  } diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c index dbc0191e16c8..44794782e7e0 100644 --- a/drivers/clk/ux500/u9540_clk.c +++ b/drivers/clk/ux500/u9540_clk.c @@ -12,10 +12,10 @@  #include <linux/clk-provider.h>  #include <linux/mfd/dbx500-prcmu.h>  #include <linux/platform_data/clk-ux500.h> -  #include "clk.h" -void u9540_clk_init(void) +void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base, +		    u32 clkrst5_base, u32 clkrst6_base)  {  	/* register clocks here */  } diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index 256c8be74df8..2dc8b41a339d 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -107,7 +107,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)  	osc->func = vexpress_config_func_get_by_node(node);  	if (!osc->func) {  		pr_err("Failed to obtain config func for node '%s'!\n", -				node->name); +				node->full_name);  		goto error;  	} @@ -119,7 +119,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)  	of_property_read_string(node, "clock-output-names", &init.name);  	if (!init.name) -		init.name = node->name; +		init.name = node->full_name;  	init.ops = &vexpress_osc_ops;  	init.flags = CLK_IS_ROOT; diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c index 4f45eee9e33b..812f83f8b0c6 100644 --- a/drivers/clk/x86/clk-lpt.c +++ b/drivers/clk/x86/clk-lpt.c @@ -1,5 +1,5 @@  /* - * Intel Lynxpoint LPSS clocks. + * Intel Low Power Subsystem clocks.   *   * Copyright (C) 2013, Intel Corporation   * Authors: Mika Westerberg <[email protected]> @@ -18,8 +18,6 @@  #include <linux/platform_data/clk-lpss.h>  #include <linux/platform_device.h> -#define PRV_CLOCK_PARAMS 0x800 -  static int lpt_clk_probe(struct platform_device *pdev)  {  	struct lpss_clk_data *drvdata; diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile new file mode 100644 index 000000000000..156d923f4fa9 --- /dev/null +++ b/drivers/clk/zynq/Makefile @@ -0,0 +1,3 @@ +# Zynq clock specific Makefile + +obj-$(CONFIG_ARCH_ZYNQ)	+= clkc.o pll.o diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c new file mode 100644 index 000000000000..5c205b60a82a --- /dev/null +++ b/drivers/clk/zynq/clkc.c @@ -0,0 +1,533 @@ +/* + * Zynq clock controller + * + *  Copyright (C) 2012 - 2013 Xilinx + * + *  Sören Brinkmann <[email protected]> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk/zynq.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/io.h> + +static void __iomem *zynq_slcr_base_priv; + +#define SLCR_ARMPLL_CTRL		(zynq_slcr_base_priv + 0x100) +#define SLCR_DDRPLL_CTRL		(zynq_slcr_base_priv + 0x104) +#define SLCR_IOPLL_CTRL			(zynq_slcr_base_priv + 0x108) +#define SLCR_PLL_STATUS			(zynq_slcr_base_priv + 0x10c) +#define SLCR_ARM_CLK_CTRL		(zynq_slcr_base_priv + 0x120) +#define SLCR_DDR_CLK_CTRL		(zynq_slcr_base_priv + 0x124) +#define SLCR_DCI_CLK_CTRL		(zynq_slcr_base_priv + 0x128) +#define SLCR_APER_CLK_CTRL		(zynq_slcr_base_priv + 0x12c) +#define SLCR_GEM0_CLK_CTRL		(zynq_slcr_base_priv + 0x140) +#define SLCR_GEM1_CLK_CTRL		(zynq_slcr_base_priv + 0x144) +#define SLCR_SMC_CLK_CTRL		(zynq_slcr_base_priv + 0x148) +#define SLCR_LQSPI_CLK_CTRL		(zynq_slcr_base_priv + 0x14c) +#define SLCR_SDIO_CLK_CTRL		(zynq_slcr_base_priv + 0x150) +#define SLCR_UART_CLK_CTRL		(zynq_slcr_base_priv + 0x154) +#define SLCR_SPI_CLK_CTRL		(zynq_slcr_base_priv + 0x158) +#define SLCR_CAN_CLK_CTRL		(zynq_slcr_base_priv + 0x15c) +#define SLCR_CAN_MIOCLK_CTRL		(zynq_slcr_base_priv + 0x160) +#define SLCR_DBG_CLK_CTRL		(zynq_slcr_base_priv + 0x164) +#define SLCR_PCAP_CLK_CTRL		(zynq_slcr_base_priv + 0x168) +#define SLCR_FPGA0_CLK_CTRL		(zynq_slcr_base_priv + 0x170) +#define SLCR_621_TRUE			(zynq_slcr_base_priv + 0x1c4) +#define SLCR_SWDT_CLK_SEL		(zynq_slcr_base_priv + 0x304) + +#define NUM_MIO_PINS	54 + +enum zynq_clk { +	armpll, ddrpll, iopll, +	cpu_6or4x, cpu_3or2x, cpu_2x, cpu_1x, +	ddr2x, ddr3x, dci, +	lqspi, smc, pcap, gem0, gem1, fclk0, fclk1, fclk2, fclk3, can0, can1, +	sdio0, sdio1, uart0, uart1, spi0, spi1, dma, +	usb0_aper, usb1_aper, gem0_aper, gem1_aper, +	sdio0_aper, sdio1_aper, spi0_aper, spi1_aper, can0_aper, can1_aper, +	i2c0_aper, i2c1_aper, uart0_aper, uart1_aper, gpio_aper, lqspi_aper, +	smc_aper, swdt, dbg_trc, dbg_apb, clk_max}; + +static struct clk *ps_clk; +static struct clk *clks[clk_max]; +static struct clk_onecell_data clk_data; + +static DEFINE_SPINLOCK(armpll_lock); +static DEFINE_SPINLOCK(ddrpll_lock); +static DEFINE_SPINLOCK(iopll_lock); +static DEFINE_SPINLOCK(armclk_lock); +static DEFINE_SPINLOCK(ddrclk_lock); +static DEFINE_SPINLOCK(dciclk_lock); +static DEFINE_SPINLOCK(gem0clk_lock); +static DEFINE_SPINLOCK(gem1clk_lock); +static DEFINE_SPINLOCK(canclk_lock); +static DEFINE_SPINLOCK(canmioclk_lock); +static DEFINE_SPINLOCK(dbgclk_lock); +static DEFINE_SPINLOCK(aperclk_lock); + +static const char dummy_nm[] __initconst = "dummy_name"; + +static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"}; +static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"}; +static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"}; +static const char *gem0_mux_parents[] __initdata = {"gem0_div1", dummy_nm}; +static const char *gem1_mux_parents[] __initdata = {"gem1_div1", dummy_nm}; +static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate", +	"can0_mio_mux"}; +static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate", +	"can1_mio_mux"}; +static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div", +	dummy_nm}; + +static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"}; +static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"}; +static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"}; +static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; + +static void __init zynq_clk_register_fclk(enum zynq_clk fclk, +		const char *clk_name, void __iomem *fclk_ctrl_reg, +		const char **parents) +{ +	struct clk *clk; +	char *mux_name; +	char *div0_name; +	char *div1_name; +	spinlock_t *fclk_lock; +	spinlock_t *fclk_gate_lock; +	void __iomem *fclk_gate_reg = fclk_ctrl_reg + 8; + +	fclk_lock = kmalloc(sizeof(*fclk_lock), GFP_KERNEL); +	if (!fclk_lock) +		goto err; +	fclk_gate_lock = kmalloc(sizeof(*fclk_gate_lock), GFP_KERNEL); +	if (!fclk_gate_lock) +		goto err; +	spin_lock_init(fclk_lock); +	spin_lock_init(fclk_gate_lock); + +	mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name); +	div0_name = kasprintf(GFP_KERNEL, "%s_div0", clk_name); +	div1_name = kasprintf(GFP_KERNEL, "%s_div1", clk_name); + +	clk = clk_register_mux(NULL, mux_name, parents, 4, 0, +			fclk_ctrl_reg, 4, 2, 0, fclk_lock); + +	clk = clk_register_divider(NULL, div0_name, mux_name, +			0, fclk_ctrl_reg, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, fclk_lock); + +	clk = clk_register_divider(NULL, div1_name, div0_name, +			CLK_SET_RATE_PARENT, fclk_ctrl_reg, 20, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			fclk_lock); + +	clks[fclk] = clk_register_gate(NULL, clk_name, +			div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, +			0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); +	kfree(mux_name); +	kfree(div0_name); +	kfree(div1_name); + +	return; + +err: +	clks[fclk] = ERR_PTR(-ENOMEM); +} + +static void __init zynq_clk_register_periph_clk(enum zynq_clk clk0, +		enum zynq_clk clk1, const char *clk_name0, +		const char *clk_name1, void __iomem *clk_ctrl, +		const char **parents, unsigned int two_gates) +{ +	struct clk *clk; +	char *mux_name; +	char *div_name; +	spinlock_t *lock; + +	lock = kmalloc(sizeof(*lock), GFP_KERNEL); +	if (!lock) +		goto err; +	spin_lock_init(lock); + +	mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name0); +	div_name = kasprintf(GFP_KERNEL, "%s_div", clk_name0); + +	clk = clk_register_mux(NULL, mux_name, parents, 4, 0, +			clk_ctrl, 4, 2, 0, lock); + +	clk = clk_register_divider(NULL, div_name, mux_name, 0, clk_ctrl, 8, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, lock); + +	clks[clk0] = clk_register_gate(NULL, clk_name0, div_name, +			CLK_SET_RATE_PARENT, clk_ctrl, 0, 0, lock); +	if (two_gates) +		clks[clk1] = clk_register_gate(NULL, clk_name1, div_name, +				CLK_SET_RATE_PARENT, clk_ctrl, 1, 0, lock); + +	kfree(mux_name); +	kfree(div_name); + +	return; + +err: +	clks[clk0] = ERR_PTR(-ENOMEM); +	if (two_gates) +		clks[clk1] = ERR_PTR(-ENOMEM); +} + +static void __init zynq_clk_setup(struct device_node *np) +{ +	int i; +	u32 tmp; +	int ret; +	struct clk *clk; +	char *clk_name; +	const char *clk_output_name[clk_max]; +	const char *cpu_parents[4]; +	const char *periph_parents[4]; +	const char *swdt_ext_clk_mux_parents[2]; +	const char *can_mio_mux_parents[NUM_MIO_PINS]; + +	pr_info("Zynq clock init\n"); + +	/* get clock output names from DT */ +	for (i = 0; i < clk_max; i++) { +		if (of_property_read_string_index(np, "clock-output-names", +				  i, &clk_output_name[i])) { +			pr_err("%s: clock output name not in DT\n", __func__); +			BUG(); +		} +	} +	cpu_parents[0] = clk_output_name[armpll]; +	cpu_parents[1] = clk_output_name[armpll]; +	cpu_parents[2] = clk_output_name[ddrpll]; +	cpu_parents[3] = clk_output_name[iopll]; +	periph_parents[0] = clk_output_name[iopll]; +	periph_parents[1] = clk_output_name[iopll]; +	periph_parents[2] = clk_output_name[armpll]; +	periph_parents[3] = clk_output_name[ddrpll]; + +	/* ps_clk */ +	ret = of_property_read_u32(np, "ps-clk-frequency", &tmp); +	if (ret) { +		pr_warn("ps_clk frequency not specified, using 33 MHz.\n"); +		tmp = 33333333; +	} +	ps_clk = clk_register_fixed_rate(NULL, "ps_clk", NULL, CLK_IS_ROOT, +			tmp); + +	/* PLLs */ +	clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL, +			SLCR_PLL_STATUS, 0, &armpll_lock); +	clks[armpll] = clk_register_mux(NULL, clk_output_name[armpll], +			armpll_parents, 2, 0, SLCR_ARMPLL_CTRL, 4, 1, 0, +			&armpll_lock); + +	clk = clk_register_zynq_pll("ddrpll_int", "ps_clk", SLCR_DDRPLL_CTRL, +			SLCR_PLL_STATUS, 1, &ddrpll_lock); +	clks[ddrpll] = clk_register_mux(NULL, clk_output_name[ddrpll], +			ddrpll_parents, 2, 0, SLCR_DDRPLL_CTRL, 4, 1, 0, +			&ddrpll_lock); + +	clk = clk_register_zynq_pll("iopll_int", "ps_clk", SLCR_IOPLL_CTRL, +			SLCR_PLL_STATUS, 2, &iopll_lock); +	clks[iopll] = clk_register_mux(NULL, clk_output_name[iopll], +			iopll_parents, 2, 0, SLCR_IOPLL_CTRL, 4, 1, 0, +			&iopll_lock); + +	/* CPU clocks */ +	tmp = readl(SLCR_621_TRUE) & 1; +	clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, 0, +			SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock); +	clk = clk_register_divider(NULL, "cpu_div", "cpu_mux", 0, +			SLCR_ARM_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &armclk_lock); + +	clks[cpu_6or4x] = clk_register_gate(NULL, clk_output_name[cpu_6or4x], +			"cpu_div", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, +			SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock); + +	clk = clk_register_fixed_factor(NULL, "cpu_3or2x_div", "cpu_div", 0, +			1, 2); +	clks[cpu_3or2x] = clk_register_gate(NULL, clk_output_name[cpu_3or2x], +			"cpu_3or2x_div", CLK_IGNORE_UNUSED, +			SLCR_ARM_CLK_CTRL, 25, 0, &armclk_lock); + +	clk = clk_register_fixed_factor(NULL, "cpu_2x_div", "cpu_div", 0, 1, +			2 + tmp); +	clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x], +			"cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, +			26, 0, &armclk_lock); + +	clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1, +			4 + 2 * tmp); +	clks[cpu_1x] = clk_register_gate(NULL, clk_output_name[cpu_1x], +			"cpu_1x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 27, +			0, &armclk_lock); + +	/* Timers */ +	swdt_ext_clk_mux_parents[0] = clk_output_name[cpu_1x]; +	for (i = 0; i < ARRAY_SIZE(swdt_ext_clk_input_names); i++) { +		int idx = of_property_match_string(np, "clock-names", +				swdt_ext_clk_input_names[i]); +		if (idx >= 0) +			swdt_ext_clk_mux_parents[i + 1] = +				of_clk_get_parent_name(np, idx); +		else +			swdt_ext_clk_mux_parents[i + 1] = dummy_nm; +	} +	clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt], +			swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT, +			SLCR_SWDT_CLK_SEL, 0, 1, 0, &gem0clk_lock); + +	/* DDR clocks */ +	clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0, +			SLCR_DDR_CLK_CTRL, 26, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock); +	clks[ddr2x] = clk_register_gate(NULL, clk_output_name[ddr2x], +			"ddr2x_div", 0, SLCR_DDR_CLK_CTRL, 1, 0, &ddrclk_lock); +	clk_prepare_enable(clks[ddr2x]); +	clk = clk_register_divider(NULL, "ddr3x_div", "ddrpll", 0, +			SLCR_DDR_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock); +	clks[ddr3x] = clk_register_gate(NULL, clk_output_name[ddr3x], +			"ddr3x_div", 0, SLCR_DDR_CLK_CTRL, 0, 0, &ddrclk_lock); +	clk_prepare_enable(clks[ddr3x]); + +	clk = clk_register_divider(NULL, "dci_div0", "ddrpll", 0, +			SLCR_DCI_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &dciclk_lock); +	clk = clk_register_divider(NULL, "dci_div1", "dci_div0", +			CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 20, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			&dciclk_lock); +	clks[dci] = clk_register_gate(NULL, clk_output_name[dci], "dci_div1", +			CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 0, 0, +			&dciclk_lock); +	clk_prepare_enable(clks[dci]); + +	/* Peripheral clocks */ +	for (i = fclk0; i <= fclk3; i++) +		zynq_clk_register_fclk(i, clk_output_name[i], +				SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0), +				periph_parents); + +	zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL, +			SLCR_LQSPI_CLK_CTRL, periph_parents, 0); + +	zynq_clk_register_periph_clk(smc, 0, clk_output_name[smc], NULL, +			SLCR_SMC_CLK_CTRL, periph_parents, 0); + +	zynq_clk_register_periph_clk(pcap, 0, clk_output_name[pcap], NULL, +			SLCR_PCAP_CLK_CTRL, periph_parents, 0); + +	zynq_clk_register_periph_clk(sdio0, sdio1, clk_output_name[sdio0], +			clk_output_name[sdio1], SLCR_SDIO_CLK_CTRL, +			periph_parents, 1); + +	zynq_clk_register_periph_clk(uart0, uart1, clk_output_name[uart0], +			clk_output_name[uart1], SLCR_UART_CLK_CTRL, +			periph_parents, 1); + +	zynq_clk_register_periph_clk(spi0, spi1, clk_output_name[spi0], +			clk_output_name[spi1], SLCR_SPI_CLK_CTRL, +			periph_parents, 1); + +	for (i = 0; i < ARRAY_SIZE(gem0_emio_input_names); i++) { +		int idx = of_property_match_string(np, "clock-names", +				gem0_emio_input_names[i]); +		if (idx >= 0) +			gem0_mux_parents[i + 1] = of_clk_get_parent_name(np, +					idx); +	} +	clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4, 0, +			SLCR_GEM0_CLK_CTRL, 4, 2, 0, &gem0clk_lock); +	clk = clk_register_divider(NULL, "gem0_div0", "gem0_mux", 0, +			SLCR_GEM0_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock); +	clk = clk_register_divider(NULL, "gem0_div1", "gem0_div0", +			CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			&gem0clk_lock); +	clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, 0, +			SLCR_GEM0_CLK_CTRL, 6, 1, 0, &gem0clk_lock); +	clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0], +			"gem0_emio_mux", CLK_SET_RATE_PARENT, +			SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock); + +	for (i = 0; i < ARRAY_SIZE(gem1_emio_input_names); i++) { +		int idx = of_property_match_string(np, "clock-names", +				gem1_emio_input_names[i]); +		if (idx >= 0) +			gem1_mux_parents[i + 1] = of_clk_get_parent_name(np, +					idx); +	} +	clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4, 0, +			SLCR_GEM1_CLK_CTRL, 4, 2, 0, &gem1clk_lock); +	clk = clk_register_divider(NULL, "gem1_div0", "gem1_mux", 0, +			SLCR_GEM1_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock); +	clk = clk_register_divider(NULL, "gem1_div1", "gem1_div0", +			CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			&gem1clk_lock); +	clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, 0, +			SLCR_GEM1_CLK_CTRL, 6, 1, 0, &gem1clk_lock); +	clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1], +			"gem1_emio_mux", CLK_SET_RATE_PARENT, +			SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock); + +	tmp = strlen("mio_clk_00x"); +	clk_name = kmalloc(tmp, GFP_KERNEL); +	for (i = 0; i < NUM_MIO_PINS; i++) { +		int idx; + +		snprintf(clk_name, tmp, "mio_clk_%2.2d", i); +		idx = of_property_match_string(np, "clock-names", clk_name); +		if (idx >= 0) +			can_mio_mux_parents[i] = of_clk_get_parent_name(np, +						idx); +		else +			can_mio_mux_parents[i] = dummy_nm; +	} +	kfree(clk_name); +	clk = clk_register_mux(NULL, "can_mux", periph_parents, 4, 0, +			SLCR_CAN_CLK_CTRL, 4, 2, 0, &canclk_lock); +	clk = clk_register_divider(NULL, "can_div0", "can_mux", 0, +			SLCR_CAN_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &canclk_lock); +	clk = clk_register_divider(NULL, "can_div1", "can_div0", +			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 20, 6, +			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, +			&canclk_lock); +	clk = clk_register_gate(NULL, "can0_gate", "can_div1", +			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 0, 0, +			&canclk_lock); +	clk = clk_register_gate(NULL, "can1_gate", "can_div1", +			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 1, 0, +			&canclk_lock); +	clk = clk_register_mux(NULL, "can0_mio_mux", +			can_mio_mux_parents, 54, CLK_SET_RATE_PARENT, +			SLCR_CAN_MIOCLK_CTRL, 0, 6, 0, &canmioclk_lock); +	clk = clk_register_mux(NULL, "can1_mio_mux", +			can_mio_mux_parents, 54, CLK_SET_RATE_PARENT, +			SLCR_CAN_MIOCLK_CTRL, 16, 6, 0, &canmioclk_lock); +	clks[can0] = clk_register_mux(NULL, clk_output_name[can0], +			can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT, +			SLCR_CAN_MIOCLK_CTRL, 6, 1, 0, &canmioclk_lock); +	clks[can1] = clk_register_mux(NULL, clk_output_name[can1], +			can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT, +			SLCR_CAN_MIOCLK_CTRL, 22, 1, 0, &canmioclk_lock); + +	for (i = 0; i < ARRAY_SIZE(dbgtrc_emio_input_names); i++) { +		int idx = of_property_match_string(np, "clock-names", +				dbgtrc_emio_input_names[i]); +		if (idx >= 0) +			dbg_emio_mux_parents[i + 1] = of_clk_get_parent_name(np, +					idx); +	} +	clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4, 0, +			SLCR_DBG_CLK_CTRL, 4, 2, 0, &dbgclk_lock); +	clk = clk_register_divider(NULL, "dbg_div", "dbg_mux", 0, +			SLCR_DBG_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED | +			CLK_DIVIDER_ALLOW_ZERO, &dbgclk_lock); +	clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2, 0, +			SLCR_DBG_CLK_CTRL, 6, 1, 0, &dbgclk_lock); +	clks[dbg_trc] = clk_register_gate(NULL, clk_output_name[dbg_trc], +			"dbg_emio_mux", CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL, +			0, 0, &dbgclk_lock); +	clks[dbg_apb] = clk_register_gate(NULL, clk_output_name[dbg_apb], +			clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0, +			&dbgclk_lock); + +	/* One gated clock for all APER clocks. */ +	clks[dma] = clk_register_gate(NULL, clk_output_name[dma], +			clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0, +			&aperclk_lock); +	clks[usb0_aper] = clk_register_gate(NULL, clk_output_name[usb0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 2, 0, +			&aperclk_lock); +	clks[usb1_aper] = clk_register_gate(NULL, clk_output_name[usb1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 3, 0, +			&aperclk_lock); +	clks[gem0_aper] = clk_register_gate(NULL, clk_output_name[gem0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 6, 0, +			&aperclk_lock); +	clks[gem1_aper] = clk_register_gate(NULL, clk_output_name[gem1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 7, 0, +			&aperclk_lock); +	clks[sdio0_aper] = clk_register_gate(NULL, clk_output_name[sdio0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 10, 0, +			&aperclk_lock); +	clks[sdio1_aper] = clk_register_gate(NULL, clk_output_name[sdio1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 11, 0, +			&aperclk_lock); +	clks[spi0_aper] = clk_register_gate(NULL, clk_output_name[spi0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 14, 0, +			&aperclk_lock); +	clks[spi1_aper] = clk_register_gate(NULL, clk_output_name[spi1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 15, 0, +			&aperclk_lock); +	clks[can0_aper] = clk_register_gate(NULL, clk_output_name[can0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 16, 0, +			&aperclk_lock); +	clks[can1_aper] = clk_register_gate(NULL, clk_output_name[can1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 17, 0, +			&aperclk_lock); +	clks[i2c0_aper] = clk_register_gate(NULL, clk_output_name[i2c0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 18, 0, +			&aperclk_lock); +	clks[i2c1_aper] = clk_register_gate(NULL, clk_output_name[i2c1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 19, 0, +			&aperclk_lock); +	clks[uart0_aper] = clk_register_gate(NULL, clk_output_name[uart0_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 20, 0, +			&aperclk_lock); +	clks[uart1_aper] = clk_register_gate(NULL, clk_output_name[uart1_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 21, 0, +			&aperclk_lock); +	clks[gpio_aper] = clk_register_gate(NULL, clk_output_name[gpio_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 22, 0, +			&aperclk_lock); +	clks[lqspi_aper] = clk_register_gate(NULL, clk_output_name[lqspi_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 23, 0, +			&aperclk_lock); +	clks[smc_aper] = clk_register_gate(NULL, clk_output_name[smc_aper], +			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 24, 0, +			&aperclk_lock); + +	for (i = 0; i < ARRAY_SIZE(clks); i++) { +		if (IS_ERR(clks[i])) { +			pr_err("Zynq clk %d: register failed with %ld\n", +			       i, PTR_ERR(clks[i])); +			BUG(); +		} +	} + +	clk_data.clks = clks; +	clk_data.clk_num = ARRAY_SIZE(clks); +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +CLK_OF_DECLARE(zynq_clkc, "xlnx,ps7-clkc", zynq_clk_setup); + +void __init zynq_clock_init(void __iomem *slcr_base) +{ +	zynq_slcr_base_priv = slcr_base; +	of_clk_init(NULL); +} diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c new file mode 100644 index 000000000000..47e307c25a7b --- /dev/null +++ b/drivers/clk/zynq/pll.c @@ -0,0 +1,235 @@ +/* + * Zynq PLL driver + * + *  Copyright (C) 2013 Xilinx + * + *  Sören Brinkmann <[email protected]> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + * + */ +#include <linux/clk/zynq.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> + +/** + * struct zynq_pll + * @hw:		Handle between common and hardware-specific interfaces + * @pll_ctrl:	PLL control register + * @pll_status:	PLL status register + * @lock:	Register lock + * @lockbit:	Indicates the associated PLL_LOCKED bit in the PLL status + *		register. + */ +struct zynq_pll { +	struct clk_hw	hw; +	void __iomem	*pll_ctrl; +	void __iomem	*pll_status; +	spinlock_t	*lock; +	u8		lockbit; +}; +#define to_zynq_pll(_hw)	container_of(_hw, struct zynq_pll, hw) + +/* Register bitfield defines */ +#define PLLCTRL_FBDIV_MASK	0x7f000 +#define PLLCTRL_FBDIV_SHIFT	12 +#define PLLCTRL_BPQUAL_MASK	(1 << 3) +#define PLLCTRL_PWRDWN_MASK	2 +#define PLLCTRL_PWRDWN_SHIFT	1 +#define PLLCTRL_RESET_MASK	1 +#define PLLCTRL_RESET_SHIFT	0 + +/** + * zynq_pll_round_rate() - Round a clock frequency + * @hw:		Handle between common and hardware-specific interfaces + * @rate:	Desired clock frequency + * @prate:	Clock frequency of parent clock + * Returns frequency closest to @rate the hardware can generate. + */ +static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate, +		unsigned long *prate) +{ +	u32 fbdiv; + +	fbdiv = DIV_ROUND_CLOSEST(rate, *prate); +	if (fbdiv < 13) +		fbdiv = 13; +	else if (fbdiv > 66) +		fbdiv = 66; + +	return *prate * fbdiv; +} + +/** + * zynq_pll_recalc_rate() - Recalculate clock frequency + * @hw:			Handle between common and hardware-specific interfaces + * @parent_rate:	Clock frequency of parent clock + * Returns current clock frequency. + */ +static unsigned long zynq_pll_recalc_rate(struct clk_hw *hw, +		unsigned long parent_rate) +{ +	struct zynq_pll *clk = to_zynq_pll(hw); +	u32 fbdiv; + +	/* +	 * makes probably sense to redundantly save fbdiv in the struct +	 * zynq_pll to save the IO access. +	 */ +	fbdiv = (readl(clk->pll_ctrl) & PLLCTRL_FBDIV_MASK) >> +			PLLCTRL_FBDIV_SHIFT; + +	return parent_rate * fbdiv; +} + +/** + * zynq_pll_is_enabled - Check if a clock is enabled + * @hw:		Handle between common and hardware-specific interfaces + * Returns 1 if the clock is enabled, 0 otherwise. + * + * Not sure this is a good idea, but since disabled means bypassed for + * this clock implementation we say we are always enabled. + */ +static int zynq_pll_is_enabled(struct clk_hw *hw) +{ +	unsigned long flags = 0; +	u32 reg; +	struct zynq_pll *clk = to_zynq_pll(hw); + +	spin_lock_irqsave(clk->lock, flags); + +	reg = readl(clk->pll_ctrl); + +	spin_unlock_irqrestore(clk->lock, flags); + +	return !(reg & (PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK)); +} + +/** + * zynq_pll_enable - Enable clock + * @hw:		Handle between common and hardware-specific interfaces + * Returns 0 on success + */ +static int zynq_pll_enable(struct clk_hw *hw) +{ +	unsigned long flags = 0; +	u32 reg; +	struct zynq_pll *clk = to_zynq_pll(hw); + +	if (zynq_pll_is_enabled(hw)) +		return 0; + +	pr_info("PLL: enable\n"); + +	/* Power up PLL and wait for lock */ +	spin_lock_irqsave(clk->lock, flags); + +	reg = readl(clk->pll_ctrl); +	reg &= ~(PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK); +	writel(reg, clk->pll_ctrl); +	while (!(readl(clk->pll_status) & (1 << clk->lockbit))) +		; + +	spin_unlock_irqrestore(clk->lock, flags); + +	return 0; +} + +/** + * zynq_pll_disable - Disable clock + * @hw:		Handle between common and hardware-specific interfaces + * Returns 0 on success + */ +static void zynq_pll_disable(struct clk_hw *hw) +{ +	unsigned long flags = 0; +	u32 reg; +	struct zynq_pll *clk = to_zynq_pll(hw); + +	if (!zynq_pll_is_enabled(hw)) +		return; + +	pr_info("PLL: shutdown\n"); + +	/* shut down PLL */ +	spin_lock_irqsave(clk->lock, flags); + +	reg = readl(clk->pll_ctrl); +	reg |= PLLCTRL_RESET_MASK | PLLCTRL_PWRDWN_MASK; +	writel(reg, clk->pll_ctrl); + +	spin_unlock_irqrestore(clk->lock, flags); +} + +static const struct clk_ops zynq_pll_ops = { +	.enable = zynq_pll_enable, +	.disable = zynq_pll_disable, +	.is_enabled = zynq_pll_is_enabled, +	.round_rate = zynq_pll_round_rate, +	.recalc_rate = zynq_pll_recalc_rate +}; + +/** + * clk_register_zynq_pll() - Register PLL with the clock framework + * @np	Pointer to the DT device node + */ +struct clk *clk_register_zynq_pll(const char *name, const char *parent, +		void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index, +		spinlock_t *lock) +{ +	struct zynq_pll *pll; +	struct clk *clk; +	u32 reg; +	const char *parent_arr[1] = {parent}; +	unsigned long flags = 0; +	struct clk_init_data initd = { +		.name = name, +		.parent_names = parent_arr, +		.ops = &zynq_pll_ops, +		.num_parents = 1, +		.flags = 0 +	}; + +	pll = kmalloc(sizeof(*pll), GFP_KERNEL); +	if (!pll) { +		pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__); +		return ERR_PTR(-ENOMEM); +	} + +	/* Populate the struct */ +	pll->hw.init = &initd; +	pll->pll_ctrl = pll_ctrl; +	pll->pll_status = pll_status; +	pll->lockbit = lock_index; +	pll->lock = lock; + +	spin_lock_irqsave(pll->lock, flags); + +	reg = readl(pll->pll_ctrl); +	reg &= ~PLLCTRL_BPQUAL_MASK; +	writel(reg, pll->pll_ctrl); + +	spin_unlock_irqrestore(pll->lock, flags); + +	clk = clk_register(NULL, &pll->hw); +	if (WARN_ON(IS_ERR(clk))) +		goto free_pll; + +	return clk; + +free_pll: +	kfree(pll); + +	return clk; +} |