diff options
Diffstat (limited to 'drivers/clk')
49 files changed, 3553 insertions, 376 deletions
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 62e2509f9df1..bbdb1b985c91 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -57,7 +57,7 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, static long clk_programmable_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_hw) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -84,7 +84,7 @@ static long clk_programmable_determine_rate(struct clk_hw *hw, if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) { best_rate = tmp_rate; *best_parent_rate = parent_rate; - *best_parent_clk = parent; + *best_parent_hw = __clk_get_hw(parent); } if (!best_rate) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 24b5b020753a..a23ac0c724f0 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -52,29 +52,26 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, tmp = pmc_read(pmc, AT91_PMC_USB); usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; - return parent_rate / (usbdiv + 1); + + return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); } static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { unsigned long div; - unsigned long bestrate; - unsigned long tmp; + + if (!rate) + return -EINVAL; if (rate >= *parent_rate) return *parent_rate; - div = *parent_rate / rate; - if (div >= SAM9X5_USB_MAX_DIV) - return *parent_rate / (SAM9X5_USB_MAX_DIV + 1); - - bestrate = *parent_rate / div; - tmp = *parent_rate / (div + 1); - if (bestrate - rate > rate - tmp) - bestrate = tmp; + div = DIV_ROUND_CLOSEST(*parent_rate, rate); + if (div > SAM9X5_USB_MAX_DIV + 1) + div = SAM9X5_USB_MAX_DIV + 1; - return bestrate; + return DIV_ROUND_CLOSEST(*parent_rate, div); } static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) @@ -106,9 +103,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, u32 tmp; struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); struct at91_pmc *pmc = usb->pmc; - unsigned long div = parent_rate / rate; + unsigned long div; + + if (!rate) + return -EINVAL; - if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV) + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > SAM9X5_USB_MAX_DIV + 1 || !div) return -EINVAL; tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; @@ -253,7 +254,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, tmp_parent_rate = rate * usb->divisors[i]; tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); - tmprate = tmp_parent_rate / usb->divisors[i]; + tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]); if (tmprate < rate) tmpdiff = rate - tmprate; else @@ -281,10 +282,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, struct at91_pmc *pmc = usb->pmc; unsigned long div; - if (!rate || parent_rate % rate) + if (!rate) return -EINVAL; - div = parent_rate / rate; + div = DIV_ROUND_CLOSEST(parent_rate, rate); for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { if (usb->divisors[i] == div) { diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 95af2e665dd3..1c06f6f3a8c5 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1032,7 +1032,7 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, } static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, struct clk **best_parent) + unsigned long *best_parent_rate, struct clk_hw **best_parent) { struct kona_clk *bcm_clk = to_kona_clk(hw); struct clk *clk = hw->clk; @@ -1075,7 +1075,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, if (delta < best_delta) { best_delta = delta; best_rate = other_rate; - *best_parent = parent; + *best_parent = __clk_get_hw(parent); *best_parent_rate = parent_rate; } } diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index b9355daf8065..4386697236a7 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -57,7 +57,7 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; @@ -80,8 +80,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, *best_parent_p = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { - *best_parent_p = clk_get_parent(mux_hw->clk); - *best_parent_rate = __clk_get_rate(*best_parent_p); + parent = clk_get_parent(mux_hw->clk); + *best_parent_p = __clk_get_hw(parent); + *best_parent_rate = __clk_get_rate(parent); return rate_ops->round_rate(rate_hw, rate, best_parent_rate); @@ -103,7 +104,7 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, if (!rate_diff || !*best_parent_p || best_rate_diff > rate_diff) { - *best_parent_p = parent; + *best_parent_p = __clk_get_hw(parent); *best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 18a9de29df0e..c0a842b335c5 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -263,6 +263,14 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, if (!rate) rate = 1; + /* if read only, just return current value */ + if (divider->flags & CLK_DIVIDER_READ_ONLY) { + bestdiv = readl(divider->reg) >> divider->shift; + bestdiv &= div_mask(divider); + bestdiv = _get_div(divider, bestdiv); + return bestdiv; + } + maxdiv = _get_maxdiv(divider); if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { @@ -361,11 +369,6 @@ const struct clk_ops clk_divider_ops = { }; EXPORT_SYMBOL_GPL(clk_divider_ops); -const struct clk_ops clk_divider_ro_ops = { - .recalc_rate = clk_divider_recalc_rate, -}; -EXPORT_SYMBOL_GPL(clk_divider_ro_ops); - static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, @@ -391,10 +394,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, } init.name = name; - if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) - init.ops = &clk_divider_ro_ops; - else - init.ops = &clk_divider_ops; + init.ops = &clk_divider_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = (parent_name ? &parent_name: NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 4f96ff3ba728..6e1ecf94bf58 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -77,7 +77,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) else { if (mux->flags & CLK_MUX_INDEX_BIT) - index = (1 << ffs(index)); + index = 1 << index; if (mux->flags & CLK_MUX_INDEX_ONE) index++; diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index b7797fb12e12..4f98898efd3c 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -23,6 +23,7 @@ #include <linux/clk-provider.h> #include <linux/platform_device.h> #include <linux/mfd/samsung/s2mps11.h> +#include <linux/mfd/samsung/s2mps13.h> #include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s5m8767.h> #include <linux/mfd/samsung/core.h> @@ -120,6 +121,24 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = { }, }; +static struct clk_init_data s2mps13_clks_init[S2MPS11_CLKS_NUM] = { + [S2MPS11_CLK_AP] = { + .name = "s2mps13_ap", + .ops = &s2mps11_clk_ops, + .flags = CLK_IS_ROOT, + }, + [S2MPS11_CLK_CP] = { + .name = "s2mps13_cp", + .ops = &s2mps11_clk_ops, + .flags = CLK_IS_ROOT, + }, + [S2MPS11_CLK_BT] = { + .name = "s2mps13_bt", + .ops = &s2mps11_clk_ops, + .flags = CLK_IS_ROOT, + }, +}; + static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = { [S2MPS11_CLK_AP] = { .name = "s2mps14_ap", @@ -184,6 +203,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev) s2mps11_reg = S2MPS11_REG_RTC_CTRL; clks_init = s2mps11_clks_init; break; + case S2MPS13X: + s2mps11_reg = S2MPS13_REG_RTCCTRL; + clks_init = s2mps13_clks_init; + break; case S2MPS14X: s2mps11_reg = S2MPS14_REG_RTCCTRL; clks_init = s2mps14_clks_init; @@ -195,7 +218,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "Invalid device type\n"); return -EINVAL; - }; + } /* Store clocks of_node in first element of s2mps11_clks array */ s2mps11_clks->clk_np = s2mps11_clk_parse_dt(pdev, clks_init); @@ -279,6 +302,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev) static const struct platform_device_id s2mps11_clk_id[] = { { "s2mps11-clk", S2MPS11X}, + { "s2mps13-clk", S2MPS13X}, { "s2mps14-clk", S2MPS14X}, { "s5m8767-clk", S5M8767X}, { }, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 4896ae9e23da..44cdc47a6cc5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -354,13 +354,13 @@ out: mutex_unlock(&clk_debug_lock); } -struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode, +struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode, void *data, const struct file_operations *fops) { struct dentry *d = NULL; - if (clk->dentry) - d = debugfs_create_file(name, mode, clk->dentry, data, fops); + if (hw->clk->dentry) + d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops); return d; } @@ -574,11 +574,6 @@ unsigned int __clk_get_enable_count(struct clk *clk) return !clk ? 0 : clk->enable_count; } -unsigned int __clk_get_prepare_count(struct clk *clk) -{ - return !clk ? 0 : clk->prepare_count; -} - unsigned long __clk_get_rate(struct clk *clk) { unsigned long ret; @@ -601,7 +596,7 @@ out: } EXPORT_SYMBOL_GPL(__clk_get_rate); -unsigned long __clk_get_accuracy(struct clk *clk) +static unsigned long __clk_get_accuracy(struct clk *clk) { if (!clk) return 0; @@ -707,7 +702,7 @@ struct clk *__clk_lookup(const char *name) */ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -743,7 +738,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, out: if (best_parent) - *best_parent_p = best_parent; + *best_parent_p = best_parent->hw; *best_parent_rate = best; return best; @@ -951,6 +946,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { unsigned long parent_rate = 0; struct clk *parent; + struct clk_hw *parent_hw; if (!clk) return 0; @@ -959,10 +955,11 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) if (parent) parent_rate = parent->rate; - if (clk->ops->determine_rate) + if (clk->ops->determine_rate) { + parent_hw = parent ? parent->hw : NULL; return clk->ops->determine_rate(clk->hw, rate, &parent_rate, - &parent); - else if (clk->ops->round_rate) + &parent_hw); + } else if (clk->ops->round_rate) return clk->ops->round_rate(clk->hw, rate, &parent_rate); else if (clk->flags & CLK_SET_RATE_PARENT) return __clk_round_rate(clk->parent, rate); @@ -1350,6 +1347,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) { struct clk *top = clk; struct clk *old_parent, *parent; + struct clk_hw *parent_hw; unsigned long best_parent_rate = 0; unsigned long new_rate; int p_index = 0; @@ -1365,9 +1363,11 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) /* find the closest rate and parent clk/rate */ if (clk->ops->determine_rate) { + parent_hw = parent ? parent->hw : NULL; new_rate = clk->ops->determine_rate(clk->hw, rate, &best_parent_rate, - &parent); + &parent_hw); + parent = parent_hw->clk; } else if (clk->ops->round_rate) { new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); @@ -1614,7 +1614,7 @@ static struct clk *__clk_init_parent(struct clk *clk) if (clk->num_parents == 1) { if (IS_ERR_OR_NULL(clk->parent)) - ret = clk->parent = __clk_lookup(clk->parent_names[0]); + clk->parent = __clk_lookup(clk->parent_names[0]); ret = clk->parent; goto out; } @@ -2273,14 +2273,17 @@ int __clk_get(struct clk *clk) void __clk_put(struct clk *clk) { + struct module *owner; + if (!clk || WARN_ON_ONCE(IS_ERR(clk))) return; clk_prepare_lock(); + owner = clk->owner; kref_put(&clk->ref, __clk_release); clk_prepare_unlock(); - module_put(clk->owner); + module_put(owner); } /*** clk rate change notifiers ***/ diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 339945d2503b..007144f81f50 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -38,44 +38,44 @@ #include "clk.h" /* clock parent list */ -static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", }; -static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", }; -static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", }; -static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", }; -static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", }; -static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", }; -static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", }; -static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", }; -static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", }; -static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", }; -static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", }; -static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", }; -static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", }; -static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", }; -static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", }; -static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; -static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; -static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; +static const char *timer0_mux_p[] __initconst = { "osc32k", "timerclk01", }; +static const char *timer1_mux_p[] __initconst = { "osc32k", "timerclk01", }; +static const char *timer2_mux_p[] __initconst = { "osc32k", "timerclk23", }; +static const char *timer3_mux_p[] __initconst = { "osc32k", "timerclk23", }; +static const char *timer4_mux_p[] __initconst = { "osc32k", "timerclk45", }; +static const char *timer5_mux_p[] __initconst = { "osc32k", "timerclk45", }; +static const char *timer6_mux_p[] __initconst = { "osc32k", "timerclk67", }; +static const char *timer7_mux_p[] __initconst = { "osc32k", "timerclk67", }; +static const char *timer8_mux_p[] __initconst = { "osc32k", "timerclk89", }; +static const char *timer9_mux_p[] __initconst = { "osc32k", "timerclk89", }; +static const char *uart0_mux_p[] __initconst = { "osc26m", "pclk", }; +static const char *uart1_mux_p[] __initconst = { "osc26m", "pclk", }; +static const char *uart2_mux_p[] __initconst = { "osc26m", "pclk", }; +static const char *uart3_mux_p[] __initconst = { "osc26m", "pclk", }; +static const char *uart4_mux_p[] __initconst = { "osc26m", "pclk", }; +static const char *spi0_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", }; +static const char *spi1_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", }; +static const char *spi2_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", }; /* share axi parent */ -static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", }; -static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", }; -static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", }; -static const char *sd_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *mmc1_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", }; -static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4", +static const char *saxi_mux_p[] __initconst = { "armpll3", "armpll2", }; +static const char *pwm0_mux_p[] __initconst = { "osc32k", "osc26m", }; +static const char *pwm1_mux_p[] __initconst = { "osc32k", "osc26m", }; +static const char *sd_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *mmc1_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *mmc1_mux2_p[] __initconst = { "osc26m", "mmc1_div", }; +static const char *g2d_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *venc_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *vdec_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *vpp_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *edc0_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *ldi0_mux_p[] __initconst = { "armpll2", "armpll4", "armpll3", "armpll5", }; -static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4", +static const char *edc1_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *ldi1_mux_p[] __initconst = { "armpll2", "armpll4", "armpll3", "armpll5", }; -static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", }; -static const char *mmc2_mux_p[] __initdata = { "armpll2", "armpll3", }; -static const char *mmc3_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *rclk_hsic_p[] __initconst = { "armpll3", "armpll2", }; +static const char *mmc2_mux_p[] __initconst = { "armpll2", "armpll3", }; +static const char *mmc3_mux_p[] __initconst = { "armpll2", "armpll3", }; /* fixed rate clocks */ @@ -296,7 +296,7 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk_mmc *mclk = to_mmc(hw); unsigned long best = 0; diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 392d78044ce3..3caaf7cc169c 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -2,7 +2,12 @@ # Makefile for mmp specific clk # -obj-y += clk-apbc.o clk-apmu.o clk-frac.o +obj-y += clk-apbc.o clk-apmu.o clk-frac.o clk-mix.o clk-gate.o clk.o + +obj-$(CONFIG_RESET_CONTROLLER) += reset.o + +obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o +obj-$(CONFIG_MACH_MMP2_DT) += clk-of-mmp2.o obj-$(CONFIG_CPU_PXA168) += clk-pxa168.o obj-$(CONFIG_CPU_PXA910) += clk-pxa910.o diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 23a56f561812..584a9927993b 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -22,19 +22,12 @@ * numerator/denominator = Fin / (Fout * factor) */ -#define to_clk_factor(hw) container_of(hw, struct clk_factor, hw) -struct clk_factor { - struct clk_hw hw; - void __iomem *base; - struct clk_factor_masks *masks; - struct clk_factor_tbl *ftbl; - unsigned int ftbl_cnt; -}; +#define to_clk_factor(hw) container_of(hw, struct mmp_clk_factor, hw) static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, unsigned long *prate) { - struct clk_factor *factor = to_clk_factor(hw); + struct mmp_clk_factor *factor = to_clk_factor(hw); unsigned long rate = 0, prev_rate; int i; @@ -58,8 +51,8 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct clk_factor *factor = to_clk_factor(hw); - struct clk_factor_masks *masks = factor->masks; + struct mmp_clk_factor *factor = to_clk_factor(hw); + struct mmp_clk_factor_masks *masks = factor->masks; unsigned int val, num, den; val = readl_relaxed(factor->base); @@ -81,11 +74,12 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) { - struct clk_factor *factor = to_clk_factor(hw); - struct clk_factor_masks *masks = factor->masks; + struct mmp_clk_factor *factor = to_clk_factor(hw); + struct mmp_clk_factor_masks *masks = factor->masks; int i; unsigned long val; unsigned long prev_rate, rate = 0; + unsigned long flags = 0; for (i = 0; i < factor->ftbl_cnt; i++) { prev_rate = rate; @@ -97,6 +91,9 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, if (i > 0) i--; + if (factor->lock) + spin_lock_irqsave(factor->lock, flags); + val = readl_relaxed(factor->base); val &= ~(masks->num_mask << masks->num_shift); @@ -107,21 +104,65 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(val, factor->base); + if (factor->lock) + spin_unlock_irqrestore(factor->lock, flags); + return 0; } +static void clk_factor_init(struct clk_hw *hw) +{ + struct mmp_clk_factor *factor = to_clk_factor(hw); + struct mmp_clk_factor_masks *masks = factor->masks; + u32 val, num, den; + int i; + unsigned long flags = 0; + + if (factor->lock) + spin_lock_irqsave(factor->lock, flags); + + val = readl(factor->base); + + /* calculate numerator */ + num = (val >> masks->num_shift) & masks->num_mask; + + /* calculate denominator */ + den = (val >> masks->den_shift) & masks->den_mask; + + for (i = 0; i < factor->ftbl_cnt; i++) + if (den == factor->ftbl[i].den && num == factor->ftbl[i].num) + break; + + if (i >= factor->ftbl_cnt) { + val &= ~(masks->num_mask << masks->num_shift); + val |= (factor->ftbl[0].num & masks->num_mask) << + masks->num_shift; + + val &= ~(masks->den_mask << masks->den_shift); + val |= (factor->ftbl[0].den & masks->den_mask) << + masks->den_shift; + + writel(val, factor->base); + } + + if (factor->lock) + spin_unlock_irqrestore(factor->lock, flags); +} + static struct clk_ops clk_factor_ops = { .recalc_rate = clk_factor_recalc_rate, .round_rate = clk_factor_round_rate, .set_rate = clk_factor_set_rate, + .init = clk_factor_init, }; struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, unsigned long flags, void __iomem *base, - struct clk_factor_masks *masks, struct clk_factor_tbl *ftbl, - unsigned int ftbl_cnt) + struct mmp_clk_factor_masks *masks, + struct mmp_clk_factor_tbl *ftbl, + unsigned int ftbl_cnt, spinlock_t *lock) { - struct clk_factor *factor; + struct mmp_clk_factor *factor; struct clk_init_data init; struct clk *clk; @@ -142,6 +183,7 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, factor->ftbl = ftbl; factor->ftbl_cnt = ftbl_cnt; factor->hw.init = &init; + factor->lock = lock; init.name = name; init.ops = &clk_factor_ops; diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c new file mode 100644 index 000000000000..adbd9d64ded2 --- /dev/null +++ b/drivers/clk/mmp/clk-gate.c @@ -0,0 +1,133 @@ +/* + * mmp gate clock operation source file + * + * Copyright (C) 2014 Marvell + * Chao Xie <chao.xie@marvell.com> + * + * 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/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/delay.h> + +#include "clk.h" + +/* + * Some clocks will have mutiple bits to enable the clocks, and + * the bits to disable the clock is not same as enabling bits. + */ + +#define to_clk_mmp_gate(hw) container_of(hw, struct mmp_clk_gate, hw) + +static int mmp_clk_gate_enable(struct clk_hw *hw) +{ + struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); + struct clk *clk = hw->clk; + unsigned long flags = 0; + unsigned long rate; + u32 tmp; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + tmp = readl(gate->reg); + tmp &= ~gate->mask; + tmp |= gate->val_enable; + writel(tmp, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + + if (gate->flags & MMP_CLK_GATE_NEED_DELAY) { + rate = __clk_get_rate(clk); + /* Need delay 2 cycles. */ + udelay(2000000/rate); + } + + return 0; +} + +static void mmp_clk_gate_disable(struct clk_hw *hw) +{ + struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); + unsigned long flags = 0; + u32 tmp; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + tmp = readl(gate->reg); + tmp &= ~gate->mask; + tmp |= gate->val_disable; + writel(tmp, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static int mmp_clk_gate_is_enabled(struct clk_hw *hw) +{ + struct mmp_clk_gate *gate = to_clk_mmp_gate(hw); + unsigned long flags = 0; + u32 tmp; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + tmp = readl(gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + + return (tmp & gate->mask) == gate->val_enable; +} + +const struct clk_ops mmp_clk_gate_ops = { + .enable = mmp_clk_gate_enable, + .disable = mmp_clk_gate_disable, + .is_enabled = mmp_clk_gate_is_enabled, +}; + +struct clk *mmp_clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable, + unsigned int gate_flags, spinlock_t *lock) +{ + struct mmp_clk_gate *gate; + struct clk *clk; + struct clk_init_data init; + + /* allocate the gate */ + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + pr_err("%s:%s could not allocate gate clk\n", __func__, name); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &mmp_clk_gate_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->mask = mask; + gate->val_enable = val_enable; + gate->val_disable = val_disable; + gate->flags = gate_flags; + gate->lock = lock; + gate->hw.init = &init; + + clk = clk_register(dev, &gate->hw); + + if (IS_ERR(clk)) + kfree(gate); + + return clk; +} diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c new file mode 100644 index 000000000000..48fa53c7ce5e --- /dev/null +++ b/drivers/clk/mmp/clk-mix.c @@ -0,0 +1,513 @@ +/* + * mmp mix(div and mux) clock operation source file + * + * Copyright (C) 2014 Marvell + * Chao Xie <chao.xie@marvell.com> + * + * 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/clk-provider.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> + +#include "clk.h" + +/* + * The mix clock is a clock combined mux and div type clock. + * Because the div field and mux field need to be set at same + * time, we can not divide it into 2 types of clock + */ + +#define to_clk_mix(hw) container_of(hw, struct mmp_clk_mix, hw) + +static unsigned int _get_maxdiv(struct mmp_clk_mix *mix) +{ + unsigned int div_mask = (1 << mix->reg_info.width_div) - 1; + unsigned int maxdiv = 0; + struct clk_div_table *clkt; + + if (mix->div_flags & CLK_DIVIDER_ONE_BASED) + return div_mask; + if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << div_mask; + if (mix->div_table) { + for (clkt = mix->div_table; clkt->div; clkt++) + if (clkt->div > maxdiv) + maxdiv = clkt->div; + return maxdiv; + } + return div_mask + 1; +} + +static unsigned int _get_div(struct mmp_clk_mix *mix, unsigned int val) +{ + struct clk_div_table *clkt; + + if (mix->div_flags & CLK_DIVIDER_ONE_BASED) + return val; + if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) + return 1 << val; + if (mix->div_table) { + for (clkt = mix->div_table; clkt->div; clkt++) + if (clkt->val == val) + return clkt->div; + if (clkt->div == 0) + return 0; + } + return val + 1; +} + +static unsigned int _get_mux(struct mmp_clk_mix *mix, unsigned int val) +{ + int num_parents = __clk_get_num_parents(mix->hw.clk); + int i; + + if (mix->mux_flags & CLK_MUX_INDEX_BIT) + return ffs(val) - 1; + if (mix->mux_flags & CLK_MUX_INDEX_ONE) + return val - 1; + if (mix->mux_table) { + for (i = 0; i < num_parents; i++) + if (mix->mux_table[i] == val) + return i; + if (i == num_parents) + return 0; + } + + return val; +} +static unsigned int _get_div_val(struct mmp_clk_mix *mix, unsigned int div) +{ + struct clk_div_table *clkt; + + if (mix->div_flags & CLK_DIVIDER_ONE_BASED) + return div; + if (mix->div_flags & CLK_DIVIDER_POWER_OF_TWO) + return __ffs(div); + if (mix->div_table) { + for (clkt = mix->div_table; clkt->div; clkt++) + if (clkt->div == div) + return clkt->val; + if (clkt->div == 0) + return 0; + } + + return div - 1; +} + +static unsigned int _get_mux_val(struct mmp_clk_mix *mix, unsigned int mux) +{ + if (mix->mux_table) + return mix->mux_table[mux]; + + return mux; +} + +static void _filter_clk_table(struct mmp_clk_mix *mix, + struct mmp_clk_mix_clk_table *table, + unsigned int table_size) +{ + int i; + struct mmp_clk_mix_clk_table *item; + struct clk *parent, *clk; + unsigned long parent_rate; + + clk = mix->hw.clk; + + for (i = 0; i < table_size; i++) { + item = &table[i]; + parent = clk_get_parent_by_index(clk, item->parent_index); + parent_rate = __clk_get_rate(parent); + if (parent_rate % item->rate) { + item->valid = 0; + } else { + item->divisor = parent_rate / item->rate; + item->valid = 1; + } + } +} + +static int _set_rate(struct mmp_clk_mix *mix, u32 mux_val, u32 div_val, + unsigned int change_mux, unsigned int change_div) +{ + struct mmp_clk_mix_reg_info *ri = &mix->reg_info; + u8 width, shift; + u32 mux_div, fc_req; + int ret, timeout = 50; + unsigned long flags = 0; + + if (!change_mux && !change_div) + return -EINVAL; + + if (mix->lock) + spin_lock_irqsave(mix->lock, flags); + + if (mix->type == MMP_CLK_MIX_TYPE_V1 + || mix->type == MMP_CLK_MIX_TYPE_V2) + mux_div = readl(ri->reg_clk_ctrl); + else + mux_div = readl(ri->reg_clk_sel); + + if (change_div) { + width = ri->width_div; + shift = ri->shift_div; + mux_div &= ~MMP_CLK_BITS_MASK(width, shift); + mux_div |= MMP_CLK_BITS_SET_VAL(div_val, width, shift); + } + + if (change_mux) { + width = ri->width_mux; + shift = ri->shift_mux; + mux_div &= ~MMP_CLK_BITS_MASK(width, shift); + mux_div |= MMP_CLK_BITS_SET_VAL(mux_val, width, shift); + } + + if (mix->type == MMP_CLK_MIX_TYPE_V1) { + writel(mux_div, ri->reg_clk_ctrl); + } else if (mix->type == MMP_CLK_MIX_TYPE_V2) { + mux_div |= (1 << ri->bit_fc); + writel(mux_div, ri->reg_clk_ctrl); + + do { + fc_req = readl(ri->reg_clk_ctrl); + timeout--; + if (!(fc_req & (1 << ri->bit_fc))) + break; + } while (timeout); + + if (timeout == 0) { + pr_err("%s:%s cannot do frequency change\n", + __func__, __clk_get_name(mix->hw.clk)); + ret = -EBUSY; + goto error; + } + } else { + fc_req = readl(ri->reg_clk_ctrl); + fc_req |= 1 << ri->bit_fc; + writel(fc_req, ri->reg_clk_ctrl); + writel(mux_div, ri->reg_clk_sel); + fc_req &= ~(1 << ri->bit_fc); + } + + ret = 0; +error: + if (mix->lock) + spin_unlock_irqrestore(mix->lock, flags); + + return ret; +} + +static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + struct mmp_clk_mix_clk_table *item; + struct clk *parent, *parent_best, *mix_clk; + unsigned long parent_rate, mix_rate, mix_rate_best, parent_rate_best; + unsigned long gap, gap_best; + u32 div_val_max; + unsigned int div; + int i, j; + + mix_clk = hw->clk; + + parent = NULL; + mix_rate_best = 0; + parent_rate_best = 0; + gap_best = rate; + parent_best = NULL; + + if (mix->table) { + for (i = 0; i < mix->table_size; i++) { + item = &mix->table[i]; + if (item->valid == 0) + continue; + parent = clk_get_parent_by_index(mix_clk, + item->parent_index); + parent_rate = __clk_get_rate(parent); + mix_rate = parent_rate / item->divisor; + gap = abs(mix_rate - rate); + if (parent_best == NULL || gap < gap_best) { + parent_best = parent; + parent_rate_best = parent_rate; + mix_rate_best = mix_rate; + gap_best = gap; + if (gap_best == 0) + goto found; + } + } + } else { + for (i = 0; i < __clk_get_num_parents(mix_clk); i++) { + parent = clk_get_parent_by_index(mix_clk, i); + parent_rate = __clk_get_rate(parent); + div_val_max = _get_maxdiv(mix); + for (j = 0; j < div_val_max; j++) { + div = _get_div(mix, j); + mix_rate = parent_rate / div; + gap = abs(mix_rate - rate); + if (parent_best == NULL || gap < gap_best) { + parent_best = parent; + parent_rate_best = parent_rate; + mix_rate_best = mix_rate; + gap_best = gap; + if (gap_best == 0) + goto found; + } + } + } + } + +found: + *best_parent_rate = parent_rate_best; + *best_parent_clk = __clk_get_hw(parent_best); + + return mix_rate_best; +} + +static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + unsigned int div; + u32 div_val, mux_val; + + div = parent_rate / rate; + div_val = _get_div_val(mix, div); + mux_val = _get_mux_val(mix, index); + + return _set_rate(mix, mux_val, div_val, 1, 1); +} + +static u8 mmp_clk_mix_get_parent(struct clk_hw *hw) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + struct mmp_clk_mix_reg_info *ri = &mix->reg_info; + unsigned long flags = 0; + u32 mux_div = 0; + u8 width, shift; + u32 mux_val; + + if (mix->lock) + spin_lock_irqsave(mix->lock, flags); + + if (mix->type == MMP_CLK_MIX_TYPE_V1 + || mix->type == MMP_CLK_MIX_TYPE_V2) + mux_div = readl(ri->reg_clk_ctrl); + else + mux_div = readl(ri->reg_clk_sel); + + if (mix->lock) + spin_unlock_irqrestore(mix->lock, flags); + + width = mix->reg_info.width_mux; + shift = mix->reg_info.shift_mux; + + mux_val = MMP_CLK_BITS_GET_VAL(mux_div, width, shift); + + return _get_mux(mix, mux_val); +} + +static unsigned long mmp_clk_mix_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + struct mmp_clk_mix_reg_info *ri = &mix->reg_info; + unsigned long flags = 0; + u32 mux_div = 0; + u8 width, shift; + unsigned int div; + + if (mix->lock) + spin_lock_irqsave(mix->lock, flags); + + if (mix->type == MMP_CLK_MIX_TYPE_V1 + || mix->type == MMP_CLK_MIX_TYPE_V2) + mux_div = readl(ri->reg_clk_ctrl); + else + mux_div = readl(ri->reg_clk_sel); + + if (mix->lock) + spin_unlock_irqrestore(mix->lock, flags); + + width = mix->reg_info.width_div; + shift = mix->reg_info.shift_div; + + div = _get_div(mix, MMP_CLK_BITS_GET_VAL(mux_div, width, shift)); + + return parent_rate / div; +} + +static int mmp_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + struct mmp_clk_mix_clk_table *item; + int i; + u32 div_val, mux_val; + + if (mix->table) { + for (i = 0; i < mix->table_size; i++) { + item = &mix->table[i]; + if (item->valid == 0) + continue; + if (item->parent_index == index) + break; + } + if (i < mix->table_size) { + div_val = _get_div_val(mix, item->divisor); + mux_val = _get_mux_val(mix, item->parent_index); + } else + return -EINVAL; + } else { + mux_val = _get_mux_val(mix, index); + div_val = 0; + } + + return _set_rate(mix, mux_val, div_val, 1, div_val ? 1 : 0); +} + +static int mmp_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long best_parent_rate) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + struct mmp_clk_mix_clk_table *item; + unsigned long parent_rate; + unsigned int best_divisor; + struct clk *mix_clk, *parent; + int i; + + best_divisor = best_parent_rate / rate; + + mix_clk = hw->clk; + if (mix->table) { + for (i = 0; i < mix->table_size; i++) { + item = &mix->table[i]; + if (item->valid == 0) + continue; + parent = clk_get_parent_by_index(mix_clk, + item->parent_index); + parent_rate = __clk_get_rate(parent); + if (parent_rate == best_parent_rate + && item->divisor == best_divisor) + break; + } + if (i < mix->table_size) + return _set_rate(mix, + _get_mux_val(mix, item->parent_index), + _get_div_val(mix, item->divisor), + 1, 1); + else + return -EINVAL; + } else { + for (i = 0; i < __clk_get_num_parents(mix_clk); i++) { + parent = clk_get_parent_by_index(mix_clk, i); + parent_rate = __clk_get_rate(parent); + if (parent_rate == best_parent_rate) + break; + } + if (i < __clk_get_num_parents(mix_clk)) + return _set_rate(mix, _get_mux_val(mix, i), + _get_div_val(mix, best_divisor), 1, 1); + else + return -EINVAL; + } +} + +static void mmp_clk_mix_init(struct clk_hw *hw) +{ + struct mmp_clk_mix *mix = to_clk_mix(hw); + + if (mix->table) + _filter_clk_table(mix, mix->table, mix->table_size); +} + +const struct clk_ops mmp_clk_mix_ops = { + .determine_rate = mmp_clk_mix_determine_rate, + .set_rate_and_parent = mmp_clk_mix_set_rate_and_parent, + .set_rate = mmp_clk_set_rate, + .set_parent = mmp_clk_set_parent, + .get_parent = mmp_clk_mix_get_parent, + .recalc_rate = mmp_clk_mix_recalc_rate, + .init = mmp_clk_mix_init, +}; + +struct clk *mmp_clk_register_mix(struct device *dev, + const char *name, + const char **parent_names, + u8 num_parents, + unsigned long flags, + struct mmp_clk_mix_config *config, + spinlock_t *lock) +{ + struct mmp_clk_mix *mix; + struct clk *clk; + struct clk_init_data init; + size_t table_bytes; + + mix = kzalloc(sizeof(*mix), GFP_KERNEL); + if (!mix) { + pr_err("%s:%s: could not allocate mmp mix clk\n", + __func__, name); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.flags = flags | CLK_GET_RATE_NOCACHE; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.ops = &mmp_clk_mix_ops; + + memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info)); + if (config->table) { + table_bytes = sizeof(*config->table) * config->table_size; + mix->table = kzalloc(table_bytes, GFP_KERNEL); + if (!mix->table) { + pr_err("%s:%s: could not allocate mmp mix table\n", + __func__, name); + kfree(mix); + return ERR_PTR(-ENOMEM); + } + memcpy(mix->table, config->table, table_bytes); + mix->table_size = config->table_size; + } + + if (config->mux_table) { + table_bytes = sizeof(u32) * num_parents; + mix->mux_table = kzalloc(table_bytes, GFP_KERNEL); + if (!mix->mux_table) { + pr_err("%s:%s: could not allocate mmp mix mux-table\n", + __func__, name); + kfree(mix->table); + kfree(mix); + return ERR_PTR(-ENOMEM); + } + memcpy(mix->mux_table, config->mux_table, table_bytes); + } + + mix->div_flags = config->div_flags; + mix->mux_flags = config->mux_flags; + mix->lock = lock; + mix->hw.init = &init; + + if (config->reg_info.bit_fc >= 32) + mix->type = MMP_CLK_MIX_TYPE_V1; + else if (config->reg_info.reg_clk_sel) + mix->type = MMP_CLK_MIX_TYPE_V3; + else + mix->type = MMP_CLK_MIX_TYPE_V2; + clk = clk_register(dev, &mix->hw); + + if (IS_ERR(clk)) { + kfree(mix->mux_table); + kfree(mix->table); + kfree(mix); + } + + return clk; +} diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index b2721cae257a..5c90a4230fa3 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -54,7 +54,7 @@ static DEFINE_SPINLOCK(clk_lock); -static struct clk_factor_masks uart_factor_masks = { +static struct mmp_clk_factor_masks uart_factor_masks = { .factor = 2, .num_mask = 0x1fff, .den_mask = 0x1fff, @@ -62,7 +62,7 @@ static struct clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct clk_factor_tbl uart_factor_tbl[] = { +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { {.num = 14634, .den = 2165}, /*14.745MHZ */ {.num = 3521, .den = 689}, /*19.23MHZ */ {.num = 9679, .den = 5728}, /*58.9824MHZ */ @@ -191,7 +191,7 @@ void __init mmp2_clk_init(void) clk = mmp_clk_register_factor("uart_pll", "pll1_4", 0, mpmu_base + MPMU_UART_PLL, &uart_factor_masks, uart_factor_tbl, - ARRAY_SIZE(uart_factor_tbl)); + ARRAY_SIZE(uart_factor_tbl), &clk_lock); clk_set_rate(clk, 14745600); clk_register_clkdev(clk, "uart_pll", NULL); diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c new file mode 100644 index 000000000000..2cbc2b43ae52 --- /dev/null +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -0,0 +1,334 @@ +/* + * mmp2 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie <xiechao.mail@gmail.com> + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/of_address.h> + +#include <dt-bindings/clock/marvell,mmp2.h> + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x0 +#define APBC_TWSI0 0x4 +#define APBC_TWSI1 0x8 +#define APBC_TWSI2 0xc +#define APBC_TWSI3 0x10 +#define APBC_TWSI4 0x7c +#define APBC_TWSI5 0x80 +#define APBC_KPC 0x18 +#define APBC_UART0 0x2c +#define APBC_UART1 0x30 +#define APBC_UART2 0x34 +#define APBC_UART3 0x88 +#define APBC_GPIO 0x38 +#define APBC_PWM0 0x3c +#define APBC_PWM1 0x40 +#define APBC_PWM2 0x44 +#define APBC_PWM3 0x48 +#define APBC_SSP0 0x50 +#define APBC_SSP1 0x54 +#define APBC_SSP2 0x58 +#define APBC_SSP3 0x5c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_SDH2 0xe8 +#define APMU_SDH3 0xec +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_DISP1 0x110 +#define APMU_CCIC0 0x50 +#define APMU_CCIC1 0xf4 +#define MPMU_UART_PLL 0x14 + +struct mmp2_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {MMP2_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {MMP2_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {MMP2_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 800000000}, + {MMP2_CLK_PLL2, "pll2", NULL, CLK_IS_ROOT, 960000000}, + {MMP2_CLK_USB_PLL, "usb_pll", NULL, CLK_IS_ROOT, 480000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {MMP2_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {MMP2_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {MMP2_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {MMP2_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {MMP2_CLK_PLL1_20, "pll1_20", "pll1_4", 1, 5, 0}, + {MMP2_CLK_PLL1_3, "pll1_3", "pll1", 1, 3, 0}, + {MMP2_CLK_PLL1_6, "pll1_6", "pll1_3", 1, 2, 0}, + {MMP2_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {MMP2_CLK_PLL2_2, "pll2_2", "pll2", 1, 2, 0}, + {MMP2_CLK_PLL2_4, "pll2_4", "pll2_2", 1, 2, 0}, + {MMP2_CLK_PLL2_8, "pll2_8", "pll2_4", 1, 2, 0}, + {MMP2_CLK_PLL2_16, "pll2_16", "pll2_8", 1, 2, 0}, + {MMP2_CLK_PLL2_3, "pll2_3", "pll2", 1, 3, 0}, + {MMP2_CLK_PLL2_6, "pll2_6", "pll2_3", 1, 2, 0}, + {MMP2_CLK_PLL2_12, "pll2_12", "pll2_6", 1, 2, 0}, + {MMP2_CLK_VCTCXO_2, "vctcxo_2", "vctcxo", 1, 2, 0}, + {MMP2_CLK_VCTCXO_4, "vctcxo_4", "vctcxo_2", 1, 2, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 14634, .den = 2165}, /*14.745MHZ */ + {.num = 3521, .den = 689}, /*19.23MHZ */ + {.num = 9679, .den = 5728}, /*58.9824MHZ */ + {.num = 15850, .den = 9451}, /*59.429MHZ */ +}; + +static void mmp2_pll_init(struct mmp2_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, MMP2_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"uart_pll", "vctcxo"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static DEFINE_SPINLOCK(ssp2_lock); +static DEFINE_SPINLOCK(ssp3_lock); +static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock}, + {0, "uart3_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART3, 4, 3, 0, &uart2_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, + {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, + {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {MMP2_CLK_TWSI0, "twsi0_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI1, "twsi1_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI2, "twsi2_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI2, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI3, "twsi3_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI4, "twsi4_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI4, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_TWSI5, "twsi5_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_TWSI5, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP2_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, &reset_lock}, + {MMP2_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x7, 0x3, 0x0, 0, &reset_lock}, + {MMP2_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x7, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {MMP2_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 0x3, 0x0, 0, &uart0_lock}, + {MMP2_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 0x3, 0x0, 0, &uart1_lock}, + {MMP2_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock}, + {MMP2_CLK_UART3, "uart3_clk", "uart3_mux", CLK_SET_RATE_PARENT, APBC_UART3, 0x7, 0x3, 0x0, 0, &uart2_lock}, + {MMP2_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x7, 0x3, 0x0, 0, &ssp0_lock}, + {MMP2_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x7, 0x3, 0x0, 0, &ssp1_lock}, + {MMP2_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x7, 0x3, 0x0, 0, &ssp2_lock}, + {MMP2_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x7, 0x3, 0x0, 0, &ssp3_lock}, +}; + +static void mmp2_apb_periph_clk_init(struct mmp2_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); +} + +static DEFINE_SPINLOCK(sdh_lock); +static const char *sdh_parent_names[] = {"pll1_4", "pll2", "usb_pll", "pll1"}; +static struct mmp_clk_mix_config sdh_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 10, 2, 8, 32), +}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static DEFINE_SPINLOCK(disp1_lock); +static const char *disp_parent_names[] = {"pll1", "pll1_16", "pll2", "vctcxo"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static DEFINE_SPINLOCK(ccic1_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_16", "vctcxo"}; +static struct mmp_clk_mix_config ccic0_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 17, 2, 6, 32), +}; +static struct mmp_clk_mix_config ccic1_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(4, 16, 2, 6, 32), +}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {MMP2_CLK_DISP0_MUX, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 2, 0, &disp0_lock}, + {MMP2_CLK_DISP1_MUX, "disp1_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP1, 6, 2, 0, &disp1_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock}, + {0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock}, + {0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, 0, &disp1_lock}, + {0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, + {0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {MMP2_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {MMP2_CLK_SDH0, "sdh0_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh1_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh2_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH2, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_SDH1, "sdh3_clk", "sdh_mix_clk", CLK_SET_RATE_PARENT, APMU_SDH3, 0x1b, 0x1b, 0x0, 0, &sdh_lock}, + {MMP2_CLK_DISP0, "disp0_clk", "disp0_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP0_SPHY, "disp0_sphy_clk", "disp0_sphy_div", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1024, 0x1024, 0x0, 0, &disp0_lock}, + {MMP2_CLK_DISP1, "disp1_clk", "disp1_div", CLK_SET_RATE_PARENT, APMU_DISP1, 0x1b, 0x1b, 0x0, 0, &disp1_lock}, + {MMP2_CLK_CCIC_ARBITER, "ccic_arbiter", "vctcxo", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1800, 0x1800, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0, "ccic0_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, + {MMP2_CLK_CCIC1, "ccic1_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x1b, 0x1b, 0x0, 0, &ccic1_lock}, + {MMP2_CLK_CCIC1_PHY, "ccic1_phy_clk", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x24, 0x24, 0x0, 0, &ccic1_lock}, + {MMP2_CLK_CCIC1_SPHY, "ccic1_sphy_clk", "ccic1_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC1, 0x300, 0x300, 0x0, 0, &ccic1_lock}, +}; + +static void mmp2_axi_periph_clk_init(struct mmp2_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_SDH0; + clk = mmp_clk_register_mix(NULL, "sdh_mix_clk", sdh_parent_names, + ARRAY_SIZE(sdh_parent_names), + CLK_SET_RATE_PARENT, + &sdh_mix_config, &sdh_lock); + + ccic0_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC0; + clk = mmp_clk_register_mix(NULL, "ccic0_mix_clk", ccic_parent_names, + ARRAY_SIZE(ccic_parent_names), + CLK_SET_RATE_PARENT, + &ccic0_mix_config, &ccic0_lock); + mmp_clk_add(unit, MMP2_CLK_CCIC0_MIX, clk); + + ccic1_mix_config.reg_info.reg_clk_ctrl = pxa_unit->apmu_base + APMU_CCIC1; + clk = mmp_clk_register_mix(NULL, "ccic1_mix_clk", ccic_parent_names, + ARRAY_SIZE(ccic_parent_names), + CLK_SET_RATE_PARENT, + &ccic1_mix_config, &ccic1_lock); + mmp_clk_add(unit, MMP2_CLK_CCIC1_MIX, clk); + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void mmp2_clk_reset_init(struct device_node *np, + struct mmp2_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, nr_resets; + + nr_resets = ARRAY_SIZE(apbc_gate_clks); + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + for (i = 0; i < nr_resets; i++) { + cells[i].clk_id = apbc_gate_clks[i].id; + cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[i].flags = 0; + cells[i].lock = apbc_gate_clks[i].lock; + cells[i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init mmp2_clk_init(struct device_node *np) +{ + struct mmp2_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS); + + mmp2_pll_init(pxa_unit); + + mmp2_apb_periph_clk_init(pxa_unit); + + mmp2_axi_periph_clk_init(pxa_unit); + + mmp2_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(mmp2_clk, "marvell,mmp2-clock", mmp2_clk_init); diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c new file mode 100644 index 000000000000..5b1810dc4bd2 --- /dev/null +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -0,0 +1,279 @@ +/* + * pxa168 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie <xiechao.mail@gmail.com> + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/of_address.h> + +#include <dt-bindings/clock/marvell,pxa168.h> + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x30 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x81c +#define APBC_SSP1 0x820 +#define APBC_SSP2 0x84c +#define APBC_SSP3 0x858 +#define APBC_SSP4 0x85c +#define APBC_TWSI1 0x6c +#define APBC_UART2 0x70 +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +struct pxa168_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {PXA168_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {PXA168_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {PXA168_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {PXA168_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {PXA168_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {PXA168_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {PXA168_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {PXA168_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0}, + {PXA168_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {PXA168_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, + {PXA168_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, + {PXA168_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA168_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, + {PXA168_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, + {PXA168_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, + {PXA168_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static void pxa168_pll_init(struct pxa168_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, PXA168_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static DEFINE_SPINLOCK(ssp2_lock); +static DEFINE_SPINLOCK(ssp3_lock); +static DEFINE_SPINLOCK(ssp4_lock); +static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART2, 4, 3, 0, &uart2_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, + {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP2, 4, 3, 0, &ssp2_lock}, + {0, "ssp3_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP3, 4, 3, 0, &ssp3_lock}, + {0, "ssp4_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP4, 4, 3, 0, &ssp4_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {PXA168_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA168_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA168_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA168_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA168_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock}, + {PXA168_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock}, + {PXA168_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBC_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock}, + {PXA168_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock}, + {PXA168_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock}, + {PXA168_CLK_SSP2, "ssp2_clk", "ssp2_mux", CLK_SET_RATE_PARENT, APBC_SSP2, 0x3, 0x3, 0x0, 0, &ssp2_lock}, + {PXA168_CLK_SSP3, "ssp3_clk", "ssp3_mux", CLK_SET_RATE_PARENT, APBC_SSP3, 0x3, 0x3, 0x0, 0, &ssp3_lock}, + {PXA168_CLK_SSP4, "ssp4_clk", "ssp4_mux", CLK_SET_RATE_PARENT, APBC_SSP4, 0x3, 0x3, 0x0, 0, &ssp4_lock}, +}; + +static void pxa168_apb_periph_clk_init(struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); + +} + +static DEFINE_SPINLOCK(sdh0_lock); +static DEFINE_SPINLOCK(sdh1_lock); +static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static const char *disp_parent_names[] = {"pll1_2", "pll1_12"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock}, + {0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock}, + {0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock}, + {0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock}, + {0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA168_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL}, + {PXA168_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + {PXA168_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {PXA168_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock}, + {PXA168_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock}, + {PXA168_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {PXA168_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {PXA168_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {PXA168_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, +}; + +static void pxa168_axi_periph_clk_init(struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void pxa168_clk_reset_init(struct device_node *np, + struct pxa168_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, nr_resets; + + nr_resets = ARRAY_SIZE(apbc_gate_clks); + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + for (i = 0; i < nr_resets; i++) { + cells[i].clk_id = apbc_gate_clks[i].id; + cells[i].reg = pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[i].flags = 0; + cells[i].lock = apbc_gate_clks[i].lock; + cells[i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init pxa168_clk_init(struct device_node *np) +{ + struct pxa168_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, PXA168_NR_CLKS); + + pxa168_pll_init(pxa_unit); + + pxa168_apb_periph_clk_init(pxa_unit); + + pxa168_axi_periph_clk_init(pxa_unit); + + pxa168_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(pxa168_clk, "marvell,pxa168-clock", pxa168_clk_init); diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c new file mode 100644 index 000000000000..5e3c80dad336 --- /dev/null +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -0,0 +1,301 @@ +/* + * pxa910 clock framework source file + * + * Copyright (C) 2012 Marvell + * Chao Xie <xiechao.mail@gmail.com> + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/of_address.h> + +#include <dt-bindings/clock/marvell,pxa910.h> + +#include "clk.h" +#include "reset.h" + +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x18 +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x1c +#define APBC_SSP1 0x20 +#define APBC_SSP2 0x4c +#define APBCP_TWSI1 0x28 +#define APBCP_UART2 0x1c +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_DISP0 0x4c +#define APMU_CCIC0 0x50 +#define APMU_DFC 0x60 +#define MPMU_UART_PLL 0x14 + +struct pxa910_clk_unit { + struct mmp_clk_unit unit; + void __iomem *mpmu_base; + void __iomem *apmu_base; + void __iomem *apbc_base; + void __iomem *apbcp_base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {PXA910_CLK_CLK32, "clk32", NULL, CLK_IS_ROOT, 32768}, + {PXA910_CLK_VCTCXO, "vctcxo", NULL, CLK_IS_ROOT, 26000000}, + {PXA910_CLK_PLL1, "pll1", NULL, CLK_IS_ROOT, 624000000}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {PXA910_CLK_PLL1_2, "pll1_2", "pll1", 1, 2, 0}, + {PXA910_CLK_PLL1_4, "pll1_4", "pll1_2", 1, 2, 0}, + {PXA910_CLK_PLL1_8, "pll1_8", "pll1_4", 1, 2, 0}, + {PXA910_CLK_PLL1_16, "pll1_16", "pll1_8", 1, 2, 0}, + {PXA910_CLK_PLL1_6, "pll1_6", "pll1_2", 1, 3, 0}, + {PXA910_CLK_PLL1_12, "pll1_12", "pll1_6", 1, 2, 0}, + {PXA910_CLK_PLL1_24, "pll1_24", "pll1_12", 1, 2, 0}, + {PXA910_CLK_PLL1_48, "pll1_48", "pll1_24", 1, 2, 0}, + {PXA910_CLK_PLL1_96, "pll1_96", "pll1_48", 1, 2, 0}, + {PXA910_CLK_PLL1_13, "pll1_13", "pll1", 1, 13, 0}, + {PXA910_CLK_PLL1_13_1_5, "pll1_13_1_5", "pll1_13", 2, 3, 0}, + {PXA910_CLK_PLL1_2_1_5, "pll1_2_1_5", "pll1_2", 2, 3, 0}, + {PXA910_CLK_PLL1_3_16, "pll1_3_16", "pll1", 3, 16, 0}, +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = 0x1fff, + .den_mask = 0x1fff, + .num_shift = 16, + .den_shift = 0, +}; + +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { + {.num = 8125, .den = 1536}, /*14.745MHZ */ +}; + +static void pxa910_pll_init(struct pxa910_clk_unit *pxa_unit) +{ + struct clk *clk; + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + clk = mmp_clk_register_factor("uart_pll", "pll1_4", + CLK_SET_RATE_PARENT, + pxa_unit->mpmu_base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); + mmp_clk_add(unit, PXA910_CLK_UART_PLL, clk); +} + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); +static DEFINE_SPINLOCK(uart2_lock); +static const char *uart_parent_names[] = {"pll1_3_16", "uart_pll"}; + +static DEFINE_SPINLOCK(ssp0_lock); +static DEFINE_SPINLOCK(ssp1_lock); +static const char *ssp_parent_names[] = {"pll1_96", "pll1_48", "pll1_24", "pll1_12"}; + +static DEFINE_SPINLOCK(reset_lock); + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP0, 4, 3, 0, &ssp0_lock}, + {0, "ssp1_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), CLK_SET_RATE_PARENT, APBC_SSP1, 4, 3, 0, &ssp1_lock}, +}; + +static struct mmp_param_mux_clk apbcp_mux_clks[] = { + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 4, 3, 0, &uart2_lock}, +}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {PXA910_CLK_TWSI0, "twsi0_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 0x3, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA910_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0x0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA910_CLK_PWM0, "pwm0_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM0, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM1, "pwm1_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM1, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM2, "pwm2_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM2, 0x3, 0x3, 0x0, 0, &reset_lock}, + {PXA910_CLK_PWM3, "pwm3_clk", "pll1_48", CLK_SET_RATE_PARENT, APBC_PWM3, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 0x3, 0x0, 0, &uart0_lock}, + {PXA910_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 0x3, 0x0, 0, &uart1_lock}, + {PXA910_CLK_SSP0, "ssp0_clk", "ssp0_mux", CLK_SET_RATE_PARENT, APBC_SSP0, 0x3, 0x3, 0x0, 0, &ssp0_lock}, + {PXA910_CLK_SSP1, "ssp1_clk", "ssp1_mux", CLK_SET_RATE_PARENT, APBC_SSP1, 0x3, 0x3, 0x0, 0, &ssp1_lock}, +}; + +static struct mmp_param_gate_clk apbcp_gate_clks[] = { + {PXA910_CLK_TWSI1, "twsi1_clk", "pll1_13_1_5", CLK_SET_RATE_PARENT, APBCP_TWSI1, 0x3, 0x3, 0x0, 0, &reset_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock}, +}; + +static void pxa910_apb_periph_clk_init(struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_mux_clks)); + + mmp_register_mux_clks(unit, apbcp_mux_clks, pxa_unit->apbcp_base, + ARRAY_SIZE(apbcp_mux_clks)); + + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->apbc_base, + ARRAY_SIZE(apbc_gate_clks)); + + mmp_register_gate_clks(unit, apbcp_gate_clks, pxa_unit->apbcp_base, + ARRAY_SIZE(apbcp_gate_clks)); +} + +static DEFINE_SPINLOCK(sdh0_lock); +static DEFINE_SPINLOCK(sdh1_lock); +static const char *sdh_parent_names[] = {"pll1_12", "pll1_13"}; + +static DEFINE_SPINLOCK(usb_lock); + +static DEFINE_SPINLOCK(disp0_lock); +static const char *disp_parent_names[] = {"pll1_2", "pll1_12"}; + +static DEFINE_SPINLOCK(ccic0_lock); +static const char *ccic_parent_names[] = {"pll1_2", "pll1_12"}; +static const char *ccic_phy_parent_names[] = {"pll1_6", "pll1_12"}; + +static struct mmp_param_mux_clk apmu_mux_clks[] = { + {0, "sdh0_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH0, 6, 1, 0, &sdh0_lock}, + {0, "sdh1_mux", sdh_parent_names, ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, APMU_SDH1, 6, 1, 0, &sdh1_lock}, + {0, "disp0_mux", disp_parent_names, ARRAY_SIZE(disp_parent_names), CLK_SET_RATE_PARENT, APMU_DISP0, 6, 1, 0, &disp0_lock}, + {0, "ccic0_mux", ccic_parent_names, ARRAY_SIZE(ccic_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 6, 1, 0, &ccic0_lock}, + {0, "ccic0_phy_mux", ccic_phy_parent_names, ARRAY_SIZE(ccic_phy_parent_names), CLK_SET_RATE_PARENT, APMU_CCIC0, 7, 1, 0, &ccic0_lock}, +}; + +static struct mmp_param_div_clk apmu_div_clks[] = { + {0, "ccic0_sphy_div", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock}, +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA910_CLK_DFC, "dfc_clk", "pll1_4", CLK_SET_RATE_PARENT, APMU_DFC, 0x19b, 0x19b, 0x0, 0, NULL}, + {PXA910_CLK_USB, "usb_clk", "usb_pll", 0, APMU_USB, 0x9, 0x9, 0x0, 0, &usb_lock}, + {PXA910_CLK_SPH, "sph_clk", "usb_pll", 0, APMU_USB, 0x12, 0x12, 0x0, 0, &usb_lock}, + /* The gate clocks has mux parent. */ + {PXA910_CLK_SDH0, "sdh0_clk", "sdh0_mux", CLK_SET_RATE_PARENT, APMU_SDH0, 0x1b, 0x1b, 0x0, 0, &sdh0_lock}, + {PXA910_CLK_SDH1, "sdh1_clk", "sdh1_mux", CLK_SET_RATE_PARENT, APMU_SDH1, 0x1b, 0x1b, 0x0, 0, &sdh1_lock}, + {PXA910_CLK_DISP0, "disp0_clk", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 0x1b, 0x1b, 0x0, 0, &disp0_lock}, + {PXA910_CLK_CCIC0, "ccic0_clk", "ccic0_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x1b, 0x1b, 0x0, 0, &ccic0_lock}, + {PXA910_CLK_CCIC0_PHY, "ccic0_phy_clk", "ccic0_phy_mux", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x24, 0x24, 0x0, 0, &ccic0_lock}, + {PXA910_CLK_CCIC0_SPHY, "ccic0_sphy_clk", "ccic0_sphy_div", CLK_SET_RATE_PARENT, APMU_CCIC0, 0x300, 0x300, 0x0, 0, &ccic0_lock}, +}; + +static void pxa910_axi_periph_clk_init(struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apmu_mux_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_mux_clks)); + + mmp_register_div_clks(unit, apmu_div_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_div_clks)); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->apmu_base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static void pxa910_clk_reset_init(struct device_node *np, + struct pxa910_clk_unit *pxa_unit) +{ + struct mmp_clk_reset_cell *cells; + int i, base, nr_resets_apbc, nr_resets_apbcp, nr_resets; + + nr_resets_apbc = ARRAY_SIZE(apbc_gate_clks); + nr_resets_apbcp = ARRAY_SIZE(apbcp_gate_clks); + nr_resets = nr_resets_apbc + nr_resets_apbcp; + cells = kcalloc(nr_resets, sizeof(*cells), GFP_KERNEL); + if (!cells) + return; + + base = 0; + for (i = 0; i < nr_resets_apbc; i++) { + cells[base + i].clk_id = apbc_gate_clks[i].id; + cells[base + i].reg = + pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[base + i].flags = 0; + cells[base + i].lock = apbc_gate_clks[i].lock; + cells[base + i].bits = 0x4; + } + + base = nr_resets_apbc; + for (i = 0; i < nr_resets_apbcp; i++) { + cells[base + i].clk_id = apbcp_gate_clks[i].id; + cells[base + i].reg = + pxa_unit->apbc_base + apbc_gate_clks[i].offset; + cells[base + i].flags = 0; + cells[base + i].lock = apbc_gate_clks[i].lock; + cells[base + i].bits = 0x4; + } + + mmp_clk_reset_register(np, cells, nr_resets); +} + +static void __init pxa910_clk_init(struct device_node *np) +{ + struct pxa910_clk_unit *pxa_unit; + + pxa_unit = kzalloc(sizeof(*pxa_unit), GFP_KERNEL); + if (!pxa_unit) + return; + + pxa_unit->mpmu_base = of_iomap(np, 0); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map mpmu registers\n"); + return; + } + + pxa_unit->apmu_base = of_iomap(np, 1); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apmu registers\n"); + return; + } + + pxa_unit->apbc_base = of_iomap(np, 2); + if (!pxa_unit->apbc_base) { + pr_err("failed to map apbc registers\n"); + return; + } + + pxa_unit->apbcp_base = of_iomap(np, 3); + if (!pxa_unit->mpmu_base) { + pr_err("failed to map apbcp registers\n"); + return; + } + + mmp_clk_init(np, &pxa_unit->unit, PXA910_NR_CLKS); + + pxa910_pll_init(pxa_unit); + + pxa910_apb_periph_clk_init(pxa_unit); + + pxa910_axi_periph_clk_init(pxa_unit); + + pxa910_clk_reset_init(np, pxa_unit); +} + +CLK_OF_DECLARE(pxa910_clk, "marvell,pxa910-clock", pxa910_clk_init); diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c index 014396b028a2..93e967c0f972 100644 --- a/drivers/clk/mmp/clk-pxa168.c +++ b/drivers/clk/mmp/clk-pxa168.c @@ -47,7 +47,7 @@ static DEFINE_SPINLOCK(clk_lock); -static struct clk_factor_masks uart_factor_masks = { +static struct mmp_clk_factor_masks uart_factor_masks = { .factor = 2, .num_mask = 0x1fff, .den_mask = 0x1fff, @@ -55,7 +55,7 @@ static struct clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct clk_factor_tbl uart_factor_tbl[] = { +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { {.num = 8125, .den = 1536}, /*14.745MHZ */ }; @@ -158,7 +158,7 @@ void __init pxa168_clk_init(void) uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, mpmu_base + MPMU_UART_PLL, &uart_factor_masks, uart_factor_tbl, - ARRAY_SIZE(uart_factor_tbl)); + ARRAY_SIZE(uart_factor_tbl), &clk_lock); clk_set_rate(uart_pll, 14745600); clk_register_clkdev(uart_pll, "uart_pll", NULL); diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c index 9efc6a47535d..993abcdb32cc 100644 --- a/drivers/clk/mmp/clk-pxa910.c +++ b/drivers/clk/mmp/clk-pxa910.c @@ -45,7 +45,7 @@ static DEFINE_SPINLOCK(clk_lock); -static struct clk_factor_masks uart_factor_masks = { +static struct mmp_clk_factor_masks uart_factor_masks = { .factor = 2, .num_mask = 0x1fff, .den_mask = 0x1fff, @@ -53,7 +53,7 @@ static struct clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct clk_factor_tbl uart_factor_tbl[] = { +static struct mmp_clk_factor_tbl uart_factor_tbl[] = { {.num = 8125, .den = 1536}, /*14.745MHZ */ }; @@ -163,7 +163,7 @@ void __init pxa910_clk_init(void) uart_pll = mmp_clk_register_factor("uart_pll", "pll1_4", 0, mpmu_base + MPMU_UART_PLL, &uart_factor_masks, uart_factor_tbl, - ARRAY_SIZE(uart_factor_tbl)); + ARRAY_SIZE(uart_factor_tbl), &clk_lock); clk_set_rate(uart_pll, 14745600); clk_register_clkdev(uart_pll, "uart_pll", NULL); diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c new file mode 100644 index 000000000000..cf038ef54c59 --- /dev/null +++ b/drivers/clk/mmp/clk.c @@ -0,0 +1,192 @@ +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include "clk.h" + +void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit, + int nr_clks) +{ + static struct clk **clk_table; + + clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL); + if (!clk_table) + return; + + unit->clk_table = clk_table; + unit->nr_clks = nr_clks; + unit->clk_data.clks = clk_table; + unit->clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &unit->clk_data); +} + +void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit, + struct mmp_param_fixed_rate_clk *clks, + int size) +{ + int i; + struct clk *clk; + + for (i = 0; i < size; i++) { + clk = clk_register_fixed_rate(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + clks[i].fixed_rate); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit, + struct mmp_param_fixed_factor_clk *clks, + int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + clk = clk_register_fixed_factor(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, clks[i].mult, + clks[i].div); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_register_general_gate_clks(struct mmp_clk_unit *unit, + struct mmp_param_general_gate_clk *clks, + void __iomem *base, int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + clk = clk_register_gate(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + base + clks[i].offset, + clks[i].bit_idx, + clks[i].gate_flags, + clks[i].lock); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_register_gate_clks(struct mmp_clk_unit *unit, + struct mmp_param_gate_clk *clks, + void __iomem *base, int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + clk = mmp_clk_register_gate(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + base + clks[i].offset, + clks[i].mask, + clks[i].val_enable, + clks[i].val_disable, + clks[i].gate_flags, + clks[i].lock); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_register_mux_clks(struct mmp_clk_unit *unit, + struct mmp_param_mux_clk *clks, + void __iomem *base, int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + clk = clk_register_mux(NULL, clks[i].name, + clks[i].parent_name, + clks[i].num_parents, + clks[i].flags, + base + clks[i].offset, + clks[i].shift, + clks[i].width, + clks[i].mux_flags, + clks[i].lock); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_register_div_clks(struct mmp_clk_unit *unit, + struct mmp_param_div_clk *clks, + void __iomem *base, int size) +{ + struct clk *clk; + int i; + + for (i = 0; i < size; i++) { + clk = clk_register_divider(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + base + clks[i].offset, + clks[i].shift, + clks[i].width, + clks[i].div_flags, + clks[i].lock); + + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + if (clks[i].id) + unit->clk_table[clks[i].id] = clk; + } +} + +void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id, + struct clk *clk) +{ + if (IS_ERR_OR_NULL(clk)) { + pr_err("CLK %d has invalid pointer %p\n", id, clk); + return; + } + if (id > unit->nr_clks) { + pr_err("CLK %d is invalid\n", id); + return; + } + + unit->clk_table[id] = clk; +} diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h index ab86dd4a416a..adf9b711b037 100644 --- a/drivers/clk/mmp/clk.h +++ b/drivers/clk/mmp/clk.h @@ -7,19 +7,123 @@ #define APBC_NO_BUS_CTRL BIT(0) #define APBC_POWER_CTRL BIT(1) -struct clk_factor_masks { - unsigned int factor; - unsigned int num_mask; - unsigned int den_mask; - unsigned int num_shift; - unsigned int den_shift; + +/* Clock type "factor" */ +struct mmp_clk_factor_masks { + unsigned int factor; + unsigned int num_mask; + unsigned int den_mask; + unsigned int num_shift; + unsigned int den_shift; }; -struct clk_factor_tbl { +struct mmp_clk_factor_tbl { unsigned int num; unsigned int den; }; +struct mmp_clk_factor { + struct clk_hw hw; + void __iomem *base; + struct mmp_clk_factor_masks *masks; + struct mmp_clk_factor_tbl *ftbl; + unsigned int ftbl_cnt; + spinlock_t *lock; +}; + +extern struct clk *mmp_clk_register_factor(const char *name, + const char *parent_name, unsigned long flags, + void __iomem *base, struct mmp_clk_factor_masks *masks, + struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt, + spinlock_t *lock); + +/* Clock type "mix" */ +#define MMP_CLK_BITS_MASK(width, shift) \ + (((1 << (width)) - 1) << (shift)) +#define MMP_CLK_BITS_GET_VAL(data, width, shift) \ + ((data & MMP_CLK_BITS_MASK(width, shift)) >> (shift)) +#define MMP_CLK_BITS_SET_VAL(val, width, shift) \ + (((val) << (shift)) & MMP_CLK_BITS_MASK(width, shift)) + +enum { + MMP_CLK_MIX_TYPE_V1, + MMP_CLK_MIX_TYPE_V2, + MMP_CLK_MIX_TYPE_V3, +}; + +/* The register layout */ +struct mmp_clk_mix_reg_info { + void __iomem *reg_clk_ctrl; + void __iomem *reg_clk_sel; + u8 width_div; + u8 shift_div; + u8 width_mux; + u8 shift_mux; + u8 bit_fc; +}; + +/* The suggested clock table from user. */ +struct mmp_clk_mix_clk_table { + unsigned long rate; + u8 parent_index; + unsigned int divisor; + unsigned int valid; +}; + +struct mmp_clk_mix_config { + struct mmp_clk_mix_reg_info reg_info; + struct mmp_clk_mix_clk_table *table; + unsigned int table_size; + u32 *mux_table; + struct clk_div_table *div_table; + u8 div_flags; + u8 mux_flags; +}; + +struct mmp_clk_mix { + struct clk_hw hw; + struct mmp_clk_mix_reg_info reg_info; + struct mmp_clk_mix_clk_table *table; + u32 *mux_table; + struct clk_div_table *div_table; + unsigned int table_size; + u8 div_flags; + u8 mux_flags; + unsigned int type; + spinlock_t *lock; +}; + +extern const struct clk_ops mmp_clk_mix_ops; +extern struct clk *mmp_clk_register_mix(struct device *dev, + const char *name, + const char **parent_names, + u8 num_parents, + unsigned long flags, + struct mmp_clk_mix_config *config, + spinlock_t *lock); + + +/* Clock type "gate". MMP private gate */ +#define MMP_CLK_GATE_NEED_DELAY BIT(0) + +struct mmp_clk_gate { + struct clk_hw hw; + void __iomem *reg; + u32 mask; + u32 val_enable; + u32 val_disable; + unsigned int flags; + spinlock_t *lock; +}; + +extern const struct clk_ops mmp_clk_gate_ops; +extern struct clk *mmp_clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u32 mask, u32 val_enable, + u32 val_disable, unsigned int gate_flags, + spinlock_t *lock); + + extern struct clk *mmp_clk_register_pll2(const char *name, const char *parent_name, unsigned long flags); extern struct clk *mmp_clk_register_apbc(const char *name, @@ -28,8 +132,108 @@ extern struct clk *mmp_clk_register_apbc(const char *name, extern struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, void __iomem *base, u32 enable_mask, spinlock_t *lock); -extern struct clk *mmp_clk_register_factor(const char *name, - const char *parent_name, unsigned long flags, - void __iomem *base, struct clk_factor_masks *masks, - struct clk_factor_tbl *ftbl, unsigned int ftbl_cnt); + +struct mmp_clk_unit { + unsigned int nr_clks; + struct clk **clk_table; + struct clk_onecell_data clk_data; +}; + +struct mmp_param_fixed_rate_clk { + unsigned int id; + char *name; + const char *parent_name; + unsigned long flags; + unsigned long fixed_rate; +}; +void mmp_register_fixed_rate_clks(struct mmp_clk_unit *unit, + struct mmp_param_fixed_rate_clk *clks, + int size); + +struct mmp_param_fixed_factor_clk { + unsigned int id; + char *name; + const char *parent_name; + unsigned long mult; + unsigned long div; + unsigned long flags; +}; +void mmp_register_fixed_factor_clks(struct mmp_clk_unit *unit, + struct mmp_param_fixed_factor_clk *clks, + int size); + +struct mmp_param_general_gate_clk { + unsigned int id; + const char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 bit_idx; + u8 gate_flags; + spinlock_t *lock; +}; +void mmp_register_general_gate_clks(struct mmp_clk_unit *unit, + struct mmp_param_general_gate_clk *clks, + void __iomem *base, int size); + +struct mmp_param_gate_clk { + unsigned int id; + char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u32 mask; + u32 val_enable; + u32 val_disable; + unsigned int gate_flags; + spinlock_t *lock; +}; +void mmp_register_gate_clks(struct mmp_clk_unit *unit, + struct mmp_param_gate_clk *clks, + void __iomem *base, int size); + +struct mmp_param_mux_clk { + unsigned int id; + char *name; + const char **parent_name; + u8 num_parents; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 mux_flags; + spinlock_t *lock; +}; +void mmp_register_mux_clks(struct mmp_clk_unit *unit, + struct mmp_param_mux_clk *clks, + void __iomem *base, int size); + +struct mmp_param_div_clk { + unsigned int id; + char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 div_flags; + spinlock_t *lock; +}; +void mmp_register_div_clks(struct mmp_clk_unit *unit, + struct mmp_param_div_clk *clks, + void __iomem *base, int size); + +#define DEFINE_MIX_REG_INFO(w_d, s_d, w_m, s_m, fc) \ +{ \ + .width_div = (w_d), \ + .shift_div = (s_d), \ + .width_mux = (w_m), \ + .shift_mux = (s_m), \ + .bit_fc = (fc), \ +} + +void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit, + int nr_clks); +void mmp_clk_add(struct mmp_clk_unit *unit, unsigned int id, + struct clk *clk); #endif diff --git a/drivers/clk/mmp/reset.c b/drivers/clk/mmp/reset.c new file mode 100644 index 000000000000..b54da1fe73f0 --- /dev/null +++ b/drivers/clk/mmp/reset.c @@ -0,0 +1,99 @@ +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/reset-controller.h> + +#include "reset.h" + +#define rcdev_to_unit(rcdev) container_of(rcdev, struct mmp_clk_reset_unit, rcdev) + +static int mmp_of_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); + struct mmp_clk_reset_cell *cell; + int i; + + if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) + return -EINVAL; + + for (i = 0; i < rcdev->nr_resets; i++) { + cell = &unit->cells[i]; + if (cell->clk_id == reset_spec->args[0]) + break; + } + + if (i == rcdev->nr_resets) + return -EINVAL; + + return i; +} + +static int mmp_clk_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); + struct mmp_clk_reset_cell *cell; + unsigned long flags = 0; + u32 val; + + cell = &unit->cells[id]; + if (cell->lock) + spin_lock_irqsave(cell->lock, flags); + + val = readl(cell->reg); + val |= cell->bits; + writel(val, cell->reg); + + if (cell->lock) + spin_unlock_irqrestore(cell->lock, flags); + + return 0; +} + +static int mmp_clk_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct mmp_clk_reset_unit *unit = rcdev_to_unit(rcdev); + struct mmp_clk_reset_cell *cell; + unsigned long flags = 0; + u32 val; + + cell = &unit->cells[id]; + if (cell->lock) + spin_lock_irqsave(cell->lock, flags); + + val = readl(cell->reg); + val &= ~cell->bits; + writel(val, cell->reg); + + if (cell->lock) + spin_unlock_irqrestore(cell->lock, flags); + + return 0; +} + +static struct reset_control_ops mmp_clk_reset_ops = { + .assert = mmp_clk_reset_assert, + .deassert = mmp_clk_reset_deassert, +}; + +void mmp_clk_reset_register(struct device_node *np, + struct mmp_clk_reset_cell *cells, int nr_resets) +{ + struct mmp_clk_reset_unit *unit; + + unit = kzalloc(sizeof(*unit), GFP_KERNEL); + if (!unit) + return; + + unit->cells = cells; + unit->rcdev.of_reset_n_cells = 1; + unit->rcdev.nr_resets = nr_resets; + unit->rcdev.ops = &mmp_clk_reset_ops; + unit->rcdev.of_node = np; + unit->rcdev.of_xlate = mmp_of_reset_xlate; + + reset_controller_register(&unit->rcdev); +} diff --git a/drivers/clk/mmp/reset.h b/drivers/clk/mmp/reset.h new file mode 100644 index 000000000000..be8b1a7000f7 --- /dev/null +++ b/drivers/clk/mmp/reset.h @@ -0,0 +1,31 @@ +#ifndef __MACH_MMP_CLK_RESET_H +#define __MACH_MMP_CLK_RESET_H + +#include <linux/reset-controller.h> + +#define MMP_RESET_INVERT 1 + +struct mmp_clk_reset_cell { + unsigned int clk_id; + void __iomem *reg; + u32 bits; + unsigned int flags; + spinlock_t *lock; +}; + +struct mmp_clk_reset_unit { + struct reset_controller_dev rcdev; + struct mmp_clk_reset_cell *cells; +}; + +#ifdef CONFIG_RESET_CONTROLLER +void mmp_clk_reset_register(struct device_node *np, + struct mmp_clk_reset_cell *cells, int nr_resets); +#else +static inline void mmp_clk_reset_register(struct device_node *np, + struct mmp_clk_reset_cell *cells, int nr_resets) +{ +} +#endif + +#endif diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile index 4ff2abcd500b..38e915344605 100644 --- a/drivers/clk/pxa/Makefile +++ b/drivers/clk/pxa/Makefile @@ -1,2 +1,3 @@ obj-y += clk-pxa.o +obj-$(CONFIG_PXA25x) += clk-pxa25x.o obj-$(CONFIG_PXA27x) += clk-pxa27x.o diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c index ef3c05389c0a..4e834753ab09 100644 --- a/drivers/clk/pxa/clk-pxa.c +++ b/drivers/clk/pxa/clk-pxa.c @@ -26,12 +26,20 @@ static struct clk_onecell_data onecell_data = { .clk_num = CLK_MAX, }; -#define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk_cken, hw) +struct pxa_clk { + struct clk_hw hw; + struct clk_fixed_factor lp; + struct clk_fixed_factor hp; + struct clk_gate gate; + bool (*is_in_low_power)(void); +}; + +#define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk, hw) static unsigned long cken_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct pxa_clk_cken *pclk = to_pxa_clk(hw); + struct pxa_clk *pclk = to_pxa_clk(hw); struct clk_fixed_factor *fix; if (!pclk->is_in_low_power || pclk->is_in_low_power()) @@ -48,7 +56,7 @@ static struct clk_ops cken_rate_ops = { static u8 cken_get_parent(struct clk_hw *hw) { - struct pxa_clk_cken *pclk = to_pxa_clk(hw); + struct pxa_clk *pclk = to_pxa_clk(hw); if (!pclk->is_in_low_power) return 0; @@ -69,29 +77,32 @@ void __init clkdev_pxa_register(int ckid, const char *con_id, clk_register_clkdev(clk, con_id, dev_id); } -int __init clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks) +int __init clk_pxa_cken_init(const struct desc_clk_cken *clks, int nb_clks) { int i; - struct pxa_clk_cken *pclk; + struct pxa_clk *pxa_clk; struct clk *clk; for (i = 0; i < nb_clks; i++) { - pclk = clks + i; - pclk->gate.lock = &lock; - clk = clk_register_composite(NULL, pclk->name, - pclk->parent_names, 2, - &pclk->hw, &cken_mux_ops, - &pclk->hw, &cken_rate_ops, - &pclk->gate.hw, &clk_gate_ops, - pclk->flags); - clkdev_pxa_register(pclk->ckid, pclk->con_id, pclk->dev_id, - clk); + pxa_clk = kzalloc(sizeof(*pxa_clk), GFP_KERNEL); + pxa_clk->is_in_low_power = clks[i].is_in_low_power; + pxa_clk->lp = clks[i].lp; + pxa_clk->hp = clks[i].hp; + pxa_clk->gate = clks[i].gate; + pxa_clk->gate.lock = &lock; + clk = clk_register_composite(NULL, clks[i].name, + clks[i].parent_names, 2, + &pxa_clk->hw, &cken_mux_ops, + &pxa_clk->hw, &cken_rate_ops, + &pxa_clk->gate.hw, &clk_gate_ops, + clks[i].flags); + clkdev_pxa_register(clks[i].ckid, clks[i].con_id, + clks[i].dev_id, clk); } return 0; } -static void __init pxa_dt_clocks_init(struct device_node *np) +void __init clk_pxa_dt_common_init(struct device_node *np) { of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); } -CLK_OF_DECLARE(pxa_clks, "marvell,pxa-clocks", pxa_dt_clocks_init); diff --git a/drivers/clk/pxa/clk-pxa.h b/drivers/clk/pxa/clk-pxa.h index 5fe219d06b49..323965430111 100644 --- a/drivers/clk/pxa/clk-pxa.h +++ b/drivers/clk/pxa/clk-pxa.h @@ -25,7 +25,7 @@ static struct clk_ops name ## _rate_ops = { \ .recalc_rate = name ## _get_rate, \ }; \ - static struct clk *clk_register_ ## name(void) \ + static struct clk * __init clk_register_ ## name(void) \ { \ return clk_register_composite(NULL, clk_name, \ name ## _parents, \ @@ -40,7 +40,7 @@ static struct clk_ops name ## _rate_ops = { \ .recalc_rate = name ## _get_rate, \ }; \ - static struct clk *clk_register_ ## name(void) \ + static struct clk * __init clk_register_ ## name(void) \ { \ return clk_register_composite(NULL, clk_name, \ name ## _parents, \ @@ -66,7 +66,7 @@ * | Clock | --- | / div_hp | * +------------+ +-----------+ */ -struct pxa_clk_cken { +struct desc_clk_cken { struct clk_hw hw; int ckid; const char *name; @@ -102,6 +102,7 @@ static int dummy_clk_set_parent(struct clk_hw *hw, u8 index) extern void clkdev_pxa_register(int ckid, const char *con_id, const char *dev_id, struct clk *clk); -extern int clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks); +extern int clk_pxa_cken_init(const struct desc_clk_cken *clks, int nb_clks); +void clk_pxa_dt_common_init(struct device_node *np); #endif diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c new file mode 100644 index 000000000000..6cd88d963a7f --- /dev/null +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -0,0 +1,273 @@ +/* + * Marvell PXA25x family clocks + * + * Copyright (C) 2014 Robert Jarzmik + * + * Heavily inspired from former arch/arm/mach-pxa/pxa25x.c. + * + * 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; version 2 of the License. + * + * For non-devicetree platforms. Once pxa is fully converted to devicetree, this + * should go away. + */ +#include <linux/clk-provider.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/of.h> +#include <mach/pxa25x.h> +#include <mach/pxa2xx-regs.h> + +#include <dt-bindings/clock/pxa-clock.h> +#include "clk-pxa.h" + +#define KHz 1000 +#define MHz (1000 * 1000) + +enum { + PXA_CORE_RUN = 0, + PXA_CORE_TURBO, +}; + +/* + * Various clock factors driven by the CCCR register. + */ + +/* Crystal Frequency to Memory Frequency Multiplier (L) */ +static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; + +/* Memory Frequency to Run Mode Frequency Multiplier (M) */ +static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; + +/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ +/* Note: we store the value N * 2 here. */ +static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; + +static const char * const get_freq_khz[] = { + "core", "run", "cpll", "memory" +}; + +/* + * Get the clock frequency as reflected by CCCR and the turbo flag. + * We assume these values have been applied via a fcs. + * If info is not 0 we also display the current settings. + */ +unsigned int pxa25x_get_clk_frequency_khz(int info) +{ + struct clk *clk; + unsigned long clks[5]; + int i; + + for (i = 0; i < ARRAY_SIZE(get_freq_khz); i++) { + clk = clk_get(NULL, get_freq_khz[i]); + if (IS_ERR(clk)) { + clks[i] = 0; + } else { + clks[i] = clk_get_rate(clk); + clk_put(clk); + } + } + + if (info) { + pr_info("Run Mode clock: %ld.%02ldMHz\n", + clks[1] / 1000000, (clks[1] % 1000000) / 10000); + pr_info("Turbo Mode clock: %ld.%02ldMHz\n", + clks[2] / 1000000, (clks[2] % 1000000) / 10000); + pr_info("Memory clock: %ld.%02ldMHz\n", + clks[3] / 1000000, (clks[3] % 1000000) / 10000); + } + + return (unsigned int)clks[0]; +} + +static unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long cccr = CCCR; + unsigned int m = M_clk_mult[(cccr >> 5) & 0x03]; + + return parent_rate / m; +} +PARENTS(clk_pxa25x_memory) = { "run" }; +RATE_RO_OPS(clk_pxa25x_memory, "memory"); + +PARENTS(pxa25x_pbus95) = { "ppll_95_85mhz", "ppll_95_85mhz" }; +PARENTS(pxa25x_pbus147) = { "ppll_147_46mhz", "ppll_147_46mhz" }; +PARENTS(pxa25x_osc3) = { "osc_3_6864mhz", "osc_3_6864mhz" }; + +#define PXA25X_CKEN(dev_id, con_id, parents, mult, div, \ + bit, is_lp, flags) \ + PXA_CKEN(dev_id, con_id, bit, parents, mult, div, mult, div, \ + is_lp, &CKEN, CKEN_ ## bit, flags) +#define PXA25X_PBUS95_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ + PXA25X_CKEN(dev_id, con_id, pxa25x_pbus95_parents, mult_hp, \ + div_hp, bit, NULL, 0) +#define PXA25X_PBUS147_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay)\ + PXA25X_CKEN(dev_id, con_id, pxa25x_pbus147_parents, mult_hp, \ + div_hp, bit, NULL, 0) +#define PXA25X_OSC3_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ + PXA25X_CKEN(dev_id, con_id, pxa25x_osc3_parents, mult_hp, \ + div_hp, bit, NULL, 0) + +#define PXA25X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ + PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ + &CKEN, CKEN_ ## bit, 0) +#define PXA25X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ + PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ + &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) + +static struct desc_clk_cken pxa25x_clocks[] __initdata = { + PXA25X_PBUS95_CKEN("pxa2xx-mci.0", NULL, MMC, 1, 5, 0), + PXA25X_PBUS95_CKEN("pxa2xx-i2c.0", NULL, I2C, 1, 3, 0), + PXA25X_PBUS95_CKEN("pxa2xx-ir", "FICPCLK", FICP, 1, 2, 0), + PXA25X_PBUS95_CKEN("pxa25x-udc", NULL, USB, 1, 2, 5), + PXA25X_PBUS147_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 10, 1), + PXA25X_PBUS147_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 10, 1), + PXA25X_PBUS147_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 10, 1), + PXA25X_PBUS147_CKEN("pxa2xx-uart.3", NULL, HWUART, 1, 10, 1), + PXA25X_PBUS147_CKEN("pxa2xx-i2s", NULL, I2S, 1, 10, 0), + PXA25X_PBUS147_CKEN(NULL, "AC97CLK", AC97, 1, 12, 0), + PXA25X_OSC3_CKEN("pxa25x-ssp.0", NULL, SSP, 1, 1, 0), + PXA25X_OSC3_CKEN("pxa25x-nssp.1", NULL, NSSP, 1, 1, 0), + PXA25X_OSC3_CKEN("pxa25x-nssp.2", NULL, ASSP, 1, 1, 0), + PXA25X_OSC3_CKEN("pxa25x-pwm.0", NULL, PWM0, 1, 1, 0), + PXA25X_OSC3_CKEN("pxa25x-pwm.1", NULL, PWM1, 1, 1, 0), + + PXA25X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, clk_pxa25x_memory_parents, 0), + PXA25X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, + clk_pxa25x_memory_parents, 0), +}; + +static u8 clk_pxa25x_core_get_parent(struct clk_hw *hw) +{ + unsigned long clkcfg; + unsigned int t; + + asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); + t = clkcfg & (1 << 0); + if (t) + return PXA_CORE_TURBO; + return PXA_CORE_RUN; +} + +static unsigned long clk_pxa25x_core_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate; +} +PARENTS(clk_pxa25x_core) = { "run", "cpll" }; +MUX_RO_RATE_RO_OPS(clk_pxa25x_core, "core"); + +static unsigned long clk_pxa25x_run_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long cccr = CCCR; + unsigned int n2 = N2_clk_mult[(cccr >> 7) & 0x07]; + + return (parent_rate / n2) * 2; +} +PARENTS(clk_pxa25x_run) = { "cpll" }; +RATE_RO_OPS(clk_pxa25x_run, "run"); + +static unsigned long clk_pxa25x_cpll_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long clkcfg, cccr = CCCR; + unsigned int l, m, n2, t; + + asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); + t = clkcfg & (1 << 0); + l = L_clk_mult[(cccr >> 0) & 0x1f]; + m = M_clk_mult[(cccr >> 5) & 0x03]; + n2 = N2_clk_mult[(cccr >> 7) & 0x07]; + + if (t) + return m * l * n2 * parent_rate / 2; + return m * l * parent_rate; +} +PARENTS(clk_pxa25x_cpll) = { "osc_3_6864mhz" }; +RATE_RO_OPS(clk_pxa25x_cpll, "cpll"); + +static void __init pxa25x_register_core(void) +{ + clk_register_clk_pxa25x_cpll(); + clk_register_clk_pxa25x_run(); + clkdev_pxa_register(CLK_CORE, "core", NULL, + clk_register_clk_pxa25x_core()); +} + +static void __init pxa25x_register_plls(void) +{ + clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL, + CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, + 3686400); + clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, + CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, + 32768); + clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); + clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz", + 0, 26, 1); + clk_register_fixed_factor(NULL, "ppll_147_46mhz", "osc_3_6864mhz", + 0, 40, 1); +} + +static void __init pxa25x_base_clocks_init(void) +{ + pxa25x_register_plls(); + pxa25x_register_core(); + clk_register_clk_pxa25x_memory(); +} + +#define DUMMY_CLK(_con_id, _dev_id, _parent) \ + { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent } +struct dummy_clk { + const char *con_id; + const char *dev_id; + const char *parent; +}; +static struct dummy_clk dummy_clks[] __initdata = { + DUMMY_CLK(NULL, "pxa25x-gpio", "osc_32_768khz"), + DUMMY_CLK(NULL, "pxa26x-gpio", "osc_32_768khz"), + DUMMY_CLK("GPIO11_CLK", NULL, "osc_3_6864mhz"), + DUMMY_CLK("GPIO12_CLK", NULL, "osc_32_768khz"), + DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"), + DUMMY_CLK("OSTIMER0", NULL, "osc_32_768khz"), + DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"), +}; + +static void __init pxa25x_dummy_clocks_init(void) +{ + struct clk *clk; + struct dummy_clk *d; + const char *name; + int i; + + /* + * All pinctrl logic has been wiped out of the clock driver, especially + * for gpio11 and gpio12 outputs. Machine code should ensure proper pin + * control (ie. pxa2xx_mfp_config() invocation). + */ + for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) { + d = &dummy_clks[i]; + name = d->dev_id ? d->dev_id : d->con_id; + clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1); + clk_register_clkdev(clk, d->con_id, d->dev_id); + } +} + +int __init pxa25x_clocks_init(void) +{ + pxa25x_base_clocks_init(); + pxa25x_dummy_clocks_init(); + return clk_pxa_cken_init(pxa25x_clocks, ARRAY_SIZE(pxa25x_clocks)); +} + +static void __init pxa25x_dt_clocks_init(struct device_node *np) +{ + pxa25x_clocks_init(); + clk_pxa_dt_common_init(np); +} +CLK_OF_DECLARE(pxa25x_clks, "marvell,pxa250-core-clocks", + pxa25x_dt_clocks_init); diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index b345cc791e5d..5f9b54b024b9 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -111,7 +111,7 @@ PARENTS(pxa27x_membus) = { "lcd_base", "lcd_base" }; PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) -static struct pxa_clk_cken pxa27x_clocks[] = { +static struct desc_clk_cken pxa27x_clocks[] __initdata = { PXA27X_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 2, 42, 1), PXA27X_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 2, 42, 1), PXA27X_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 2, 42, 1), @@ -322,7 +322,7 @@ static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, unsigned long ccsr = CCSR; osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); - a = cccr & CCCR_A_BIT; + a = cccr & (1 << CCCR_A_BIT); l = ccsr & CCSR_L_MASK; if (osc_forced || a) @@ -341,7 +341,7 @@ static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) unsigned long ccsr = CCSR; osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); - a = cccr & CCCR_A_BIT; + a = cccr & (1 << CCCR_A_BIT); if (osc_forced) return PXA_MEM_13Mhz; if (a) @@ -368,3 +368,10 @@ static int __init pxa27x_clocks_init(void) return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks)); } postcore_initcall(pxa27x_clocks_init); + +static void __init pxa27x_dt_clocks_init(struct device_node *np) +{ + pxa27x_clocks_init(); + clk_pxa_dt_common_init(np); +} +CLK_OF_DECLARE(pxa_clks, "marvell,pxa270-clocks", pxa27x_dt_clocks_init); diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index b823bc3b6250..60873a7f45d9 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -141,7 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) static long clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_pll *pll = to_clk_pll(hw); const struct pll_freq_tbl *f; diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index b6e6959e89aa..0b93972c8807 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -368,16 +368,17 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) static long _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { unsigned long clk_flags; + struct clk *p; f = qcom_find_freq(f, rate); if (!f) return -EINVAL; clk_flags = __clk_get_flags(hw->clk); - *p = clk_get_parent_by_index(hw->clk, f->src); + p = clk_get_parent_by_index(hw->clk, f->src); if (clk_flags & CLK_SET_RATE_PARENT) { rate = rate * f->pre_div; if (f->n) { @@ -387,15 +388,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, rate = tmp; } } else { - rate = __clk_get_rate(*p); + rate = __clk_get_rate(p); } + *p_hw = __clk_get_hw(p); *p_rate = rate; return f->freq; } static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg *rcg = to_clk_rcg(hw); @@ -403,7 +405,7 @@ static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, } static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); @@ -411,13 +413,15 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, } static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { struct clk_rcg *rcg = to_clk_rcg(hw); const struct freq_tbl *f = rcg->freq_tbl; + struct clk *p; - *p = clk_get_parent_by_index(hw->clk, f->src); - *p_rate = __clk_round_rate(*p, rate); + p = clk_get_parent_by_index(hw->clk, f->src); + *p_hw = __clk_get_hw(p); + *p_rate = __clk_round_rate(p, rate); return *p_rate; } diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index cfa9eb4fe9ca..08b8b3729f53 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -175,16 +175,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) static long _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { unsigned long clk_flags; + struct clk *p; f = qcom_find_freq(f, rate); if (!f) return -EINVAL; clk_flags = __clk_get_flags(hw->clk); - *p = clk_get_parent_by_index(hw->clk, f->src); + p = clk_get_parent_by_index(hw->clk, f->src); if (clk_flags & CLK_SET_RATE_PARENT) { if (f->pre_div) { rate /= 2; @@ -198,15 +199,16 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, rate = tmp; } } else { - rate = __clk_get_rate(*p); + rate = __clk_get_rate(p); } + *p_hw = __clk_get_hw(p); *p_rate = rate; return f->freq; } static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); @@ -359,7 +361,7 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, } static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -371,7 +373,7 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, u32 hid_div; /* Force the correct parent */ - *p = clk_get_parent_by_index(hw->clk, f->src); + *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, f->src)); if (src_rate == 810000000) frac = frac_table_810m; @@ -410,18 +412,20 @@ const struct clk_ops clk_edp_pixel_ops = { EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p_hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; unsigned long parent_rate, div; u32 mask = BIT(rcg->hid_width) - 1; + struct clk *p; if (rate == 0) return -EINVAL; - *p = clk_get_parent_by_index(hw->clk, f->src); - *p_rate = parent_rate = __clk_round_rate(*p, rate); + p = clk_get_parent_by_index(hw->clk, f->src); + *p_hw = __clk_get_hw(p); + *p_rate = parent_rate = __clk_round_rate(p, rate); div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; div = min_t(u32, div, mask); @@ -472,14 +476,16 @@ static const struct frac_entry frac_table_pixel[] = { }; static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *p_rate, struct clk **p) + unsigned long *p_rate, struct clk_hw **p) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; int delta = 100000; const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac = frac_table_pixel; - struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src); + struct clk *parent = clk_get_parent_by_index(hw->clk, f->src); + + *p = __clk_get_hw(parent); for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index dab988ab8cf1..157139a5c1ca 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -3122,7 +3122,7 @@ static struct clk_regmap *mmcc_apq8084_clocks[] = { [ESC1_CLK_SRC] = &esc1_clk_src.clkr, [HDMI_CLK_SRC] = &hdmi_clk_src.clkr, [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, - [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr, + [MMSS_RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr, [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr, [MAPLE_CLK_SRC] = &maple_clk_src.clkr, [VDP_CLK_SRC] = &vdp_clk_src.clkr, diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index bd8514d63634..2714097f90db 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,6 +6,7 @@ obj-y += clk-rockchip.o obj-y += clk.o obj-y += clk-pll.o obj-y += clk-cpu.o +obj-y += clk-mmc-phase.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3188.o diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c new file mode 100644 index 000000000000..c842e3b60f21 --- /dev/null +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -0,0 +1,154 @@ +/* + * Copyright 2014 Google, Inc + * Author: Alexandru M Stan <amstan@chromium.org> + * + * 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/slab.h> +#include <linux/clk-provider.h> +#include "clk.h" + +struct rockchip_mmc_clock { + struct clk_hw hw; + void __iomem *reg; + int id; + int shift; +}; + +#define to_mmc_clock(_hw) container_of(_hw, struct rockchip_mmc_clock, hw) + +#define RK3288_MMC_CLKGEN_DIV 2 + +static unsigned long rockchip_mmc_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate / RK3288_MMC_CLKGEN_DIV; +} + +#define ROCKCHIP_MMC_DELAY_SEL BIT(10) +#define ROCKCHIP_MMC_DEGREE_MASK 0x3 +#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 +#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) + +#define PSECS_PER_SEC 1000000000000LL + +/* + * Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to + * simplify calculations. So 45degs could be anywhere between 33deg and 66deg. + */ +#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 + +static int rockchip_mmc_get_phase(struct clk_hw *hw) +{ + struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw); + unsigned long rate = clk_get_rate(hw->clk); + u32 raw_value; + u16 degrees; + u32 delay_num = 0; + + raw_value = readl(mmc_clock->reg) >> (mmc_clock->shift); + + degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; + + if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { + /* degrees/delaynum * 10000 */ + unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * + 36 * (rate / 1000000); + + delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); + delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; + degrees += delay_num * factor / 10000; + } + + return degrees % 360; +} + +static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees) +{ + struct rockchip_mmc_clock *mmc_clock = to_mmc_clock(hw); + unsigned long rate = clk_get_rate(hw->clk); + u8 nineties, remainder; + u8 delay_num; + u32 raw_value; + u64 delay; + + /* allow 22 to be 22.5 */ + degrees++; + /* floor to 22.5 increment */ + degrees -= ((degrees) * 10 % 225) / 10; + + nineties = degrees / 90; + /* 22.5 multiples */ + remainder = (degrees % 90) / 22; + + delay = PSECS_PER_SEC; + do_div(delay, rate); + /* / 360 / 22.5 */ + do_div(delay, 16); + do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC); + + delay *= remainder; + delay_num = (u8) min(delay, 255ULL); + + raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; + raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; + raw_value |= nineties; + writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg); + + pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n", + __clk_get_name(hw->clk), degrees, delay_num, + mmc_clock->reg, raw_value>>(mmc_clock->shift), + rockchip_mmc_get_phase(hw) + ); + + return 0; +} + +static const struct clk_ops rockchip_mmc_clk_ops = { + .recalc_rate = rockchip_mmc_recalc, + .get_phase = rockchip_mmc_get_phase, + .set_phase = rockchip_mmc_set_phase, +}; + +struct clk *rockchip_clk_register_mmc(const char *name, + const char **parent_names, u8 num_parents, + void __iomem *reg, int shift) +{ + struct clk_init_data init; + struct rockchip_mmc_clock *mmc_clock; + struct clk *clk; + + mmc_clock = kmalloc(sizeof(*mmc_clock), GFP_KERNEL); + if (!mmc_clock) + return NULL; + + init.num_parents = num_parents; + init.parent_names = parent_names; + init.ops = &rockchip_mmc_clk_ops; + + mmc_clock->hw.init = &init; + mmc_clock->reg = reg; + mmc_clock->shift = shift; + + if (name) + init.name = name; + + clk = clk_register(NULL, &mmc_clock->hw); + if (IS_ERR(clk)) + goto err_free; + + return clk; + +err_free: + kfree(mmc_clock); + return NULL; +} diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index a3e886a38480..f8d3baf275b2 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -39,6 +39,7 @@ struct rockchip_clk_pll { int lock_offset; unsigned int lock_shift; enum rockchip_pll_type type; + u8 flags; const struct rockchip_pll_rate_table *rate_table; unsigned int rate_count; spinlock_t *lock; @@ -257,6 +258,55 @@ static int rockchip_rk3066_pll_is_enabled(struct clk_hw *hw) return !(pllcon & RK3066_PLLCON3_PWRDOWN); } +static void rockchip_rk3066_pll_init(struct clk_hw *hw) +{ + struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); + const struct rockchip_pll_rate_table *rate; + unsigned int nf, nr, no, bwadj; + unsigned long drate; + u32 pllcon; + + if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE)) + return; + + drate = __clk_get_rate(hw->clk); + rate = rockchip_get_pll_settings(pll, drate); + + /* when no rate setting for the current rate, rely on clk_set_rate */ + if (!rate) + return; + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(0)); + nr = ((pllcon >> RK3066_PLLCON0_NR_SHIFT) & RK3066_PLLCON0_NR_MASK) + 1; + no = ((pllcon >> RK3066_PLLCON0_OD_SHIFT) & RK3066_PLLCON0_OD_MASK) + 1; + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(1)); + nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK) + 1; + + pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2)); + bwadj = (pllcon >> RK3066_PLLCON2_BWADJ_SHIFT) & RK3066_PLLCON2_BWADJ_MASK; + + pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), bwadj(%d:%d)\n", + __func__, __clk_get_name(hw->clk), drate, rate->nr, nr, + rate->no, no, rate->nf, nf, rate->bwadj, bwadj); + if (rate->nr != nr || rate->no != no || rate->nf != nf + || rate->bwadj != bwadj) { + struct clk *parent = __clk_get_parent(hw->clk); + unsigned long prate; + + if (!parent) { + pr_warn("%s: parent of %s not available\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n", + __func__, __clk_get_name(hw->clk)); + prate = __clk_get_rate(parent); + rockchip_rk3066_pll_set_rate(hw, drate, prate); + } +} + static const struct clk_ops rockchip_rk3066_pll_clk_norate_ops = { .recalc_rate = rockchip_rk3066_pll_recalc_rate, .enable = rockchip_rk3066_pll_enable, @@ -271,6 +321,7 @@ static const struct clk_ops rockchip_rk3066_pll_clk_ops = { .enable = rockchip_rk3066_pll_enable, .disable = rockchip_rk3066_pll_disable, .is_enabled = rockchip_rk3066_pll_is_enabled, + .init = rockchip_rk3066_pll_init, }; /* @@ -282,7 +333,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, void __iomem *base, int con_offset, int grf_lock_offset, int lock_shift, int mode_offset, int mode_shift, struct rockchip_pll_rate_table *rate_table, - spinlock_t *lock) + u8 clk_pll_flags, spinlock_t *lock) { const char *pll_parents[3]; struct clk_init_data init; @@ -345,8 +396,22 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, pll->reg_base = base + con_offset; pll->lock_offset = grf_lock_offset; pll->lock_shift = lock_shift; + pll->flags = clk_pll_flags; pll->lock = lock; + /* create the mux on top of the real pll */ + pll->pll_mux_ops = &clk_mux_ops; + pll_mux = &pll->pll_mux; + pll_mux->reg = base + mode_offset; + pll_mux->shift = mode_shift; + pll_mux->mask = PLL_MODE_MASK; + pll_mux->flags = 0; + pll_mux->lock = lock; + pll_mux->hw.init = &init; + + if (pll_type == pll_rk3066) + pll_mux->flags |= CLK_MUX_HIWORD_MASK; + pll_clk = clk_register(NULL, &pll->hw); if (IS_ERR(pll_clk)) { pr_err("%s: failed to register pll clock %s : %ld\n", @@ -355,10 +420,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, goto err_pll; } - /* create the mux on top of the real pll */ - pll->pll_mux_ops = &clk_mux_ops; - pll_mux = &pll->pll_mux; - /* the actual muxing is xin24m, pll-output, xin32k */ pll_parents[0] = parent_names[0]; pll_parents[1] = pll_name; @@ -370,16 +431,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, init.parent_names = pll_parents; init.num_parents = ARRAY_SIZE(pll_parents); - pll_mux->reg = base + mode_offset; - pll_mux->shift = mode_shift; - pll_mux->mask = PLL_MODE_MASK; - pll_mux->flags = 0; - pll_mux->lock = lock; - pll_mux->hw.init = &init; - - if (pll_type == pll_rk3066) - pll_mux->flags |= CLK_MUX_HIWORD_MASK; - mux_clk = clk_register(NULL, &pll_mux->hw); if (IS_ERR(mux_clk)) goto err_mux; diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index beed49c79126..c54078960847 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -212,13 +212,13 @@ PNAME(mux_sclk_macref_p) = { "mac_src", "ext_rmii" }; static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = { [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0), - RK2928_MODE_CON, 0, 6, rk3188_pll_rates), + RK2928_MODE_CON, 0, 6, 0, rk3188_pll_rates), [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4), - RK2928_MODE_CON, 4, 5, NULL), + RK2928_MODE_CON, 4, 5, 0, NULL), [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8), - RK2928_MODE_CON, 8, 7, rk3188_pll_rates), + RK2928_MODE_CON, 8, 7, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates), [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12), - RK2928_MODE_CON, 12, 8, rk3188_pll_rates), + RK2928_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates), }; #define MFLAGS CLK_MUX_HIWORD_MASK @@ -257,9 +257,9 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(0, "hclk_vdpu", "aclk_vdpu", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS), - GATE(0, "gpll_ddr", "gpll", 0, + GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 7, GFLAGS), - COMPOSITE(0, "ddrphy", mux_ddrphy_p, 0, + COMPOSITE(0, "ddrphy", mux_ddrphy_p, CLK_IGNORE_UNUSED, RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK2928_CLKGATE_CON(0), 2, GFLAGS), @@ -270,10 +270,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 6, GFLAGS), GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 5, GFLAGS), - GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, + GATE(0, "hclk_cpu", "hclk_cpu_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(0), 4, GFLAGS), - COMPOSITE(0, "aclk_lcdc0_pre", mux_pll_src_cpll_gpll_p, 0, + COMPOSITE(0, "aclk_lcdc0_pre", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, RK2928_CLKSEL_CON(31), 7, 1, MFLAGS, 0, 5, DFLAGS, RK2928_CLKGATE_CON(3), 0, GFLAGS), COMPOSITE(0, "aclk_lcdc1_pre", mux_pll_src_cpll_gpll_p, 0, @@ -304,9 +304,9 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { * the 480m are generated inside the usb block from these clocks, * but they are also a source for the hsicphy clock. */ - GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", 0, + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 5, GFLAGS), - GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", 0, + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(1), 6, GFLAGS), COMPOSITE(0, "mac_src", mux_mac_p, 0, @@ -320,9 +320,9 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0, RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, RK2928_CLKGATE_CON(2), 6, GFLAGS), - COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", + COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0, RK2928_CLKSEL_CON(23), 0, - RK2928_CLKGATE_CON(2), 7, 0, GFLAGS), + RK2928_CLKGATE_CON(2), 7, GFLAGS), MUX(SCLK_HSADC, "sclk_hsadc", mux_sclk_hsadc_p, 0, RK2928_CLKSEL_CON(22), 4, 2, MFLAGS), @@ -330,6 +330,15 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { RK2928_CLKSEL_CON(24), 8, 8, DFLAGS, RK2928_CLKGATE_CON(2), 8, GFLAGS), + COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, + RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, + RK2928_CLKGATE_CON(0), 13, GFLAGS), + COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0, + RK2928_CLKSEL_CON(9), 0, + RK2928_CLKGATE_CON(0), 14, GFLAGS), + MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0, + RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), + /* * Clock-Architecture Diagram 4 */ @@ -399,8 +408,8 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { /* aclk_cpu gates */ GATE(ACLK_DMA1, "aclk_dma1", "aclk_cpu", 0, RK2928_CLKGATE_CON(5), 0, GFLAGS), - GATE(0, "aclk_intmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(4), 12, GFLAGS), - GATE(0, "aclk_strc_sys", "aclk_cpu", 0, RK2928_CLKGATE_CON(4), 10, GFLAGS), + GATE(0, "aclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 12, GFLAGS), + GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 10, GFLAGS), /* hclk_cpu gates */ GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(5), 6, GFLAGS), @@ -410,14 +419,14 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { /* hclk_ahb2apb is part of a clk branch */ GATE(0, "hclk_vio_bus", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS), GATE(HCLK_LCDC0, "hclk_lcdc0", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 1, GFLAGS), - GATE(HCLK_LCDC1, "hclk_lcdc1", "aclk_cpu", 0, RK2928_CLKGATE_CON(6), 2, GFLAGS), + GATE(HCLK_LCDC1, "hclk_lcdc1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 2, GFLAGS), GATE(HCLK_CIF0, "hclk_cif0", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 4, GFLAGS), GATE(HCLK_IPP, "hclk_ipp", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 9, GFLAGS), GATE(HCLK_RGA, "hclk_rga", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 10, GFLAGS), /* hclk_peri gates */ - GATE(0, "hclk_peri_axi_matrix", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 0, GFLAGS), - GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 6, GFLAGS), + GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 6, GFLAGS), GATE(0, "hclk_emem_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 7, GFLAGS), GATE(HCLK_EMAC, "hclk_emac", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS), GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS), @@ -457,18 +466,18 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(0, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS), GATE(0, "pclk_ddrpubl", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS), GATE(0, "pclk_dbg", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS), - GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 4, GFLAGS), - GATE(PCLK_PMU, "pclk_pmu", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 5, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 5, GFLAGS), /* aclk_peri */ GATE(ACLK_DMA2, "aclk_dma2", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS), GATE(ACLK_SMC, "aclk_smc", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 8, GFLAGS), - GATE(0, "aclk_peri_niu", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 4, GFLAGS), - GATE(0, "aclk_cpu_peri", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 2, GFLAGS), - GATE(0, "aclk_peri_axi_matrix", "aclk_peri", 0, RK2928_CLKGATE_CON(4), 3, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 4, GFLAGS), + GATE(0, "aclk_cpu_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS), + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 3, GFLAGS), /* pclk_peri gates */ - GATE(0, "pclk_peri_axi_matrix", "pclk_peri", 0, RK2928_CLKGATE_CON(4), 1, GFLAGS), + GATE(0, "pclk_peri_axi_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS), GATE(PCLK_PWM23, "pclk_pwm23", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 11, GFLAGS), GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS), GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS), @@ -511,7 +520,7 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { | CLK_DIVIDER_READ_ONLY, RK2928_CLKGATE_CON(4), 9, GFLAGS), - GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, + GATE(CORE_L2C, "core_l2c", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 4, GFLAGS), COMPOSITE(0, "aclk_peri_pre", mux_pll_src_gpll_cpll_p, 0, @@ -577,14 +586,6 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 12, GFLAGS), MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0, RK2928_CLKSEL_CON(4), 8, 2, MFLAGS), - COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, - RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, - RK2928_CLKGATE_CON(0), 13, GFLAGS), - COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0, - RK2928_CLKSEL_CON(9), 0, - RK2928_CLKGATE_CON(0), 14, GFLAGS), - MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0, - RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), @@ -618,7 +619,7 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", "gpll", "cpll" }; static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { - COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, + COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED, RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), @@ -633,7 +634,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK2928_CLKGATE_CON(4), 9, GFLAGS), - GATE(CORE_L2C, "core_l2c", "armclk", 0, + GATE(CORE_L2C, "core_l2c", "armclk", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 4, GFLAGS), COMPOSITE(0, "aclk_peri_pre", mux_pll_src_cpll_gpll_p, 0, @@ -663,7 +664,7 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { RK2928_CLKSEL_CON(30), 0, 2, DFLAGS, RK2928_CLKGATE_CON(3), 6, GFLAGS), DIV(0, "sclk_hsicphy_12m", "sclk_hsicphy_480m", 0, - RK2928_CLKGATE_CON(11), 8, 6, DFLAGS), + RK2928_CLKSEL_CON(11), 8, 6, DFLAGS), MUX(0, "i2s_src", mux_pll_src_gpll_cpll_p, 0, RK2928_CLKSEL_CON(2), 15, 1, MFLAGS), @@ -675,14 +676,6 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { RK2928_CLKGATE_CON(0), 10, GFLAGS), MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0, RK2928_CLKSEL_CON(3), 8, 2, MFLAGS), - COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0, - RK2928_CLKSEL_CON(5), 0, 7, DFLAGS, - RK2928_CLKGATE_CON(13), 13, GFLAGS), - COMPOSITE_FRAC(0, "spdif_frac", "spdif_pll", 0, - RK2928_CLKSEL_CON(9), 0, - RK2928_CLKGATE_CON(0), 14, GFLAGS), - MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0, - RK2928_CLKSEL_CON(5), 8, 2, MFLAGS), GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 23278291da44..ac6be7c0132d 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -16,6 +16,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include <dt-bindings/clock/rk3288-cru.h> #include "clk.h" @@ -83,11 +84,13 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = { RK3066_PLL_RATE( 742500000, 8, 495, 2), RK3066_PLL_RATE( 696000000, 1, 58, 2), RK3066_PLL_RATE( 600000000, 1, 50, 2), - RK3066_PLL_RATE( 594000000, 2, 198, 4), + RK3066_PLL_RATE_BWADJ(594000000, 1, 198, 8, 1), RK3066_PLL_RATE( 552000000, 1, 46, 2), RK3066_PLL_RATE( 504000000, 1, 84, 4), + RK3066_PLL_RATE( 500000000, 3, 125, 2), RK3066_PLL_RATE( 456000000, 1, 76, 4), RK3066_PLL_RATE( 408000000, 1, 68, 4), + RK3066_PLL_RATE( 400000000, 3, 100, 2), RK3066_PLL_RATE( 384000000, 2, 128, 4), RK3066_PLL_RATE( 360000000, 1, 60, 4), RK3066_PLL_RATE( 312000000, 1, 52, 4), @@ -173,14 +176,14 @@ PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu" }; PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; -PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" }; +PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usbphy480m_src" }; +PNAME(mux_pll_src_cpll_gll_usb_npll_p) = { "cpll", "gpll", "usbphy480m_src", "npll" }; PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "xin24m" }; PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" }; PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" }; PNAME(mux_spdif_p) = { "spdif_pre", "spdif_frac", "xin12m" }; PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac", "xin12m" }; -PNAME(mux_uart0_pll_p) = { "cpll", "gpll", "usbphy_480m_src", "npll" }; PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; @@ -192,22 +195,22 @@ PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; -PNAME(mux_usbphy480m_p) = { "sclk_otgphy0", "sclk_otgphy1", - "sclk_otgphy2" }; +PNAME(mux_usbphy480m_p) = { "sclk_otgphy1", "sclk_otgphy2", + "sclk_otgphy0" }; PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy480m_src" }; PNAME(mux_hsicphy12m_p) = { "hsicphy12m_xin12m", "hsicphy12m_usbphy" }; static struct rockchip_pll_clock rk3288_pll_clks[] __initdata = { [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK3288_PLL_CON(0), - RK3288_MODE_CON, 0, 6, rk3288_pll_rates), + RK3288_MODE_CON, 0, 6, 0, rk3288_pll_rates), [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3288_PLL_CON(4), - RK3288_MODE_CON, 4, 5, NULL), + RK3288_MODE_CON, 4, 5, 0, NULL), [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3288_PLL_CON(8), - RK3288_MODE_CON, 8, 7, rk3288_pll_rates), + RK3288_MODE_CON, 8, 7, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3288_PLL_CON(12), - RK3288_MODE_CON, 12, 8, rk3288_pll_rates), + RK3288_MODE_CON, 12, 8, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3288_PLL_CON(16), - RK3288_MODE_CON, 14, 9, rk3288_pll_rates), + RK3288_MODE_CON, 14, 9, ROCKCHIP_PLL_SYNC_RATE, rk3288_pll_rates), }; static struct clk_div_table div_hclk_cpu_t[] = { @@ -226,67 +229,67 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { * Clock-Architecture Diagram 1 */ - GATE(0, "apll_core", "apll", 0, + GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 1, GFLAGS), - GATE(0, "gpll_core", "gpll", 0, + GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 2, GFLAGS), - COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, + COMPOSITE_NOMUX(0, "armcore0", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(36), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 0, GFLAGS), - COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, + COMPOSITE_NOMUX(0, "armcore1", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(36), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 1, GFLAGS), - COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, + COMPOSITE_NOMUX(0, "armcore2", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(36), 8, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 2, GFLAGS), - COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, + COMPOSITE_NOMUX(0, "armcore3", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(36), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 3, GFLAGS), - COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, + COMPOSITE_NOMUX(0, "l2ram", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(37), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 4, GFLAGS), - COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, + COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(0), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 5, GFLAGS), - COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, + COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(0), 4, 4, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 6, GFLAGS), COMPOSITE_NOMUX(0, "atclk", "armclk", 0, RK3288_CLKSEL_CON(37), 4, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 7, GFLAGS), - COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, + COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(37), 9, 5, DFLAGS | CLK_DIVIDER_READ_ONLY, RK3288_CLKGATE_CON(12), 8, GFLAGS), GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, RK3288_CLKGATE_CON(12), 9, GFLAGS), - GATE(0, "cs_dbg", "pclk_dbg_pre", 0, + GATE(0, "cs_dbg", "pclk_dbg_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(12), 10, GFLAGS), GATE(0, "pclk_core_niu", "pclk_dbg_pre", 0, RK3288_CLKGATE_CON(12), 11, GFLAGS), - GATE(0, "dpll_ddr", "dpll", 0, + GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 8, GFLAGS), GATE(0, "gpll_ddr", "gpll", 0, RK3288_CLKGATE_CON(0), 9, GFLAGS), - COMPOSITE_NOGATE(0, "ddrphy", mux_ddrphy_p, 0, + COMPOSITE_NOGATE(0, "ddrphy", mux_ddrphy_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(26), 2, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), - GATE(0, "gpll_aclk_cpu", "gpll", 0, + GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 10, GFLAGS), - GATE(0, "cpll_aclk_cpu", "cpll", 0, + GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 11, GFLAGS), - COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0, + COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(1), 15, 1, MFLAGS, 3, 5, DFLAGS), - DIV(0, "aclk_cpu_pre", "aclk_cpu_src", 0, + DIV(0, "aclk_cpu_pre", "aclk_cpu_src", CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(1), 0, 3, DFLAGS), - GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_pre", 0, + GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 3, GFLAGS), - COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_pre", 0, + COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(1), 12, 3, DFLAGS, RK3288_CLKGATE_CON(0), 5, GFLAGS), - COMPOSITE_NOMUX_DIVTBL(HCLK_CPU, "hclk_cpu", "aclk_cpu_pre", 0, + COMPOSITE_NOMUX_DIVTBL(HCLK_CPU, "hclk_cpu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(1), 8, 2, DFLAGS, div_hclk_cpu_t, RK3288_CLKGATE_CON(0), 4, GFLAGS), GATE(0, "c2c_host", "aclk_cpu_src", 0, @@ -294,7 +297,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0, RK3288_CLKSEL_CON(26), 6, 2, DFLAGS, RK3288_CLKGATE_CON(5), 4, GFLAGS), - GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", 0, + GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(0), 7, GFLAGS), COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0, @@ -305,7 +308,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKGATE_CON(4), 2, GFLAGS), MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(4), 8, 2, MFLAGS), - COMPOSITE_NODIV(0, "i2s0_clkout", mux_i2s_clkout_p, CLK_SET_RATE_PARENT, + COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0, RK3288_CLKSEL_CON(4), 12, 1, MFLAGS, RK3288_CLKGATE_CON(4), 0, GFLAGS), GATE(SCLK_I2S0, "sclk_i2s0", "i2s_pre", CLK_SET_RATE_PARENT, @@ -325,7 +328,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0, RK3288_CLKSEL_CON(40), 0, 7, DFLAGS, RK3288_CLKGATE_CON(4), 7, GFLAGS), - COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", 0, + COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_pre", 0, RK3288_CLKSEL_CON(41), 0, RK3288_CLKGATE_CON(4), 8, GFLAGS), COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, @@ -373,12 +376,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_vcodec_pre", 0, RK3288_CLKGATE_CON(9), 1, GFLAGS), - COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, 0, + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(31), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(3), 0, GFLAGS), DIV(0, "hclk_vio", "aclk_vio0", 0, RK3288_CLKSEL_CON(28), 8, 5, DFLAGS), - COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, 0, + COMPOSITE(0, "aclk_vio1", mux_pll_src_cpll_gpll_usb480m_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(3), 2, GFLAGS), @@ -436,24 +439,24 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { DIV(0, "pclk_pd_alive", "gpll", 0, RK3288_CLKSEL_CON(33), 8, 5, DFLAGS), - COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", 0, + COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(33), 0, 5, DFLAGS, RK3288_CLKGATE_CON(5), 8, GFLAGS), - COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_cpll_gpll_usb480m_p, 0, + COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_cpll_gll_usb_npll_p, 0, RK3288_CLKSEL_CON(34), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(5), 7, GFLAGS), - COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, 0, + COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(10), 15, 1, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(2), 0, GFLAGS), COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, RK3288_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK3288_CLKGATE_CON(2), 3, GFLAGS), - COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0, + COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, RK3288_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK3288_CLKGATE_CON(2), 2, GFLAGS), - GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0, + GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(2), 1, GFLAGS), /* @@ -483,6 +486,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(12), 14, 2, MFLAGS, 8, 6, DFLAGS, RK3288_CLKGATE_CON(13), 3, GFLAGS), + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3288_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3288_SDMMC_CON1, 0), + + MMC(SCLK_SDIO0_DRV, "sdio0_drv", "sclk_sdio0", RK3288_SDIO0_CON0, 1), + MMC(SCLK_SDIO0_SAMPLE, "sdio0_sample", "sclk_sdio0", RK3288_SDIO0_CON1, 0), + + MMC(SCLK_SDIO1_DRV, "sdio1_drv", "sclk_sdio1", RK3288_SDIO1_CON0, 1), + MMC(SCLK_SDIO1_SAMPLE, "sdio1_sample", "sclk_sdio1", RK3288_SDIO1_CON1, 0), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3288_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3288_EMMC_CON1, 0), + COMPOSITE(0, "sclk_tspout", mux_tspout_p, 0, RK3288_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(4), 11, GFLAGS), @@ -490,13 +505,13 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS, RK3288_CLKGATE_CON(4), 10, GFLAGS), - GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", 0, + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "usb480m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 4, GFLAGS), - GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", 0, + GATE(SCLK_OTGPHY1, "sclk_otgphy1", "usb480m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 5, GFLAGS), - GATE(SCLK_OTGPHY2, "sclk_otgphy2", "usb480m", 0, + GATE(SCLK_OTGPHY2, "sclk_otgphy2", "usb480m", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 6, GFLAGS), - GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", 0, + GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(13), 7, GFLAGS), COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin32k", 0, @@ -517,7 +532,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { RK3288_CLKSEL_CON(38), 15, 1, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(5), 6, GFLAGS), - COMPOSITE(0, "uart0_src", mux_uart0_pll_p, 0, + COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0, RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS, RK3288_CLKGATE_CON(1), 8, GFLAGS), COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0, @@ -585,7 +600,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0, RK3288_CLKSEL_CON(13), 11, 2, MFLAGS, - RK3288_CLKGATE_CON(5), 15, GFLAGS), + RK3288_CLKGATE_CON(5), 14, GFLAGS), COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0, RK3288_CLKSEL_CON(29), 0, 2, MFLAGS, RK3288_CLKGATE_CON(3), 6, GFLAGS), @@ -601,19 +616,19 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { */ /* aclk_cpu gates */ - GATE(0, "sclk_intmem0", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 5, GFLAGS), - GATE(0, "sclk_intmem1", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 6, GFLAGS), - GATE(0, "sclk_intmem2", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 7, GFLAGS), + GATE(0, "sclk_intmem0", "aclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 5, GFLAGS), + GATE(0, "sclk_intmem1", "aclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 6, GFLAGS), + GATE(0, "sclk_intmem2", "aclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 7, GFLAGS), GATE(ACLK_DMAC1, "aclk_dmac1", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 12, GFLAGS), - GATE(0, "aclk_strc_sys", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 13, GFLAGS), - GATE(0, "aclk_intmem", "aclk_cpu", 0, RK3288_CLKGATE_CON(10), 4, GFLAGS), + GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 13, GFLAGS), + GATE(0, "aclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 4, GFLAGS), GATE(ACLK_CRYPTO, "aclk_crypto", "aclk_cpu", 0, RK3288_CLKGATE_CON(11), 6, GFLAGS), GATE(0, "aclk_ccp", "aclk_cpu", 0, RK3288_CLKGATE_CON(11), 8, GFLAGS), /* hclk_cpu gates */ GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_cpu", 0, RK3288_CLKGATE_CON(11), 7, GFLAGS), GATE(HCLK_I2S0, "hclk_i2s0", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 8, GFLAGS), - GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 9, GFLAGS), + GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(10), 9, GFLAGS), GATE(HCLK_SPDIF, "hclk_spdif", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 10, GFLAGS), GATE(HCLK_SPDIF8CH, "hclk_spdif_8ch", "hclk_cpu", 0, RK3288_CLKGATE_CON(10), 11, GFLAGS), @@ -622,42 +637,42 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(PCLK_TIMER, "pclk_timer", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 1, GFLAGS), GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 2, GFLAGS), GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 3, GFLAGS), - GATE(0, "pclk_ddrupctl0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 14, GFLAGS), - GATE(0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS), - GATE(0, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS), - GATE(0, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS), + GATE(PCLK_DDRUPCTL0, "pclk_ddrupctl0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 14, GFLAGS), + GATE(PCLK_PUBL0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS), + GATE(PCLK_DDRUPCTL1, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS), + GATE(PCLK_PUBL1, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS), GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS), GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS), GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS), GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS), - GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 11, GFLAGS), + GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS), /* ddrctrl [DDR Controller PHY clock] gates */ - GATE(0, "nclk_ddrupctl0", "ddrphy", 0, RK3288_CLKGATE_CON(11), 4, GFLAGS), - GATE(0, "nclk_ddrupctl1", "ddrphy", 0, RK3288_CLKGATE_CON(11), 5, GFLAGS), + GATE(0, "nclk_ddrupctl0", "ddrphy", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 4, GFLAGS), + GATE(0, "nclk_ddrupctl1", "ddrphy", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 5, GFLAGS), /* ddrphy gates */ - GATE(0, "sclk_ddrphy0", "ddrphy", 0, RK3288_CLKGATE_CON(4), 12, GFLAGS), - GATE(0, "sclk_ddrphy1", "ddrphy", 0, RK3288_CLKGATE_CON(4), 13, GFLAGS), + GATE(0, "sclk_ddrphy0", "ddrphy", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(4), 12, GFLAGS), + GATE(0, "sclk_ddrphy1", "ddrphy", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(4), 13, GFLAGS), /* aclk_peri gates */ - GATE(0, "aclk_peri_axi_matrix", "aclk_peri", 0, RK3288_CLKGATE_CON(6), 2, GFLAGS), + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(6), 2, GFLAGS), GATE(ACLK_DMAC2, "aclk_dmac2", "aclk_peri", 0, RK3288_CLKGATE_CON(6), 3, GFLAGS), - GATE(0, "aclk_peri_niu", "aclk_peri", 0, RK3288_CLKGATE_CON(7), 11, GFLAGS), - GATE(ACLK_MMU, "aclk_mmu", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 12, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 11, GFLAGS), + GATE(ACLK_MMU, "aclk_mmu", "aclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(8), 12, GFLAGS), GATE(ACLK_GMAC, "aclk_gmac", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 0, GFLAGS), GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK3288_CLKGATE_CON(8), 2, GFLAGS), /* hclk_peri gates */ - GATE(0, "hclk_peri_matrix", "hclk_peri", 0, RK3288_CLKGATE_CON(6), 0, GFLAGS), - GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 4, GFLAGS), + GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(6), 0, GFLAGS), + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 4, GFLAGS), GATE(HCLK_USBHOST0, "hclk_host0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 6, GFLAGS), - GATE(HCLK_USBHOST1, "hclk_host1", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 7, GFLAGS), + GATE(HCLK_USBHOST1, "hclk_host1", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 7, GFLAGS), GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 8, GFLAGS), - GATE(0, "hclk_usb_peri", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 9, GFLAGS), - GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 10, GFLAGS), - GATE(0, "hclk_emem", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 12, GFLAGS), - GATE(0, "hclk_mem", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 13, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 9, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 10, GFLAGS), + GATE(0, "hclk_emem", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 12, GFLAGS), + GATE(0, "hclk_mem", "hclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(7), 13, GFLAGS), GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 14, GFLAGS), GATE(HCLK_NANDC1, "hclk_nandc1", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 15, GFLAGS), GATE(HCLK_TSP, "hclk_tsp", "hclk_peri", 0, RK3288_CLKGATE_CON(8), 8, GFLAGS), @@ -669,7 +684,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(0, "pmu_hclk_otg0", "hclk_peri", 0, RK3288_CLKGATE_CON(7), 5, GFLAGS), /* pclk_peri gates */ - GATE(0, "pclk_peri_matrix", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 1, GFLAGS), + GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(6), 1, GFLAGS), GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 4, GFLAGS), GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 5, GFLAGS), GATE(PCLK_SPI2, "pclk_spi2", "pclk_peri", 0, RK3288_CLKGATE_CON(6), 6, GFLAGS), @@ -705,48 +720,48 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { GATE(PCLK_GPIO4, "pclk_gpio4", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 4, GFLAGS), GATE(PCLK_GPIO5, "pclk_gpio5", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 5, GFLAGS), GATE(PCLK_GPIO6, "pclk_gpio6", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 6, GFLAGS), - GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 11, GFLAGS), - GATE(0, "pclk_alive_niu", "pclk_pd_alive", 0, RK3288_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(14), 11, GFLAGS), + GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(14), 12, GFLAGS), /* pclk_pd_pmu gates */ - GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 0, GFLAGS), - GATE(0, "pclk_intmem1", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 1, GFLAGS), - GATE(0, "pclk_pmu_niu", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 2, GFLAGS), - GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 3, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 0, GFLAGS), + GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 1, GFLAGS), + GATE(0, "pclk_pmu_niu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 2, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(17), 3, GFLAGS), GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3288_CLKGATE_CON(17), 4, GFLAGS), /* hclk_vio gates */ GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 1, GFLAGS), GATE(HCLK_VOP0, "hclk_vop0", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 6, GFLAGS), GATE(HCLK_VOP1, "hclk_vop1", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 8, GFLAGS), - GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 9, GFLAGS), - GATE(HCLK_VIO_NIU, "hclk_vio_niu", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 10, GFLAGS), + GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(15), 9, GFLAGS), + GATE(HCLK_VIO_NIU, "hclk_vio_niu", "hclk_vio", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(15), 10, GFLAGS), GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 15, GFLAGS), GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3288_CLKGATE_CON(15), 3, GFLAGS), GATE(HCLK_ISP, "hclk_isp", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 1, GFLAGS), - GATE(HCLK_VIO2_H2P, "hclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 10, GFLAGS), + GATE(HCLK_VIO2_H2P, "hclk_vio2_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(16), 10, GFLAGS), GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 4, GFLAGS), GATE(PCLK_MIPI_DSI1, "pclk_mipi_dsi1", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 5, GFLAGS), GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 6, GFLAGS), GATE(PCLK_LVDS_PHY, "pclk_lvds_phy", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 7, GFLAGS), - GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 8, GFLAGS), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(16), 8, GFLAGS), GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 9, GFLAGS), - GATE(PCLK_VIO2_H2P, "pclk_vio2_h2p", "hclk_vio", 0, RK3288_CLKGATE_CON(16), 11, GFLAGS), + GATE(PCLK_VIO2_H2P, "pclk_vio2_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(16), 11, GFLAGS), /* aclk_vio0 gates */ GATE(ACLK_VOP0, "aclk_vop0", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 5, GFLAGS), GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 2, GFLAGS), - GATE(ACLK_VIO0_NIU, "aclk_vio0_niu", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 11, GFLAGS), + GATE(ACLK_VIO0_NIU, "aclk_vio0_niu", "aclk_vio0", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(15), 11, GFLAGS), GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3288_CLKGATE_CON(15), 14, GFLAGS), /* aclk_vio1 gates */ GATE(ACLK_VOP1, "aclk_vop1", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 7, GFLAGS), GATE(ACLK_ISP, "aclk_isp", "aclk_vio1", 0, RK3288_CLKGATE_CON(16), 2, GFLAGS), - GATE(ACLK_VIO1_NIU, "aclk_vio1_niu", "aclk_vio1", 0, RK3288_CLKGATE_CON(15), 12, GFLAGS), + GATE(ACLK_VIO1_NIU, "aclk_vio1_niu", "aclk_vio1", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(15), 12, GFLAGS), /* aclk_rga_pre gates */ GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 0, GFLAGS), - GATE(ACLK_RGA_NIU, "aclk_rga_niu", "aclk_rga_pre", 0, RK3288_CLKGATE_CON(15), 13, GFLAGS), + GATE(ACLK_RGA_NIU, "aclk_rga_niu", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(15), 13, GFLAGS), /* * Other ungrouped clocks. @@ -762,6 +777,64 @@ static const char *rk3288_critical_clocks[] __initconst = { "hclk_peri", }; +#ifdef CONFIG_PM_SLEEP +static void __iomem *rk3288_cru_base; + +/* Some CRU registers will be reset in maskrom when the system + * wakes up from fastboot. + * So save them before suspend, restore them after resume. + */ +static const int rk3288_saved_cru_reg_ids[] = { + RK3288_MODE_CON, + RK3288_CLKSEL_CON(0), + RK3288_CLKSEL_CON(1), + RK3288_CLKSEL_CON(10), + RK3288_CLKSEL_CON(33), + RK3288_CLKSEL_CON(37), +}; + +static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)]; + +static int rk3288_clk_suspend(void) +{ + int i, reg_id; + + for (i = 0; i < ARRAY_SIZE(rk3288_saved_cru_reg_ids); i++) { + reg_id = rk3288_saved_cru_reg_ids[i]; + + rk3288_saved_cru_regs[i] = + readl_relaxed(rk3288_cru_base + reg_id); + } + return 0; +} + +static void rk3288_clk_resume(void) +{ + int i, reg_id; + + for (i = ARRAY_SIZE(rk3288_saved_cru_reg_ids) - 1; i >= 0; i--) { + reg_id = rk3288_saved_cru_reg_ids[i]; + + writel_relaxed(rk3288_saved_cru_regs[i] | 0xffff0000, + rk3288_cru_base + reg_id); + } +} + +static struct syscore_ops rk3288_clk_syscore_ops = { + .suspend = rk3288_clk_suspend, + .resume = rk3288_clk_resume, +}; + +static void rk3288_clk_sleep_init(void __iomem *reg_base) +{ + rk3288_cru_base = reg_base; + register_syscore_ops(&rk3288_clk_syscore_ops); +} + +#else /* CONFIG_PM_SLEEP */ +static void rk3288_clk_sleep_init(void __iomem *reg_base) {} +#endif + static void __init rk3288_clk_init(struct device_node *np) { void __iomem *reg_base; @@ -810,5 +883,6 @@ static void __init rk3288_clk_init(struct device_node *np) ROCKCHIP_SOFTRST_HIWORD_MASK); rockchip_register_restart_notifier(RK3288_GLB_SRST_FST); + rk3288_clk_sleep_init(reg_base); } CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 1e68bff481b8..20e05bbb3a67 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -90,9 +90,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, div->width = div_width; div->lock = lock; div->table = div_table; - div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) - ? &clk_divider_ro_ops - : &clk_divider_ops; + div_ops = &clk_divider_ops; } clk = clk_register_composite(NULL, name, parent_names, num_parents, @@ -199,7 +197,8 @@ void __init rockchip_clk_register_plls(struct rockchip_pll_clock *list, list->parent_names, list->num_parents, reg_base, list->con_offset, grf_lock_offset, list->lock_shift, list->mode_offset, - list->mode_shift, list->rate_table, &clk_lock); + list->mode_shift, list->rate_table, + list->pll_flags, &clk_lock); if (IS_ERR(clk)) { pr_err("%s: failed to register clock %s\n", __func__, list->name); @@ -246,9 +245,6 @@ void __init rockchip_clk_register_branches( list->div_flags, &clk_lock); break; case branch_fraction_divider: - /* keep all gates untouched for now */ - flags |= CLK_IGNORE_UNUSED; - clk = rockchip_clk_register_frac_branch(list->name, list->parent_names, list->num_parents, reg_base, list->muxdiv_offset, list->div_flags, @@ -258,18 +254,12 @@ void __init rockchip_clk_register_branches( case branch_gate: flags |= CLK_SET_RATE_PARENT; - /* keep all gates untouched for now */ - flags |= CLK_IGNORE_UNUSED; - clk = clk_register_gate(NULL, list->name, list->parent_names[0], flags, reg_base + list->gate_offset, list->gate_shift, list->gate_flags, &clk_lock); break; case branch_composite: - /* keep all gates untouched for now */ - flags |= CLK_IGNORE_UNUSED; - clk = rockchip_clk_register_branch(list->name, list->parent_names, list->num_parents, reg_base, list->muxdiv_offset, list->mux_shift, @@ -279,6 +269,14 @@ void __init rockchip_clk_register_branches( list->gate_offset, list->gate_shift, list->gate_flags, flags, &clk_lock); break; + case branch_mmc: + clk = rockchip_clk_register_mmc( + list->name, + list->parent_names, list->num_parents, + reg_base + list->muxdiv_offset, + list->div_shift + ); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index ca009ab0a33a..58d2e3bdf22f 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -48,6 +48,14 @@ #define RK3288_GLB_SRST_SND 0x1b4 #define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8) #define RK3288_MISC_CON 0x1e8 +#define RK3288_SDMMC_CON0 0x200 +#define RK3288_SDMMC_CON1 0x204 +#define RK3288_SDIO0_CON0 0x208 +#define RK3288_SDIO0_CON1 0x20c +#define RK3288_SDIO1_CON0 0x210 +#define RK3288_SDIO1_CON1 0x214 +#define RK3288_EMMC_CON0 0x218 +#define RK3288_EMMC_CON1 0x21c enum rockchip_pll_type { pll_rk3066, @@ -62,6 +70,15 @@ enum rockchip_pll_type { .bwadj = (_nf >> 1), \ } +#define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \ +{ \ + .rate = _rate##U, \ + .nr = _nr, \ + .nf = _nf, \ + .no = _no, \ + .bwadj = _bw, \ +} + struct rockchip_pll_rate_table { unsigned long rate; unsigned int nr; @@ -81,7 +98,12 @@ struct rockchip_pll_rate_table { * @mode_shift: offset inside the mode-register for the mode of this pll. * @lock_shift: offset inside the lock register for the lock status. * @type: Type of PLL to be registered. + * @pll_flags: hardware-specific flags * @rate_table: Table of usable pll rates + * + * Flags: + * ROCKCHIP_PLL_SYNC_RATE - check rate parameters to match against the + * rate_table parameters and ajust them if necessary. */ struct rockchip_pll_clock { unsigned int id; @@ -94,11 +116,14 @@ struct rockchip_pll_clock { int mode_shift; int lock_shift; enum rockchip_pll_type type; + u8 pll_flags; struct rockchip_pll_rate_table *rate_table; }; +#define ROCKCHIP_PLL_SYNC_RATE BIT(0) + #define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ - _lshift, _rtable) \ + _lshift, _pflags, _rtable) \ { \ .id = _id, \ .type = _type, \ @@ -110,6 +135,7 @@ struct rockchip_pll_clock { .mode_offset = _mode, \ .mode_shift = _mshift, \ .lock_shift = _lshift, \ + .pll_flags = _pflags, \ .rate_table = _rtable, \ } @@ -118,7 +144,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, void __iomem *base, int con_offset, int grf_lock_offset, int lock_shift, int reg_mode, int mode_shift, struct rockchip_pll_rate_table *rate_table, - spinlock_t *lock); + u8 clk_pll_flags, spinlock_t *lock); struct rockchip_cpuclk_clksel { int reg; @@ -152,6 +178,10 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, const struct rockchip_cpuclk_rate_table *rates, int nrates, void __iomem *reg_base, spinlock_t *lock); +struct clk *rockchip_clk_register_mmc(const char *name, + const char **parent_names, u8 num_parents, + void __iomem *reg, int shift); + #define PNAME(x) static const char *x[] __initconst enum rockchip_clk_branch_type { @@ -160,6 +190,7 @@ enum rockchip_clk_branch_type { branch_divider, branch_fraction_divider, branch_gate, + branch_mmc, }; struct rockchip_clk_branch { @@ -352,6 +383,16 @@ struct rockchip_clk_branch { .gate_flags = gf, \ } +#define MMC(_id, cname, pname, offset, shift) \ + { \ + .id = _id, \ + .branch_type = branch_mmc, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .muxdiv_offset = offset, \ + .div_shift = shift, \ + } void rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c index f065f694cb65..639241e31e03 100644 --- a/drivers/clk/shmobile/clk-div6.c +++ b/drivers/clk/shmobile/clk-div6.c @@ -32,6 +32,9 @@ struct div6_clock { struct clk_hw hw; void __iomem *reg; unsigned int div; + u32 src_shift; + u32 src_width; + u8 *parents; }; #define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw) @@ -39,8 +42,11 @@ struct div6_clock { static int cpg_div6_clock_enable(struct clk_hw *hw) { struct div6_clock *clock = to_div6_clock(hw); + u32 val; - clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg); + val = (clk_readl(clock->reg) & ~(CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP)) + | CPG_DIV6_DIV(clock->div - 1); + clk_writel(val, clock->reg); return 0; } @@ -52,7 +58,7 @@ static void cpg_div6_clock_disable(struct clk_hw *hw) /* DIV6 clocks require the divisor field to be non-zero when stopping * the clock. */ - clk_writel(CPG_DIV6_CKSTP | CPG_DIV6_DIV(CPG_DIV6_DIV_MASK), + clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK, clock->reg); } @@ -94,12 +100,53 @@ static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate, { struct div6_clock *clock = to_div6_clock(hw); unsigned int div = cpg_div6_clock_calc_div(rate, parent_rate); + u32 val; clock->div = div; + val = clk_readl(clock->reg) & ~CPG_DIV6_DIV_MASK; /* Only program the new divisor if the clock isn't stopped. */ - if (!(clk_readl(clock->reg) & CPG_DIV6_CKSTP)) - clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg); + if (!(val & CPG_DIV6_CKSTP)) + clk_writel(val | CPG_DIV6_DIV(clock->div - 1), clock->reg); + + return 0; +} + +static u8 cpg_div6_clock_get_parent(struct clk_hw *hw) +{ + struct div6_clock *clock = to_div6_clock(hw); + unsigned int i; + u8 hw_index; + + if (clock->src_width == 0) + return 0; + + hw_index = (clk_readl(clock->reg) >> clock->src_shift) & + (BIT(clock->src_width) - 1); + for (i = 0; i < __clk_get_num_parents(hw->clk); i++) { + if (clock->parents[i] == hw_index) + return i; + } + + pr_err("%s: %s DIV6 clock set to invalid parent %u\n", + __func__, __clk_get_name(hw->clk), hw_index); + return 0; +} + +static int cpg_div6_clock_set_parent(struct clk_hw *hw, u8 index) +{ + struct div6_clock *clock = to_div6_clock(hw); + u8 hw_index; + u32 mask; + + if (index >= __clk_get_num_parents(hw->clk)) + return -EINVAL; + + mask = ~((BIT(clock->src_width) - 1) << clock->src_shift); + hw_index = clock->parents[index]; + + clk_writel((clk_readl(clock->reg) & mask) | + (hw_index << clock->src_shift), clock->reg); return 0; } @@ -108,6 +155,8 @@ static const struct clk_ops cpg_div6_clock_ops = { .enable = cpg_div6_clock_enable, .disable = cpg_div6_clock_disable, .is_enabled = cpg_div6_clock_is_enabled, + .get_parent = cpg_div6_clock_get_parent, + .set_parent = cpg_div6_clock_set_parent, .recalc_rate = cpg_div6_clock_recalc_rate, .round_rate = cpg_div6_clock_round_rate, .set_rate = cpg_div6_clock_set_rate, @@ -115,20 +164,33 @@ static const struct clk_ops cpg_div6_clock_ops = { static void __init cpg_div6_clock_init(struct device_node *np) { + unsigned int num_parents, valid_parents; + const char **parent_names; struct clk_init_data init; struct div6_clock *clock; - const char *parent_name; const char *name; struct clk *clk; + unsigned int i; int ret; clock = kzalloc(sizeof(*clock), GFP_KERNEL); - if (!clock) { - pr_err("%s: failed to allocate %s DIV6 clock\n", + if (!clock) + return; + + num_parents = of_clk_get_parent_count(np); + if (num_parents < 1) { + pr_err("%s: no parent found for %s DIV6 clock\n", __func__, np->name); return; } + clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents), + GFP_KERNEL); + parent_names = kmalloc_array(num_parents, sizeof(*parent_names), + GFP_KERNEL); + if (!parent_names) + return; + /* Remap the clock register and read the divisor. Disabling the * clock overwrites the divisor, so we need to cache its value for the * enable operation. @@ -150,9 +212,34 @@ static void __init cpg_div6_clock_init(struct device_node *np) goto error; } - parent_name = of_clk_get_parent_name(np, 0); - if (parent_name == NULL) { - pr_err("%s: failed to get %s DIV6 clock parent name\n", + + for (i = 0, valid_parents = 0; i < num_parents; i++) { + const char *name = of_clk_get_parent_name(np, i); + + if (name) { + parent_names[valid_parents] = name; + clock->parents[valid_parents] = i; + valid_parents++; + } + } + + switch (num_parents) { + case 1: + /* fixed parent clock */ + clock->src_shift = clock->src_width = 0; + break; + case 4: + /* clock with EXSRC bits 6-7 */ + clock->src_shift = 6; + clock->src_width = 2; + break; + case 8: + /* VCLK with EXSRC bits 12-14 */ + clock->src_shift = 12; + clock->src_width = 3; + break; + default: + pr_err("%s: invalid number of parents for DIV6 clock %s\n", __func__, np->name); goto error; } @@ -161,8 +248,8 @@ static void __init cpg_div6_clock_init(struct device_node *np) init.name = name; init.ops = &cpg_div6_clock_ops; init.flags = CLK_IS_BASIC; - init.parent_names = &parent_name; - init.num_parents = 1; + init.parent_names = parent_names; + init.num_parents = valid_parents; clock->hw.init = &init; @@ -175,11 +262,13 @@ static void __init cpg_div6_clock_init(struct device_node *np) of_clk_add_provider(np, of_clk_src_simple_get, clk); + kfree(parent_names); return; error: if (clock->reg) iounmap(clock->reg); + kfree(parent_names); kfree(clock); } CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init); diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 7ddc2b553846..a66953c0f430 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -7,6 +7,7 @@ obj-y += clk-a10-hosc.o obj-y += clk-a20-gmac.o obj-y += clk-mod0.o obj-y += clk-sun8i-mbus.o +obj-y += clk-sun9i-core.o obj-$(CONFIG_MFD_SUN6I_PRCM) += \ clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c index 5296fd6dd7b3..0dcf4f205fb8 100644 --- a/drivers/clk/sunxi/clk-a20-gmac.c +++ b/drivers/clk/sunxi/clk-a20-gmac.c @@ -53,6 +53,11 @@ static DEFINE_SPINLOCK(gmac_lock); #define SUN7I_A20_GMAC_MASK 0x3 #define SUN7I_A20_GMAC_PARENTS 2 +static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = { + 0x00, /* Select mii_phy_tx_clk */ + 0x02, /* Select gmac_int_tx_clk */ +}; + static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) { struct clk *clk; @@ -90,7 +95,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) gate->lock = &gmac_lock; mux->reg = reg; mux->mask = SUN7I_A20_GMAC_MASK; - mux->flags = CLK_MUX_INDEX_BIT; + mux->table = sun7i_a20_gmac_mux_table; mux->lock = &gmac_lock; clk = clk_register_composite(NULL, clk_name, diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index f83ba097126c..62e08fb58554 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -81,7 +81,7 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_p) + struct clk_hw **best_parent_p) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -108,7 +108,7 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_p = best_parent; + *best_parent_p = __clk_get_hw(best_parent); *best_parent_rate = best; return best_child_rate; @@ -224,7 +224,7 @@ struct clk * __init sunxi_factors_register(struct device_node *node, /* set up gate properties */ mux->reg = reg; mux->shift = data->mux; - mux->mask = SUNXI_FACTORS_MUX_MASK; + mux->mask = data->muxmask; mux->lock = factors->lock; mux_hw = &mux->hw; } diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index 9913840018d3..912238fde132 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h @@ -7,8 +7,6 @@ #define SUNXI_FACTORS_NOT_APPLICABLE (0) -#define SUNXI_FACTORS_MUX_MASK 0x3 - struct clk_factors_config { u8 nshift; u8 nwidth; @@ -24,6 +22,7 @@ struct clk_factors_config { struct factors_data { int enable; int mux; + int muxmask; struct clk_factors_config *table; void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); const char *name; diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index 4a563850ee6e..da0524eaee94 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -70,6 +70,7 @@ static struct clk_factors_config sun4i_a10_mod0_config = { static const struct factors_data sun4i_a10_mod0_data __initconst = { .enable = 31, .mux = 24, + .muxmask = BIT(1) | BIT(0), .table = &sun4i_a10_mod0_config, .getter = sun4i_a10_get_mod0_factors, }; diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index acca53290be2..3d282fb8f85c 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -46,7 +46,7 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long *best_parent_rate, - struct clk **best_parent_clk) + struct clk_hw **best_parent_clk) { int nparents = __clk_get_num_parents(hw->clk); long best_rate = -EINVAL; @@ -100,7 +100,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, tmp_rate = (parent_rate >> shift) / div; if (!*best_parent_clk || tmp_rate > best_rate) { - *best_parent_clk = parent; + *best_parent_clk = __clk_get_hw(parent); *best_parent_rate = parent_rate; best_rate = tmp_rate; } diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c index 8e49b44cee41..ef49786eefd3 100644 --- a/drivers/clk/sunxi/clk-sun8i-mbus.c +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c @@ -60,6 +60,7 @@ static struct clk_factors_config sun8i_a23_mbus_config = { static const struct factors_data sun8i_a23_mbus_data __initconst = { .enable = 31, .mux = 24, + .muxmask = BIT(1) | BIT(0), .table = &sun8i_a23_mbus_config, .getter = sun8i_a23_get_mbus_factors, }; diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c new file mode 100644 index 000000000000..3cb9036d91bb --- /dev/null +++ b/drivers/clk/sunxi/clk-sun9i-core.c @@ -0,0 +1,271 @@ +/* + * Copyright 2014 Chen-Yu Tsai + * + * Chen-Yu Tsai <wens@csie.org> + * + * 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> +#include <linux/log2.h> + +#include "clk-factors.h" + + +/** + * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1 + * PLL4 rate is calculated as follows + * rate = (parent_rate * n >> p) / (m + 1); + * parent_rate is always 24Mhz + * + * p and m are named div1 and div2 in Allwinner's SDK + */ + +static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + int div; + + /* Normalize value to a 6M multiple */ + div = DIV_ROUND_UP(*freq, 6000000); + + /* divs above 256 cannot be odd */ + if (div > 256) + div = round_up(div, 2); + + /* divs above 512 must be a multiple of 4 */ + if (div > 512) + div = round_up(div, 4); + + *freq = 6000000 * div; + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + /* p will be 1 for divs under 512 */ + if (div < 512) + *p = 1; + else + *p = 0; + + /* m will be 1 if div is odd */ + if (div & 1) + *m = 1; + else + *m = 0; + + /* calculate a suitable n based on m and p */ + *n = div / (*p + 1) / (*m + 1); +} + +static struct clk_factors_config sun9i_a80_pll4_config = { + .mshift = 18, + .mwidth = 1, + .nshift = 8, + .nwidth = 8, + .pshift = 16, + .pwidth = 1, +}; + +static const struct factors_data sun9i_a80_pll4_data __initconst = { + .enable = 31, + .table = &sun9i_a80_pll4_config, + .getter = sun9i_a80_get_pll4_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); + +static void __init sun9i_a80_pll4_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock); +} +CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); + + +/** + * sun9i_a80_get_gt_factors() - calculates m factor for GT + * GT rate is calculated as follows + * rate = parent_rate / (m + 1); + */ + +static void sun9i_a80_get_gt_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 div; + + if (parent_rate < *freq) + *freq = parent_rate; + + div = DIV_ROUND_UP(parent_rate, *freq); + + /* maximum divider is 4 */ + if (div > 4) + div = 4; + + *freq = parent_rate / div; + + /* we were called to round the frequency, we can now return */ + if (!m) + return; + + *m = div; +} + +static struct clk_factors_config sun9i_a80_gt_config = { + .mshift = 0, + .mwidth = 2, +}; + +static const struct factors_data sun9i_a80_gt_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), + .table = &sun9i_a80_gt_config, + .getter = sun9i_a80_get_gt_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_gt_lock); + +static void __init sun9i_a80_gt_setup(struct device_node *node) +{ + struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data, + &sun9i_a80_gt_lock); + + /* The GT bus clock needs to be always enabled */ + __clk_get(gt); + clk_prepare_enable(gt); +} +CLK_OF_DECLARE(sun9i_a80_gt, "allwinner,sun9i-a80-gt-clk", sun9i_a80_gt_setup); + + +/** + * sun9i_a80_get_ahb_factors() - calculates p factor for AHB0/1/2 + * AHB rate is calculated as follows + * rate = parent_rate >> p; + */ + +static void sun9i_a80_get_ahb_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 _p; + + if (parent_rate < *freq) + *freq = parent_rate; + + _p = order_base_2(DIV_ROUND_UP(parent_rate, *freq)); + + /* maximum p is 3 */ + if (_p > 3) + _p = 3; + + *freq = parent_rate >> _p; + + /* we were called to round the frequency, we can now return */ + if (!p) + return; + + *p = _p; +} + +static struct clk_factors_config sun9i_a80_ahb_config = { + .pshift = 0, + .pwidth = 2, +}; + +static const struct factors_data sun9i_a80_ahb_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), + .table = &sun9i_a80_ahb_config, + .getter = sun9i_a80_get_ahb_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); + +static void __init sun9i_a80_ahb_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock); +} +CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); + + +static const struct factors_data sun9i_a80_apb0_data __initconst = { + .mux = 24, + .muxmask = BIT(0), + .table = &sun9i_a80_ahb_config, + .getter = sun9i_a80_get_ahb_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_apb0_lock); + +static void __init sun9i_a80_apb0_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock); +} +CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); + + +/** + * sun9i_a80_get_apb1_factors() - calculates m, p factors for APB1 + * APB1 rate is calculated as follows + * rate = (parent_rate >> p) / (m + 1); + */ + +static void sun9i_a80_get_apb1_factors(u32 *freq, u32 parent_rate, + u8 *n, u8 *k, u8 *m, u8 *p) +{ + u32 div; + u8 calcm, calcp; + + if (parent_rate < *freq) + *freq = parent_rate; + + div = DIV_ROUND_UP(parent_rate, *freq); + + /* Highest possible divider is 256 (p = 3, m = 31) */ + if (div > 256) + div = 256; + + calcp = order_base_2(div); + calcm = (parent_rate >> calcp) - 1; + *freq = (parent_rate >> calcp) / (calcm + 1); + + /* we were called to round the frequency, we can now return */ + if (n == NULL) + return; + + *m = calcm; + *p = calcp; +} + +static struct clk_factors_config sun9i_a80_apb1_config = { + .mshift = 0, + .mwidth = 5, + .pshift = 16, + .pwidth = 2, +}; + +static const struct factors_data sun9i_a80_apb1_data __initconst = { + .mux = 24, + .muxmask = BIT(0), + .table = &sun9i_a80_apb1_config, + .getter = sun9i_a80_get_apb1_factors, +}; + +static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); + +static void __init sun9i_a80_apb1_setup(struct device_node *node) +{ + sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock); +} +CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d5dc951264ca..570202582dcf 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -245,9 +245,9 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate, } /** - * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6 - * PLL6 rate is calculated as follows - * rate = parent_rate * n * (k + 1) / 2 + * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6x2 + * PLL6x2 rate is calculated as follows + * rate = parent_rate * (n + 1) * (k + 1) * parent_rate is always 24Mhz */ @@ -256,13 +256,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate, { u8 div; - /* - * We always have 24MHz / 2, so we can just say that our - * parent clock is 12MHz. - */ - parent_rate = parent_rate / 2; - - /* Normalize value to a parent_rate multiple (24M / 2) */ + /* Normalize value to a parent_rate multiple (24M) */ div = *freq / parent_rate; *freq = parent_rate * div; @@ -274,7 +268,7 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate, if (*k > 3) *k = 3; - *n = DIV_ROUND_UP(div, (*k+1)); + *n = DIV_ROUND_UP(div, (*k+1)) - 1; } /** @@ -445,6 +439,7 @@ static struct clk_factors_config sun6i_a31_pll6_config = { .nwidth = 5, .kshift = 4, .kwidth = 2, + .n_start = 1, }; static struct clk_factors_config sun4i_apb1_config = { @@ -504,9 +499,12 @@ static const struct factors_data sun6i_a31_pll6_data __initconst = { .enable = 31, .table = &sun6i_a31_pll6_config, .getter = sun6i_a31_get_pll6_factors, + .name = "pll6x2", }; static const struct factors_data sun4i_apb1_data __initconst = { + .mux = 24, + .muxmask = BIT(1) | BIT(0), .table = &sun4i_apb1_config, .getter = sun4i_get_apb1_factors, }; @@ -514,6 +512,7 @@ static const struct factors_data sun4i_apb1_data __initconst = { static const struct factors_data sun7i_a20_out_data __initconst = { .enable = 31, .mux = 24, + .muxmask = BIT(1) | BIT(0), .table = &sun7i_a20_out_config, .getter = sun7i_a20_get_out_factors, }; @@ -544,10 +543,6 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = { .shift = 12, }; -static const struct mux_data sun4i_apb1_mux_data __initconst = { - .shift = 24, -}; - static void __init sunxi_mux_clk_setup(struct device_node *node, struct mux_data *data) { @@ -633,12 +628,6 @@ static const struct div_data sun4i_apb0_data __initconst = { .table = sun4i_apb0_table, }; -static const struct div_data sun6i_a31_apb2_div_data __initconst = { - .shift = 0, - .pow = 0, - .width = 4, -}; - static void __init sunxi_divider_clk_setup(struct device_node *node, struct div_data *data) { @@ -757,6 +746,18 @@ static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = { .mask = {0x25386742, 0x2505111}, }; +static const struct gates_data sun9i_a80_ahb0_gates_data __initconst = { + .mask = {0xF5F12B}, +}; + +static const struct gates_data sun9i_a80_ahb1_gates_data __initconst = { + .mask = {0x1E20003}, +}; + +static const struct gates_data sun9i_a80_ahb2_gates_data __initconst = { + .mask = {0x9B7}, +}; + static const struct gates_data sun4i_apb0_gates_data __initconst = { .mask = {0x4EF}, }; @@ -773,6 +774,10 @@ static const struct gates_data sun7i_a20_apb0_gates_data __initconst = { .mask = { 0x4ff }, }; +static const struct gates_data sun9i_a80_apb0_gates_data __initconst = { + .mask = {0xEB822}, +}; + static const struct gates_data sun4i_apb1_gates_data __initconst = { .mask = {0xFF00F7}, }; @@ -801,6 +806,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = { .mask = { 0xff80ff }, }; +static const struct gates_data sun9i_a80_apb1_gates_data __initconst = { + .mask = {0x3F001F}, +}; + static const struct gates_data sun8i_a23_apb2_gates_data __initconst = { .mask = {0x1F0007}, }; @@ -893,6 +902,7 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, struct divs_data { const struct factors_data *factors; /* data for the factor clock */ + int ndivs; /* number of children */ struct { u8 fixed; /* is it a fixed divisor? if not... */ struct clk_div_table *table; /* is it a table based divisor? */ @@ -912,6 +922,7 @@ static struct clk_div_table pll6_sata_tbl[] = { static const struct divs_data pll5_divs_data __initconst = { .factors = &sun4i_pll5_data, + .ndivs = 2, .div = { { .shift = 0, .pow = 0, }, /* M, DDR */ { .shift = 16, .pow = 1, }, /* P, other */ @@ -920,12 +931,21 @@ static const struct divs_data pll5_divs_data __initconst = { static const struct divs_data pll6_divs_data __initconst = { .factors = &sun4i_pll6_data, + .ndivs = 2, .div = { { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ { .fixed = 2 }, /* P, other */ } }; +static const struct divs_data sun6i_a31_pll6_divs_data __initconst = { + .factors = &sun6i_a31_pll6_data, + .ndivs = 1, + .div = { + { .fixed = 2 }, /* normal output */ + } +}; + /** * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks * @@ -950,7 +970,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, struct clk_fixed_factor *fix_factor; struct clk_divider *divider; void __iomem *reg; - int i = 0; + int ndivs = SUNXI_DIVS_MAX_QTY, i = 0; int flags, clkflags; /* Set up factor clock that we will be dividing */ @@ -973,7 +993,11 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, * our RAM clock! */ clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; - for (i = 0; i < SUNXI_DIVS_MAX_QTY; i++) { + /* if number of children known, use it */ + if (data->ndivs) + ndivs = data->ndivs; + + for (i = 0; i < ndivs; i++) { if (of_property_read_string_index(node, "clock-output-names", i, &clk_name) != 0) break; @@ -1062,7 +1086,6 @@ static const struct of_device_id clk_factors_match[] __initconst = { {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,}, {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, - {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, {} @@ -1074,7 +1097,6 @@ static const struct of_device_id clk_div_match[] __initconst = { {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,}, {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, - {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, {} }; @@ -1082,13 +1104,13 @@ static const struct of_device_id clk_div_match[] __initconst = { static const struct of_device_id clk_divs_match[] __initconst = { {.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,}, {.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,}, + {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_divs_data,}, {} }; /* Matches for mux clocks */ static const struct of_device_id clk_mux_match[] __initconst = { {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,}, - {.compatible = "allwinner,sun4i-a10-apb1-mux-clk", .data = &sun4i_apb1_mux_data,}, {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,}, {} }; @@ -1102,16 +1124,21 @@ static const struct of_device_id clk_gates_match[] __initconst = { {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb0-gates-clk", .data = &sun9i_a80_ahb0_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb1-gates-clk", .data = &sun9i_a80_ahb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-ahb2-gates-clk", .data = &sun9i_a80_ahb2_gates_data,}, {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,}, + {.compatible = "allwinner,sun9i-a80-apb0-gates-clk", .data = &sun9i_a80_apb0_gates_data,}, {.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,}, {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,}, + {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,}, {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,}, {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, @@ -1200,3 +1227,9 @@ static void __init sun6i_init_clocks(struct device_node *node) } CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); + +static void __init sun9i_init_clocks(struct device_node *node) +{ + sunxi_init_clocks(NULL, 0); +} +CLK_OF_DECLARE(sun9i_a80_clk_init, "allwinner,sun9i-a80", sun9i_init_clocks); |