diff options
Diffstat (limited to 'drivers/clk')
102 files changed, 9066 insertions, 617 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 6a8ac04bedeb..56c1998ced3e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -33,7 +33,7 @@ source "drivers/clk/versatile/Kconfig" config COMMON_CLK_MAX77686 tristate "Clock driver for Maxim 77620/77686/77802 MFD" - depends on MFD_MAX77686 || MFD_MAX77620 + depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST ---help--- This driver supports Maxim 77620/77686/77802 crystal oscillator clock. @@ -119,7 +119,7 @@ config COMMON_CLK_CS2000_CP config COMMON_CLK_S2MPS11 tristate "Clock driver for S2MPS1X/S5M8767 MFD" - depends on MFD_SEC_CORE + depends on MFD_SEC_CORE || COMPILE_TEST ---help--- This driver supports S2MPS11/S2MPS14/S5M8767 crystal oscillator clock. These multi-function devices have two (S2MPS14) or three diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 190122e64a3a..85a449cf61e3 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -203,7 +203,7 @@ at91_clk_register_programmable(struct regmap *regmap, ret = clk_hw_register(NULL, &prog->hw); if (ret) { kfree(prog); - hw = &prog->hw; + hw = ERR_PTR(ret); } return hw; diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index b68bf573dcfb..8c7763fd9efc 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -502,8 +502,12 @@ static long bcm2835_pll_rate_from_divisors(unsigned long parent_rate, static long bcm2835_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { + struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); + const struct bcm2835_pll_data *data = pll->data; u32 ndiv, fdiv; + rate = clamp(rate, data->min_rate, data->max_rate); + bcm2835_pll_choose_ndiv_and_fdiv(rate, *parent_rate, &ndiv, &fdiv); return bcm2835_pll_rate_from_divisors(*parent_rate, ndiv, fdiv, 1); @@ -608,13 +612,6 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, u32 ana[4]; int i; - if (rate < data->min_rate || rate > data->max_rate) { - dev_err(cprman->dev, "%s: rate out of spec: %lu vs (%lu, %lu)\n", - clk_hw_get_name(hw), rate, - data->min_rate, data->max_rate); - return -EINVAL; - } - if (rate > data->max_fb_rate) { use_fb_prediv = true; rate /= 2; diff --git a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c index edf3b96b3b73..1d99292e2039 100644 --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -685,7 +685,7 @@ static void __init berlin2_clock_setup(struct device_node *np) } /* register clk-provider */ - of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); return; diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c index 0718e831475f..3b784b593afd 100644 --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -382,7 +382,7 @@ static void __init berlin2q_clock_setup(struct device_node *np) } /* register clk-provider */ - of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); return; diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index 8802a2dd56ac..f674778fb3ac 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -82,6 +82,6 @@ static void __init efm32gg_cmu_init(struct device_node *np) hws[clk_HFPERCLKDAC0] = clk_hw_register_gate(NULL, "HFPERCLK.DAC0", "HFXO", 0, base + CMU_HFPERCLKEN0, 17, 0, NULL); - of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data); + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); } CLK_OF_DECLARE(efm32ggcmu, "efm32gg,cmu", efm32gg_cmu_init); diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 4e691e35483a..4e0c054a787c 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -145,8 +145,8 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, init.name = name; init.ops = &clk_gate_ops; init.flags = flags | CLK_IS_BASIC; - init.parent_names = (parent_name ? &parent_name: NULL); - init.num_parents = (parent_name ? 1 : 0); + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; /* struct clk_gate assignments */ gate->reg = reg; diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index b637f5979023..eb953d3b0b69 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -216,6 +216,7 @@ static int max77686_clk_probe(struct platform_device *pdev) return -EINVAL; } + drv_data->num_clks = num_clks; drv_data->max_clk_data = devm_kcalloc(dev, num_clks, sizeof(*drv_data->max_clk_data), GFP_KERNEL); diff --git a/drivers/clk/clk-oxnas.c b/drivers/clk/clk-oxnas.c index 47649ac5d399..e51e0023fc6e 100644 --- a/drivers/clk/clk-oxnas.c +++ b/drivers/clk/clk-oxnas.c @@ -20,31 +20,43 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/stringify.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> +#include <dt-bindings/clock/oxsemi,ox810se.h> +#include <dt-bindings/clock/oxsemi,ox820.h> + /* Standard regmap gate clocks */ -struct clk_oxnas { +struct clk_oxnas_gate { struct clk_hw hw; - signed char bit; + unsigned int bit; struct regmap *regmap; }; +struct oxnas_stdclk_data { + struct clk_hw_onecell_data *onecell_data; + struct clk_oxnas_gate **gates; + unsigned int ngates; + struct clk_oxnas_pll **plls; + unsigned int nplls; +}; + /* Regmap offsets */ #define CLK_STAT_REGOFFSET 0x24 #define CLK_SET_REGOFFSET 0x2c #define CLK_CLR_REGOFFSET 0x30 -static inline struct clk_oxnas *to_clk_oxnas(struct clk_hw *hw) +static inline struct clk_oxnas_gate *to_clk_oxnas_gate(struct clk_hw *hw) { - return container_of(hw, struct clk_oxnas, hw); + return container_of(hw, struct clk_oxnas_gate, hw); } -static int oxnas_clk_is_enabled(struct clk_hw *hw) +static int oxnas_clk_gate_is_enabled(struct clk_hw *hw) { - struct clk_oxnas *std = to_clk_oxnas(hw); + struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); int ret; unsigned int val; @@ -55,29 +67,29 @@ static int oxnas_clk_is_enabled(struct clk_hw *hw) return val & BIT(std->bit); } -static int oxnas_clk_enable(struct clk_hw *hw) +static int oxnas_clk_gate_enable(struct clk_hw *hw) { - struct clk_oxnas *std = to_clk_oxnas(hw); + struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); regmap_write(std->regmap, CLK_SET_REGOFFSET, BIT(std->bit)); return 0; } -static void oxnas_clk_disable(struct clk_hw *hw) +static void oxnas_clk_gate_disable(struct clk_hw *hw) { - struct clk_oxnas *std = to_clk_oxnas(hw); + struct clk_oxnas_gate *std = to_clk_oxnas_gate(hw); regmap_write(std->regmap, CLK_CLR_REGOFFSET, BIT(std->bit)); } -static const struct clk_ops oxnas_clk_ops = { - .enable = oxnas_clk_enable, - .disable = oxnas_clk_disable, - .is_enabled = oxnas_clk_is_enabled, +static const struct clk_ops oxnas_clk_gate_ops = { + .enable = oxnas_clk_gate_enable, + .disable = oxnas_clk_gate_disable, + .is_enabled = oxnas_clk_gate_is_enabled, }; -static const char *const oxnas_clk_parents[] = { +static const char *const osc_parents[] = { "oscillator", }; @@ -85,63 +97,138 @@ static const char *const eth_parents[] = { "gmacclk", }; -#define DECLARE_STD_CLKP(__clk, __parent) \ -static const struct clk_init_data clk_##__clk##_init = { \ - .name = __stringify(__clk), \ - .ops = &oxnas_clk_ops, \ - .parent_names = __parent, \ - .num_parents = ARRAY_SIZE(__parent), \ +#define OXNAS_GATE(_name, _bit, _parents) \ +struct clk_oxnas_gate _name = { \ + .bit = (_bit), \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &oxnas_clk_gate_ops, \ + .parent_names = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + }, \ } -#define DECLARE_STD_CLK(__clk) DECLARE_STD_CLKP(__clk, oxnas_clk_parents) +static OXNAS_GATE(ox810se_leon, 0, osc_parents); +static OXNAS_GATE(ox810se_dma_sgdma, 1, osc_parents); +static OXNAS_GATE(ox810se_cipher, 2, osc_parents); +static OXNAS_GATE(ox810se_sata, 4, osc_parents); +static OXNAS_GATE(ox810se_audio, 5, osc_parents); +static OXNAS_GATE(ox810se_usbmph, 6, osc_parents); +static OXNAS_GATE(ox810se_etha, 7, eth_parents); +static OXNAS_GATE(ox810se_pciea, 8, osc_parents); +static OXNAS_GATE(ox810se_nand, 9, osc_parents); + +static struct clk_oxnas_gate *ox810se_gates[] = { + &ox810se_leon, + &ox810se_dma_sgdma, + &ox810se_cipher, + &ox810se_sata, + &ox810se_audio, + &ox810se_usbmph, + &ox810se_etha, + &ox810se_pciea, + &ox810se_nand, +}; + +static OXNAS_GATE(ox820_leon, 0, osc_parents); +static OXNAS_GATE(ox820_dma_sgdma, 1, osc_parents); +static OXNAS_GATE(ox820_cipher, 2, osc_parents); +static OXNAS_GATE(ox820_sd, 3, osc_parents); +static OXNAS_GATE(ox820_sata, 4, osc_parents); +static OXNAS_GATE(ox820_audio, 5, osc_parents); +static OXNAS_GATE(ox820_usbmph, 6, osc_parents); +static OXNAS_GATE(ox820_etha, 7, eth_parents); +static OXNAS_GATE(ox820_pciea, 8, osc_parents); +static OXNAS_GATE(ox820_nand, 9, osc_parents); +static OXNAS_GATE(ox820_ethb, 10, eth_parents); +static OXNAS_GATE(ox820_pcieb, 11, osc_parents); +static OXNAS_GATE(ox820_ref600, 12, osc_parents); +static OXNAS_GATE(ox820_usbdev, 13, osc_parents); + +static struct clk_oxnas_gate *ox820_gates[] = { + &ox820_leon, + &ox820_dma_sgdma, + &ox820_cipher, + &ox820_sd, + &ox820_sata, + &ox820_audio, + &ox820_usbmph, + &ox820_etha, + &ox820_pciea, + &ox820_nand, + &ox820_etha, + &ox820_pciea, + &ox820_ref600, + &ox820_usbdev, +}; + +static struct clk_hw_onecell_data ox810se_hw_onecell_data = { + .hws = { + [CLK_810_LEON] = &ox810se_leon.hw, + [CLK_810_DMA_SGDMA] = &ox810se_dma_sgdma.hw, + [CLK_810_CIPHER] = &ox810se_cipher.hw, + [CLK_810_SATA] = &ox810se_sata.hw, + [CLK_810_AUDIO] = &ox810se_audio.hw, + [CLK_810_USBMPH] = &ox810se_usbmph.hw, + [CLK_810_ETHA] = &ox810se_etha.hw, + [CLK_810_PCIEA] = &ox810se_pciea.hw, + [CLK_810_NAND] = &ox810se_nand.hw, + }, + .num = ARRAY_SIZE(ox810se_gates), +}; + +static struct clk_hw_onecell_data ox820_hw_onecell_data = { + .hws = { + [CLK_820_LEON] = &ox820_leon.hw, + [CLK_820_DMA_SGDMA] = &ox820_dma_sgdma.hw, + [CLK_820_CIPHER] = &ox820_cipher.hw, + [CLK_820_SD] = &ox820_sd.hw, + [CLK_820_SATA] = &ox820_sata.hw, + [CLK_820_AUDIO] = &ox820_audio.hw, + [CLK_820_USBMPH] = &ox820_usbmph.hw, + [CLK_820_ETHA] = &ox820_etha.hw, + [CLK_820_PCIEA] = &ox820_pciea.hw, + [CLK_820_NAND] = &ox820_nand.hw, + [CLK_820_ETHB] = &ox820_ethb.hw, + [CLK_820_PCIEB] = &ox820_pcieb.hw, + [CLK_820_REF600] = &ox820_ref600.hw, + [CLK_820_USBDEV] = &ox820_usbdev.hw, + }, + .num = ARRAY_SIZE(ox820_gates), +}; -/* Hardware Bit - Clock association */ -struct clk_oxnas_init_data { - unsigned long bit; - const struct clk_init_data *clk_init; +static struct oxnas_stdclk_data ox810se_stdclk_data = { + .onecell_data = &ox810se_hw_onecell_data, + .gates = ox810se_gates, + .ngates = ARRAY_SIZE(ox810se_gates), }; -/* Clk init data declaration */ -DECLARE_STD_CLK(leon); -DECLARE_STD_CLK(dma_sgdma); -DECLARE_STD_CLK(cipher); -DECLARE_STD_CLK(sata); -DECLARE_STD_CLK(audio); -DECLARE_STD_CLK(usbmph); -DECLARE_STD_CLKP(etha, eth_parents); -DECLARE_STD_CLK(pciea); -DECLARE_STD_CLK(nand); - -/* Table index is clock indice */ -static const struct clk_oxnas_init_data clk_oxnas_init[] = { - [0] = {0, &clk_leon_init}, - [1] = {1, &clk_dma_sgdma_init}, - [2] = {2, &clk_cipher_init}, - /* Skip & Do not touch to DDR clock */ - [3] = {4, &clk_sata_init}, - [4] = {5, &clk_audio_init}, - [5] = {6, &clk_usbmph_init}, - [6] = {7, &clk_etha_init}, - [7] = {8, &clk_pciea_init}, - [8] = {9, &clk_nand_init}, +static struct oxnas_stdclk_data ox820_stdclk_data = { + .onecell_data = &ox820_hw_onecell_data, + .gates = ox820_gates, + .ngates = ARRAY_SIZE(ox820_gates), }; -struct clk_oxnas_data { - struct clk_oxnas clk_oxnas[ARRAY_SIZE(clk_oxnas_init)]; - struct clk_onecell_data onecell_data[ARRAY_SIZE(clk_oxnas_init)]; - struct clk *clks[ARRAY_SIZE(clk_oxnas_init)]; +static const struct of_device_id oxnas_stdclk_dt_ids[] = { + { .compatible = "oxsemi,ox810se-stdclk", &ox810se_stdclk_data }, + { .compatible = "oxsemi,ox820-stdclk", &ox820_stdclk_data }, + { } }; static int oxnas_stdclk_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct clk_oxnas_data *clk_oxnas; + const struct oxnas_stdclk_data *data; + const struct of_device_id *id; struct regmap *regmap; + int ret; int i; - clk_oxnas = devm_kzalloc(&pdev->dev, sizeof(*clk_oxnas), GFP_KERNEL); - if (!clk_oxnas) - return -ENOMEM; + id = of_match_device(oxnas_stdclk_dt_ids, &pdev->dev); + if (!id) + return -ENODEV; + data = id->data; regmap = syscon_node_to_regmap(of_get_parent(np)); if (IS_ERR(regmap)) { @@ -149,32 +236,23 @@ static int oxnas_stdclk_probe(struct platform_device *pdev) return PTR_ERR(regmap); } - for (i = 0; i < ARRAY_SIZE(clk_oxnas_init); i++) { - struct clk_oxnas *_clk; + for (i = 0 ; i < data->ngates ; ++i) + data->gates[i]->regmap = regmap; - _clk = &clk_oxnas->clk_oxnas[i]; - _clk->bit = clk_oxnas_init[i].bit; - _clk->hw.init = clk_oxnas_init[i].clk_init; - _clk->regmap = regmap; + for (i = 0; i < data->onecell_data->num; i++) { + if (!data->onecell_data->hws[i]) + continue; - clk_oxnas->clks[i] = - devm_clk_register(&pdev->dev, &_clk->hw); - if (WARN_ON(IS_ERR(clk_oxnas->clks[i]))) - return PTR_ERR(clk_oxnas->clks[i]); + ret = devm_clk_hw_register(&pdev->dev, + data->onecell_data->hws[i]); + if (ret) + return ret; } - clk_oxnas->onecell_data->clks = clk_oxnas->clks; - clk_oxnas->onecell_data->clk_num = ARRAY_SIZE(clk_oxnas_init); - - return of_clk_add_provider(np, of_clk_src_onecell_get, - clk_oxnas->onecell_data); + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, + data->onecell_data); } -static const struct of_device_id oxnas_stdclk_dt_ids[] = { - { .compatible = "oxsemi,ox810se-stdclk" }, - { } -}; - static struct platform_driver oxnas_stdclk_driver = { .probe = oxnas_stdclk_probe, .driver = { diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 20b105584f82..7dd4351efdd6 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -266,6 +266,31 @@ static const struct clockgen_muxinfo ls1043a_hwa2 = { }, }; +static const struct clockgen_muxinfo ls1046a_hwa1 = { + { + {}, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, + { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + }, +}; + +static const struct clockgen_muxinfo ls1046a_hwa2 = { + { + {}, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, + { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, + {}, + {}, + { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, + }, +}; + static const struct clockgen_muxinfo t1023_hwa1 = { { {}, @@ -489,6 +514,21 @@ static const struct clockgen_chipinfo chipinfo[] = { .flags = CG_PLL_8BIT, }, { + .compat = "fsl,ls1046a-clockgen", + .init_periph = t2080_init_periph, + .cmux_groups = { + &t1040_cmux + }, + .hwaccel = { + &ls1046a_hwa1, &ls1046a_hwa2 + }, + .cmux_to_group = { + 0, -1 + }, + .pll_mask = 0x07, + .flags = CG_PLL_8BIT, + }, + { .compat = "fsl,ls2080a-clockgen", .cmux_groups = { &clockgen2_cmux_cga12, &clockgen2_cmux_cgb @@ -700,6 +740,7 @@ static struct clk * __init create_mux_common(struct clockgen *cg, struct mux_hwclock *hwc, const struct clk_ops *ops, unsigned long min_rate, + unsigned long max_rate, unsigned long pct80_rate, const char *fmt, int idx) { @@ -728,6 +769,8 @@ static struct clk * __init create_mux_common(struct clockgen *cg, continue; if (rate < min_rate) continue; + if (rate > max_rate) + continue; parent_names[j] = div->name; hwc->parent_to_clksel[j] = i; @@ -759,7 +802,7 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) struct mux_hwclock *hwc; const struct clockgen_pll_div *div; unsigned long plat_rate, min_rate; - u64 pct80_rate; + u64 max_rate, pct80_rate; u32 clksel; hwc = kzalloc(sizeof(*hwc), GFP_KERNEL); @@ -787,8 +830,8 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) return NULL; } - pct80_rate = clk_get_rate(div->clk); - pct80_rate *= 8; + max_rate = clk_get_rate(div->clk); + pct80_rate = max_rate * 8; do_div(pct80_rate, 10); plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk); @@ -798,7 +841,7 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) else min_rate = plat_rate / 2; - return create_mux_common(cg, hwc, &cmux_ops, min_rate, + return create_mux_common(cg, hwc, &cmux_ops, min_rate, max_rate, pct80_rate, "cg-cmux%d", idx); } @@ -813,7 +856,7 @@ static struct clk * __init create_one_hwaccel(struct clockgen *cg, int idx) hwc->reg = cg->regs + 0x20 * idx + 0x10; hwc->info = cg->info.hwaccel[idx]; - return create_mux_common(cg, hwc, &hwaccel_ops, 0, 0, + return create_mux_common(cg, hwc, &hwaccel_ops, 0, ULONG_MAX, 0, "cg-hwaccel%d", idx); } @@ -1272,6 +1315,7 @@ CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init); +CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init); CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init); /* Legacy nodes */ diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 02d681008401..5eb05dbf59b8 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -19,10 +19,14 @@ #include <linux/clk-provider.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> #define STM32F4_RCC_PLLCFGR 0x04 #define STM32F4_RCC_CFGR 0x08 @@ -31,6 +35,8 @@ #define STM32F4_RCC_AHB3ENR 0x38 #define STM32F4_RCC_APB1ENR 0x40 #define STM32F4_RCC_APB2ENR 0x44 +#define STM32F4_RCC_BDCR 0x70 +#define STM32F4_RCC_CSR 0x74 struct stm32f4_gate_data { u8 offset; @@ -40,7 +46,7 @@ struct stm32f4_gate_data { unsigned long flags; }; -static const struct stm32f4_gate_data stm32f4_gates[] __initconst = { +static const struct stm32f4_gate_data stm32f429_gates[] __initconst = { { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" }, { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" }, { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" }, @@ -120,26 +126,113 @@ static const struct stm32f4_gate_data stm32f4_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; -/* - * MAX_CLKS is the maximum value in the enumeration below plus the combined - * hweight of stm32f42xx_gate_map (plus one). - */ -#define MAX_CLKS 74 +static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { + { STM32F4_RCC_AHB1ENR, 0, "gpioa", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 1, "gpiob", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 2, "gpioc", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 3, "gpiod", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 4, "gpioe", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 5, "gpiof", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 6, "gpiog", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 7, "gpioh", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 8, "gpioi", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 9, "gpioj", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 10, "gpiok", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 12, "crc", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 18, "bkpsra", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 20, "ccmdatam", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 21, "dma1", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 22, "dma2", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 23, "dma2d", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 25, "ethmac", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 26, "ethmactx", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 27, "ethmacrx", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 28, "ethmacptp", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 29, "otghs", "ahb_div" }, + { STM32F4_RCC_AHB1ENR, 30, "otghsulpi", "ahb_div" }, + + { STM32F4_RCC_AHB2ENR, 0, "dcmi", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 4, "cryp", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 5, "hash", "ahb_div" }, + { STM32F4_RCC_AHB2ENR, 6, "rng", "pll48" }, + { STM32F4_RCC_AHB2ENR, 7, "otgfs", "pll48" }, + + { STM32F4_RCC_AHB3ENR, 0, "fmc", "ahb_div", + CLK_IGNORE_UNUSED }, + { STM32F4_RCC_AHB3ENR, 1, "qspi", "ahb_div", + CLK_IGNORE_UNUSED }, + + { STM32F4_RCC_APB1ENR, 0, "tim2", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 1, "tim3", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 2, "tim4", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 3, "tim5", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 4, "tim6", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 5, "tim7", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 6, "tim12", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 7, "tim13", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 8, "tim14", "apb1_mul" }, + { STM32F4_RCC_APB1ENR, 11, "wwdg", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 14, "spi2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 15, "spi3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 17, "uart2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 18, "uart3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 19, "uart4", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 20, "uart5", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 21, "i2c1", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 22, "i2c2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 23, "i2c3", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 25, "can1", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 26, "can2", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 28, "pwr", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 29, "dac", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 30, "uart7", "apb1_div" }, + { STM32F4_RCC_APB1ENR, 31, "uart8", "apb1_div" }, + + { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 4, "usart1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 5, "usart6", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 11, "sdio", "pll48" }, + { STM32F4_RCC_APB2ENR, 12, "spi1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 13, "spi4", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 14, "syscfg", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 16, "tim9", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 17, "tim10", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 18, "tim11", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, + { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, +}; -enum { SYSTICK, FCLK }; +enum { SYSTICK, FCLK, CLK_LSI, CLK_LSE, CLK_HSE_RTC, CLK_RTC, END_PRIMARY_CLK }; /* * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx * have gate bits associated with them. Its combined hweight is 71. */ -static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull, - 0x0000000000000001ull, - 0x04777f33f6fec9ffull }; +#define MAX_GATE_MAP 3 + +static const u64 stm32f42xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, + 0x0000000000000001ull, + 0x04777f33f6fec9ffull }; + +static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, + 0x0000000000000003ull, + 0x0c777f33f6fec9ffull }; + +static const u64 *stm32f4_gate_map; + +static struct clk_hw **clks; -static struct clk_hw *clks[MAX_CLKS]; static DEFINE_SPINLOCK(stm32f4_clk_lock); static void __iomem *base; +static struct regmap *pdrm; + /* * "Multiplier" device for APBx clocks. * @@ -256,15 +349,15 @@ static void stm32f4_rcc_register_pll(const char *hse_clk, const char *hsi_clk) */ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) { - u64 table[ARRAY_SIZE(stm32f42xx_gate_map)]; + u64 table[MAX_GATE_MAP]; if (primary == 1) { - if (WARN_ON(secondary > FCLK)) + if (WARN_ON(secondary >= END_PRIMARY_CLK)) return -EINVAL; return secondary; } - memcpy(table, stm32f42xx_gate_map, sizeof(table)); + memcpy(table, stm32f4_gate_map, sizeof(table)); /* only bits set in table can be used as indices */ if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) || @@ -276,7 +369,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary) table[BIT_ULL_WORD(secondary)] &= GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0); - return FCLK + hweight64(table[0]) + + return END_PRIMARY_CLK - 1 + hweight64(table[0]) + (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) + (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0); } @@ -292,6 +385,212 @@ stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data) return clks[i]; } +#define to_rgclk(_rgate) container_of(_rgate, struct stm32_rgate, gate) + +static inline void disable_power_domain_write_protection(void) +{ + if (pdrm) + regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8)); +} + +static inline void enable_power_domain_write_protection(void) +{ + if (pdrm) + regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8)); +} + +static inline void sofware_reset_backup_domain(void) +{ + unsigned long val; + + val = readl(base + STM32F4_RCC_BDCR); + writel(val | BIT(16), base + STM32F4_RCC_BDCR); + writel(val & ~BIT(16), base + STM32F4_RCC_BDCR); +} + +struct stm32_rgate { + struct clk_gate gate; + u8 bit_rdy_idx; +}; + +#define RTC_TIMEOUT 1000000 + +static int rgclk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_rgate *rgate = to_rgclk(gate); + u32 reg; + int ret; + + disable_power_domain_write_protection(); + + clk_gate_ops.enable(hw); + + ret = readl_relaxed_poll_timeout_atomic(gate->reg, reg, + reg & rgate->bit_rdy_idx, 1000, RTC_TIMEOUT); + + enable_power_domain_write_protection(); + return ret; +} + +static void rgclk_disable(struct clk_hw *hw) +{ + clk_gate_ops.disable(hw); +} + +static int rgclk_is_enabled(struct clk_hw *hw) +{ + return clk_gate_ops.is_enabled(hw); +} + +static const struct clk_ops rgclk_ops = { + .enable = rgclk_enable, + .disable = rgclk_disable, + .is_enabled = rgclk_is_enabled, +}; + +static struct clk_hw *clk_register_rgate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, u8 bit_rdy_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct stm32_rgate *rgate; + struct clk_init_data init = { NULL }; + struct clk_hw *hw; + int ret; + + rgate = kzalloc(sizeof(*rgate), GFP_KERNEL); + if (!rgate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &rgclk_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + rgate->bit_rdy_idx = bit_rdy_idx; + + rgate->gate.lock = lock; + rgate->gate.reg = reg; + rgate->gate.bit_idx = bit_idx; + rgate->gate.hw.init = &init; + + hw = &rgate->gate.hw; + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(rgate); + hw = ERR_PTR(ret); + } + + return hw; +} + +static int cclk_gate_enable(struct clk_hw *hw) +{ + int ret; + + disable_power_domain_write_protection(); + + ret = clk_gate_ops.enable(hw); + + enable_power_domain_write_protection(); + + return ret; +} + +static void cclk_gate_disable(struct clk_hw *hw) +{ + disable_power_domain_write_protection(); + + clk_gate_ops.disable(hw); + + enable_power_domain_write_protection(); +} + +static int cclk_gate_is_enabled(struct clk_hw *hw) +{ + return clk_gate_ops.is_enabled(hw); +} + +static const struct clk_ops cclk_gate_ops = { + .enable = cclk_gate_enable, + .disable = cclk_gate_disable, + .is_enabled = cclk_gate_is_enabled, +}; + +static u8 cclk_mux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int cclk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + int ret; + + disable_power_domain_write_protection(); + + sofware_reset_backup_domain(); + + ret = clk_mux_ops.set_parent(hw, index); + + enable_power_domain_write_protection(); + + return ret; +} + +static const struct clk_ops cclk_mux_ops = { + .get_parent = cclk_mux_get_parent, + .set_parent = cclk_mux_set_parent, +}; + +static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name, + const char * const *parent_names, int num_parents, + void __iomem *reg, u8 bit_idx, u8 shift, unsigned long flags, + spinlock_t *lock) +{ + struct clk_hw *hw; + struct clk_gate *gate; + struct clk_mux *mux; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + hw = ERR_PTR(-EINVAL); + goto fail; + } + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) { + kfree(gate); + hw = ERR_PTR(-EINVAL); + goto fail; + } + + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = 0; + gate->lock = lock; + + mux->reg = reg; + mux->shift = shift; + mux->mask = 3; + mux->flags = 0; + + hw = clk_hw_register_composite(dev, name, parent_names, num_parents, + &mux->hw, &cclk_mux_ops, + NULL, NULL, + &gate->hw, &cclk_gate_ops, + flags); + + if (IS_ERR(hw)) { + kfree(gate); + kfree(mux); + } + +fail: + return hw; +} + static const char *sys_parents[] __initdata = { "hsi", NULL, "pll" }; static const struct clk_div_table ahb_div_table[] = { @@ -308,10 +607,46 @@ static const struct clk_div_table apb_div_table[] = { { 0 }, }; +static const char *rtc_parents[4] = { + "no-clock", "lse", "lsi", "hse-rtc" +}; + +struct stm32f4_clk_data { + const struct stm32f4_gate_data *gates_data; + const u64 *gates_map; + int gates_num; +}; + +static const struct stm32f4_clk_data stm32f429_clk_data = { + .gates_data = stm32f429_gates, + .gates_map = stm32f42xx_gate_map, + .gates_num = ARRAY_SIZE(stm32f429_gates), +}; + +static const struct stm32f4_clk_data stm32f469_clk_data = { + .gates_data = stm32f469_gates, + .gates_map = stm32f46xx_gate_map, + .gates_num = ARRAY_SIZE(stm32f469_gates), +}; + +static const struct of_device_id stm32f4_of_match[] = { + { + .compatible = "st,stm32f42xx-rcc", + .data = &stm32f429_clk_data + }, + { + .compatible = "st,stm32f469-rcc", + .data = &stm32f469_clk_data + }, + {} +}; + static void __init stm32f4_rcc_init(struct device_node *np) { const char *hse_clk; int n; + const struct of_device_id *match; + const struct stm32f4_clk_data *data; base = of_iomap(np, 0); if (!base) { @@ -319,6 +654,25 @@ static void __init stm32f4_rcc_init(struct device_node *np) return; } + pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); + if (IS_ERR(pdrm)) { + pdrm = NULL; + pr_warn("%s: Unable to get syscfg\n", __func__); + } + + match = of_match_node(stm32f4_of_match, np); + if (WARN_ON(!match)) + return; + + data = match->data; + + clks = kmalloc_array(data->gates_num + END_PRIMARY_CLK, + sizeof(*clks), GFP_KERNEL); + if (!clks) + goto fail; + + stm32f4_gate_map = data->gates_map; + hse_clk = of_clk_get_parent_name(np, 0); clk_register_fixed_rate_with_accuracy(NULL, "hsi", NULL, 0, @@ -351,11 +705,15 @@ static void __init stm32f4_rcc_init(struct device_node *np) clks[FCLK] = clk_hw_register_fixed_factor(NULL, "fclk", "ahb_div", 0, 1, 1); - for (n = 0; n < ARRAY_SIZE(stm32f4_gates); n++) { - const struct stm32f4_gate_data *gd = &stm32f4_gates[n]; - unsigned int secondary = - 8 * (gd->offset - STM32F4_RCC_AHB1ENR) + gd->bit_idx; - int idx = stm32f4_rcc_lookup_clk_idx(0, secondary); + for (n = 0; n < data->gates_num; n++) { + const struct stm32f4_gate_data *gd; + unsigned int secondary; + int idx; + + gd = &data->gates_data[n]; + secondary = 8 * (gd->offset - STM32F4_RCC_AHB1ENR) + + gd->bit_idx; + idx = stm32f4_rcc_lookup_clk_idx(0, secondary); if (idx < 0) goto fail; @@ -371,9 +729,44 @@ static void __init stm32f4_rcc_init(struct device_node *np) } } + clks[CLK_LSI] = clk_register_rgate(NULL, "lsi", "clk-lsi", 0, + base + STM32F4_RCC_CSR, 0, 2, 0, &stm32f4_clk_lock); + + if (IS_ERR(clks[CLK_LSI])) { + pr_err("Unable to register lsi clock\n"); + goto fail; + } + + clks[CLK_LSE] = clk_register_rgate(NULL, "lse", "clk-lse", 0, + base + STM32F4_RCC_BDCR, 0, 2, 0, &stm32f4_clk_lock); + + if (IS_ERR(clks[CLK_LSE])) { + pr_err("Unable to register lse clock\n"); + goto fail; + } + + clks[CLK_HSE_RTC] = clk_hw_register_divider(NULL, "hse-rtc", "clk-hse", + 0, base + STM32F4_RCC_CFGR, 16, 5, 0, + &stm32f4_clk_lock); + + if (IS_ERR(clks[CLK_HSE_RTC])) { + pr_err("Unable to register hse-rtc clock\n"); + goto fail; + } + + clks[CLK_RTC] = stm32_register_cclk(NULL, "rtc", rtc_parents, 4, + base + STM32F4_RCC_BDCR, 15, 8, 0, &stm32f4_clk_lock); + + if (IS_ERR(clks[CLK_RTC])) { + pr_err("Unable to register rtc clock\n"); + goto fail; + } + of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL); return; fail: + kfree(clks); iounmap(base); } -CLK_OF_DECLARE(stm32f4_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 5daddf5ecc4b..bc37030e38ba 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -463,22 +463,20 @@ static int xgene_clk_enable(struct clk_hw *hw) struct xgene_clk *pclk = to_xgene_clk(hw); unsigned long flags = 0; u32 data; - phys_addr_t reg; if (pclk->lock) spin_lock_irqsave(pclk->lock, flags); if (pclk->param.csr_reg != NULL) { pr_debug("%s clock enabled\n", clk_hw_get_name(hw)); - reg = __pa(pclk->param.csr_reg); /* First enable the clock */ data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_clk_offset); data |= pclk->param.reg_clk_mask; xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_clk_offset); - pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n", - clk_hw_get_name(hw), ®, + pr_debug("%s clk offset 0x%08X mask 0x%08X value 0x%08X\n", + clk_hw_get_name(hw), pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, data); @@ -488,8 +486,8 @@ static int xgene_clk_enable(struct clk_hw *hw) data &= ~pclk->param.reg_csr_mask; xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_csr_offset); - pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n", - clk_hw_get_name(hw), ®, + pr_debug("%s csr offset 0x%08X mask 0x%08X value 0x%08X\n", + clk_hw_get_name(hw), pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, data); } diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 3f537a04c6a6..cbed6602172b 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -1,3 +1,11 @@ +config COMMON_CLK_HI3516CV300 + tristate "HI3516CV300 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + select RESET_HISI + default ARCH_HISI + help + Build the clock driver for hi3516cv300. + config COMMON_CLK_HI3519 tristate "Hi3519 Clock Driver" depends on ARCH_HISI || COMPILE_TEST @@ -6,6 +14,14 @@ config COMMON_CLK_HI3519 help Build the clock driver for hi3519. +config COMMON_CLK_HI3798CV200 + tristate "Hi3798CV200 Clock Driver" + depends on ARCH_HISI || COMPILE_TEST + select RESET_HISI + default ARCH_HISI + help + Build the clock driver for hi3798cv200. + config COMMON_CLK_HI6220 bool "Hi6220 Clock Driver" depends on ARCH_HISI || COMPILE_TEST @@ -23,5 +39,6 @@ config RESET_HISI config STUB_CLK_HI6220 bool "Hi6220 Stub Clock Driver" depends on COMMON_CLK_HI6220 && MAILBOX + default ARCH_HISI help Build the Hisilicon Hi6220 stub clock driver. diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index e169ec7da023..4eec5e511e4c 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -7,7 +7,9 @@ obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o +obj-$(CONFIG_COMMON_CLK_HI3516CV300) += crg-hi3516cv300.o obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o +obj-$(CONFIG_COMMON_CLK_HI3798CV200) += crg-hi3798cv200.o obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o obj-$(CONFIG_RESET_HISI) += reset.o obj-$(CONFIG_STUB_CLK_HI6220) += clk-hi6220-stub.o diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index fe364e63f8de..c0e8e1f196aa 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -195,7 +195,7 @@ static void __init hi6220_clk_sys_init(struct device_node *np) hi6220_clk_register_divider(hi6220_div_clks_sys, ARRAY_SIZE(hi6220_div_clks_sys), clk_data); } -CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init); +CLK_OF_DECLARE_DRIVER(hi6220_clk_sys, "hisilicon,hi6220-sysctrl", hi6220_clk_sys_init); /* clocks in media controller */ @@ -252,7 +252,7 @@ static void __init hi6220_clk_media_init(struct device_node *np) hi6220_clk_register_divider(hi6220_div_clks_media, ARRAY_SIZE(hi6220_div_clks_media), clk_data); } -CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init); +CLK_OF_DECLARE_DRIVER(hi6220_clk_media, "hisilicon,hi6220-mediactrl", hi6220_clk_media_init); /* clocks in pmctrl */ diff --git a/drivers/clk/hisilicon/crg-hi3516cv300.c b/drivers/clk/hisilicon/crg-hi3516cv300.c new file mode 100644 index 000000000000..2007123832bb --- /dev/null +++ b/drivers/clk/hisilicon/crg-hi3516cv300.c @@ -0,0 +1,330 @@ +/* + * Hi3516CV300 Clock and Reset Generator Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <dt-bindings/clock/hi3516cv300-clock.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include "clk.h" +#include "crg.h" +#include "reset.h" + +/* hi3516CV300 core CRG */ +#define HI3516CV300_INNER_CLK_OFFSET 64 +#define HI3516CV300_FIXED_3M 65 +#define HI3516CV300_FIXED_6M 66 +#define HI3516CV300_FIXED_24M 67 +#define HI3516CV300_FIXED_49P5 68 +#define HI3516CV300_FIXED_50M 69 +#define HI3516CV300_FIXED_83P3M 70 +#define HI3516CV300_FIXED_99M 71 +#define HI3516CV300_FIXED_100M 72 +#define HI3516CV300_FIXED_148P5M 73 +#define HI3516CV300_FIXED_198M 74 +#define HI3516CV300_FIXED_297M 75 +#define HI3516CV300_UART_MUX 76 +#define HI3516CV300_FMC_MUX 77 +#define HI3516CV300_MMC0_MUX 78 +#define HI3516CV300_MMC1_MUX 79 +#define HI3516CV300_MMC2_MUX 80 +#define HI3516CV300_MMC3_MUX 81 +#define HI3516CV300_PWM_MUX 82 +#define HI3516CV300_CRG_NR_CLKS 128 + +static const struct hisi_fixed_rate_clock hi3516cv300_fixed_rate_clks[] = { + { HI3516CV300_FIXED_3M, "3m", NULL, 0, 3000000, }, + { HI3516CV300_FIXED_6M, "6m", NULL, 0, 6000000, }, + { HI3516CV300_FIXED_24M, "24m", NULL, 0, 24000000, }, + { HI3516CV300_FIXED_49P5, "49.5m", NULL, 0, 49500000, }, + { HI3516CV300_FIXED_50M, "50m", NULL, 0, 50000000, }, + { HI3516CV300_FIXED_83P3M, "83.3m", NULL, 0, 83300000, }, + { HI3516CV300_FIXED_99M, "99m", NULL, 0, 99000000, }, + { HI3516CV300_FIXED_100M, "100m", NULL, 0, 100000000, }, + { HI3516CV300_FIXED_148P5M, "148.5m", NULL, 0, 148500000, }, + { HI3516CV300_FIXED_198M, "198m", NULL, 0, 198000000, }, + { HI3516CV300_FIXED_297M, "297m", NULL, 0, 297000000, }, + { HI3516CV300_APB_CLK, "apb", NULL, 0, 50000000, }, +}; + +static const char *const uart_mux_p[] = {"24m", "6m"}; +static const char *const fmc_mux_p[] = { + "24m", "83.3m", "148.5m", "198m", "297m" +}; +static const char *const mmc_mux_p[] = {"49.5m"}; +static const char *const mmc2_mux_p[] = {"99m", "49.5m"}; +static const char *const pwm_mux_p[] = {"3m", "50m", "24m", "24m"}; + +static u32 uart_mux_table[] = {0, 1}; +static u32 fmc_mux_table[] = {0, 1, 2, 3, 4}; +static u32 mmc_mux_table[] = {0}; +static u32 mmc2_mux_table[] = {0, 2}; +static u32 pwm_mux_table[] = {0, 1, 2, 3}; + +static const struct hisi_mux_clock hi3516cv300_mux_clks[] = { + { HI3516CV300_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p), + CLK_SET_RATE_PARENT, 0xe4, 19, 1, 0, uart_mux_table, }, + { HI3516CV300_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p), + CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, }, + { HI3516CV300_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xc4, 4, 2, 0, mmc_mux_table, }, + { HI3516CV300_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xc4, 12, 2, 0, mmc_mux_table, }, + { HI3516CV300_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p), + CLK_SET_RATE_PARENT, 0xc4, 20, 2, 0, mmc2_mux_table, }, + { HI3516CV300_MMC3_MUX, "mmc3_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xc8, 4, 2, 0, mmc_mux_table, }, + { HI3516CV300_PWM_MUX, "pwm_mux", pwm_mux_p, ARRAY_SIZE(pwm_mux_p), + CLK_SET_RATE_PARENT, 0x38, 2, 2, 0, pwm_mux_table, }, +}; + +static const struct hisi_gate_clock hi3516cv300_gate_clks[] = { + + { HI3516CV300_UART0_CLK, "clk_uart0", "uart_mux", CLK_SET_RATE_PARENT, + 0xe4, 15, 0, }, + { HI3516CV300_UART1_CLK, "clk_uart1", "uart_mux", CLK_SET_RATE_PARENT, + 0xe4, 16, 0, }, + { HI3516CV300_UART2_CLK, "clk_uart2", "uart_mux", CLK_SET_RATE_PARENT, + 0xe4, 17, 0, }, + + { HI3516CV300_SPI0_CLK, "clk_spi0", "100m", CLK_SET_RATE_PARENT, + 0xe4, 13, 0, }, + { HI3516CV300_SPI1_CLK, "clk_spi1", "100m", CLK_SET_RATE_PARENT, + 0xe4, 14, 0, }, + + { HI3516CV300_FMC_CLK, "clk_fmc", "fmc_mux", CLK_SET_RATE_PARENT, + 0xc0, 1, 0, }, + { HI3516CV300_MMC0_CLK, "clk_mmc0", "mmc0_mux", CLK_SET_RATE_PARENT, + 0xc4, 1, 0, }, + { HI3516CV300_MMC1_CLK, "clk_mmc1", "mmc1_mux", CLK_SET_RATE_PARENT, + 0xc4, 9, 0, }, + { HI3516CV300_MMC2_CLK, "clk_mmc2", "mmc2_mux", CLK_SET_RATE_PARENT, + 0xc4, 17, 0, }, + { HI3516CV300_MMC3_CLK, "clk_mmc3", "mmc3_mux", CLK_SET_RATE_PARENT, + 0xc8, 1, 0, }, + + { HI3516CV300_ETH_CLK, "clk_eth", NULL, 0, 0xec, 1, 0, }, + + { HI3516CV300_DMAC_CLK, "clk_dmac", NULL, 0, 0xd8, 5, 0, }, + { HI3516CV300_PWM_CLK, "clk_pwm", "pwm_mux", CLK_SET_RATE_PARENT, + 0x38, 1, 0, }, + + { HI3516CV300_USB2_BUS_CLK, "clk_usb2_bus", NULL, 0, 0xb8, 0, 0, }, + { HI3516CV300_USB2_OHCI48M_CLK, "clk_usb2_ohci48m", NULL, 0, + 0xb8, 1, 0, }, + { HI3516CV300_USB2_OHCI12M_CLK, "clk_usb2_ohci12m", NULL, 0, + 0xb8, 2, 0, }, + { HI3516CV300_USB2_OTG_UTMI_CLK, "clk_usb2_otg_utmi", NULL, 0, + 0xb8, 3, 0, }, + { HI3516CV300_USB2_HST_PHY_CLK, "clk_usb2_hst_phy", NULL, 0, + 0xb8, 4, 0, }, + { HI3516CV300_USB2_UTMI0_CLK, "clk_usb2_utmi0", NULL, 0, 0xb8, 5, 0, }, + { HI3516CV300_USB2_PHY_CLK, "clk_usb2_phy", NULL, 0, 0xb8, 7, 0, }, +}; + +static struct hisi_clock_data *hi3516cv300_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3516CV300_CRG_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_fixed_rate(hi3516cv300_fixed_rate_clks, + ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data); + if (ret) + return ERR_PTR(ret); + + ret = hisi_clk_register_mux(hi3516cv300_mux_clks, + ARRAY_SIZE(hi3516cv300_mux_clks), clk_data); + if (ret) + goto unregister_fixed_rate; + + ret = hisi_clk_register_gate(hi3516cv300_gate_clks, + ARRAY_SIZE(hi3516cv300_gate_clks), clk_data); + if (ret) + goto unregister_mux; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_gate: + hisi_clk_unregister_gate(hi3516cv300_gate_clks, + ARRAY_SIZE(hi3516cv300_gate_clks), clk_data); +unregister_mux: + hisi_clk_unregister_mux(hi3516cv300_mux_clks, + ARRAY_SIZE(hi3516cv300_mux_clks), clk_data); +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks, + ARRAY_SIZE(hi3516cv300_fixed_rate_clks), clk_data); + return ERR_PTR(ret); +} + +static void hi3516cv300_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3516cv300_gate_clks, + ARRAY_SIZE(hi3516cv300_gate_clks), crg->clk_data); + hisi_clk_unregister_mux(hi3516cv300_mux_clks, + ARRAY_SIZE(hi3516cv300_mux_clks), crg->clk_data); + hisi_clk_unregister_fixed_rate(hi3516cv300_fixed_rate_clks, + ARRAY_SIZE(hi3516cv300_fixed_rate_clks), crg->clk_data); +} + +static const struct hisi_crg_funcs hi3516cv300_crg_funcs = { + .register_clks = hi3516cv300_clk_register, + .unregister_clks = hi3516cv300_clk_unregister, +}; + +/* hi3516CV300 sysctrl CRG */ +#define HI3516CV300_SYSCTRL_NR_CLKS 16 + +static const char *wdt_mux_p[] __initconst = { "3m", "apb" }; +static u32 wdt_mux_table[] = {0, 1}; + +static const struct hisi_mux_clock hi3516cv300_sysctrl_mux_clks[] = { + { HI3516CV300_WDT_CLK, "wdt", wdt_mux_p, ARRAY_SIZE(wdt_mux_p), + CLK_SET_RATE_PARENT, 0x0, 23, 1, 0, wdt_mux_table, }, +}; + +static struct hisi_clock_data *hi3516cv300_sysctrl_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3516CV300_SYSCTRL_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_mux(hi3516cv300_sysctrl_mux_clks, + ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data); + if (ret) + return ERR_PTR(ret); + + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_mux; + + return clk_data; + +unregister_mux: + hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks, + ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), clk_data); + return ERR_PTR(ret); +} + +static void hi3516cv300_sysctrl_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_mux(hi3516cv300_sysctrl_mux_clks, + ARRAY_SIZE(hi3516cv300_sysctrl_mux_clks), + crg->clk_data); +} + +static const struct hisi_crg_funcs hi3516cv300_sysctrl_funcs = { + .register_clks = hi3516cv300_sysctrl_clk_register, + .unregister_clks = hi3516cv300_sysctrl_clk_unregister, +}; + +static const struct of_device_id hi3516cv300_crg_match_table[] = { + { + .compatible = "hisilicon,hi3516cv300-crg", + .data = &hi3516cv300_crg_funcs + }, + { + .compatible = "hisilicon,hi3516cv300-sysctrl", + .data = &hi3516cv300_sysctrl_funcs + }, + { } +}; +MODULE_DEVICE_TABLE(of, hi3516cv300_crg_match_table); + +static int hi3516cv300_crg_probe(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg; + + crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); + if (!crg) + return -ENOMEM; + + crg->funcs = of_device_get_match_data(&pdev->dev); + if (!crg->funcs) + return -ENOENT; + + crg->rstc = hisi_reset_init(pdev); + if (!crg->rstc) + return -ENOMEM; + + crg->clk_data = crg->funcs->register_clks(pdev); + if (IS_ERR(crg->clk_data)) { + hisi_reset_exit(crg->rstc); + return PTR_ERR(crg->clk_data); + } + + platform_set_drvdata(pdev, crg); + return 0; +} + +static int hi3516cv300_crg_remove(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + hisi_reset_exit(crg->rstc); + crg->funcs->unregister_clks(pdev); + return 0; +} + +static struct platform_driver hi3516cv300_crg_driver = { + .probe = hi3516cv300_crg_probe, + .remove = hi3516cv300_crg_remove, + .driver = { + .name = "hi3516cv300-crg", + .of_match_table = hi3516cv300_crg_match_table, + }, +}; + +static int __init hi3516cv300_crg_init(void) +{ + return platform_driver_register(&hi3516cv300_crg_driver); +} +core_initcall(hi3516cv300_crg_init); + +static void __exit hi3516cv300_crg_exit(void) +{ + platform_driver_unregister(&hi3516cv300_crg_driver); +} +module_exit(hi3516cv300_crg_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon Hi3516CV300 CRG Driver"); diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c new file mode 100644 index 000000000000..fc8b5bc2d50d --- /dev/null +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -0,0 +1,337 @@ +/* + * Hi3798CV200 Clock and Reset Generator Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <dt-bindings/clock/histb-clock.h> +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include "clk.h" +#include "crg.h" +#include "reset.h" + +/* hi3798CV200 core CRG */ +#define HI3798CV200_INNER_CLK_OFFSET 64 +#define HI3798CV200_FIXED_24M 65 +#define HI3798CV200_FIXED_25M 66 +#define HI3798CV200_FIXED_50M 67 +#define HI3798CV200_FIXED_75M 68 +#define HI3798CV200_FIXED_100M 69 +#define HI3798CV200_FIXED_150M 70 +#define HI3798CV200_FIXED_200M 71 +#define HI3798CV200_FIXED_250M 72 +#define HI3798CV200_FIXED_300M 73 +#define HI3798CV200_FIXED_400M 74 +#define HI3798CV200_MMC_MUX 75 +#define HI3798CV200_ETH_PUB_CLK 76 +#define HI3798CV200_ETH_BUS_CLK 77 +#define HI3798CV200_ETH_BUS0_CLK 78 +#define HI3798CV200_ETH_BUS1_CLK 79 +#define HI3798CV200_COMBPHY1_MUX 80 + +#define HI3798CV200_CRG_NR_CLKS 128 + +static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = { + { HISTB_OSC_CLK, "clk_osc", NULL, 0, 24000000, }, + { HISTB_APB_CLK, "clk_apb", NULL, 0, 100000000, }, + { HISTB_AHB_CLK, "clk_ahb", NULL, 0, 200000000, }, + { HI3798CV200_FIXED_24M, "24m", NULL, 0, 24000000, }, + { HI3798CV200_FIXED_25M, "25m", NULL, 0, 25000000, }, + { HI3798CV200_FIXED_50M, "50m", NULL, 0, 50000000, }, + { HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, }, + { HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, }, + { HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, }, + { HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, }, + { HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, }, +}; + +static const char *const mmc_mux_p[] = { + "100m", "50m", "25m", "200m", "150m" }; +static u32 mmc_mux_table[] = {0, 1, 2, 3, 6}; + +static const char *const comphy1_mux_p[] = { + "100m", "25m"}; +static u32 comphy1_mux_table[] = {2, 3}; + +static struct hisi_mux_clock hi3798cv200_mux_clks[] = { + { HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, }, + { HI3798CV200_COMBPHY1_MUX, "combphy1_mux", + comphy1_mux_p, ARRAY_SIZE(comphy1_mux_p), + CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy1_mux_table, }, +}; + +static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { + /* UART */ + { HISTB_UART2_CLK, "clk_uart2", "75m", + CLK_SET_RATE_PARENT, 0x68, 4, 0, }, + /* I2C */ + { HISTB_I2C0_CLK, "clk_i2c0", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 4, 0, }, + { HISTB_I2C1_CLK, "clk_i2c1", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 8, 0, }, + { HISTB_I2C2_CLK, "clk_i2c2", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 12, 0, }, + { HISTB_I2C3_CLK, "clk_i2c3", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 16, 0, }, + { HISTB_I2C4_CLK, "clk_i2c4", "clk_apb", + CLK_SET_RATE_PARENT, 0x6C, 20, 0, }, + /* SPI */ + { HISTB_SPI0_CLK, "clk_spi0", "clk_apb", + CLK_SET_RATE_PARENT, 0x70, 0, 0, }, + /* SDIO */ + { HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m", + CLK_SET_RATE_PARENT, 0x9c, 0, 0, }, + { HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "mmc_mux", + CLK_SET_RATE_PARENT, 0x9c, 1, 0, }, + /* EMMC */ + { HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m", + CLK_SET_RATE_PARENT, 0xa0, 0, 0, }, + { HISTB_MMC_CIU_CLK, "clk_mmc_ciu", "mmc_mux", + CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, + /* PCIE*/ + { HISTB_PCIE_BUS_CLK, "clk_pcie_bus", "200m", + CLK_SET_RATE_PARENT, 0x18c, 0, 0, }, + { HISTB_PCIE_SYS_CLK, "clk_pcie_sys", "100m", + CLK_SET_RATE_PARENT, 0x18c, 1, 0, }, + { HISTB_PCIE_PIPE_CLK, "clk_pcie_pipe", "250m", + CLK_SET_RATE_PARENT, 0x18c, 2, 0, }, + { HISTB_PCIE_AUX_CLK, "clk_pcie_aux", "24m", + CLK_SET_RATE_PARENT, 0x18c, 3, 0, }, + /* Ethernet */ + { HI3798CV200_ETH_PUB_CLK, "clk_pub", NULL, + CLK_SET_RATE_PARENT, 0xcc, 5, 0, }, + { HI3798CV200_ETH_BUS_CLK, "clk_bus", "clk_pub", + CLK_SET_RATE_PARENT, 0xcc, 0, 0, }, + { HI3798CV200_ETH_BUS0_CLK, "clk_bus_m0", "clk_bus", + CLK_SET_RATE_PARENT, 0xcc, 1, 0, }, + { HI3798CV200_ETH_BUS1_CLK, "clk_bus_m1", "clk_bus", + CLK_SET_RATE_PARENT, 0xcc, 2, 0, }, + { HISTB_ETH0_MAC_CLK, "clk_mac0", "clk_bus_m0", + CLK_SET_RATE_PARENT, 0xcc, 3, 0, }, + { HISTB_ETH0_MACIF_CLK, "clk_macif0", "clk_bus_m0", + CLK_SET_RATE_PARENT, 0xcc, 24, 0, }, + { HISTB_ETH1_MAC_CLK, "clk_mac1", "clk_bus_m1", + CLK_SET_RATE_PARENT, 0xcc, 4, 0, }, + { HISTB_ETH1_MACIF_CLK, "clk_macif1", "clk_bus_m1", + CLK_SET_RATE_PARENT, 0xcc, 25, 0, }, + /* COMBPHY1 */ + { HISTB_COMBPHY1_CLK, "clk_combphy1", "combphy1_mux", + CLK_SET_RATE_PARENT, 0x188, 8, 0, }, +}; + +static struct hisi_clock_data *hi3798cv200_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3798CV200_CRG_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + + ret = hisi_clk_register_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + clk_data); + if (ret) + goto unregister_fixed_rate; + + ret = hisi_clk_register_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + clk_data); + if (ret) + goto unregister_mux; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + clk_data); + +unregister_mux: + hisi_clk_unregister_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + clk_data); +unregister_gate: + hisi_clk_unregister_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + clk_data); + return ERR_PTR(ret); +} + +static void hi3798cv200_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3798cv200_gate_clks, + ARRAY_SIZE(hi3798cv200_gate_clks), + crg->clk_data); + hisi_clk_unregister_mux(hi3798cv200_mux_clks, + ARRAY_SIZE(hi3798cv200_mux_clks), + crg->clk_data); + hisi_clk_unregister_fixed_rate(hi3798cv200_fixed_rate_clks, + ARRAY_SIZE(hi3798cv200_fixed_rate_clks), + crg->clk_data); +} + +static const struct hisi_crg_funcs hi3798cv200_crg_funcs = { + .register_clks = hi3798cv200_clk_register, + .unregister_clks = hi3798cv200_clk_unregister, +}; + +/* hi3798CV200 sysctrl CRG */ + +#define HI3798CV200_SYSCTRL_NR_CLKS 16 + +static const struct hisi_gate_clock hi3798cv200_sysctrl_gate_clks[] = { + { HISTB_IR_CLK, "clk_ir", "100m", + CLK_SET_RATE_PARENT, 0x48, 4, 0, }, + { HISTB_TIMER01_CLK, "clk_timer01", "24m", + CLK_SET_RATE_PARENT, 0x48, 6, 0, }, + { HISTB_UART0_CLK, "clk_uart0", "75m", + CLK_SET_RATE_PARENT, 0x48, 10, 0, }, +}; + +static struct hisi_clock_data *hi3798cv200_sysctrl_clk_register( + struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3798CV200_SYSCTRL_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + clk_data); + if (ret) + return ERR_PTR(ret); + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_gate: + hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + clk_data); + return ERR_PTR(ret); +} + +static void hi3798cv200_sysctrl_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3798cv200_sysctrl_gate_clks, + ARRAY_SIZE(hi3798cv200_sysctrl_gate_clks), + crg->clk_data); +} + +static const struct hisi_crg_funcs hi3798cv200_sysctrl_funcs = { + .register_clks = hi3798cv200_sysctrl_clk_register, + .unregister_clks = hi3798cv200_sysctrl_clk_unregister, +}; + +static const struct of_device_id hi3798cv200_crg_match_table[] = { + { .compatible = "hisilicon,hi3798cv200-crg", + .data = &hi3798cv200_crg_funcs }, + { .compatible = "hisilicon,hi3798cv200-sysctrl", + .data = &hi3798cv200_sysctrl_funcs }, + { } +}; +MODULE_DEVICE_TABLE(of, hi3798cv200_crg_match_table); + +static int hi3798cv200_crg_probe(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg; + + crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); + if (!crg) + return -ENOMEM; + + crg->funcs = of_device_get_match_data(&pdev->dev); + if (!crg->funcs) + return -ENOENT; + + crg->rstc = hisi_reset_init(pdev); + if (!crg->rstc) + return -ENOMEM; + + crg->clk_data = crg->funcs->register_clks(pdev); + if (IS_ERR(crg->clk_data)) { + hisi_reset_exit(crg->rstc); + return PTR_ERR(crg->clk_data); + } + + platform_set_drvdata(pdev, crg); + return 0; +} + +static int hi3798cv200_crg_remove(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + hisi_reset_exit(crg->rstc); + crg->funcs->unregister_clks(pdev); + return 0; +} + +static struct platform_driver hi3798cv200_crg_driver = { + .probe = hi3798cv200_crg_probe, + .remove = hi3798cv200_crg_remove, + .driver = { + .name = "hi3798cv200-crg", + .of_match_table = hi3798cv200_crg_match_table, + }, +}; + +static int __init hi3798cv200_crg_init(void) +{ + return platform_driver_register(&hi3798cv200_crg_driver); +} +core_initcall(hi3798cv200_crg_init); + +static void __exit hi3798cv200_crg_exit(void) +{ + platform_driver_unregister(&hi3798cv200_crg_driver); +} +module_exit(hi3798cv200_crg_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon Hi3798CV200 CRG Driver"); diff --git a/drivers/clk/hisilicon/crg.h b/drivers/clk/hisilicon/crg.h new file mode 100644 index 000000000000..e0739717de9a --- /dev/null +++ b/drivers/clk/hisilicon/crg.h @@ -0,0 +1,34 @@ +/* + * HiSilicon Clock and Reset Driver Header + * + * Copyright (c) 2016 HiSilicon Limited. + * + * 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. + */ + +#ifndef __HISI_CRG_H +#define __HISI_CRG_H + +struct hisi_clock_data; +struct hisi_reset_controller; + +struct hisi_crg_funcs { + struct hisi_clock_data* (*register_clks)(struct platform_device *pdev); + void (*unregister_clks)(struct platform_device *pdev); +}; + +struct hisi_crg_dev { + struct hisi_clock_data *clk_data; + struct hisi_reset_controller *rstc; + const struct hisi_crg_funcs *funcs; +}; + +#endif /* __HISI_CRG_H */ diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index ce8ea10407e4..42ffc1c92bab 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -156,10 +156,267 @@ static struct clk ** const uart_clks[] __initconst = { NULL }; +static int ldb_di_sel_by_clock_id(int clock_id) +{ + switch (clock_id) { + case IMX6QDL_CLK_PLL5_VIDEO_DIV: + if (clk_on_imx6q() && + imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) + return -ENOENT; + return 0; + case IMX6QDL_CLK_PLL2_PFD0_352M: + return 1; + case IMX6QDL_CLK_PLL2_PFD2_396M: + return 2; + case IMX6QDL_CLK_MMDC_CH1_AXI: + return 3; + case IMX6QDL_CLK_PLL3_USB_OTG: + return 4; + default: + return -ENOENT; + } +} + +static void of_assigned_ldb_sels(struct device_node *node, + unsigned int *ldb_di0_sel, + unsigned int *ldb_di1_sel) +{ + struct of_phandle_args clkspec; + int index, rc, num_parents; + int parent, child, sel; + + num_parents = of_count_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells"); + for (index = 0; index < num_parents; index++) { + rc = of_parse_phandle_with_args(node, "assigned-clock-parents", + "#clock-cells", index, &clkspec); + if (rc < 0) { + /* skip empty (null) phandles */ + if (rc == -ENOENT) + continue; + else + return; + } + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: parent clock %d not in ccm\n", index); + return; + } + parent = clkspec.args[0]; + + rc = of_parse_phandle_with_args(node, "assigned-clocks", + "#clock-cells", index, &clkspec); + if (rc < 0) + return; + if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) { + pr_err("ccm: child clock %d not in ccm\n", index); + return; + } + child = clkspec.args[0]; + + if (child != IMX6QDL_CLK_LDB_DI0_SEL && + child != IMX6QDL_CLK_LDB_DI1_SEL) + continue; + + sel = ldb_di_sel_by_clock_id(parent); + if (sel < 0) { + pr_err("ccm: invalid ldb_di%d parent clock: %d\n", + child == IMX6QDL_CLK_LDB_DI1_SEL, parent); + continue; + } + + if (child == IMX6QDL_CLK_LDB_DI0_SEL) + *ldb_di0_sel = sel; + if (child == IMX6QDL_CLK_LDB_DI1_SEL) + *ldb_di1_sel = sel; + } +} + +#define CCM_CCDR 0x04 +#define CCM_CCSR 0x0c +#define CCM_CS2CDR 0x2c + +#define CCDR_MMDC_CH1_MASK BIT(16) +#define CCSR_PLL3_SW_CLK_SEL BIT(0) + +#define CS2CDR_LDB_DI0_CLK_SEL_SHIFT 9 +#define CS2CDR_LDB_DI1_CLK_SEL_SHIFT 12 + +static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base) +{ + unsigned int reg; + + reg = readl_relaxed(ccm_base + CCM_CCDR); + reg |= CCDR_MMDC_CH1_MASK; + writel_relaxed(reg, ccm_base + CCM_CCDR); +} + +/* + * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk + * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the + * bypass clock source, since there is no CG bit for mmdc_ch1. + */ +static void mmdc_ch1_disable(void __iomem *ccm_base) +{ + unsigned int reg; + + clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL], + clk[IMX6QDL_CLK_PLL3_USB_OTG]); + + /* + * Handshake with mmdc_ch1 module must be masked when changing + * periph2_clk_sel. + */ + clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]); + + /* Disable pll3_sw_clk by selecting the bypass clock source */ + reg = readl_relaxed(ccm_base + CCM_CCSR); + reg |= CCSR_PLL3_SW_CLK_SEL; + writel_relaxed(reg, ccm_base + CCM_CCSR); +} + +static void mmdc_ch1_reenable(void __iomem *ccm_base) +{ + unsigned int reg; + + /* Enable pll3_sw_clk by disabling the bypass */ + reg = readl_relaxed(ccm_base + CCM_CCSR); + reg &= ~CCSR_PLL3_SW_CLK_SEL; + writel_relaxed(reg, ccm_base + CCM_CCSR); + + clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]); +} + +/* + * We have to follow a strict procedure when changing the LDB clock source, + * otherwise we risk introducing a glitch that can lock up the LDB divider. + * Things to keep in mind: + * + * 1. The current and new parent clock inputs to the mux must be disabled. + * 2. The default clock input for ldb_di0/1_clk_sel is mmdc_ch1_axi, which + * has no CG bit. + * 3. pll2_pfd2_396m can not be gated if it is used as memory clock. + * 4. In the RTL implementation of the LDB_DI_CLK_SEL muxes the top four + * options are in one mux and the PLL3 option along with three unused + * inputs is in a second mux. There is a third mux with two inputs used + * to decide between the first and second 4-port mux: + * + * pll5_video_div 0 --|\ + * pll2_pfd0_352m 1 --| |_ + * pll2_pfd2_396m 2 --| | `-|\ + * mmdc_ch1_axi 3 --|/ | | + * | |-- + * pll3_usb_otg 4 --|\ | | + * 5 --| |_,-|/ + * 6 --| | + * 7 --|/ + * + * The ldb_di0/1_clk_sel[1:0] bits control both 4-port muxes at the same time. + * The ldb_di0/1_clk_sel[2] bit controls the 2-port mux. The code below + * switches the parent to the bottom mux first and then manipulates the top + * mux to ensure that no glitch will enter the divider. + */ +static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base) +{ + unsigned int reg; + unsigned int sel[2][4]; + int i; + + reg = readl_relaxed(ccm_base + CCM_CS2CDR); + sel[0][0] = (reg >> CS2CDR_LDB_DI0_CLK_SEL_SHIFT) & 7; + sel[1][0] = (reg >> CS2CDR_LDB_DI1_CLK_SEL_SHIFT) & 7; + + sel[0][3] = sel[0][2] = sel[0][1] = sel[0][0]; + sel[1][3] = sel[1][2] = sel[1][1] = sel[1][0]; + + of_assigned_ldb_sels(np, &sel[0][3], &sel[1][3]); + + for (i = 0; i < 2; i++) { + /* Warn if a glitch might have been introduced already */ + if (sel[i][0] != 3) { + pr_warn("ccm: ldb_di%d_sel already changed from reset value: %d\n", + i, sel[i][0]); + } + + if (sel[i][0] == sel[i][3]) + continue; + + /* Only switch to or from pll2_pfd2_396m if it is disabled */ + if ((sel[i][0] == 2 || sel[i][3] == 2) && + (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) == + clk[IMX6QDL_CLK_PLL2_PFD2_396M])) { + pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n", + i); + sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0]; + continue; + } + + /* First switch to the bottom mux */ + sel[i][1] = sel[i][0] | 4; + + /* Then configure the top mux before switching back to it */ + sel[i][2] = sel[i][3] | 4; + + pr_debug("ccm: switching ldb_di%d_sel: %d->%d->%d->%d\n", i, + sel[i][0], sel[i][1], sel[i][2], sel[i][3]); + } + + if (sel[0][0] == sel[0][3] && sel[1][0] == sel[1][3]) + return; + + mmdc_ch1_disable(ccm_base); + + for (i = 1; i < 4; i++) { + reg = readl_relaxed(ccm_base + CCM_CS2CDR); + reg &= ~((7 << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) | + (7 << CS2CDR_LDB_DI1_CLK_SEL_SHIFT)); + reg |= ((sel[0][i] << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) | + (sel[1][i] << CS2CDR_LDB_DI1_CLK_SEL_SHIFT)); + writel_relaxed(reg, ccm_base + CCM_CS2CDR); + } + + mmdc_ch1_reenable(ccm_base); +} + +#define CCM_ANALOG_PLL_VIDEO 0xa0 +#define CCM_ANALOG_PFD_480 0xf0 +#define CCM_ANALOG_PFD_528 0x100 + +#define PLL_ENABLE BIT(13) + +#define PFD0_CLKGATE BIT(7) +#define PFD1_CLKGATE BIT(15) +#define PFD2_CLKGATE BIT(23) +#define PFD3_CLKGATE BIT(31) + +static void disable_anatop_clocks(void __iomem *anatop_base) +{ + unsigned int reg; + + /* Make sure PLL2 PFDs 0-2 are gated */ + reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528); + /* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */ + if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) == + clk[IMX6QDL_CLK_PLL2_PFD2_396M]) + reg |= PFD0_CLKGATE | PFD1_CLKGATE; + else + reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE; + writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_528); + + /* Make sure PLL3 PFDs 0-3 are gated */ + reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_480); + reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE | PFD3_CLKGATE; + writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_480); + + /* Make sure PLL5 is disabled */ + reg = readl_relaxed(anatop_base + CCM_ANALOG_PLL_VIDEO); + reg &= ~PLL_ENABLE; + writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO); +} + static void __init imx6q_clocks_init(struct device_node *ccm_node) { struct device_node *np; - void __iomem *base; + void __iomem *anatop_base, *base; int i; int ret; @@ -172,7 +429,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0); np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); - base = of_iomap(np, 0); + anatop_base = base = of_iomap(np, 0); WARN_ON(!base); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ @@ -330,8 +587,20 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); - clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); - clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); + + disable_anatop_clocks(anatop_base); + + imx6q_mmdc_ch1_mask_handshake(base); + + /* + * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware + * bug. Set the muxes to the requested values before registering the + * ldb_di_sel clocks. + */ + init_ldb_clks(np, base); + + clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); @@ -582,12 +851,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL); - if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || - clk_on_imx6dl()) { - clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); - } - clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000); if (clk_on_imx6dl()) clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]); diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index d1d7787ce211..75c35fb12b60 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -64,6 +64,10 @@ static const char *perclk_sels[] = { "ipg", "osc", }; static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +/* epdc_pre_sels, epdc_sels, esai_sels only exists on i.MX6ULL */ +static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; +static const char *esai_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; +static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; static struct clk *clks[IMX6UL_CLK_END]; static struct clk_onecell_data clk_data; @@ -102,6 +106,17 @@ static u32 share_count_audio; static u32 share_count_sai1; static u32 share_count_sai2; static u32 share_count_sai3; +static u32 share_count_esai; + +static inline int clk_on_imx6ul(void) +{ + return of_machine_is_compatible("fsl,imx6ul"); +} + +static inline int clk_on_imx6ull(void) +{ + return of_machine_is_compatible("fsl,imx6ull"); +} static void __init imx6ul_clocks_init(struct device_node *ccm_node) { @@ -238,12 +253,19 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels)); + if (clk_on_imx6ull()) + clks[IMX6ULL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels)); clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels)); clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); - clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels)); - clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels)); + if (clk_on_imx6ul()) { + clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels)); + clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels)); + } else if (clk_on_imx6ull()) { + clks[IMX6ULL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels)); + clks[IMX6ULL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels)); + } clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); @@ -276,6 +298,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6); clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3); clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6); + if (clk_on_imx6ull()) { + clks[IMX6ULL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); + clks[IMX6ULL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); + } clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3); @@ -298,9 +324,15 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); - clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); - clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); - clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + if (clk_on_imx6ul()) { + clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + } else if (clk_on_imx6ull()) { + clks[IMX6ULL_CLK_DCP_CLK] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10); + clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x68, 12); + clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x68, 12); + } clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16); clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); @@ -309,7 +341,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26); clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); - clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + if (clk_on_imx6ul()) + clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + else if (clk_on_imx6ull()) + clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18); /* CCGR1 */ clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -328,6 +363,11 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); /* CCGR2 */ + if (clk_on_imx6ull()) { + clks[IMX6ULL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x70, 0, &share_count_esai); + clks[IMX6ULL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x70, 0, &share_count_esai); + clks[IMX6ULL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x70, 0, &share_count_esai); + } clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); @@ -340,8 +380,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) /* CCGR3 */ clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2); clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2); - clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); - clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4); + if (clk_on_imx6ul()) { + clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); + clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4); + } else if (clk_on_imx6ull()) { + clks[IMX6ULL_CLK_EPDC_ACLK] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4); + clks[IMX6ULL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4); + } clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); @@ -385,8 +430,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); - clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6); - clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8); + if (clk_on_imx6ul()) { + clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6); + clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8); + } clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10); clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14); @@ -441,7 +488,10 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) } clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]); - clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + if (clk_on_imx6ul()) + clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + else if (clk_on_imx6ull()) + clk_set_parent(clks[IMX6ULL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]); clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]); } diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index 19f9b622981a..ed3a2df536ea 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -223,7 +223,7 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw, temp64 *= mfn; do_div(temp64, mfd); - return (parent_rate * div) + (u32)temp64; + return parent_rate * div + (unsigned long)temp64; } static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, @@ -234,6 +234,7 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long max_rate = parent_rate * 54; u32 div; u32 mfn, mfd = 1000000; + u32 max_mfd = 0x3FFFFFFF; u64 temp64; if (rate > max_rate) @@ -241,13 +242,20 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, else if (rate < min_rate) rate = min_rate; + if (parent_rate <= max_mfd) + mfd = parent_rate; + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; do_div(temp64, parent_rate); mfn = temp64; - return parent_rate * div + parent_rate * mfn / mfd; + temp64 = (u64)parent_rate; + temp64 *= mfn; + do_div(temp64, mfd); + + return parent_rate * div + (unsigned long)temp64; } static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, @@ -258,11 +266,15 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long max_rate = parent_rate * 54; u32 val, div; u32 mfn, mfd = 1000000; + u32 max_mfd = 0x3FFFFFFF; u64 temp64; if (rate < min_rate || rate > max_rate) return -EINVAL; + if (parent_rate <= max_mfd) + mfd = parent_rate; + div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 3799ff82a9b4..4afad3b96a61 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -75,6 +75,14 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate) return clk_register_fixed_rate(NULL, name, NULL, 0, rate); } +static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, int num_parents) +{ + return clk_register_mux(NULL, name, parents, num_parents, + CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg, + shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock); +} + static inline struct clk *imx_clk_fixed_factor(const char *name, const char *parent, unsigned int mult, unsigned int div) { diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index a26ba2184454..185f19c6836e 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -154,7 +154,7 @@ out: } /** - * _of_clk_init - PLL initialisation via DT + * _of_pll_clk_init - PLL initialisation via DT * @node: device tree node for this clock * @pllctrl: If true, lower 6 bits of multiplier is in pllm register of * pll controller, else it is in the control register0(bit 11-6) @@ -235,7 +235,7 @@ CLK_OF_DECLARE(keystone_pll_clock, "ti,keystone,pll-clock", of_keystone_pll_clk_init); /** - * of_keystone_pll_main_clk_init - Main PLL initialisation DT wrapper + * of_keystone_main_pll_clk_init - Main PLL initialisation DT wrapper * @node: device tree node for this clock */ static void __init of_keystone_main_pll_clk_init(struct device_node *node) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 380c372d528e..0bd631a41f6a 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -6,8 +6,52 @@ config COMMON_CLK_MEDIATEK ---help--- Mediatek SoCs' clock support. +config COMMON_CLK_MT2701 + bool "Clock driver for Mediatek MT2701" + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports Mediatek MT2701 basic clocks. + +config COMMON_CLK_MT2701_MMSYS + bool "Clock driver for Mediatek MT2701 mmsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 mmsys clocks. + +config COMMON_CLK_MT2701_IMGSYS + bool "Clock driver for Mediatek MT2701 imgsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 imgsys clocks. + +config COMMON_CLK_MT2701_VDECSYS + bool "Clock driver for Mediatek MT2701 vdecsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 vdecsys clocks. + +config COMMON_CLK_MT2701_HIFSYS + bool "Clock driver for Mediatek MT2701 hifsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 hifsys clocks. + +config COMMON_CLK_MT2701_ETHSYS + bool "Clock driver for Mediatek MT2701 ethsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 ethsys clocks. + +config COMMON_CLK_MT2701_BDPSYS + bool "Clock driver for Mediatek MT2701 bdpsys" + select COMMON_CLK_MT2701 + ---help--- + This driver supports Mediatek MT2701 bdpsys clocks. + config COMMON_CLK_MT8135 bool "Clock driver for Mediatek MT8135" + depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- @@ -15,6 +59,7 @@ config COMMON_CLK_MT8135 config COMMON_CLK_MT8173 bool "Clock driver for Mediatek MT8173" + depends on ARCH_MEDIATEK || COMPILE_TEST select COMMON_CLK_MEDIATEK default ARCH_MEDIATEK ---help--- diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index 32e7222e7305..19ae7ef79b57 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -1,4 +1,11 @@ obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o obj-$(CONFIG_RESET_CONTROLLER) += reset.o +obj-$(CONFIG_COMMON_CLK_MT2701) += clk-mt2701.o +obj-$(CONFIG_COMMON_CLK_MT2701_BDPSYS) += clk-mt2701-bdp.o +obj-$(CONFIG_COMMON_CLK_MT2701_ETHSYS) += clk-mt2701-eth.o +obj-$(CONFIG_COMMON_CLK_MT2701_HIFSYS) += clk-mt2701-hif.o +obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o +obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o +obj-$(CONFIG_COMMON_CLK_MT2701_VDECSYS) += clk-mt2701-vdec.o obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index d8787bf444eb..934bf0e45e26 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -61,6 +61,22 @@ static void mtk_cg_clr_bit(struct clk_hw *hw) regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); } +static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 cgbit = BIT(cg->bit); + + regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, cgbit); +} + +static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw) +{ + struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); + u32 cgbit = BIT(cg->bit); + + regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, 0); +} + static int mtk_cg_enable(struct clk_hw *hw) { mtk_cg_clr_bit(hw); @@ -85,6 +101,30 @@ static void mtk_cg_disable_inv(struct clk_hw *hw) mtk_cg_clr_bit(hw); } +static int mtk_cg_enable_no_setclr(struct clk_hw *hw) +{ + mtk_cg_clr_bit_no_setclr(hw); + + return 0; +} + +static void mtk_cg_disable_no_setclr(struct clk_hw *hw) +{ + mtk_cg_set_bit_no_setclr(hw); +} + +static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw) +{ + mtk_cg_set_bit_no_setclr(hw); + + return 0; +} + +static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw) +{ + mtk_cg_clr_bit_no_setclr(hw); +} + const struct clk_ops mtk_clk_gate_ops_setclr = { .is_enabled = mtk_cg_bit_is_cleared, .enable = mtk_cg_enable, @@ -97,6 +137,18 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = { .disable = mtk_cg_disable_inv, }; +const struct clk_ops mtk_clk_gate_ops_no_setclr = { + .is_enabled = mtk_cg_bit_is_cleared, + .enable = mtk_cg_enable_no_setclr, + .disable = mtk_cg_disable_no_setclr, +}; + +const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { + .is_enabled = mtk_cg_bit_is_set, + .enable = mtk_cg_enable_inv_no_setclr, + .disable = mtk_cg_disable_inv_no_setclr, +}; + struct clk *mtk_clk_register_gate( const char *name, const char *parent_name, diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index b1821603b887..72ef89b3ad7b 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -36,6 +36,8 @@ static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) extern const struct clk_ops mtk_clk_gate_ops_setclr; extern const struct clk_ops mtk_clk_gate_ops_setclr_inv; +extern const struct clk_ops mtk_clk_gate_ops_no_setclr; +extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv; struct clk *mtk_clk_register_gate( const char *name, diff --git a/drivers/clk/mediatek/clk-mt2701-bdp.c b/drivers/clk/mediatek/clk-mt2701-bdp.c new file mode 100644 index 000000000000..fe4964d05b5f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-bdp.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs bdp0_cg_regs = { + .set_ofs = 0x0104, + .clr_ofs = 0x0108, + .sta_ofs = 0x0100, +}; + +static const struct mtk_gate_regs bdp1_cg_regs = { + .set_ofs = 0x0114, + .clr_ofs = 0x0118, + .sta_ofs = 0x0110, +}; + +#define GATE_BDP0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &bdp0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_BDP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &bdp1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +static const struct mtk_gate bdp_clks[] = { + GATE_BDP0(CLK_BDP_BRG_BA, "brg_baclk", "mm_sel", 0), + GATE_BDP0(CLK_BDP_BRG_DRAM, "brg_dram", "mm_sel", 1), + GATE_BDP0(CLK_BDP_LARB_DRAM, "larb_dram", "mm_sel", 2), + GATE_BDP0(CLK_BDP_WR_VDI_PXL, "wr_vdi_pxl", "hdmi_0_deep340m", 3), + GATE_BDP0(CLK_BDP_WR_VDI_DRAM, "wr_vdi_dram", "mm_sel", 4), + GATE_BDP0(CLK_BDP_WR_B, "wr_bclk", "mm_sel", 5), + GATE_BDP0(CLK_BDP_DGI_IN, "dgi_in", "dpi1_sel", 6), + GATE_BDP0(CLK_BDP_DGI_OUT, "dgi_out", "dpi1_sel", 7), + GATE_BDP0(CLK_BDP_FMT_MAST_27, "fmt_mast_27", "dpi1_sel", 8), + GATE_BDP0(CLK_BDP_FMT_B, "fmt_bclk", "mm_sel", 9), + GATE_BDP0(CLK_BDP_OSD_B, "osd_bclk", "mm_sel", 10), + GATE_BDP0(CLK_BDP_OSD_DRAM, "osd_dram", "mm_sel", 11), + GATE_BDP0(CLK_BDP_OSD_AGENT, "osd_agent", "osd_sel", 12), + GATE_BDP0(CLK_BDP_OSD_PXL, "osd_pxl", "dpi1_sel", 13), + GATE_BDP0(CLK_BDP_RLE_B, "rle_bclk", "mm_sel", 14), + GATE_BDP0(CLK_BDP_RLE_AGENT, "rle_agent", "mm_sel", 15), + GATE_BDP0(CLK_BDP_RLE_DRAM, "rle_dram", "mm_sel", 16), + GATE_BDP0(CLK_BDP_F27M, "f27m", "di_sel", 17), + GATE_BDP0(CLK_BDP_F27M_VDOUT, "f27m_vdout", "di_sel", 18), + GATE_BDP0(CLK_BDP_F27_74_74, "f27_74_74", "di_sel", 19), + GATE_BDP0(CLK_BDP_F2FS, "f2fs", "di_sel", 20), + GATE_BDP0(CLK_BDP_F2FS74_148, "f2fs74_148", "di_sel", 21), + GATE_BDP0(CLK_BDP_FB, "fbclk", "mm_sel", 22), + GATE_BDP0(CLK_BDP_VDO_DRAM, "vdo_dram", "mm_sel", 23), + GATE_BDP0(CLK_BDP_VDO_2FS, "vdo_2fs", "di_sel", 24), + GATE_BDP0(CLK_BDP_VDO_B, "vdo_bclk", "mm_sel", 25), + GATE_BDP0(CLK_BDP_WR_DI_PXL, "wr_di_pxl", "di_sel", 26), + GATE_BDP0(CLK_BDP_WR_DI_DRAM, "wr_di_dram", "mm_sel", 27), + GATE_BDP0(CLK_BDP_WR_DI_B, "wr_di_bclk", "mm_sel", 28), + GATE_BDP0(CLK_BDP_NR_PXL, "nr_pxl", "nr_sel", 29), + GATE_BDP0(CLK_BDP_NR_DRAM, "nr_dram", "mm_sel", 30), + GATE_BDP0(CLK_BDP_NR_B, "nr_bclk", "mm_sel", 31), + GATE_BDP1(CLK_BDP_RX_F, "rx_fclk", "hadds2_fbclk", 0), + GATE_BDP1(CLK_BDP_RX_X, "rx_xclk", "clk26m", 1), + GATE_BDP1(CLK_BDP_RXPDT, "rxpdtclk", "hdmi_0_pix340m", 2), + GATE_BDP1(CLK_BDP_RX_CSCL_N, "rx_cscl_n", "clk26m", 3), + GATE_BDP1(CLK_BDP_RX_CSCL, "rx_cscl", "clk26m", 4), + GATE_BDP1(CLK_BDP_RX_DDCSCL_N, "rx_ddcscl_n", "hdmi_scl_rx", 5), + GATE_BDP1(CLK_BDP_RX_DDCSCL, "rx_ddcscl", "hdmi_scl_rx", 6), + GATE_BDP1(CLK_BDP_RX_VCO, "rx_vcoclk", "hadds2pll_294m", 7), + GATE_BDP1(CLK_BDP_RX_DP, "rx_dpclk", "hdmi_0_pll340m", 8), + GATE_BDP1(CLK_BDP_RX_P, "rx_pclk", "hdmi_0_pll340m", 9), + GATE_BDP1(CLK_BDP_RX_M, "rx_mclk", "hadds2pll_294m", 10), + GATE_BDP1(CLK_BDP_RX_PLL, "rx_pllclk", "hdmi_0_pix340m", 11), + GATE_BDP1(CLK_BDP_BRG_RT_B, "brg_rt_bclk", "mm_sel", 12), + GATE_BDP1(CLK_BDP_BRG_RT_DRAM, "brg_rt_dram", "mm_sel", 13), + GATE_BDP1(CLK_BDP_LARBRT_DRAM, "larbrt_dram", "mm_sel", 14), + GATE_BDP1(CLK_BDP_TMDS_SYN, "tmds_syn", "hdmi_0_pll340m", 15), + GATE_BDP1(CLK_BDP_HDMI_MON, "hdmi_mon", "hdmi_0_pll340m", 16), +}; + +static const struct of_device_id of_match_clk_mt2701_bdp[] = { + { .compatible = "mediatek,mt2701-bdpsys", }, + {} +}; + +static int clk_mt2701_bdp_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_BDP_NR); + + mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_bdp_drv = { + .probe = clk_mt2701_bdp_probe, + .driver = { + .name = "clk-mt2701-bdp", + .of_match_table = of_match_clk_mt2701_bdp, + }, +}; + +builtin_platform_driver(clk_mt2701_bdp_drv); diff --git a/drivers/clk/mediatek/clk-mt2701-eth.c b/drivers/clk/mediatek/clk-mt2701-eth.c new file mode 100644 index 000000000000..877be8715afa --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-eth.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs eth_cg_regs = { + .sta_ofs = 0x0030, +}; + +#define GATE_ETH(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = ð_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate eth_clks[] = { + GATE_ETH(CLK_ETHSYS_HSDMA, "hsdma_clk", "ethif_sel", 5), + GATE_ETH(CLK_ETHSYS_ESW, "esw_clk", "ethpll_500m_ck", 6), + GATE_ETH(CLK_ETHSYS_GP2, "gp2_clk", "trgpll", 7), + GATE_ETH(CLK_ETHSYS_GP1, "gp1_clk", "ethpll_500m_ck", 8), + GATE_ETH(CLK_ETHSYS_PCM, "pcm_clk", "ethif_sel", 11), + GATE_ETH(CLK_ETHSYS_GDMA, "gdma_clk", "ethif_sel", 14), + GATE_ETH(CLK_ETHSYS_I2S, "i2s_clk", "ethif_sel", 17), + GATE_ETH(CLK_ETHSYS_CRYPTO, "crypto_clk", "ethif_sel", 29), +}; + +static const struct of_device_id of_match_clk_mt2701_eth[] = { + { .compatible = "mediatek,mt2701-ethsys", }, + {} +}; + +static int clk_mt2701_eth_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_ETHSYS_NR); + + mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_eth_drv = { + .probe = clk_mt2701_eth_probe, + .driver = { + .name = "clk-mt2701-eth", + .of_match_table = of_match_clk_mt2701_eth, + }, +}; + +builtin_platform_driver(clk_mt2701_eth_drv); diff --git a/drivers/clk/mediatek/clk-mt2701-hif.c b/drivers/clk/mediatek/clk-mt2701-hif.c new file mode 100644 index 000000000000..18f3723be3e8 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-hif.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs hif_cg_regs = { + .sta_ofs = 0x0030, +}; + +#define GATE_HIF(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &hif_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate hif_clks[] = { + GATE_HIF(CLK_HIFSYS_USB0PHY, "usb0_phy_clk", "ethpll_500m_ck", 21), + GATE_HIF(CLK_HIFSYS_USB1PHY, "usb1_phy_clk", "ethpll_500m_ck", 22), + GATE_HIF(CLK_HIFSYS_PCIE0, "pcie0_clk", "ethpll_500m_ck", 24), + GATE_HIF(CLK_HIFSYS_PCIE1, "pcie1_clk", "ethpll_500m_ck", 25), + GATE_HIF(CLK_HIFSYS_PCIE2, "pcie2_clk", "ethpll_500m_ck", 26), +}; + +static const struct of_device_id of_match_clk_mt2701_hif[] = { + { .compatible = "mediatek,mt2701-hifsys", }, + {} +}; + +static int clk_mt2701_hif_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_HIFSYS_NR); + + mtk_clk_register_gates(node, hif_clks, ARRAY_SIZE(hif_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + return r; + } + + mtk_register_reset_controller(node, 1, 0x34); + + return 0; +} + +static struct platform_driver clk_mt2701_hif_drv = { + .probe = clk_mt2701_hif_probe, + .driver = { + .name = "clk-mt2701-hif", + .of_match_table = of_match_clk_mt2701_hif, + }, +}; + +builtin_platform_driver(clk_mt2701_hif_drv); diff --git a/drivers/clk/mediatek/clk-mt2701-img.c b/drivers/clk/mediatek/clk-mt2701-img.c new file mode 100644 index 000000000000..b7441c98bda8 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-img.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs img_cg_regs = { + .set_ofs = 0x0004, + .clr_ofs = 0x0008, + .sta_ofs = 0x0000, +}; + +#define GATE_IMG(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &img_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate img_clks[] = { + GATE_IMG(CLK_IMG_SMI_COMM, "img_smi_comm", "mm_sel", 0), + GATE_IMG(CLK_IMG_RESZ, "img_resz", "mm_sel", 1), + GATE_IMG(CLK_IMG_JPGDEC_SMI, "img_jpgdec_smi", "mm_sel", 5), + GATE_IMG(CLK_IMG_JPGDEC, "img_jpgdec", "mm_sel", 6), + GATE_IMG(CLK_IMG_VENC_LT, "img_venc_lt", "mm_sel", 8), + GATE_IMG(CLK_IMG_VENC, "img_venc", "mm_sel", 9), +}; + +static const struct of_device_id of_match_clk_mt2701_img[] = { + { .compatible = "mediatek,mt2701-imgsys", }, + {} +}; + +static int clk_mt2701_img_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IMG_NR); + + mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_img_drv = { + .probe = clk_mt2701_img_probe, + .driver = { + .name = "clk-mt2701-img", + .of_match_table = of_match_clk_mt2701_img, + }, +}; + +builtin_platform_driver(clk_mt2701_img_drv); diff --git a/drivers/clk/mediatek/clk-mt2701-mm.c b/drivers/clk/mediatek/clk-mt2701-mm.c new file mode 100644 index 000000000000..fe1f85072fc5 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-mm.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs disp0_cg_regs = { + .set_ofs = 0x0104, + .clr_ofs = 0x0108, + .sta_ofs = 0x0100, +}; + +static const struct mtk_gate_regs disp1_cg_regs = { + .set_ofs = 0x0114, + .clr_ofs = 0x0118, + .sta_ofs = 0x0110, +}; + +#define GATE_DISP0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &disp0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_DISP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &disp1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate mm_clks[] = { + GATE_DISP0(CLK_MM_SMI_COMMON, "mm_smi_comm", "mm_sel", 0), + GATE_DISP0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), + GATE_DISP0(CLK_MM_CMDQ, "mm_cmdq", "mm_sel", 2), + GATE_DISP0(CLK_MM_MUTEX, "mm_mutex", "mm_sel", 3), + GATE_DISP0(CLK_MM_DISP_COLOR, "mm_disp_color", "mm_sel", 4), + GATE_DISP0(CLK_MM_DISP_BLS, "mm_disp_bls", "mm_sel", 5), + GATE_DISP0(CLK_MM_DISP_WDMA, "mm_disp_wdma", "mm_sel", 6), + GATE_DISP0(CLK_MM_DISP_RDMA, "mm_disp_rdma", "mm_sel", 7), + GATE_DISP0(CLK_MM_DISP_OVL, "mm_disp_ovl", "mm_sel", 8), + GATE_DISP0(CLK_MM_MDP_TDSHP, "mm_mdp_tdshp", "mm_sel", 9), + GATE_DISP0(CLK_MM_MDP_WROT, "mm_mdp_wrot", "mm_sel", 10), + GATE_DISP0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11), + GATE_DISP0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 12), + GATE_DISP0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 13), + GATE_DISP0(CLK_MM_MDP_RDMA, "mm_mdp_rdma", "mm_sel", 14), + GATE_DISP0(CLK_MM_MDP_BLS_26M, "mm_mdp_bls_26m", "pwm_sel", 15), + GATE_DISP0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 16), + GATE_DISP0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 17), + GATE_DISP0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "rtc_sel", 18), + GATE_DISP0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19), + GATE_DISP0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 20), + GATE_DISP1(CLK_MM_DSI_ENGINE, "mm_dsi_eng", "mm_sel", 0), + GATE_DISP1(CLK_MM_DSI_DIG, "mm_dsi_dig", "dsi0_lntc_dsi", 1), + GATE_DISP1(CLK_MM_DPI_DIGL, "mm_dpi_digl", "dpi0_sel", 2), + GATE_DISP1(CLK_MM_DPI_ENGINE, "mm_dpi_eng", "mm_sel", 3), + GATE_DISP1(CLK_MM_DPI1_DIGL, "mm_dpi1_digl", "dpi1_sel", 4), + GATE_DISP1(CLK_MM_DPI1_ENGINE, "mm_dpi1_eng", "mm_sel", 5), + GATE_DISP1(CLK_MM_TVE_OUTPUT, "mm_tve_output", "tve_sel", 6), + GATE_DISP1(CLK_MM_TVE_INPUT, "mm_tve_input", "dpi0_sel", 7), + GATE_DISP1(CLK_MM_HDMI_PIXEL, "mm_hdmi_pixel", "dpi1_sel", 8), + GATE_DISP1(CLK_MM_HDMI_PLL, "mm_hdmi_pll", "hdmi_sel", 9), + GATE_DISP1(CLK_MM_HDMI_AUDIO, "mm_hdmi_audio", "apll_sel", 10), + GATE_DISP1(CLK_MM_HDMI_SPDIF, "mm_hdmi_spdif", "apll_sel", 11), + GATE_DISP1(CLK_MM_TVE_FMM, "mm_tve_fmm", "mm_sel", 14), +}; + +static const struct of_device_id of_match_clk_mt2701_mm[] = { + { .compatible = "mediatek,mt2701-mmsys", }, + {} +}; + +static int clk_mt2701_mm_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_MM_NR); + + mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_mm_drv = { + .probe = clk_mt2701_mm_probe, + .driver = { + .name = "clk-mt2701-mm", + .of_match_table = of_match_clk_mt2701_mm, + }, +}; + +builtin_platform_driver(clk_mt2701_mm_drv); diff --git a/drivers/clk/mediatek/clk-mt2701-vdec.c b/drivers/clk/mediatek/clk-mt2701-vdec.c new file mode 100644 index 000000000000..d3c0fc9d6f02 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701-vdec.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +static const struct mtk_gate_regs vdec0_cg_regs = { + .set_ofs = 0x0000, + .clr_ofs = 0x0004, + .sta_ofs = 0x0000, +}; + +static const struct mtk_gate_regs vdec1_cg_regs = { + .set_ofs = 0x0008, + .clr_ofs = 0x000c, + .sta_ofs = 0x0008, +}; + +#define GATE_VDEC0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vdec0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_VDEC1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vdec1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +static const struct mtk_gate vdec_clks[] = { + GATE_VDEC0(CLK_VDEC_CKGEN, "vdec_cken", "vdec_sel", 0), + GATE_VDEC1(CLK_VDEC_LARB, "vdec_larb_cken", "mm_sel", 0), +}; + +static const struct of_device_id of_match_clk_mt2701_vdec[] = { + { .compatible = "mediatek,mt2701-vdecsys", }, + {} +}; + +static int clk_mt2701_vdec_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_VDEC_NR); + + mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_vdec_drv = { + .probe = clk_mt2701_vdec_probe, + .driver = { + .name = "clk-mt2701-vdec", + .of_match_table = of_match_clk_mt2701_vdec, + }, +}; + +builtin_platform_driver(clk_mt2701_vdec_drv); diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c new file mode 100644 index 000000000000..6f26e6a37a6b --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: Shunli Wang <shunli.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2701-clk.h> + +/* + * For some clocks, we don't care what their actual rates are. And these + * clocks may change their rate on different products or different scenarios. + * So we model these clocks' rate as 0, to denote it's not an actual rate. + */ +#define DUMMY_RATE 0 + +static DEFINE_SPINLOCK(mt2701_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_DPI, "dpi_ck", "clk26m", + 108 * MHZ), + FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", "clk26m", + 400 * MHZ), + FIXED_CLK(CLK_TOP_VENCPLL, "vencpll_ck", "clk26m", + 295750000), + FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, "hdmi_0_pix340m", "clk26m", + 340 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, "hdmi_0_deep340m", "clk26m", + 340 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, "hdmi_0_pll340m", "clk26m", + 340 * MHZ), + FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, "hdmitx_dig_cts", "clk26m", + 300 * MHZ), + FIXED_CLK(CLK_TOP_HADDS2_FB, "hadds2_fbclk", "clk26m", + 27 * MHZ), + FIXED_CLK(CLK_TOP_WBG_DIG_416M, "wbg_dig_ck_416m", "clk26m", + 416 * MHZ), + FIXED_CLK(CLK_TOP_DSI0_LNTC_DSI, "dsi0_lntc_dsi", "clk26m", + 143 * MHZ), + FIXED_CLK(CLK_TOP_HDMI_SCL_RX, "hdmi_scl_rx", "clk26m", + 27 * MHZ), + FIXED_CLK(CLK_TOP_AUD_EXT1, "aud_ext1", "clk26m", + DUMMY_RATE), + FIXED_CLK(CLK_TOP_AUD_EXT2, "aud_ext2", "clk26m", + DUMMY_RATE), + FIXED_CLK(CLK_TOP_NFI1X_PAD, "nfi1x_pad", "clk26m", + DUMMY_RATE), +}; + +static const struct mtk_fixed_factor top_fixed_divs[] = { + FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, 1), + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "mainpll", 1, 7), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, 4), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, 8), + FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, 16), + FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, 2), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, 4), + FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "syspll_d3", 1, 8), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, 2), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, 4), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, 2), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, 4), + + FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, 1), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7), + FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26), + FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll", 1, 52), + FACTOR(CLK_TOP_UNIVPLL_D108, "univpll_d108", "univpll", 1, 108), + FACTOR(CLK_TOP_USB_PHY48M, "usb_phy48m_ck", "univpll", 1, 26), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, 4), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, 8), + FACTOR(CLK_TOP_8BDAC, "8bdac_ck", "univpll_d2", 1, 1), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, 2), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, 4), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, 8), + FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll_d3", 1, 16), + FACTOR(CLK_TOP_UNIVPLL2_D32, "univpll2_d32", "univpll_d3", 1, 32), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, 2), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, 4), + FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, 8), + + FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, 1), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4), + FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8), + + FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, 1), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), + + FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "dmpll_ck", 1, 2), + FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "dmpll_ck", 1, 4), + FACTOR(CLK_TOP_DMPLL_X2, "dmpll_x2", "dmpll_ck", 1, 1), + + FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, 1), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4), + + FACTOR(CLK_TOP_VDECPLL, "vdecpll_ck", "vdecpll", 1, 1), + FACTOR(CLK_TOP_TVD2PLL, "tvd2pll_ck", "tvd2pll", 1, 1), + FACTOR(CLK_TOP_TVD2PLL_D2, "tvd2pll_d2", "tvd2pll", 1, 2), + + FACTOR(CLK_TOP_MIPIPLL, "mipipll", "dpi_ck", 1, 1), + FACTOR(CLK_TOP_MIPIPLL_D2, "mipipll_d2", "dpi_ck", 1, 2), + FACTOR(CLK_TOP_MIPIPLL_D4, "mipipll_d4", "dpi_ck", 1, 4), + + FACTOR(CLK_TOP_HDMIPLL, "hdmipll_ck", "hdmitx_dig_cts", 1, 1), + FACTOR(CLK_TOP_HDMIPLL_D2, "hdmipll_d2", "hdmitx_dig_cts", 1, 2), + FACTOR(CLK_TOP_HDMIPLL_D3, "hdmipll_d3", "hdmitx_dig_cts", 1, 3), + + FACTOR(CLK_TOP_ARMPLL_1P3G, "armpll_1p3g_ck", "armpll", 1, 1), + + FACTOR(CLK_TOP_AUDPLL, "audpll", "audpll_sel", 1, 1), + FACTOR(CLK_TOP_AUDPLL_D4, "audpll_d4", "audpll_sel", 1, 4), + FACTOR(CLK_TOP_AUDPLL_D8, "audpll_d8", "audpll_sel", 1, 8), + FACTOR(CLK_TOP_AUDPLL_D16, "audpll_d16", "audpll_sel", 1, 16), + FACTOR(CLK_TOP_AUDPLL_D24, "audpll_d24", "audpll_sel", 1, 24), + + FACTOR(CLK_TOP_AUD1PLL_98M, "aud1pll_98m_ck", "aud1pll", 1, 3), + FACTOR(CLK_TOP_AUD2PLL_90M, "aud2pll_90m_ck", "aud2pll", 1, 3), + FACTOR(CLK_TOP_HADDS2PLL_98M, "hadds2pll_98m", "hadds2pll", 1, 3), + FACTOR(CLK_TOP_HADDS2PLL_294M, "hadds2pll_294m", "hadds2pll", 1, 1), + FACTOR(CLK_TOP_ETHPLL_500M, "ethpll_500m_ck", "ethpll", 1, 1), + FACTOR(CLK_TOP_CLK26M_D8, "clk26m_d8", "clk26m", 1, 8), + FACTOR(CLK_TOP_32K_INTERNAL, "32k_internal", "clk26m", 1, 793), + FACTOR(CLK_TOP_32K_EXTERNAL, "32k_external", "rtc32k", 1, 1), +}; + +static const char * const axi_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "mmpll_d2", + "dmpll_d2" +}; + +static const char * const mem_parents[] = { + "clk26m", + "dmpll_ck" +}; + +static const char * const ddrphycfg_parents[] = { + "clk26m", + "syspll1_d8" +}; + +static const char * const mm_parents[] = { + "clk26m", + "vencpll_ck", + "syspll1_d2", + "syspll1_d4", + "univpll_d5", + "univpll1_d2", + "univpll2_d2", + "dmpll_ck" +}; + +static const char * const pwm_parents[] = { + "clk26m", + "univpll2_d4", + "univpll3_d2", + "univpll1_d4", +}; + +static const char * const vdec_parents[] = { + "clk26m", + "vdecpll_ck", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "vencpll_ck", + "msdcpll_d2", + "mmpll_d2" +}; + +static const char * const mfg_parents[] = { + "clk26m", + "mmpll_ck", + "dmpll_x2_ck", + "msdcpll_ck", + "clk26m", + "syspll_d3", + "univpll_d3", + "univpll1_d2" +}; + +static const char * const camtg_parents[] = { + "clk26m", + "univpll_d26", + "univpll2_d2", + "syspll3_d2", + "syspll3_d4", + "msdcpll_d2", + "mmpll_d2" +}; + +static const char * const uart_parents[] = { + "clk26m", + "univpll2_d8" +}; + +static const char * const spi_parents[] = { + "clk26m", + "syspll3_d2", + "syspll4_d2", + "univpll2_d4", + "univpll1_d8" +}; + +static const char * const usb20_parents[] = { + "clk26m", + "univpll1_d8", + "univpll3_d4" +}; + +static const char * const msdc30_parents[] = { + "clk26m", + "msdcpll_d2", + "syspll2_d2", + "syspll1_d4", + "univpll1_d4", + "univpll2_d4" +}; + +static const char * const audio_parents[] = { + "clk26m", + "syspll1_d16" +}; + +static const char * const aud_intbus_parents[] = { + "clk26m", + "syspll1_d4", + "syspll3_d2", + "syspll4_d2", + "univpll3_d2", + "univpll2_d4" +}; + +static const char * const pmicspi_parents[] = { + "clk26m", + "syspll1_d8", + "syspll2_d4", + "syspll4_d2", + "syspll3_d4", + "syspll2_d8", + "syspll1_d16", + "univpll3_d4", + "univpll_d26", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const scp_parents[] = { + "clk26m", + "syspll1_d8", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const dpi0_parents[] = { + "clk26m", + "mipipll", + "mipipll_d2", + "mipipll_d4", + "clk26m", + "tvdpll_ck", + "tvdpll_d2", + "tvdpll_d4" +}; + +static const char * const dpi1_parents[] = { + "clk26m", + "tvdpll_ck", + "tvdpll_d2", + "tvdpll_d4" +}; + +static const char * const tve_parents[] = { + "clk26m", + "mipipll", + "mipipll_d2", + "mipipll_d4", + "clk26m", + "tvdpll_ck", + "tvdpll_d2", + "tvdpll_d4" +}; + +static const char * const hdmi_parents[] = { + "clk26m", + "hdmipll_ck", + "hdmipll_d2", + "hdmipll_d3" +}; + +static const char * const apll_parents[] = { + "clk26m", + "audpll", + "audpll_d4", + "audpll_d8", + "audpll_d16", + "audpll_d24", + "clk26m", + "clk26m" +}; + +static const char * const rtc_parents[] = { + "32k_internal", + "32k_external", + "clk26m", + "univpll3_d8" +}; + +static const char * const nfi2x_parents[] = { + "clk26m", + "syspll2_d2", + "syspll_d7", + "univpll3_d2", + "syspll2_d4", + "univpll3_d4", + "syspll4_d4", + "clk26m" +}; + +static const char * const emmc_hclk_parents[] = { + "clk26m", + "syspll1_d2", + "syspll1_d4", + "syspll2_d2" +}; + +static const char * const flash_parents[] = { + "clk26m_d8", + "clk26m", + "syspll2_d8", + "syspll3_d4", + "univpll3_d4", + "syspll4_d2", + "syspll2_d4", + "univpll2_d4" +}; + +static const char * const di_parents[] = { + "clk26m", + "tvd2pll_ck", + "tvd2pll_d2", + "clk26m" +}; + +static const char * const nr_osd_parents[] = { + "clk26m", + "vencpll_ck", + "syspll1_d2", + "syspll1_d4", + "univpll_d5", + "univpll1_d2", + "univpll2_d2", + "dmpll_ck" +}; + +static const char * const hdmirx_bist_parents[] = { + "clk26m", + "syspll_d3", + "clk26m", + "syspll1_d16", + "syspll4_d2", + "syspll1_d4", + "vencpll_ck", + "clk26m" +}; + +static const char * const intdir_parents[] = { + "clk26m", + "mmpll_ck", + "syspll_d2", + "univpll_d2" +}; + +static const char * const asm_parents[] = { + "clk26m", + "univpll2_d4", + "univpll2_d2", + "syspll_d5" +}; + +static const char * const ms_card_parents[] = { + "clk26m", + "univpll3_d8", + "syspll4_d4" +}; + +static const char * const ethif_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll1_d2", + "dmpll_ck", + "dmpll_d2" +}; + +static const char * const hdmirx_parents[] = { + "clk26m", + "univpll_d52" +}; + +static const char * const cmsys_parents[] = { + "clk26m", + "syspll1_d2", + "univpll1_d2", + "univpll_d5", + "syspll_d5", + "syspll2_d2", + "syspll1_d4", + "syspll3_d2", + "syspll2_d4", + "syspll1_d8", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m" +}; + +static const char * const clk_8bdac_parents[] = { + "32k_internal", + "8bdac_ck", + "clk26m", + "clk26m" +}; + +static const char * const aud2dvd_parents[] = { + "a1sys_hp_ck", + "a2sys_hp_ck" +}; + +static const char * const padmclk_parents[] = { + "clk26m", + "univpll_d26", + "univpll_d52", + "univpll_d108", + "univpll2_d8", + "univpll2_d16", + "univpll2_d32" +}; + +static const char * const aud_mux_parents[] = { + "clk26m", + "aud1pll_98m_ck", + "aud2pll_90m_ck", + "hadds2pll_98m", + "audio_ext1_ck", + "audio_ext2_ck" +}; + +static const char * const aud_src_parents[] = { + "aud_mux1_sel", + "aud_mux2_sel" +}; + +static const char * const cpu_parents[] = { + "clk26m", + "armpll", + "mainpll", + "mmpll" +}; + +static const struct mtk_composite top_muxes[] = { + MUX_GATE_FLAGS(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, + 0x0040, 0, 3, 7, CLK_IS_CRITICAL), + MUX_GATE_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, + 0x0040, 8, 1, 15, CLK_IS_CRITICAL), + MUX_GATE_FLAGS(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", + ddrphycfg_parents, 0x0040, 16, 1, 23, CLK_IS_CRITICAL), + MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", mm_parents, + 0x0040, 24, 3, 31), + + MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, + 0x0050, 0, 2, 7), + MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_parents, + 0x0050, 8, 4, 15), + MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", mfg_parents, + 0x0050, 16, 3, 23), + MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_parents, + 0x0050, 24, 3, 31), + MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, + 0x0060, 0, 1, 7), + + MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi_parents, + 0x0060, 8, 3, 15), + MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", usb20_parents, + 0x0060, 16, 2, 23), + MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_parents, + 0x0060, 24, 3, 31), + + MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_parents, + 0x0070, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_parents, + 0x0070, 8, 3, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", msdc30_parents, + 0x0070, 16, 1, 23), + MUX_GATE(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, + 0x0070, 24, 3, 31), + + MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, + 0x0080, 0, 4, 7), + MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", scp_parents, + 0x0080, 8, 2, 15), + MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents, + 0x0080, 16, 3, 23), + MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents, + 0x0080, 24, 2, 31), + + MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents, + 0x0090, 0, 3, 7), + MUX_GATE(CLK_TOP_HDMI_SEL, "hdmi_sel", hdmi_parents, + 0x0090, 8, 2, 15), + MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", apll_parents, + 0x0090, 16, 3, 23), + + MUX_GATE_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, + 0x00A0, 0, 2, 7, CLK_IS_CRITICAL), + MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", nfi2x_parents, + 0x00A0, 8, 3, 15), + MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, "emmc_hclk_sel", emmc_hclk_parents, + 0x00A0, 24, 2, 31), + + MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, + 0x00B0, 0, 3, 7), + MUX_GATE(CLK_TOP_DI_SEL, "di_sel", di_parents, + 0x00B0, 8, 2, 15), + MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", nr_osd_parents, + 0x00B0, 16, 3, 23), + MUX_GATE(CLK_TOP_OSD_SEL, "osd_sel", nr_osd_parents, + 0x00B0, 24, 3, 31), + + MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, "hdmirx_bist_sel", + hdmirx_bist_parents, 0x00C0, 0, 3, 7), + MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, + 0x00C0, 8, 2, 15), + MUX_GATE(CLK_TOP_ASM_I_SEL, "asm_i_sel", asm_parents, + 0x00C0, 16, 2, 23), + MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_parents, + 0x00C0, 24, 3, 31), + + MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_parents, + 0x00D0, 0, 2, 7), + MUX_GATE(CLK_TOP_MS_CARD_SEL, "ms_card_sel", ms_card_parents, + 0x00D0, 16, 2, 23), + MUX_GATE(CLK_TOP_ETHIF_SEL, "ethif_sel", ethif_parents, + 0x00D0, 24, 3, 31), + + MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, "hdmirx26_24_sel", hdmirx_parents, + 0x00E0, 0, 1, 7), + MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_parents, + 0x00E0, 8, 3, 15), + MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", cmsys_parents, + 0x00E0, 16, 4, 23), + + MUX_GATE(CLK_TOP_SPI1_SEL, "spi2_sel", spi_parents, + 0x00E0, 24, 3, 31), + MUX_GATE(CLK_TOP_SPI2_SEL, "spi1_sel", spi_parents, + 0x00F0, 0, 3, 7), + MUX_GATE(CLK_TOP_8BDAC_SEL, "8bdac_sel", clk_8bdac_parents, + 0x00F0, 8, 2, 15), + MUX_GATE(CLK_TOP_AUD2DVD_SEL, "aud2dvd_sel", aud2dvd_parents, + 0x00F0, 16, 1, 23), + + MUX(CLK_TOP_PADMCLK_SEL, "padmclk_sel", padmclk_parents, + 0x0100, 0, 3), + + MUX(CLK_TOP_AUD_MUX1_SEL, "aud_mux1_sel", aud_mux_parents, + 0x012c, 0, 3), + MUX(CLK_TOP_AUD_MUX2_SEL, "aud_mux2_sel", aud_mux_parents, + 0x012c, 3, 3), + MUX(CLK_TOP_AUDPLL_MUX_SEL, "audpll_sel", aud_mux_parents, + 0x012c, 6, 3), + MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, "aud_k1_src_sel", aud_src_parents, + 0x012c, 15, 1, 23), + MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, "aud_k2_src_sel", aud_src_parents, + 0x012c, 16, 1, 24), + MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, "aud_k3_src_sel", aud_src_parents, + 0x012c, 17, 1, 25), + MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, "aud_k4_src_sel", aud_src_parents, + 0x012c, 18, 1, 26), + MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, "aud_k5_src_sel", aud_src_parents, + 0x012c, 19, 1, 27), + MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, "aud_k6_src_sel", aud_src_parents, + 0x012c, 20, 1, 28), +}; + +static const struct mtk_clk_divider top_adj_divs[] = { + DIV_ADJ(CLK_TOP_AUD_EXTCK1_DIV, "audio_ext1_ck", "aud_ext1", + 0x0120, 0, 8), + DIV_ADJ(CLK_TOP_AUD_EXTCK2_DIV, "audio_ext2_ck", "aud_ext2", + 0x0120, 8, 8), + DIV_ADJ(CLK_TOP_AUD_MUX1_DIV, "aud_mux1_div", "aud_mux1_sel", + 0x0120, 16, 8), + DIV_ADJ(CLK_TOP_AUD_MUX2_DIV, "aud_mux2_div", "aud_mux2_sel", + 0x0120, 24, 8), + DIV_ADJ(CLK_TOP_AUD_K1_SRC_DIV, "aud_k1_src_div", "aud_k1_src_sel", + 0x0124, 0, 8), + DIV_ADJ(CLK_TOP_AUD_K2_SRC_DIV, "aud_k2_src_div", "aud_k2_src_sel", + 0x0124, 8, 8), + DIV_ADJ(CLK_TOP_AUD_K3_SRC_DIV, "aud_k3_src_div", "aud_k3_src_sel", + 0x0124, 16, 8), + DIV_ADJ(CLK_TOP_AUD_K4_SRC_DIV, "aud_k4_src_div", "aud_k4_src_sel", + 0x0124, 24, 8), + DIV_ADJ(CLK_TOP_AUD_K5_SRC_DIV, "aud_k5_src_div", "aud_k5_src_sel", + 0x0128, 0, 8), + DIV_ADJ(CLK_TOP_AUD_K6_SRC_DIV, "aud_k6_src_div", "aud_k6_src_sel", + 0x0128, 8, 8), +}; + +static const struct mtk_gate_regs top_aud_cg_regs = { + .sta_ofs = 0x012C, +}; + +#define GATE_TOP_AUD(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top_aud_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate top_clks[] = { + GATE_TOP_AUD(CLK_TOP_AUD_48K_TIMING, "a1sys_hp_ck", "aud_mux1_div", + 21), + GATE_TOP_AUD(CLK_TOP_AUD_44K_TIMING, "a2sys_hp_ck", "aud_mux2_div", + 22), + GATE_TOP_AUD(CLK_TOP_AUD_I2S1_MCLK, "aud_i2s1_mclk", "aud_k1_src_div", + 23), + GATE_TOP_AUD(CLK_TOP_AUD_I2S2_MCLK, "aud_i2s2_mclk", "aud_k2_src_div", + 24), + GATE_TOP_AUD(CLK_TOP_AUD_I2S3_MCLK, "aud_i2s3_mclk", "aud_k3_src_div", + 25), + GATE_TOP_AUD(CLK_TOP_AUD_I2S4_MCLK, "aud_i2s4_mclk", "aud_k4_src_div", + 26), + GATE_TOP_AUD(CLK_TOP_AUD_I2S5_MCLK, "aud_i2s5_mclk", "aud_k5_src_div", + 27), + GATE_TOP_AUD(CLK_TOP_AUD_I2S6_MCLK, "aud_i2s6_mclk", "aud_k6_src_div", + 28), +}; + +static int mtk_topckgen_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + struct device_node *node = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR); + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); + + mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs), + clk_data); + + mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), + base, &mt2701_clk_lock, clk_data); + + mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), + base, &mt2701_clk_lock, clk_data); + + mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x0040, + .clr_ofs = 0x0044, + .sta_ofs = 0x0048, +}; + +#define GATE_ICG(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate infra_clks[] = { + GATE_ICG(CLK_INFRA_DBG, "dbgclk", "axi_sel", 0), + GATE_ICG(CLK_INFRA_SMI, "smi_ck", "mm_sel", 1), + GATE_ICG(CLK_INFRA_QAXI_CM4, "cm4_ck", "axi_sel", 2), + GATE_ICG(CLK_INFRA_AUD_SPLIN_B, "audio_splin_bck", "hadds2pll_294m", 4), + GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "clk26m", 5), + GATE_ICG(CLK_INFRA_EFUSE, "efuse_ck", "clk26m", 6), + GATE_ICG(CLK_INFRA_L2C_SRAM, "l2c_sram_ck", "mm_sel", 7), + GATE_ICG(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8), + GATE_ICG(CLK_INFRA_CONNMCU, "connsys_bus", "wbg_dig_ck_416m", 12), + GATE_ICG(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 13), + GATE_ICG(CLK_INFRA_RAMBUFIF, "rambufif_ck", "mem_sel", 14), + GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "mem_sel", 15), + GATE_ICG(CLK_INFRA_KP, "kp_ck", "axi_sel", 16), + GATE_ICG(CLK_INFRA_CEC, "cec_ck", "rtc_sel", 18), + GATE_ICG(CLK_INFRA_IRRX, "irrx_ck", "axi_sel", 19), + GATE_ICG(CLK_INFRA_PMICSPI, "pmicspi_ck", "pmicspi_sel", 22), + GATE_ICG(CLK_INFRA_PMICWRAP, "pmicwrap_ck", "axi_sel", 23), + GATE_ICG(CLK_INFRA_DDCCI, "ddcci_ck", "axi_sel", 24), +}; + +static const struct mtk_fixed_factor infra_fixed_divs[] = { + FACTOR(CLK_INFRA_CLK_13M, "clk13m", "clk26m", 1, 2), +}; + +static struct clk_onecell_data *infra_clk_data; + +static void mtk_infrasys_init_early(struct device_node *node) +{ + int r, i; + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + + for (i = 0; i < CLK_INFRA_NR; i++) + infra_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER); + } + + mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), + infra_clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} +CLK_OF_DECLARE_DRIVER(mtk_infra, "mediatek,mt2701-infracfg", + mtk_infrasys_init_early); + +static int mtk_infrasys_init(struct platform_device *pdev) +{ + int r, i; + struct device_node *node = pdev->dev.of_node; + + if (!infra_clk_data) { + infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + } else { + for (i = 0; i < CLK_INFRA_NR; i++) { + if (infra_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER)) + infra_clk_data->clks[i] = ERR_PTR(-ENOENT); + } + } + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + infra_clk_data); + mtk_clk_register_factors(infra_fixed_divs, ARRAY_SIZE(infra_fixed_divs), + infra_clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, infra_clk_data); + if (r) + return r; + + mtk_register_reset_controller(node, 2, 0x30); + + return 0; +} + +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x0008, + .clr_ofs = 0x0010, + .sta_ofs = 0x0018, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0x000c, + .clr_ofs = 0x0014, + .sta_ofs = 0x001c, +}; + +#define GATE_PERI0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate peri_clks[] = { + GATE_PERI0(CLK_PERI_USB0_MCU, "usb0_mcu_ck", "axi_sel", 31), + GATE_PERI0(CLK_PERI_ETH, "eth_ck", "clk26m", 30), + GATE_PERI0(CLK_PERI_SPI0, "spi0_ck", "spi0_sel", 29), + GATE_PERI0(CLK_PERI_AUXADC, "auxadc_ck", "clk26m", 28), + GATE_PERI0(CLK_PERI_I2C3, "i2c3_ck", "clk26m", 27), + GATE_PERI0(CLK_PERI_I2C2, "i2c2_ck", "axi_sel", 26), + GATE_PERI0(CLK_PERI_I2C1, "i2c1_ck", "axi_sel", 25), + GATE_PERI0(CLK_PERI_I2C0, "i2c0_ck", "axi_sel", 24), + GATE_PERI0(CLK_PERI_BTIF, "bitif_ck", "axi_sel", 23), + GATE_PERI0(CLK_PERI_UART3, "uart3_ck", "axi_sel", 22), + GATE_PERI0(CLK_PERI_UART2, "uart2_ck", "axi_sel", 21), + GATE_PERI0(CLK_PERI_UART1, "uart1_ck", "axi_sel", 20), + GATE_PERI0(CLK_PERI_UART0, "uart0_ck", "axi_sel", 19), + GATE_PERI0(CLK_PERI_NLI, "nli_ck", "axi_sel", 18), + GATE_PERI0(CLK_PERI_MSDC50_3, "msdc50_3_ck", "emmc_hclk_sel", 17), + GATE_PERI0(CLK_PERI_MSDC30_3, "msdc30_3_ck", "msdc30_3_sel", 16), + GATE_PERI0(CLK_PERI_MSDC30_2, "msdc30_2_ck", "msdc30_2_sel", 15), + GATE_PERI0(CLK_PERI_MSDC30_1, "msdc30_1_ck", "msdc30_1_sel", 14), + GATE_PERI0(CLK_PERI_MSDC30_0, "msdc30_0_ck", "msdc30_0_sel", 13), + GATE_PERI0(CLK_PERI_AP_DMA, "ap_dma_ck", "axi_sel", 12), + GATE_PERI0(CLK_PERI_USB1, "usb1_ck", "usb20_sel", 11), + GATE_PERI0(CLK_PERI_USB0, "usb0_ck", "usb20_sel", 10), + GATE_PERI0(CLK_PERI_PWM, "pwm_ck", "axi_sel", 9), + GATE_PERI0(CLK_PERI_PWM7, "pwm7_ck", "axi_sel", 8), + GATE_PERI0(CLK_PERI_PWM6, "pwm6_ck", "axi_sel", 7), + GATE_PERI0(CLK_PERI_PWM5, "pwm5_ck", "axi_sel", 6), + GATE_PERI0(CLK_PERI_PWM4, "pwm4_ck", "axi_sel", 5), + GATE_PERI0(CLK_PERI_PWM3, "pwm3_ck", "axi_sel", 4), + GATE_PERI0(CLK_PERI_PWM2, "pwm2_ck", "axi_sel", 3), + GATE_PERI0(CLK_PERI_PWM1, "pwm1_ck", "axi_sel", 2), + GATE_PERI0(CLK_PERI_THERM, "therm_ck", "axi_sel", 1), + GATE_PERI0(CLK_PERI_NFI, "nfi_ck", "nfi2x_sel", 0), + + GATE_PERI1(CLK_PERI_FCI, "fci_ck", "ms_card_sel", 11), + GATE_PERI1(CLK_PERI_SPI2, "spi2_ck", "spi2_sel", 10), + GATE_PERI1(CLK_PERI_SPI1, "spi1_ck", "spi1_sel", 9), + GATE_PERI1(CLK_PERI_HOST89_DVD, "host89_dvd_ck", "aud2dvd_sel", 8), + GATE_PERI1(CLK_PERI_HOST89_SPI, "host89_spi_ck", "spi0_sel", 7), + GATE_PERI1(CLK_PERI_HOST89_INT, "host89_int_ck", "axi_sel", 6), + GATE_PERI1(CLK_PERI_FLASH, "flash_ck", "nfi2x_sel", 5), + GATE_PERI1(CLK_PERI_NFI_PAD, "nfi_pad_ck", "nfi1x_pad", 4), + GATE_PERI1(CLK_PERI_NFI_ECC, "nfi_ecc_ck", "nfi1x_pad", 3), + GATE_PERI1(CLK_PERI_GCPU, "gcpu_ck", "axi_sel", 2), + GATE_PERI1(CLK_PERI_USB_SLV, "usbslv_ck", "axi_sel", 1), + GATE_PERI1(CLK_PERI_USB1_MCU, "usb1_mcu_ck", "axi_sel", 0), +}; + +static const char * const uart_ck_sel_parents[] = { + "clk26m", + "uart_sel", +}; + +static const struct mtk_composite peri_muxs[] = { + MUX(CLK_PERI_UART0_SEL, "uart0_ck_sel", uart_ck_sel_parents, + 0x40c, 0, 1), + MUX(CLK_PERI_UART1_SEL, "uart1_ck_sel", uart_ck_sel_parents, + 0x40c, 1, 1), + MUX(CLK_PERI_UART2_SEL, "uart2_ck_sel", uart_ck_sel_parents, + 0x40c, 2, 1), + MUX(CLK_PERI_UART3_SEL, "uart3_ck_sel", uart_ck_sel_parents, + 0x40c, 3, 1), +}; + +static int mtk_pericfg_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + int r; + struct device_node *node = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR); + + mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), + clk_data); + + mtk_clk_register_composites(peri_muxs, ARRAY_SIZE(peri_muxs), base, + &mt2701_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + return r; + + mtk_register_reset_controller(node, 2, 0x0); + + return 0; +} + +#define MT8590_PLL_FMAX (2000 * MHZ) +#define CON0_MT8590_RST_BAR BIT(27) + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, \ + _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT8590_RST_BAR, \ + .fmax = MT8590_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + } + +static const struct mtk_pll_data apmixed_plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x200, 0x20c, 0x80000001, + PLL_AO, 21, 0x204, 24, 0x0, 0x204, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x210, 0x21c, 0xf0000001, + HAVE_RST_BAR, 21, 0x210, 4, 0x0, 0x214, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x220, 0x22c, 0xf3000001, + HAVE_RST_BAR, 7, 0x220, 4, 0x0, 0x224, 14), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x230, 0x23c, 0x00000001, 0, + 21, 0x230, 4, 0x0, 0x234, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x240, 0x24c, 0x00000001, 0, + 21, 0x240, 4, 0x0, 0x244, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x250, 0x25c, 0x00000001, 0, + 21, 0x250, 4, 0x0, 0x254, 0), + PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x270, 0x27c, 0x00000001, 0, + 31, 0x270, 4, 0x0, 0x274, 0), + PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x280, 0x28c, 0x00000001, 0, + 31, 0x280, 4, 0x0, 0x284, 0), + PLL(CLK_APMIXED_ETHPLL, "ethpll", 0x290, 0x29c, 0x00000001, 0, + 31, 0x290, 4, 0x0, 0x294, 0), + PLL(CLK_APMIXED_VDECPLL, "vdecpll", 0x2a0, 0x2ac, 0x00000001, 0, + 31, 0x2a0, 4, 0x0, 0x2a4, 0), + PLL(CLK_APMIXED_HADDS2PLL, "hadds2pll", 0x2b0, 0x2bc, 0x00000001, 0, + 31, 0x2b0, 4, 0x0, 0x2b4, 0), + PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x2c0, 0x2cc, 0x00000001, 0, + 31, 0x2c0, 4, 0x0, 0x2c4, 0), + PLL(CLK_APMIXED_TVD2PLL, "tvd2pll", 0x2d0, 0x2dc, 0x00000001, 0, + 21, 0x2d0, 4, 0x0, 0x2d4, 0), +}; + +static int mtk_apmixedsys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_plls(node, apmixed_plls, ARRAY_SIZE(apmixed_plls), + clk_data); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static const struct of_device_id of_match_clk_mt2701[] = { + { + .compatible = "mediatek,mt2701-topckgen", + .data = mtk_topckgen_init, + }, { + .compatible = "mediatek,mt2701-infracfg", + .data = mtk_infrasys_init, + }, { + .compatible = "mediatek,mt2701-pericfg", + .data = mtk_pericfg_init, + }, { + .compatible = "mediatek,mt2701-apmixedsys", + .data = mtk_apmixedsys_init, + }, { + /* sentinel */ + } +}; + +static int clk_mt2701_probe(struct platform_device *pdev) +{ + int (*clk_init)(struct platform_device *); + int r; + + clk_init = of_device_get_match_data(&pdev->dev); + if (!clk_init) + return -EINVAL; + + r = clk_init(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2701_drv = { + .probe = clk_mt2701_probe, + .driver = { + .name = "clk-mt2701", + .of_match_table = of_match_clk_mt2701, + }, +}; + +static int __init clk_mt2701_init(void) +{ + return platform_driver_register(&clk_mt2701_drv); +} + +arch_initcall(clk_mt2701_init); diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index bb30f7063569..0541df78141c 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -58,6 +58,9 @@ void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, for (i = 0; i < num; i++) { const struct mtk_fixed_clk *rc = &clks[i]; + if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id])) + continue; + clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0, rc->rate); @@ -81,6 +84,9 @@ void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, for (i = 0; i < num; i++) { const struct mtk_fixed_factor *ff = &clks[i]; + if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id])) + continue; + clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, CLK_SET_RATE_PARENT, ff->mult, ff->div); @@ -116,6 +122,9 @@ int mtk_clk_register_gates(struct device_node *node, for (i = 0; i < num; i++) { const struct mtk_gate *gate = &clks[i]; + if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) + continue; + clk = mtk_clk_register_gate(gate->name, gate->parent_name, regmap, gate->regs->set_ofs, @@ -232,6 +241,9 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs, for (i = 0; i < num; i++) { const struct mtk_composite *mc = &mcs[i]; + if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id])) + continue; + clk = mtk_clk_register_composite(mc, base, lock); if (IS_ERR(clk)) { @@ -244,3 +256,31 @@ void mtk_clk_register_composites(const struct mtk_composite *mcs, clk_data->clks[mc->id] = clk; } } + +void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, + int num, void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data) +{ + struct clk *clk; + int i; + + for (i = 0; i < num; i++) { + const struct mtk_clk_divider *mcd = &mcds[i]; + + if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id])) + continue; + + clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, + mcd->flags, base + mcd->div_reg, mcd->div_shift, + mcd->div_width, mcd->clk_divider_flags, lock); + + if (IS_ERR(clk)) { + pr_err("Failed to register clk %s: %ld\n", + mcd->name, PTR_ERR(clk)); + continue; + } + + if (clk_data) + clk_data->clks[mcd->id] = clk; + } +} diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 9f24fcfa304f..f5d6b70ce189 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -87,7 +87,8 @@ struct mtk_composite { * In case the rate change propagation to parent clocks is undesirable, * this macro allows to specify the clock flags manually. */ -#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, _flags) { \ +#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ + _gate, _flags) { \ .id = _id, \ .name = _name, \ .mux_reg = _reg, \ @@ -106,7 +107,8 @@ struct mtk_composite { * parent clock by default. */ #define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) \ - MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, _gate, CLK_SET_RATE_PARENT) + MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width, \ + _gate, CLK_SET_RATE_PARENT) #define MUX(_id, _name, _parents, _reg, _shift, _width) { \ .id = _id, \ @@ -121,7 +123,8 @@ struct mtk_composite { .flags = CLK_SET_RATE_PARENT, \ } -#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \ +#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, \ + _div_width, _div_shift) { \ .id = _id, \ .parent = _parent, \ .name = _name, \ @@ -156,12 +159,40 @@ struct mtk_gate { const struct clk_ops *ops; }; -int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, - int num, struct clk_onecell_data *clk_data); +int mtk_clk_register_gates(struct device_node *node, + const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data); + +struct mtk_clk_divider { + int id; + const char *name; + const char *parent_name; + unsigned long flags; + + u32 div_reg; + unsigned char div_shift; + unsigned char div_width; + unsigned char clk_divider_flags; + const struct clk_div_table *clk_div_table; +}; + +#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .div_reg = _reg, \ + .div_shift = _shift, \ + .div_width = _width, \ +} + +void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, + int num, void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data); struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); #define HAVE_RST_BAR BIT(0) +#define PLL_AO BIT(1) struct mtk_pll_div_table { u32 div; diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 0c2deac17ce9..a409142e9346 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -301,6 +301,7 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, pll->data = data; init.name = data->name; + init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; init.ops = &mtk_pll_ops; init.parent_names = &parent_name; init.num_parents = 1; diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 3a51fff1b0e7..9adaf48aea23 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -313,7 +313,7 @@ static void __init mmp2_clk_init(struct device_node *np) } pxa_unit->apmu_base = of_iomap(np, 1); - if (!pxa_unit->mpmu_base) { + if (!pxa_unit->apmu_base) { pr_err("failed to map apmu registers\n"); return; } diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index 87f2317b2a00..f110c02e83cb 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -262,7 +262,7 @@ static void __init pxa168_clk_init(struct device_node *np) } pxa_unit->apmu_base = of_iomap(np, 1); - if (!pxa_unit->mpmu_base) { + if (!pxa_unit->apmu_base) { pr_err("failed to map apmu registers\n"); return; } diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index e22a67f76d93..64d1ef49caeb 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -282,7 +282,7 @@ static void __init pxa910_clk_init(struct device_node *np) } pxa_unit->apmu_base = of_iomap(np, 1); - if (!pxa_unit->mpmu_base) { + if (!pxa_unit->apmu_base) { pr_err("failed to map apmu registers\n"); return; } @@ -294,7 +294,7 @@ static void __init pxa910_clk_init(struct device_node *np) } pxa_unit->apbcp_base = of_iomap(np, 3); - if (!pxa_unit->mpmu_base) { + if (!pxa_unit->apbcp_base) { pr_err("failed to map apbcp registers\n"); return; } diff --git a/drivers/clk/mvebu/ap806-system-controller.c b/drivers/clk/mvebu/ap806-system-controller.c index 02023baf86c9..8181b919f062 100644 --- a/drivers/clk/mvebu/ap806-system-controller.c +++ b/drivers/clk/mvebu/ap806-system-controller.c @@ -14,7 +14,7 @@ #include <linux/clk-provider.h> #include <linux/mfd/syscon.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> @@ -135,34 +135,17 @@ fail0: return ret; } -static int ap806_syscon_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - clk_unregister_fixed_factor(ap806_clks[3]); - clk_unregister_fixed_rate(ap806_clks[2]); - clk_unregister_fixed_rate(ap806_clks[1]); - clk_unregister_fixed_rate(ap806_clks[0]); - - return 0; -} - static const struct of_device_id ap806_syscon_of_match[] = { { .compatible = "marvell,ap806-system-controller", }, { } }; -MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match); static struct platform_driver ap806_syscon_driver = { .probe = ap806_syscon_clk_probe, - .remove = ap806_syscon_clk_remove, .driver = { .name = "marvell-ap806-system-controller", .of_match_table = ap806_syscon_of_match, + .suppress_bind_attrs = true, }, }; - -module_platform_driver(ap806_syscon_driver); - -MODULE_DESCRIPTION("Marvell AP806 System Controller driver"); -MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(ap806_syscon_driver); diff --git a/drivers/clk/mvebu/armada-37xx-periph.c b/drivers/clk/mvebu/armada-37xx-periph.c index 45905fc0d75b..cecb0fdfaef6 100644 --- a/drivers/clk/mvebu/armada-37xx-periph.c +++ b/drivers/clk/mvebu/armada-37xx-periph.c @@ -305,7 +305,7 @@ static const struct of_device_id armada_3700_periph_clock_of_match[] = { }; static int armada_3700_add_composite_clk(const struct clk_periph_data *data, void __iomem *reg, spinlock_t *lock, - struct device *dev, struct clk_hw *hw) + struct device *dev, struct clk_hw **hw) { const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *rate_ops = NULL; @@ -329,6 +329,7 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, gate->lock = lock; gate_ops = gate_hw->init->ops; gate->reg = reg + (u64)gate->reg; + gate->flags = CLK_GATE_SET_TO_DISABLE; } if (data->rate_hw) { @@ -353,13 +354,13 @@ static int armada_3700_add_composite_clk(const struct clk_periph_data *data, } } - hw = clk_hw_register_composite(dev, data->name, data->parent_names, + *hw = clk_hw_register_composite(dev, data->name, data->parent_names, data->num_parents, mux_hw, mux_ops, rate_hw, rate_ops, gate_hw, gate_ops, CLK_IGNORE_UNUSED); - if (IS_ERR(hw)) - return PTR_ERR(hw); + if (IS_ERR(*hw)) + return PTR_ERR(*hw); return 0; } @@ -400,7 +401,7 @@ static int armada_3700_periph_clock_probe(struct platform_device *pdev) spin_lock_init(&driver_data->lock); for (i = 0; i < num_periph; i++) { - struct clk_hw *hw = driver_data->hw_data->hws[i]; + struct clk_hw **hw = &driver_data->hw_data->hws[i]; if (armada_3700_add_composite_clk(&data[i], reg, &driver_data->lock, dev, hw)) diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index f2303da7fda7..32e5b43c086f 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -30,7 +30,7 @@ #include <linux/clk-provider.h> #include <linux/mfd/syscon.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> @@ -87,7 +87,7 @@ struct cp110_gate_clk { u8 bit_idx; }; -#define to_cp110_gate_clk(clk) container_of(clk, struct cp110_gate_clk, hw) +#define to_cp110_gate_clk(hw) container_of(hw, struct cp110_gate_clk, hw) static int cp110_gate_enable(struct clk_hw *hw) { @@ -123,13 +123,14 @@ static const struct clk_ops cp110_gate_ops = { .is_enabled = cp110_gate_is_enabled, }; -static struct clk *cp110_register_gate(const char *name, - const char *parent_name, - struct regmap *regmap, u8 bit_idx) +static struct clk_hw *cp110_register_gate(const char *name, + const char *parent_name, + struct regmap *regmap, u8 bit_idx) { struct cp110_gate_clk *gate; - struct clk *clk; + struct clk_hw *hw; struct clk_init_data init; + int ret; gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) @@ -146,39 +147,37 @@ static struct clk *cp110_register_gate(const char *name, gate->bit_idx = bit_idx; gate->hw.init = &init; - clk = clk_register(NULL, &gate->hw); - if (IS_ERR(clk)) + hw = &gate->hw; + ret = clk_hw_register(NULL, hw); + if (ret) { kfree(gate); + hw = ERR_PTR(ret); + } - return clk; + return hw; } -static void cp110_unregister_gate(struct clk *clk) +static void cp110_unregister_gate(struct clk_hw *hw) { - struct clk_hw *hw; - - hw = __clk_get_hw(clk); - if (!hw) - return; - - clk_unregister(clk); + clk_hw_unregister(hw); kfree(to_cp110_gate_clk(hw)); } -static struct clk *cp110_of_clk_get(struct of_phandle_args *clkspec, void *data) +static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec, + void *data) { - struct clk_onecell_data *clk_data = data; + struct clk_hw_onecell_data *clk_data = data; unsigned int type = clkspec->args[0]; unsigned int idx = clkspec->args[1]; if (type == CP110_CLK_TYPE_CORE) { if (idx > CP110_MAX_CORE_CLOCKS) return ERR_PTR(-EINVAL); - return clk_data->clks[idx]; + return clk_data->hws[idx]; } else if (type == CP110_CLK_TYPE_GATABLE) { if (idx > CP110_MAX_GATABLE_CLOCKS) return ERR_PTR(-EINVAL); - return clk_data->clks[CP110_MAX_CORE_CLOCKS + idx]; + return clk_data->hws[CP110_MAX_CORE_CLOCKS + idx]; } return ERR_PTR(-EINVAL); @@ -189,8 +188,8 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) struct regmap *regmap; struct device_node *np = pdev->dev.of_node; const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name; - struct clk_onecell_data *cp110_clk_data; - struct clk *clk, **cp110_clks; + struct clk_hw_onecell_data *cp110_clk_data; + struct clk_hw *hw, **cp110_clks; u32 nand_clk_ctrl; int i, ret; @@ -203,80 +202,75 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) if (ret) return ret; - cp110_clks = devm_kcalloc(&pdev->dev, sizeof(struct clk *), - CP110_CLK_NUM, GFP_KERNEL); - if (!cp110_clks) - return -ENOMEM; - - cp110_clk_data = devm_kzalloc(&pdev->dev, - sizeof(*cp110_clk_data), + cp110_clk_data = devm_kzalloc(&pdev->dev, sizeof(*cp110_clk_data) + + sizeof(struct clk_hw *) * CP110_CLK_NUM, GFP_KERNEL); if (!cp110_clk_data) return -ENOMEM; - cp110_clk_data->clks = cp110_clks; - cp110_clk_data->clk_num = CP110_CLK_NUM; + cp110_clks = cp110_clk_data->hws; + cp110_clk_data->num = CP110_CLK_NUM; - /* Register the APLL which is the root of the clk tree */ + /* Register the APLL which is the root of the hw tree */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_APLL, &apll_name); - clk = clk_register_fixed_rate(NULL, apll_name, NULL, 0, - 1000 * 1000 * 1000); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, + 1000 * 1000 * 1000); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail0; } - cp110_clks[CP110_CORE_APLL] = clk; + cp110_clks[CP110_CORE_APLL] = hw; /* PPv2 is APLL/3 */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_PPV2, &ppv2_name); - clk = clk_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail1; } - cp110_clks[CP110_CORE_PPV2] = clk; + cp110_clks[CP110_CORE_PPV2] = hw; /* EIP clock is APLL/2 */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_EIP, &eip_name); - clk = clk_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail2; } - cp110_clks[CP110_CORE_EIP] = clk; + cp110_clks[CP110_CORE_EIP] = hw; /* Core clock is EIP/2 */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_CORE, &core_name); - clk = clk_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail3; } - cp110_clks[CP110_CORE_CORE] = clk; + cp110_clks[CP110_CORE_CORE] = hw; /* NAND can be either APLL/2.5 or core clock */ of_property_read_string_index(np, "core-clock-output-names", CP110_CORE_NAND, &nand_name); if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) - clk = clk_register_fixed_factor(NULL, nand_name, - apll_name, 0, 2, 5); + hw = clk_hw_register_fixed_factor(NULL, nand_name, + apll_name, 0, 2, 5); else - clk = clk_register_fixed_factor(NULL, nand_name, - core_name, 0, 1, 1); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = clk_hw_register_fixed_factor(NULL, nand_name, + core_name, 0, 1, 1); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail4; } - cp110_clks[CP110_CORE_NAND] = clk; + cp110_clks[CP110_CORE_NAND] = hw; for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { const char *parent, *name; @@ -335,16 +329,16 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) break; } - clk = cp110_register_gate(name, parent, regmap, i); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); + hw = cp110_register_gate(name, parent, regmap, i); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); goto fail_gate; } - cp110_clks[CP110_MAX_CORE_CLOCKS + i] = clk; + cp110_clks[CP110_MAX_CORE_CLOCKS + i] = hw; } - ret = of_clk_add_provider(np, cp110_of_clk_get, cp110_clk_data); + ret = of_clk_add_hw_provider(np, cp110_of_clk_get, cp110_clk_data); if (ret) goto fail_clk_add; @@ -355,65 +349,36 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) fail_clk_add: fail_gate: for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { - clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; + hw = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; - if (clk) - cp110_unregister_gate(clk); + if (hw) + cp110_unregister_gate(hw); } - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); fail4: - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); fail3: - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); fail2: - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); fail1: - clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); + clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); fail0: return ret; } -static int cp110_syscon_clk_remove(struct platform_device *pdev) -{ - struct clk **cp110_clks = platform_get_drvdata(pdev); - int i; - - of_clk_del_provider(pdev->dev.of_node); - - for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { - struct clk *clk = cp110_clks[CP110_MAX_CORE_CLOCKS + i]; - - if (clk) - cp110_unregister_gate(clk); - } - - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); - clk_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); - clk_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); - - return 0; -} - static const struct of_device_id cp110_syscon_of_match[] = { { .compatible = "marvell,cp110-system-controller0", }, { } }; -MODULE_DEVICE_TABLE(of, armada8k_pcie_of_match); static struct platform_driver cp110_syscon_driver = { .probe = cp110_syscon_clk_probe, - .remove = cp110_syscon_clk_remove, .driver = { .name = "marvell-cp110-system-controller0", .of_match_table = cp110_syscon_of_match, + .suppress_bind_attrs = true, }, }; - -module_platform_driver(cp110_syscon_driver); - -MODULE_DESCRIPTION("Marvell CP110 System Controller 0 driver"); -MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(cp110_syscon_driver); diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index f7136b94fd0e..27781b49eb82 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -277,12 +277,15 @@ static void __init lpc18xx_ccu_init(struct device_node *np) } clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); - if (!clk_data) + if (!clk_data) { + iounmap(reg_base); return; + } clk_data->num = of_property_count_strings(np, "clock-names"); clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL); if (!clk_data->name) { + iounmap(reg_base); kfree(clk_data); return; } diff --git a/drivers/clk/nxp/clk-lpc32xx.c b/drivers/clk/nxp/clk-lpc32xx.c index 34c97353cdeb..5b98ff9076f3 100644 --- a/drivers/clk/nxp/clk-lpc32xx.c +++ b/drivers/clk/nxp/clk-lpc32xx.c @@ -1282,13 +1282,13 @@ static struct clk_hw_proto clk_hw_proto[LPC32XX_CLK_HW_MAX] = { LPC32XX_DEFINE_MUX(PWM1_MUX, PWMCLK_CTRL, 1, 0x1, NULL, 0), LPC32XX_DEFINE_DIV(PWM1_DIV, PWMCLK_CTRL, 4, 4, NULL, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO), + CLK_DIVIDER_ONE_BASED), LPC32XX_DEFINE_GATE(PWM1_GATE, PWMCLK_CTRL, 0, 0), LPC32XX_DEFINE_COMPOSITE(PWM1, PWM1_MUX, PWM1_DIV, PWM1_GATE), LPC32XX_DEFINE_MUX(PWM2_MUX, PWMCLK_CTRL, 3, 0x1, NULL, 0), LPC32XX_DEFINE_DIV(PWM2_DIV, PWMCLK_CTRL, 8, 4, NULL, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO), + CLK_DIVIDER_ONE_BASED), LPC32XX_DEFINE_GATE(PWM2_GATE, PWMCLK_CTRL, 2, 0), LPC32XX_DEFINE_COMPOSITE(PWM2, PWM2_MUX, PWM2_DIV, PWM2_GATE), @@ -1335,8 +1335,7 @@ static struct clk_hw_proto clk_hw_proto[LPC32XX_CLK_HW_MAX] = { LPC32XX_DEFINE_GATE(USB_DIV_GATE, USB_CTRL, 17, 0), LPC32XX_DEFINE_COMPOSITE(USB_DIV, _NULL, USB_DIV_DIV, USB_DIV_GATE), - LPC32XX_DEFINE_DIV(SD_DIV, MS_CTRL, 0, 4, NULL, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO), + LPC32XX_DEFINE_DIV(SD_DIV, MS_CTRL, 0, 4, NULL, CLK_DIVIDER_ONE_BASED), LPC32XX_DEFINE_CLK(SD_GATE, MS_CTRL, BIT(5) | BIT(9), BIT(5) | BIT(9), 0x0, BIT(5) | BIT(9), 0x0, 0x0, clk_mask_ops), LPC32XX_DEFINE_COMPOSITE(SD, _NULL, SD_DIV, SD_GATE), @@ -1478,6 +1477,20 @@ static struct clk * __init lpc32xx_clk_register(u32 id) return clk; } +static void __init lpc32xx_clk_div_quirk(u32 reg, u32 div_mask, u32 gate) +{ + u32 val; + + regmap_read(clk_regmap, reg, &val); + + if (!(val & div_mask)) { + val &= ~gate; + val |= BIT(__ffs(div_mask)); + } + + regmap_update_bits(clk_regmap, reg, gate | div_mask, val); +} + static void __init lpc32xx_clk_init(struct device_node *np) { unsigned int i; @@ -1517,6 +1530,17 @@ static void __init lpc32xx_clk_init(struct device_node *np) return; } + /* + * Divider part of PWM and MS clocks requires a quirk to avoid + * a misinterpretation of formally valid zero value in register + * bitfield, which indicates another clock gate. Instead of + * adding complexity to a gate clock ensure that zero value in + * divider clock is never met in runtime. + */ + lpc32xx_clk_div_quirk(LPC32XX_CLKPWR_PWMCLK_CTRL, 0xf0, BIT(0)); + lpc32xx_clk_div_quirk(LPC32XX_CLKPWR_PWMCLK_CTRL, 0xf00, BIT(2)); + lpc32xx_clk_div_quirk(LPC32XX_CLKPWR_MS_CTRL, 0xf, BIT(5) | BIT(9)); + for (i = 1; i < LPC32XX_CLK_MAX; i++) { clk[i] = lpc32xx_clk_register(i); if (IS_ERR(clk[i])) { diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c index 29cee9e8d4d9..74f64c3c4290 100644 --- a/drivers/clk/pxa/clk-pxa.c +++ b/drivers/clk/pxa/clk-pxa.c @@ -18,7 +18,27 @@ #include <dt-bindings/clock/pxa-clock.h> #include "clk-pxa.h" -DEFINE_SPINLOCK(lock); +#define KHz 1000 +#define MHz (1000 * 1000) + +#define MDREFR_K0DB4 (1 << 29) /* SDCLK0 Divide by 4 Control/Status */ +#define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */ +#define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */ +#define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */ +#define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */ +#define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */ +#define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */ +#define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */ +#define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */ +#define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */ +#define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */ +#define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */ +#define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */ +#define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */ +#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) +#define MDREFR_DRI_MASK 0xFFF + +static DEFINE_SPINLOCK(pxa_clk_lock); static struct clk *pxa_clocks[CLK_MAX]; static struct clk_onecell_data onecell_data = { @@ -89,7 +109,7 @@ int __init clk_pxa_cken_init(const struct desc_clk_cken *clks, int nb_clks) pxa_clk->lp = clks[i].lp; pxa_clk->hp = clks[i].hp; pxa_clk->gate = clks[i].gate; - pxa_clk->gate.lock = &lock; + pxa_clk->gate.lock = &pxa_clk_lock; clk = clk_register_composite(NULL, clks[i].name, clks[i].parent_names, 2, &pxa_clk->hw, &cken_mux_ops, @@ -106,3 +126,124 @@ void __init clk_pxa_dt_common_init(struct device_node *np) { of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); } + +void pxa2xx_core_turbo_switch(bool on) +{ + unsigned long flags; + unsigned int unused, clkcfg; + + local_irq_save(flags); + + asm("mrc p14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); + clkcfg &= ~CLKCFG_TURBO & ~CLKCFG_HALFTURBO; + if (on) + clkcfg |= CLKCFG_TURBO; + clkcfg |= CLKCFG_FCS; + + asm volatile( + " b 2f\n" + " .align 5\n" + "1: mcr p14, 0, %1, c6, c0, 0\n" + " b 3f\n" + "2: b 1b\n" + "3: nop\n" + : "=&r" (unused) + : "r" (clkcfg) + : ); + + local_irq_restore(flags); +} + +void pxa2xx_cpll_change(struct pxa2xx_freq *freq, + u32 (*mdrefr_dri)(unsigned int), void __iomem *mdrefr, + void __iomem *cccr) +{ + unsigned int clkcfg = freq->clkcfg; + unsigned int unused, preset_mdrefr, postset_mdrefr; + unsigned long flags; + + local_irq_save(flags); + + /* Calculate the next MDREFR. If we're slowing down the SDRAM clock + * we need to preset the smaller DRI before the change. If we're + * speeding up we need to set the larger DRI value after the change. + */ + preset_mdrefr = postset_mdrefr = readl(mdrefr); + if ((preset_mdrefr & MDREFR_DRI_MASK) > mdrefr_dri(freq->membus_khz)) { + preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK); + preset_mdrefr |= mdrefr_dri(freq->membus_khz); + } + postset_mdrefr = + (postset_mdrefr & ~MDREFR_DRI_MASK) | + mdrefr_dri(freq->membus_khz); + + /* If we're dividing the memory clock by two for the SDRAM clock, this + * must be set prior to the change. Clearing the divide must be done + * after the change. + */ + if (freq->div2) { + preset_mdrefr |= MDREFR_DB2_MASK; + postset_mdrefr |= MDREFR_DB2_MASK; + } else { + postset_mdrefr &= ~MDREFR_DB2_MASK; + } + + /* Set new the CCCR and prepare CLKCFG */ + writel(freq->cccr, cccr); + + asm volatile( + " ldr r4, [%1]\n" + " b 2f\n" + " .align 5\n" + "1: str %3, [%1] /* preset the MDREFR */\n" + " mcr p14, 0, %2, c6, c0, 0 /* set CLKCFG[FCS] */\n" + " str %4, [%1] /* postset the MDREFR */\n" + " b 3f\n" + "2: b 1b\n" + "3: nop\n" + : "=&r" (unused) + : "r" (mdrefr), "r" (clkcfg), "r" (preset_mdrefr), + "r" (postset_mdrefr) + : "r4", "r5"); + + local_irq_restore(flags); +} + +int pxa2xx_determine_rate(struct clk_rate_request *req, + struct pxa2xx_freq *freqs, int nb_freqs) +{ + int i, closest_below = -1, closest_above = -1; + unsigned long rate; + + for (i = 0; i < nb_freqs; i++) { + rate = freqs[i].cpll; + if (rate == req->rate) + break; + if (rate < req->min_rate) + continue; + if (rate > req->max_rate) + continue; + if (rate <= req->rate) + closest_below = i; + if ((rate >= req->rate) && (closest_above == -1)) + closest_above = i; + } + + req->best_parent_hw = NULL; + + if (i < nb_freqs) { + rate = req->rate; + } else if (closest_below >= 0) { + rate = freqs[closest_below].cpll; + } else if (closest_above >= 0) { + rate = freqs[closest_above].cpll; + } else { + pr_debug("%s(rate=%lu) no match\n", __func__, req->rate); + return -EINVAL; + } + + pr_debug("%s(rate=%lu) rate=%lu\n", __func__, req->rate, rate); + req->rate = rate; + + return 0; +} diff --git a/drivers/clk/pxa/clk-pxa.h b/drivers/clk/pxa/clk-pxa.h index d1de805df867..2b90c5917b32 100644 --- a/drivers/clk/pxa/clk-pxa.h +++ b/drivers/clk/pxa/clk-pxa.h @@ -13,6 +13,11 @@ #ifndef _CLK_PXA_ #define _CLK_PXA_ +#define CLKCFG_TURBO 0x1 +#define CLKCFG_FCS 0x2 +#define CLKCFG_HALFTURBO 0x4 +#define CLKCFG_FASTBUS 0x8 + #define PARENTS(name) \ static const char *const name ## _parents[] __initconst #define MUX_RO_RATE_RO_OPS(name, clk_name) \ @@ -35,10 +40,27 @@ NULL, NULL, CLK_GET_RATE_NOCACHE); \ } -#define RATE_RO_OPS(name, clk_name) \ +#define RATE_RO_OPS(name, clk_name) \ + static struct clk_hw name ## _rate_hw; \ + static const struct clk_ops name ## _rate_ops = { \ + .recalc_rate = name ## _get_rate, \ + }; \ + static struct clk * __init clk_register_ ## name(void) \ + { \ + return clk_register_composite(NULL, clk_name, \ + name ## _parents, \ + ARRAY_SIZE(name ## _parents), \ + NULL, NULL, \ + &name ## _rate_hw, &name ## _rate_ops, \ + NULL, NULL, CLK_GET_RATE_NOCACHE); \ + } + +#define RATE_OPS(name, clk_name) \ static struct clk_hw name ## _rate_hw; \ static struct clk_ops name ## _rate_ops = { \ .recalc_rate = name ## _get_rate, \ + .set_rate = name ## _set_rate, \ + .determine_rate = name ## _determine_rate, \ }; \ static struct clk * __init clk_register_ ## name(void) \ { \ @@ -50,6 +72,24 @@ NULL, NULL, CLK_GET_RATE_NOCACHE); \ } +#define MUX_OPS(name, clk_name, flags) \ + static struct clk_hw name ## _mux_hw; \ + static const struct clk_ops name ## _mux_ops = { \ + .get_parent = name ## _get_parent, \ + .set_parent = name ## _set_parent, \ + .determine_rate = name ## _determine_rate, \ + }; \ + static struct clk * __init clk_register_ ## name(void) \ + { \ + return clk_register_composite(NULL, clk_name, \ + name ## _parents, \ + ARRAY_SIZE(name ## _parents), \ + &name ## _mux_hw, &name ## _mux_ops, \ + NULL, NULL, \ + NULL, NULL, \ + CLK_GET_RATE_NOCACHE | flags); \ + } + /* * CKEN clock type * This clock takes it source from 2 possible parents : @@ -95,7 +135,15 @@ struct desc_clk_cken { PXA_CKEN(dev_id, con_id, name, parents, 1, 1, 1, 1, \ NULL, cken_reg, cken_bit, flag) -static int dummy_clk_set_parent(struct clk_hw *hw, u8 index) +struct pxa2xx_freq { + unsigned long cpll; + unsigned int membus_khz; + unsigned int cccr; + unsigned int div2; + unsigned int clkcfg; +}; + +static inline int dummy_clk_set_parent(struct clk_hw *hw, u8 index) { return 0; } @@ -105,4 +153,11 @@ extern void clkdev_pxa_register(int ckid, const char *con_id, 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); +void pxa2xx_core_turbo_switch(bool on); +void pxa2xx_cpll_change(struct pxa2xx_freq *freq, + u32 (*mdrefr_dri)(unsigned int), void __iomem *mdrefr, + void __iomem *cccr); +int pxa2xx_determine_rate(struct clk_rate_request *req, + struct pxa2xx_freq *freqs, int nb_freqs); + #endif diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c index a98b98e2a9e4..c53993b6bf87 100644 --- a/drivers/clk/pxa/clk-pxa25x.c +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -18,6 +18,7 @@ #include <linux/io.h> #include <linux/of.h> #include <mach/pxa2xx-regs.h> +#include <mach/smemc.h> #include <dt-bindings/clock/pxa-clock.h> #include "clk-pxa.h" @@ -30,6 +31,17 @@ enum { PXA_CORE_TURBO, }; +#define PXA25x_CLKCFG(T) \ + (CLKCFG_FCS | \ + ((T) ? CLKCFG_TURBO : 0)) +#define PXA25x_CCCR(N2, M, L) (N2 << 7 | M << 5 | L) + +#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3) +#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3) + +/* Define the refresh period in mSec for the SDRAM and the number of rows */ +#define SDRAM_TREF 64 /* standard 64ms SDRAM */ + /* * Various clock factors driven by the CCCR register. */ @@ -48,6 +60,34 @@ static const char * const get_freq_khz[] = { "core", "run", "cpll", "memory" }; +static int get_sdram_rows(void) +{ + static int sdram_rows; + unsigned int drac2 = 0, drac0 = 0; + u32 mdcnfg; + + if (sdram_rows) + return sdram_rows; + + mdcnfg = readl_relaxed(MDCNFG); + + if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3)) + drac2 = MDCNFG_DRAC2(mdcnfg); + + if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1)) + drac0 = MDCNFG_DRAC0(mdcnfg); + + sdram_rows = 1 << (11 + max(drac0, drac2)); + return sdram_rows; +} + +static u32 mdrefr_dri(unsigned int freq_khz) +{ + u32 interval = freq_khz * SDRAM_TREF / get_sdram_rows(); + + return interval / 32; +} + /* * Get the clock frequency as reflected by CCCR and the turbo flag. * We assume these values have been applied via a fcs. @@ -139,6 +179,21 @@ static struct desc_clk_cken pxa25x_clocks[] __initdata = { clk_pxa25x_memory_parents, 0), }; +/* + * In this table, PXA25x_CCCR(N2, M, L) has the following meaning, where : + * - freq_cpll = n * m * L * 3.6864 MHz + * - n = N2 / 2 + * - m = 2^(M - 1), where 1 <= M <= 3 + * - l = L_clk_mult[L], ie. { 0, 27, 32, 36, 40, 45, 0, }[L] + */ +static struct pxa2xx_freq pxa25x_freqs[] = { + /* CPU MEMBUS CCCR DIV2 CCLKCFG */ + { 99532800, 99500, PXA25x_CCCR(2, 1, 1), 1, PXA25x_CLKCFG(1)}, + {199065600, 99500, PXA25x_CCCR(4, 1, 1), 0, PXA25x_CLKCFG(1)}, + {298598400, 99500, PXA25x_CCCR(3, 2, 1), 0, PXA25x_CLKCFG(1)}, + {398131200, 99500, PXA25x_CCCR(4, 2, 1), 0, PXA25x_CLKCFG(1)}, +}; + static u8 clk_pxa25x_core_get_parent(struct clk_hw *hw) { unsigned long clkcfg; @@ -151,13 +206,24 @@ static u8 clk_pxa25x_core_get_parent(struct clk_hw *hw) return PXA_CORE_RUN; } -static unsigned long clk_pxa25x_core_get_rate(struct clk_hw *hw, - unsigned long parent_rate) +static int clk_pxa25x_core_set_parent(struct clk_hw *hw, u8 index) { - return parent_rate; + if (index > PXA_CORE_TURBO) + return -EINVAL; + + pxa2xx_core_turbo_switch(index == PXA_CORE_TURBO); + + return 0; +} + +static int clk_pxa25x_core_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return __clk_mux_determine_rate(hw, req); } + PARENTS(clk_pxa25x_core) = { "run", "cpll" }; -MUX_RO_RATE_RO_OPS(clk_pxa25x_core, "core"); +MUX_OPS(clk_pxa25x_core, "core", CLK_SET_RATE_PARENT); static unsigned long clk_pxa25x_run_get_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -182,17 +248,42 @@ static unsigned long clk_pxa25x_cpll_get_rate(struct clk_hw *hw, 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; + return m * l * n2 * parent_rate / 2; +} + +static int clk_pxa25x_cpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return pxa2xx_determine_rate(req, pxa25x_freqs, + ARRAY_SIZE(pxa25x_freqs)); +} + +static int clk_pxa25x_cpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + + pr_debug("%s(rate=%lu parent_rate=%lu)\n", __func__, rate, parent_rate); + for (i = 0; i < ARRAY_SIZE(pxa25x_freqs); i++) + if (pxa25x_freqs[i].cpll == rate) + break; + + if (i >= ARRAY_SIZE(pxa25x_freqs)) + return -EINVAL; + + pxa2xx_cpll_change(&pxa25x_freqs[i], mdrefr_dri, MDREFR, CCCR); + + return 0; } PARENTS(clk_pxa25x_cpll) = { "osc_3_6864mhz" }; -RATE_RO_OPS(clk_pxa25x_cpll, "cpll"); +RATE_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_NONE, "cpll", NULL, + clk_register_clk_pxa25x_cpll()); + clkdev_pxa_register(CLK_NONE, "run", NULL, + clk_register_clk_pxa25x_run()); clkdev_pxa_register(CLK_CORE, "core", NULL, clk_register_clk_pxa25x_core()); } @@ -214,7 +305,8 @@ static void __init pxa25x_base_clocks_init(void) { pxa25x_register_plls(); pxa25x_register_core(); - clk_register_clk_pxa25x_memory(); + clkdev_pxa_register(CLK_NONE, "system_bus", NULL, + clk_register_clk_pxa25x_memory()); } #define DUMMY_CLK(_con_id, _dev_id, _parent) \ diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index c40b1804f58c..25a30194d27a 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -17,6 +17,8 @@ #include <linux/clkdev.h> #include <linux/of.h> +#include <mach/smemc.h> + #include <dt-bindings/clock/pxa-clock.h> #include "clk-pxa.h" @@ -45,11 +47,52 @@ enum { PXA_MEM_RUN, }; +#define PXA27x_CLKCFG(B, HT, T) \ + (CLKCFG_FCS | \ + ((B) ? CLKCFG_FASTBUS : 0) | \ + ((HT) ? CLKCFG_HALFTURBO : 0) | \ + ((T) ? CLKCFG_TURBO : 0)) +#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L) + +#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3) +#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3) + +/* Define the refresh period in mSec for the SDRAM and the number of rows */ +#define SDRAM_TREF 64 /* standard 64ms SDRAM */ + static const char * const get_freq_khz[] = { "core", "run", "cpll", "memory", "system_bus" }; +static int get_sdram_rows(void) +{ + static int sdram_rows; + unsigned int drac2 = 0, drac0 = 0; + u32 mdcnfg; + + if (sdram_rows) + return sdram_rows; + + mdcnfg = readl_relaxed(MDCNFG); + + if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3)) + drac2 = MDCNFG_DRAC2(mdcnfg); + + if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1)) + drac0 = MDCNFG_DRAC0(mdcnfg); + + sdram_rows = 1 << (11 + max(drac0, drac2)); + return sdram_rows; +} + +static u32 mdrefr_dri(unsigned int freq_khz) +{ + u32 interval = freq_khz * SDRAM_TREF / get_sdram_rows(); + + return (interval - 31) / 32; +} + /* * Get the clock frequency as reflected by CCSR and the turbo flag. * We assume these values have been applied via a fcs. @@ -145,6 +188,42 @@ static struct desc_clk_cken pxa27x_clocks[] __initdata = { }; +/* + * PXA270 definitions + * + * For the PXA27x: + * Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG. + * + * A = 0 => memory controller clock from table 3-7, + * A = 1 => memory controller clock = system bus clock + * Run mode frequency = 13 MHz * L + * Turbo mode frequency = 13 MHz * L * N + * System bus frequency = 13 MHz * L / (B + 1) + * + * In CCCR: + * A = 1 + * L = 16 oscillator to run mode ratio + * 2N = 6 2 * (turbo mode to run mode ratio) + * + * In CCLKCFG: + * B = 1 Fast bus mode + * HT = 0 Half-Turbo mode + * T = 1 Turbo mode + * + * For now, just support some of the combinations in table 3-7 of + * PXA27x Processor Family Developer's Manual to simplify frequency + * change sequences. + */ +static struct pxa2xx_freq pxa27x_freqs[] = { + {104000000, 104000, PXA27x_CCCR(1, 8, 2), 0, PXA27x_CLKCFG(1, 0, 1) }, + {156000000, 104000, PXA27x_CCCR(1, 8, 3), 0, PXA27x_CLKCFG(1, 0, 1) }, + {208000000, 208000, PXA27x_CCCR(0, 16, 2), 1, PXA27x_CLKCFG(0, 0, 1) }, + {312000000, 208000, PXA27x_CCCR(1, 16, 3), 1, PXA27x_CLKCFG(1, 0, 1) }, + {416000000, 208000, PXA27x_CCCR(1, 16, 4), 1, PXA27x_CLKCFG(1, 0, 1) }, + {520000000, 208000, PXA27x_CCCR(1, 16, 5), 1, PXA27x_CLKCFG(1, 0, 1) }, + {624000000, 208000, PXA27x_CCCR(1, 16, 6), 1, PXA27x_CLKCFG(1, 0, 1) }, +}; + static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -162,10 +241,35 @@ static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, L = l * parent_rate; N = (L * n2) / 2; - return t ? N : L; + return N; +} + +static int clk_pxa27x_cpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return pxa2xx_determine_rate(req, pxa27x_freqs, + ARRAY_SIZE(pxa27x_freqs)); +} + +static int clk_pxa27x_cpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int i; + + pr_debug("%s(rate=%lu parent_rate=%lu)\n", __func__, rate, parent_rate); + for (i = 0; i < ARRAY_SIZE(pxa27x_freqs); i++) + if (pxa27x_freqs[i].cpll == rate) + break; + + if (i >= ARRAY_SIZE(pxa27x_freqs)) + return -EINVAL; + + pxa2xx_cpll_change(&pxa27x_freqs[i], mdrefr_dri, MDREFR, CCCR); + return 0; } + PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; -RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); +RATE_OPS(clk_pxa27x_cpll, "cpll"); static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -217,31 +321,10 @@ static void __init pxa27x_register_plls(void) clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); } -static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - unsigned long clkcfg; - unsigned int t, ht, b, osc_forced; - unsigned long ccsr = readl(CCSR); - - osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); - asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); - t = clkcfg & (1 << 0); - ht = clkcfg & (1 << 2); - b = clkcfg & (1 << 3); - - if (osc_forced) - return parent_rate; - if (ht) - return parent_rate / 2; - else - return parent_rate; -} - static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) { unsigned long clkcfg; - unsigned int t, ht, b, osc_forced; + unsigned int t, ht, osc_forced; unsigned long ccsr = readl(CCSR); osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); @@ -251,14 +334,30 @@ static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); t = clkcfg & (1 << 0); ht = clkcfg & (1 << 2); - b = clkcfg & (1 << 3); if (ht || t) return PXA_CORE_TURBO; return PXA_CORE_RUN; } + +static int clk_pxa27x_core_set_parent(struct clk_hw *hw, u8 index) +{ + if (index > PXA_CORE_TURBO) + return -EINVAL; + + pxa2xx_core_turbo_switch(index == PXA_CORE_TURBO); + + return 0; +} + +static int clk_pxa27x_core_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return __clk_mux_determine_rate(hw, req); +} + PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; -MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); +MUX_OPS(clk_pxa27x_core, "core", CLK_SET_RATE_PARENT); static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, unsigned long parent_rate) @@ -273,9 +372,10 @@ RATE_RO_OPS(clk_pxa27x_run, "run"); static void __init pxa27x_register_core(void) { - clk_register_clk_pxa27x_cpll(); - clk_register_clk_pxa27x_run(); - + clkdev_pxa_register(CLK_NONE, "cpll", NULL, + clk_register_clk_pxa27x_cpll()); + clkdev_pxa_register(CLK_NONE, "run", NULL, + clk_register_clk_pxa27x_run()); clkdev_pxa_register(CLK_CORE, "core", NULL, clk_register_clk_pxa27x_core()); } @@ -294,9 +394,9 @@ static unsigned long clk_pxa27x_system_bus_get_rate(struct clk_hw *hw, if (osc_forced) return parent_rate; if (b) - return parent_rate / 2; - else return parent_rate; + else + return parent_rate / 2; } static u8 clk_pxa27x_system_bus_get_parent(struct clk_hw *hw) @@ -385,8 +485,10 @@ static void __init pxa27x_base_clocks_init(void) { pxa27x_register_plls(); pxa27x_register_core(); - clk_register_clk_pxa27x_system_bus(); - clk_register_clk_pxa27x_memory(); + clkdev_pxa_register(CLK_NONE, "system_bus", NULL, + clk_register_clk_pxa27x_system_bus()); + clkdev_pxa_register(CLK_NONE, "memory", NULL, + clk_register_clk_pxa27x_memory()); clk_register_clk_pxa27x_lcd_base(); } diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 0146d3c2547f..5fb8d7430908 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -2,6 +2,9 @@ config QCOM_GDSC bool select PM_GENERIC_DOMAINS if PM +config QCOM_RPMCC + bool + config COMMON_CLK_QCOM tristate "Support for Qualcomm's clock controllers" depends on OF @@ -9,6 +12,32 @@ config COMMON_CLK_QCOM select REGMAP_MMIO select RESET_CONTROLLER +config QCOM_CLK_RPM + tristate "RPM based Clock Controller" + depends on COMMON_CLK_QCOM && MFD_QCOM_RPM + select QCOM_RPMCC + help + The RPM (Resource Power Manager) is a dedicated hardware engine for + managing the shared SoC resources in order to keep the lowest power + profile. It communicates with other hardware subsystems via shared + memory and accepts clock requests, aggregates the requests and turns + the clocks on/off or scales them on demand. + Say Y if you want to support the clocks exposed by the RPM on + platforms such as apq8064, msm8660, msm8960 etc. + +config QCOM_CLK_SMD_RPM + tristate "RPM over SMD based Clock Controller" + depends on COMMON_CLK_QCOM && QCOM_SMD_RPM + select QCOM_RPMCC + help + The RPM (Resource Power Manager) is a dedicated hardware engine for + managing the shared SoC resources in order to keep the lowest power + profile. It communicates with other hardware subsystems via shared + memory and accepts clock requests, aggregates the requests and turns + the clocks on/off or scales them on demand. + Say Y if you want to support the clocks exposed by the RPM on + platforms such as apq8016, apq8084, msm8974 etc. + config APQ_GCC_8084 tristate "APQ8084 Global Clock Controller" select QCOM_GDSC @@ -132,6 +161,14 @@ config MSM_MMCC_8974 Say Y if you want to support multimedia devices such as display, graphics, video encode/decode, camera, etc. +config MSM_GCC_8994 + tristate "MSM8994 Global Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on msm8994 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + i2c, USB, UFS, SD/eMMC, PCIe, etc. + config MSM_GCC_8996 tristate "MSM8996 Global Clock Controller" select QCOM_GDSC diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 1fb1f5476cb0..1c3e222b917b 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -24,8 +24,11 @@ obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o +obj-$(CONFIG_MSM_GCC_8994) += gcc-msm8994.o obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o +obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o +obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index e6a03eaf7a93..47a1da3739ce 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -18,17 +18,21 @@ #include <linux/delay.h> #include "clk-alpha-pll.h" +#include "common.h" #define PLL_MODE 0x00 # define PLL_OUTCTRL BIT(0) # define PLL_BYPASSNL BIT(1) # define PLL_RESET_N BIT(2) +# define PLL_OFFLINE_REQ BIT(7) # define PLL_LOCK_COUNT_SHIFT 8 # define PLL_LOCK_COUNT_MASK 0x3f # define PLL_BIAS_COUNT_SHIFT 14 # define PLL_BIAS_COUNT_MASK 0x3f # define PLL_VOTE_FSM_ENA BIT(20) +# define PLL_FSM_ENA BIT(20) # define PLL_VOTE_FSM_RESET BIT(21) +# define PLL_OFFLINE_ACK BIT(28) # define PLL_ACTIVE_FLAG BIT(30) # define PLL_LOCK_DET BIT(31) @@ -46,6 +50,7 @@ #define PLL_USER_CTL_U 0x14 #define PLL_CONFIG_CTL 0x18 +#define PLL_CONFIG_CTL_U 0x20 #define PLL_TEST_CTL 0x1c #define PLL_TEST_CTL_U 0x20 #define PLL_STATUS 0x24 @@ -55,6 +60,7 @@ */ #define ALPHA_REG_BITWIDTH 40 #define ALPHA_BITWIDTH 32 +#define ALPHA_16BIT_MASK 0xffff #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr) @@ -62,9 +68,10 @@ #define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll_postdiv, clkr) -static int wait_for_pll(struct clk_alpha_pll *pll) +static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, + const char *action) { - u32 val, mask, off; + u32 val, off; int count; int ret; const char *name = clk_hw_get_name(&pll->clkr.hw); @@ -74,26 +81,148 @@ static int wait_for_pll(struct clk_alpha_pll *pll) if (ret) return ret; - if (val & PLL_VOTE_FSM_ENA) - mask = PLL_ACTIVE_FLAG; - else - mask = PLL_LOCK_DET; - - /* Wait for pll to enable. */ for (count = 100; count > 0; count--) { ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); if (ret) return ret; - if ((val & mask) == mask) + if (inverse && !(val & mask)) + return 0; + else if ((val & mask) == mask) return 0; udelay(1); } - WARN(1, "%s didn't enable after voting for it!\n", name); + WARN(1, "%s failed to %s!\n", name, action); return -ETIMEDOUT; } +#define wait_for_pll_enable_active(pll) \ + wait_for_pll(pll, PLL_ACTIVE_FLAG, 0, "enable") + +#define wait_for_pll_enable_lock(pll) \ + wait_for_pll(pll, PLL_LOCK_DET, 0, "enable") + +#define wait_for_pll_disable(pll) \ + wait_for_pll(pll, PLL_ACTIVE_FLAG, 1, "disable") + +#define wait_for_pll_offline(pll) \ + wait_for_pll(pll, PLL_OFFLINE_ACK, 0, "offline") + +void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + u32 val, mask; + u32 off = pll->offset; + + regmap_write(regmap, off + PLL_L_VAL, config->l); + regmap_write(regmap, off + PLL_ALPHA_VAL, config->alpha); + regmap_write(regmap, off + PLL_CONFIG_CTL, config->config_ctl_val); + regmap_write(regmap, off + PLL_CONFIG_CTL_U, config->config_ctl_hi_val); + + val = config->main_output_mask; + val |= config->aux_output_mask; + val |= config->aux2_output_mask; + val |= config->early_output_mask; + val |= config->pre_div_val; + val |= config->post_div_val; + val |= config->vco_val; + + mask = config->main_output_mask; + mask |= config->aux_output_mask; + mask |= config->aux2_output_mask; + mask |= config->early_output_mask; + mask |= config->pre_div_mask; + mask |= config->post_div_mask; + mask |= config->vco_mask; + + regmap_update_bits(regmap, off + PLL_USER_CTL, mask, val); + + if (pll->flags & SUPPORTS_FSM_MODE) + qcom_pll_set_fsm_mode(regmap, off + PLL_MODE, 6, 0); +} + +static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw) +{ + int ret; + u32 val, off; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + + off = pll->offset; + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return ret; + + val |= PLL_FSM_ENA; + + if (pll->flags & SUPPORTS_OFFLINE_REQ) + val &= ~PLL_OFFLINE_REQ; + + ret = regmap_write(pll->clkr.regmap, off + PLL_MODE, val); + if (ret) + return ret; + + /* Make sure enable request goes through before waiting for update */ + mb(); + + return wait_for_pll_enable_active(pll); +} + +static void clk_alpha_pll_hwfsm_disable(struct clk_hw *hw) +{ + int ret; + u32 val, off; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + + off = pll->offset; + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return; + + if (pll->flags & SUPPORTS_OFFLINE_REQ) { + ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + PLL_OFFLINE_REQ, PLL_OFFLINE_REQ); + if (ret) + return; + + ret = wait_for_pll_offline(pll); + if (ret) + return; + } + + /* Disable hwfsm */ + ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, + PLL_FSM_ENA, 0); + if (ret) + return; + + wait_for_pll_disable(pll); +} + +static int pll_is_enabled(struct clk_hw *hw, u32 mask) +{ + int ret; + u32 val, off; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + + off = pll->offset; + ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val); + if (ret) + return ret; + + return !!(val & mask); +} + +static int clk_alpha_pll_hwfsm_is_enabled(struct clk_hw *hw) +{ + return pll_is_enabled(hw, PLL_ACTIVE_FLAG); +} + +static int clk_alpha_pll_is_enabled(struct clk_hw *hw) +{ + return pll_is_enabled(hw, PLL_LOCK_DET); +} + static int clk_alpha_pll_enable(struct clk_hw *hw) { int ret; @@ -112,7 +241,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) ret = clk_enable_regmap(hw); if (ret) return ret; - return wait_for_pll(pll); + return wait_for_pll_enable_active(pll); } /* Skip if already enabled */ @@ -136,7 +265,7 @@ static int clk_alpha_pll_enable(struct clk_hw *hw) if (ret) return ret; - ret = wait_for_pll(pll); + ret = wait_for_pll_enable_lock(pll); if (ret) return ret; @@ -234,9 +363,14 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl); if (ctl & PLL_ALPHA_EN) { regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low); - regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, &high); - a = (u64)high << 32 | low; - a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; + if (pll->flags & SUPPORTS_16BIT_ALPHA) { + a = low & ALPHA_16BIT_MASK; + } else { + regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, + &high); + a = (u64)high << 32 | low; + a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; + } } return alpha_pll_calc_rate(prate, l, a); @@ -257,11 +391,15 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; } - a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); - regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l); - regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, a); - regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32); + + if (pll->flags & SUPPORTS_16BIT_ALPHA) { + regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, + a & ALPHA_16BIT_MASK); + } else { + a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32); + } regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_VCO_MASK << PLL_VCO_SHIFT, @@ -294,12 +432,23 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, const struct clk_ops clk_alpha_pll_ops = { .enable = clk_alpha_pll_enable, .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, .recalc_rate = clk_alpha_pll_recalc_rate, .round_rate = clk_alpha_pll_round_rate, .set_rate = clk_alpha_pll_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_ops); +const struct clk_ops clk_alpha_pll_hwfsm_ops = { + .enable = clk_alpha_pll_hwfsm_enable, + .disable = clk_alpha_pll_hwfsm_disable, + .is_enabled = clk_alpha_pll_hwfsm_is_enabled, + .recalc_rate = clk_alpha_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = clk_alpha_pll_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops); + static unsigned long clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 90ce2016e1a0..d6e1ee2c7348 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -34,6 +34,10 @@ struct clk_alpha_pll { const struct pll_vco *vco_table; size_t num_vco; +#define SUPPORTS_OFFLINE_REQ BIT(0) +#define SUPPORTS_16BIT_ALPHA BIT(1) +#define SUPPORTS_FSM_MODE BIT(2) + u8 flags; struct clk_regmap clkr; }; @@ -51,7 +55,28 @@ struct clk_alpha_pll_postdiv { struct clk_regmap clkr; }; +struct alpha_pll_config { + u32 l; + u32 alpha; + u32 config_ctl_val; + u32 config_ctl_hi_val; + u32 main_output_mask; + u32 aux_output_mask; + u32 aux2_output_mask; + u32 early_output_mask; + u32 pre_div_val; + u32 pre_div_mask; + u32 post_div_val; + u32 post_div_mask; + u32 vco_val; + u32 vco_mask; +}; + extern const struct clk_ops clk_alpha_pll_ops; +extern const struct clk_ops clk_alpha_pll_hwfsm_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ops; +void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); + #endif diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 5b940d629045..cb6cb8710daf 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -23,16 +23,11 @@ #include <asm/div64.h> #include "clk-pll.h" +#include "common.h" #define PLL_OUTCTRL BIT(0) #define PLL_BYPASSNL BIT(1) #define PLL_RESET_N BIT(2) -#define PLL_LOCK_COUNT_SHIFT 8 -#define PLL_LOCK_COUNT_MASK 0x3f -#define PLL_BIAS_COUNT_SHIFT 14 -#define PLL_BIAS_COUNT_MASK 0x3f -#define PLL_VOTE_FSM_ENA BIT(20) -#define PLL_VOTE_FSM_RESET BIT(21) static int clk_pll_enable(struct clk_hw *hw) { @@ -228,26 +223,6 @@ const struct clk_ops clk_pll_vote_ops = { }; EXPORT_SYMBOL_GPL(clk_pll_vote_ops); -static void -clk_pll_set_fsm_mode(struct clk_pll *pll, struct regmap *regmap, u8 lock_count) -{ - u32 val; - u32 mask; - - /* De-assert reset to FSM */ - regmap_update_bits(regmap, pll->mode_reg, PLL_VOTE_FSM_RESET, 0); - - /* Program bias count and lock count */ - val = 1 << PLL_BIAS_COUNT_SHIFT | lock_count << PLL_LOCK_COUNT_SHIFT; - mask = PLL_BIAS_COUNT_MASK << PLL_BIAS_COUNT_SHIFT; - mask |= PLL_LOCK_COUNT_MASK << PLL_LOCK_COUNT_SHIFT; - regmap_update_bits(regmap, pll->mode_reg, mask, val); - - /* Enable PLL FSM voting */ - regmap_update_bits(regmap, pll->mode_reg, PLL_VOTE_FSM_ENA, - PLL_VOTE_FSM_ENA); -} - static void clk_pll_configure(struct clk_pll *pll, struct regmap *regmap, const struct pll_config *config) { @@ -280,7 +255,7 @@ void clk_pll_configure_sr(struct clk_pll *pll, struct regmap *regmap, { clk_pll_configure(pll, regmap, config); if (fsm_mode) - clk_pll_set_fsm_mode(pll, regmap, 8); + qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 8); } EXPORT_SYMBOL_GPL(clk_pll_configure_sr); @@ -289,7 +264,7 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap, { clk_pll_configure(pll, regmap, config); if (fsm_mode) - clk_pll_set_fsm_mode(pll, regmap, 0); + qcom_pll_set_fsm_mode(regmap, pll->mode_reg, 1, 0); } EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp); diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c new file mode 100644 index 000000000000..1950a9572624 --- /dev/null +++ b/drivers/clk/qcom/clk-rpm.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2016, Linaro Limited + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/err.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/mfd/qcom_rpm.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include <dt-bindings/mfd/qcom-rpm.h> +#include <dt-bindings/clock/qcom,rpmcc.h> + +#define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 +#define QCOM_RPM_SCALING_ENABLE_ID 0x2 + +#define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_active, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_name, \ + .active_only = true, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, _active, r_id, r) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .active_only = true, \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "pxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, _active, r_id, r) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ + .rpm_clk_id = (r_id), \ + .active_only = true, \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .branch = true, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) + +struct clk_rpm { + const int rpm_clk_id; + const bool active_only; + unsigned long rate; + bool enabled; + bool branch; + struct clk_rpm *peer; + struct clk_hw hw; + struct qcom_rpm *rpm; +}; + +struct rpm_cc { + struct qcom_rpm *rpm; + struct clk_hw_onecell_data data; + struct clk_hw *hws[]; +}; + +struct rpm_clk_desc { + struct clk_rpm **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpm_clk_lock); + +static int clk_rpm_handoff(struct clk_rpm *r) +{ + int ret; + u32 value = INT_MAX; + + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); + if (ret) + return ret; + ret = qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE, + r->rpm_clk_id, &value, 1); + if (ret) + return ret; + + return 0; +} + +static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate) +{ + u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */ + + return qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); +} + +static int clk_rpm_set_rate_sleep(struct clk_rpm *r, unsigned long rate) +{ + u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */ + + return qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE, + r->rpm_clk_id, &value, 1); +} + +static void to_active_sleep(struct clk_rpm *r, unsigned long rate, + unsigned long *active, unsigned long *sleep) +{ + *active = rate; + + /* + * Active-only clocks don't care what the rate is during sleep. So, + * they vote for zero. + */ + if (r->active_only) + *sleep = 0; + else + *sleep = *active; +} + +static int clk_rpm_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret = 0; + + mutex_lock(&rpm_clk_lock); + + /* Don't send requests to the RPM if the rate has not been set. */ + if (!r->rate) + goto out; + + to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + + if (r->branch) + active_rate = !!active_rate; + + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + if (r->branch) + sleep_rate = !!sleep_rate; + + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + /* Undo the active set vote and restore it */ + ret = clk_rpm_set_rate_active(r, peer_rate); + +out: + if (!ret) + r->enabled = true; + + mutex_unlock(&rpm_clk_lock); + + return ret; +} + +static void clk_rpm_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret; + + mutex_lock(&rpm_clk_lock); + + if (!r->rate) + goto out; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, &peer_rate, + &peer_sleep_rate); + + active_rate = r->branch ? !!peer_rate : peer_rate; + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate; + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->enabled = false; + +out: + mutex_unlock(&rpm_clk_lock); +} + +static int clk_rpm_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct clk_rpm *peer = r->peer; + unsigned long active_rate, sleep_rate; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + int ret = 0; + + mutex_lock(&rpm_clk_lock); + + if (!r->enabled) + goto out; + + to_active_sleep(r, rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + ret = clk_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + ret = clk_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->rate = rate; + +out: + mutex_unlock(&rpm_clk_lock); + + return ret; +} + +static long clk_rpm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate is requested. + */ + return rate; +} + +static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_rpm *r = to_clk_rpm(hw); + + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate was set. + */ + return r->rate; +} + +static const struct clk_ops clk_rpm_ops = { + .prepare = clk_rpm_prepare, + .unprepare = clk_rpm_unprepare, + .set_rate = clk_rpm_set_rate, + .round_rate = clk_rpm_round_rate, + .recalc_rate = clk_rpm_recalc_rate, +}; + +static const struct clk_ops clk_rpm_branch_ops = { + .prepare = clk_rpm_prepare, + .unprepare = clk_rpm_unprepare, + .round_rate = clk_rpm_round_rate, + .recalc_rate = clk_rpm_recalc_rate, +}; + +/* apq8064 */ +DEFINE_CLK_RPM(apq8064, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); +DEFINE_CLK_RPM(apq8064, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); +DEFINE_CLK_RPM(apq8064, mmfab_clk, mmfab_a_clk, QCOM_RPM_MM_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); +DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); +DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); +DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); + +static struct clk_rpm *apq8064_clks[] = { + [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, + [RPM_APPS_FABRIC_A_CLK] = &apq8064_afab_a_clk, + [RPM_CFPB_CLK] = &apq8064_cfpb_clk, + [RPM_CFPB_A_CLK] = &apq8064_cfpb_a_clk, + [RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk, + [RPM_DAYTONA_FABRIC_A_CLK] = &apq8064_daytona_a_clk, + [RPM_EBI1_CLK] = &apq8064_ebi1_clk, + [RPM_EBI1_A_CLK] = &apq8064_ebi1_a_clk, + [RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk, + [RPM_MM_FABRIC_A_CLK] = &apq8064_mmfab_a_clk, + [RPM_MMFPB_CLK] = &apq8064_mmfpb_clk, + [RPM_MMFPB_A_CLK] = &apq8064_mmfpb_a_clk, + [RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk, + [RPM_SYS_FABRIC_A_CLK] = &apq8064_sfab_a_clk, + [RPM_SFPB_CLK] = &apq8064_sfpb_clk, + [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, + [RPM_QDSS_CLK] = &apq8064_qdss_clk, + [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, +}; + +static const struct rpm_clk_desc rpm_clk_apq8064 = { + .clks = apq8064_clks, + .num_clks = ARRAY_SIZE(apq8064_clks), +}; + +static const struct of_device_id rpm_clk_match_table[] = { + { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_clk_match_table); + +static int rpm_clk_probe(struct platform_device *pdev) +{ + struct clk_hw **hws; + struct rpm_cc *rcc; + struct clk_hw_onecell_data *data; + int ret; + size_t num_clks, i; + struct qcom_rpm *rpm; + struct clk_rpm **rpm_clks; + const struct rpm_clk_desc *desc; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpm_clks = desc->clks; + num_clks = desc->num_clks; + + rcc = devm_kzalloc(&pdev->dev, sizeof(*rcc) + sizeof(*hws) * num_clks, + GFP_KERNEL); + if (!rcc) + return -ENOMEM; + + hws = rcc->hws; + data = &rcc->data; + data->num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rpm_clks[i]) + continue; + + rpm_clks[i]->rpm = rpm; + + ret = clk_rpm_handoff(rpm_clks[i]); + if (ret) + goto err; + } + + for (i = 0; i < num_clks; i++) { + if (!rpm_clks[i]) { + data->hws[i] = ERR_PTR(-ENOENT); + continue; + } + + ret = devm_clk_hw_register(&pdev->dev, &rpm_clks[i]->hw); + if (ret) + goto err; + } + + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + data); + if (ret) + goto err; + + return 0; +err: + dev_err(&pdev->dev, "Error registering RPM Clock driver (%d)\n", ret); + return ret; +} + +static int rpm_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpm_clk_driver = { + .driver = { + .name = "qcom-clk-rpm", + .of_match_table = rpm_clk_match_table, + }, + .probe = rpm_clk_probe, + .remove = rpm_clk_remove, +}; + +static int __init rpm_clk_init(void) +{ + return platform_driver_register(&rpm_clk_driver); +} +core_initcall(rpm_clk_init); + +static void __exit rpm_clk_exit(void) +{ + platform_driver_unregister(&rpm_clk_driver); +} +module_exit(rpm_clk_exit); + +MODULE_DESCRIPTION("Qualcomm RPM Clock Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-clk-rpm"); diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c new file mode 100644 index 000000000000..a27013dbc0aa --- /dev/null +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2016, Linaro Limited + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/err.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/smd-rpm.h> + +#include <dt-bindings/clock/qcom,rpmcc.h> +#include <dt-bindings/mfd/qcom-rpm.h> + +#define QCOM_RPM_KEY_SOFTWARE_ENABLE 0x6e657773 +#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370 +#define QCOM_RPM_SMD_KEY_RATE 0x007a484b +#define QCOM_RPM_SMD_KEY_ENABLE 0x62616e45 +#define QCOM_RPM_SMD_KEY_STATE 0x54415453 +#define QCOM_RPM_SCALING_ENABLE_ID 0x2 + +#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id, \ + key) \ + static struct clk_smd_rpm _platform##_##_active; \ + static struct clk_smd_rpm _platform##_##_name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &_platform##_##_active, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_smd_rpm _platform##_##_active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .active_only = true, \ + .rpm_key = (key), \ + .peer = &_platform##_##_name, \ + .rate = INT_MAX, \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, \ + stat_id, r, key) \ + static struct clk_smd_rpm _platform##_##_active; \ + static struct clk_smd_rpm _platform##_##_name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .branch = true, \ + .peer = &_platform##_##_active, \ + .rate = (r), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_branch_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + }; \ + static struct clk_smd_rpm _platform##_##_active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .active_only = true, \ + .rpm_key = (key), \ + .branch = true, \ + .peer = &_platform##_##_name, \ + .rate = (r), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_smd_rpm_branch_ops, \ + .name = #_active, \ + .parent_names = (const char *[]){ "xo_board" }, \ + .num_parents = 1, \ + }, \ + } + +#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id) \ + __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \ + 0, QCOM_RPM_SMD_KEY_RATE) + +#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, \ + r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE) + +#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id) \ + __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, \ + 0, QCOM_RPM_SMD_KEY_STATE) + +#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \ + QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000, \ + QCOM_RPM_KEY_SOFTWARE_ENABLE) + +#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \ + __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, \ + QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000, \ + QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY) + +#define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw) + +struct clk_smd_rpm { + const int rpm_res_type; + const int rpm_key; + const int rpm_clk_id; + const int rpm_status_id; + const bool active_only; + bool enabled; + bool branch; + struct clk_smd_rpm *peer; + struct clk_hw hw; + unsigned long rate; + struct qcom_smd_rpm *rpm; +}; + +struct clk_smd_rpm_req { + __le32 key; + __le32 nbytes; + __le32 value; +}; + +struct rpm_cc { + struct qcom_rpm *rpm; + struct clk_hw_onecell_data data; + struct clk_hw *hws[]; +}; + +struct rpm_smd_clk_desc { + struct clk_smd_rpm **clks; + size_t num_clks; +}; + +static DEFINE_MUTEX(rpm_smd_clk_lock); + +static int clk_smd_rpm_handoff(struct clk_smd_rpm *r) +{ + int ret; + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(INT_MAX), + }; + + ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); + if (ret) + return ret; + ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); + if (ret) + return ret; + + return 0; +} + +static int clk_smd_rpm_set_rate_active(struct clk_smd_rpm *r, + unsigned long rate) +{ + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */ + }; + + return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); +} + +static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r, + unsigned long rate) +{ + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(r->rpm_key), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(DIV_ROUND_UP(rate, 1000)), /* to kHz */ + }; + + return qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE, + r->rpm_res_type, r->rpm_clk_id, &req, + sizeof(req)); +} + +static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate, + unsigned long *active, unsigned long *sleep) +{ + *active = rate; + + /* + * Active-only clocks don't care what the rate is during sleep. So, + * they vote for zero. + */ + if (r->active_only) + *sleep = 0; + else + *sleep = *active; +} + +static int clk_smd_rpm_prepare(struct clk_hw *hw) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret = 0; + + mutex_lock(&rpm_smd_clk_lock); + + /* Don't send requests to the RPM if the rate has not been set. */ + if (!r->rate) + goto out; + + to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + + if (r->branch) + active_rate = !!active_rate; + + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + if (r->branch) + sleep_rate = !!sleep_rate; + + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + /* Undo the active set vote and restore it */ + ret = clk_smd_rpm_set_rate_active(r, peer_rate); + +out: + if (!ret) + r->enabled = true; + + mutex_unlock(&rpm_smd_clk_lock); + + return ret; +} + +static void clk_smd_rpm_unprepare(struct clk_hw *hw) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + unsigned long active_rate, sleep_rate; + int ret; + + mutex_lock(&rpm_smd_clk_lock); + + if (!r->rate) + goto out; + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, &peer_rate, + &peer_sleep_rate); + + active_rate = r->branch ? !!peer_rate : peer_rate; + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate; + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->enabled = false; + +out: + mutex_unlock(&rpm_smd_clk_lock); +} + +static int clk_smd_rpm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + struct clk_smd_rpm *peer = r->peer; + unsigned long active_rate, sleep_rate; + unsigned long this_rate = 0, this_sleep_rate = 0; + unsigned long peer_rate = 0, peer_sleep_rate = 0; + int ret = 0; + + mutex_lock(&rpm_smd_clk_lock); + + if (!r->enabled) + goto out; + + to_active_sleep(r, rate, &this_rate, &this_sleep_rate); + + /* Take peer clock's rate into account only if it's enabled. */ + if (peer->enabled) + to_active_sleep(peer, peer->rate, + &peer_rate, &peer_sleep_rate); + + active_rate = max(this_rate, peer_rate); + ret = clk_smd_rpm_set_rate_active(r, active_rate); + if (ret) + goto out; + + sleep_rate = max(this_sleep_rate, peer_sleep_rate); + ret = clk_smd_rpm_set_rate_sleep(r, sleep_rate); + if (ret) + goto out; + + r->rate = rate; + +out: + mutex_unlock(&rpm_smd_clk_lock); + + return ret; +} + +static long clk_smd_rpm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate is requested. + */ + return rate; +} + +static unsigned long clk_smd_rpm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_smd_rpm *r = to_clk_smd_rpm(hw); + + /* + * RPM handles rate rounding and we don't have a way to + * know what the rate will be, so just return whatever + * rate was set. + */ + return r->rate; +} + +static int clk_smd_rpm_enable_scaling(struct qcom_smd_rpm *rpm) +{ + int ret; + struct clk_smd_rpm_req req = { + .key = cpu_to_le32(QCOM_RPM_SMD_KEY_ENABLE), + .nbytes = cpu_to_le32(sizeof(u32)), + .value = cpu_to_le32(1), + }; + + ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_SLEEP_STATE, + QCOM_SMD_RPM_MISC_CLK, + QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req)); + if (ret) { + pr_err("RPM clock scaling (sleep set) not enabled!\n"); + return ret; + } + + ret = qcom_rpm_smd_write(rpm, QCOM_SMD_RPM_ACTIVE_STATE, + QCOM_SMD_RPM_MISC_CLK, + QCOM_RPM_SCALING_ENABLE_ID, &req, sizeof(req)); + if (ret) { + pr_err("RPM clock scaling (active set) not enabled!\n"); + return ret; + } + + pr_debug("%s: RPM clock scaling is enabled\n", __func__); + return 0; +} + +static const struct clk_ops clk_smd_rpm_ops = { + .prepare = clk_smd_rpm_prepare, + .unprepare = clk_smd_rpm_unprepare, + .set_rate = clk_smd_rpm_set_rate, + .round_rate = clk_smd_rpm_round_rate, + .recalc_rate = clk_smd_rpm_recalc_rate, +}; + +static const struct clk_ops clk_smd_rpm_branch_ops = { + .prepare = clk_smd_rpm_prepare, + .unprepare = clk_smd_rpm_unprepare, + .round_rate = clk_smd_rpm_round_rate, + .recalc_rate = clk_smd_rpm_recalc_rate, +}; + +/* msm8916 */ +DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); +DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk1, rf_clk1_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, rf_clk2, rf_clk2_a, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk1_pin, bb_clk1_a_pin, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, bb_clk2_pin, bb_clk2_a_pin, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5); + +static struct clk_smd_rpm *msm8916_clks[] = { + [RPM_SMD_PCNOC_CLK] = &msm8916_pcnoc_clk, + [RPM_SMD_PCNOC_A_CLK] = &msm8916_pcnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &msm8916_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8916_snoc_a_clk, + [RPM_SMD_BIMC_CLK] = &msm8916_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &msm8916_bimc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8916_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8916_qdss_a_clk, + [RPM_SMD_BB_CLK1] = &msm8916_bb_clk1, + [RPM_SMD_BB_CLK1_A] = &msm8916_bb_clk1_a, + [RPM_SMD_BB_CLK2] = &msm8916_bb_clk2, + [RPM_SMD_BB_CLK2_A] = &msm8916_bb_clk2_a, + [RPM_SMD_RF_CLK1] = &msm8916_rf_clk1, + [RPM_SMD_RF_CLK1_A] = &msm8916_rf_clk1_a, + [RPM_SMD_RF_CLK2] = &msm8916_rf_clk2, + [RPM_SMD_RF_CLK2_A] = &msm8916_rf_clk2_a, + [RPM_SMD_BB_CLK1_PIN] = &msm8916_bb_clk1_pin, + [RPM_SMD_BB_CLK1_A_PIN] = &msm8916_bb_clk1_a_pin, + [RPM_SMD_BB_CLK2_PIN] = &msm8916_bb_clk2_pin, + [RPM_SMD_BB_CLK2_A_PIN] = &msm8916_bb_clk2_a_pin, + [RPM_SMD_RF_CLK1_PIN] = &msm8916_rf_clk1_pin, + [RPM_SMD_RF_CLK1_A_PIN] = &msm8916_rf_clk1_a_pin, + [RPM_SMD_RF_CLK2_PIN] = &msm8916_rf_clk2_pin, + [RPM_SMD_RF_CLK2_A_PIN] = &msm8916_rf_clk2_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8916 = { + .clks = msm8916_clks, + .num_clks = ARRAY_SIZE(msm8916_clks), +}; + +static const struct of_device_id rpm_smd_clk_match_table[] = { + { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, + { } +}; +MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); + +static int rpm_smd_clk_probe(struct platform_device *pdev) +{ + struct clk_hw **hws; + struct rpm_cc *rcc; + struct clk_hw_onecell_data *data; + int ret; + size_t num_clks, i; + struct qcom_smd_rpm *rpm; + struct clk_smd_rpm **rpm_smd_clks; + const struct rpm_smd_clk_desc *desc; + + rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpm) { + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); + return -ENODEV; + } + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + rpm_smd_clks = desc->clks; + num_clks = desc->num_clks; + + rcc = devm_kzalloc(&pdev->dev, sizeof(*rcc) + sizeof(*hws) * num_clks, + GFP_KERNEL); + if (!rcc) + return -ENOMEM; + + hws = rcc->hws; + data = &rcc->data; + data->num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rpm_smd_clks[i]) + continue; + + rpm_smd_clks[i]->rpm = rpm; + + ret = clk_smd_rpm_handoff(rpm_smd_clks[i]); + if (ret) + goto err; + } + + ret = clk_smd_rpm_enable_scaling(rpm); + if (ret) + goto err; + + for (i = 0; i < num_clks; i++) { + if (!rpm_smd_clks[i]) { + data->hws[i] = ERR_PTR(-ENOENT); + continue; + } + + ret = devm_clk_hw_register(&pdev->dev, &rpm_smd_clks[i]->hw); + if (ret) + goto err; + } + + ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + data); + if (ret) + goto err; + + return 0; +err: + dev_err(&pdev->dev, "Error registering SMD clock driver (%d)\n", ret); + return ret; +} + +static int rpm_smd_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +static struct platform_driver rpm_smd_clk_driver = { + .driver = { + .name = "qcom-clk-smd-rpm", + .of_match_table = rpm_smd_clk_match_table, + }, + .probe = rpm_smd_clk_probe, + .remove = rpm_smd_clk_remove, +}; + +static int __init rpm_smd_clk_init(void) +{ + return platform_driver_register(&rpm_smd_clk_driver); +} +core_initcall(rpm_smd_clk_init); + +static void __exit rpm_smd_clk_exit(void) +{ + platform_driver_unregister(&rpm_smd_clk_driver); +} +module_exit(rpm_smd_clk_exit); + +MODULE_DESCRIPTION("Qualcomm RPM over SMD Clock Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:qcom-clk-smd-rpm"); diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index fffcbaf0fba7..94569f461ba7 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -74,6 +74,27 @@ qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) } EXPORT_SYMBOL_GPL(qcom_cc_map); +void +qcom_pll_set_fsm_mode(struct regmap *map, u32 reg, u8 bias_count, u8 lock_count) +{ + u32 val; + u32 mask; + + /* De-assert reset to FSM */ + regmap_update_bits(map, reg, PLL_VOTE_FSM_RESET, 0); + + /* Program bias count and lock count */ + val = bias_count << PLL_BIAS_COUNT_SHIFT | + lock_count << PLL_LOCK_COUNT_SHIFT; + mask = PLL_BIAS_COUNT_MASK << PLL_BIAS_COUNT_SHIFT; + mask |= PLL_LOCK_COUNT_MASK << PLL_LOCK_COUNT_SHIFT; + regmap_update_bits(map, reg, mask, val); + + /* Enable PLL FSM voting */ + regmap_update_bits(map, reg, PLL_VOTE_FSM_ENA, PLL_VOTE_FSM_ENA); +} +EXPORT_SYMBOL_GPL(qcom_pll_set_fsm_mode); + static void qcom_cc_del_clk_provider(void *data) { of_clk_del_provider(data); @@ -153,15 +174,12 @@ int qcom_cc_register_board_clk(struct device *dev, const char *path, const char *name, unsigned long rate) { bool add_factor = true; - struct device_node *node; - - /* The RPM clock driver will add the factor clock if present */ - if (IS_ENABLED(CONFIG_QCOM_RPMCC)) { - node = of_find_compatible_node(NULL, NULL, "qcom,rpmcc"); - if (of_device_is_available(node)) - add_factor = false; - of_node_put(node); - } + + /* + * TODO: The RPM clock driver currently does not support the xo clock. + * When xo is added to the RPM clock driver, we should change this + * function to skip registration of xo factor clocks. + */ return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor); } diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index ae9bdeb21f29..9fb5b8e89071 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -22,6 +22,13 @@ struct freq_tbl; struct clk_hw; struct parent_map; +#define PLL_LOCK_COUNT_SHIFT 8 +#define PLL_LOCK_COUNT_MASK 0x3f +#define PLL_BIAS_COUNT_SHIFT 14 +#define PLL_BIAS_COUNT_MASK 0x3f +#define PLL_VOTE_FSM_ENA BIT(20) +#define PLL_VOTE_FSM_RESET BIT(21) + struct qcom_cc_desc { const struct regmap_config *config; struct clk_regmap **clks; @@ -34,6 +41,8 @@ struct qcom_cc_desc { extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate); +extern void +qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count); extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map, u8 src); diff --git a/drivers/clk/qcom/gcc-ipq4019.c b/drivers/clk/qcom/gcc-ipq4019.c index b593065de8db..33d09138f5e5 100644 --- a/drivers/clk/qcom/gcc-ipq4019.c +++ b/drivers/clk/qcom/gcc-ipq4019.c @@ -185,8 +185,7 @@ static struct clk_branch gcc_audio_pwm_clk = { }; static const struct freq_tbl ftbl_gcc_blsp1_qup1_2_i2c_apps_clk[] = { - F(19200000, P_XO, 1, 2, 5), - F(24000000, P_XO, 1, 1, 2), + F(19050000, P_FEPLL200, 10.5, 1, 1), { } }; diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 52a7d3959875..28eb200d0f1e 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -2990,11 +2990,11 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) struct regmap *regmap; int ret; - ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000); + ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 25000000); if (ret) return ret; - ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000); + ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 25000000); if (ret) return ret; diff --git a/drivers/clk/qcom/gcc-msm8994.c b/drivers/clk/qcom/gcc-msm8994.c new file mode 100644 index 000000000000..84093c19caa6 --- /dev/null +++ b/drivers/clk/qcom/gcc-msm8994.c @@ -0,0 +1,2300 @@ +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/ctype.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,gcc-msm8994.h> + +#include "common.h" +#include "clk-regmap.h" +#include "clk-alpha-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +enum { + P_XO, + P_GPLL0, + P_GPLL4, +}; + +static const struct parent_map gcc_xo_gpll0_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, +}; + +static const char * const gcc_xo_gpll0[] = { + "xo", + "gpll0", +}; + +static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL4, 5 }, +}; + +static const char * const gcc_xo_gpll0_gpll4[] = { + "xo", + "gpll0", + "gpll4", +}; + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static struct clk_fixed_factor xo = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data) + { + .name = "xo", + .parent_names = (const char *[]) { "xo_board" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_alpha_pll gpll0_early = { + .offset = 0x00000, + .clkr = { + .enable_reg = 0x1480, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gpll0_early", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll0 = { + .offset = 0x00000, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "gpll0", + .parent_names = (const char *[]) { "gpll0_early" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ops, + }, +}; + +static struct clk_alpha_pll gpll4_early = { + .offset = 0x1dc0, + .clkr = { + .enable_reg = 0x1480, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data) + { + .name = "gpll4_early", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4 = { + .offset = 0x1dc0, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "gpll4", + .parent_names = (const char *[]) { "gpll4_early" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ops, + }, +}; + +static struct freq_tbl ftbl_ufs_axi_clk_src[] = { + F(50000000, P_GPLL0, 12, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(150000000, P_GPLL0, 4, 0, 0), + F(171430000, P_GPLL0, 3.5, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + F(240000000, P_GPLL0, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 ufs_axi_clk_src = { + .cmd_rcgr = 0x1d68, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_ufs_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "ufs_axi_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_usb30_master_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(125000000, P_GPLL0, 1, 5, 24), + { } +}; + +static struct clk_rcg2 usb30_master_clk_src = { + .cmd_rcgr = 0x03d4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_usb30_master_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "usb30_master_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_blsp_i2c_apps_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0, 12, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x0660, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup1_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_blspqup_spi_apps_clk_src[] = { + F(960000, P_XO, 10, 1, 2), + F(4800000, P_XO, 4, 0, 0), + F(9600000, P_XO, 2, 0, 0), + F(15000000, P_GPLL0, 10, 1, 4), + F(19200000, P_XO, 1, 0, 0), + F(24000000, P_GPLL0, 12.5, 1, 2), + F(25000000, P_GPLL0, 12, 1, 2), + F(48000000, P_GPLL0, 12.5, 0, 0), + F(50000000, P_GPLL0, 12, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x064c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup1_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x06e0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup2_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x06cc, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup2_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x0760, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup3_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x074c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup3_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x07e0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup4_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x07cc, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup4_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup5_i2c_apps_clk_src = { + .cmd_rcgr = 0x0860, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup5_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup5_spi_apps_clk_src = { + .cmd_rcgr = 0x084c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup5_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup6_i2c_apps_clk_src = { + .cmd_rcgr = 0x08e0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup6_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_qup6_spi_apps_clk_src = { + .cmd_rcgr = 0x08cc, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_qup6_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_blsp_uart_apps_clk_src[] = { + F(3686400, P_GPLL0, 1, 96, 15625), + F(7372800, P_GPLL0, 1, 192, 15625), + F(14745600, P_GPLL0, 1, 384, 15625), + F(16000000, P_GPLL0, 5, 2, 15), + F(19200000, P_XO, 1, 0, 0), + F(24000000, P_GPLL0, 5, 1, 5), + F(32000000, P_GPLL0, 1, 4, 75), + F(40000000, P_GPLL0, 15, 0, 0), + F(46400000, P_GPLL0, 1, 29, 375), + F(48000000, P_GPLL0, 12.5, 0, 0), + F(51200000, P_GPLL0, 1, 32, 375), + F(56000000, P_GPLL0, 1, 7, 75), + F(58982400, P_GPLL0, 1, 1536, 15625), + F(60000000, P_GPLL0, 10, 0, 0), + F(63160000, P_GPLL0, 9.5, 0, 0), + { } +}; + +static struct clk_rcg2 blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x068c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart1_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x070c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart2_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x078c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart3_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart4_apps_clk_src = { + .cmd_rcgr = 0x080c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart4_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart5_apps_clk_src = { + .cmd_rcgr = 0x088c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart5_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp1_uart6_apps_clk_src = { + .cmd_rcgr = 0x090c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp1_uart6_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x09a0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup1_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x098c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup1_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x0a20, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup2_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x0a0c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup2_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x0aa0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup3_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x0a8c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup3_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x0b20, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup4_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x0b0c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup4_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup5_i2c_apps_clk_src = { + .cmd_rcgr = 0x0ba0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup5_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup5_spi_apps_clk_src = { + .cmd_rcgr = 0x0b8c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup5_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup6_i2c_apps_clk_src = { + .cmd_rcgr = 0x0c20, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup6_i2c_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_qup6_spi_apps_clk_src = { + .cmd_rcgr = 0x0c0c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blspqup_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_qup6_spi_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart1_apps_clk_src = { + .cmd_rcgr = 0x09cc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart1_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart2_apps_clk_src = { + .cmd_rcgr = 0x0a4c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart2_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart3_apps_clk_src = { + .cmd_rcgr = 0x0acc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart3_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart4_apps_clk_src = { + .cmd_rcgr = 0x0b4c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart4_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart5_apps_clk_src = { + .cmd_rcgr = 0x0bcc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart5_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 blsp2_uart6_apps_clk_src = { + .cmd_rcgr = 0x0c4c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_blsp_uart_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "blsp2_uart6_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_gp1_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gp1_clk_src = { + .cmd_rcgr = 0x1904, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "gp1_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_gp2_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gp2_clk_src = { + .cmd_rcgr = 0x1944, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_gp2_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "gp2_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_gp3_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gp3_clk_src = { + .cmd_rcgr = 0x1984, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_gp3_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "gp3_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_pcie_0_aux_clk_src[] = { + F(1011000, P_XO, 1, 1, 19), + { } +}; + +static struct clk_rcg2 pcie_0_aux_clk_src = { + .cmd_rcgr = 0x1b00, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_pcie_0_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "pcie_0_aux_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_pcie_pipe_clk_src[] = { + F(125000000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 pcie_0_pipe_clk_src = { + .cmd_rcgr = 0x1adc, + .hid_width = 5, + .freq_tbl = ftbl_pcie_pipe_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "pcie_0_pipe_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_pcie_1_aux_clk_src[] = { + F(1011000, P_XO, 1, 1, 19), + { } +}; + +static struct clk_rcg2 pcie_1_aux_clk_src = { + .cmd_rcgr = 0x1b80, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_pcie_1_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "pcie_1_aux_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 pcie_1_pipe_clk_src = { + .cmd_rcgr = 0x1b5c, + .hid_width = 5, + .freq_tbl = ftbl_pcie_pipe_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "pcie_1_pipe_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_pdm2_clk_src[] = { + F(60000000, P_GPLL0, 10, 0, 0), + { } +}; + +static struct clk_rcg2 pdm2_clk_src = { + .cmd_rcgr = 0x0cd0, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_pdm2_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "pdm2_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_sdcc1_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0, 15, 1, 2), + F(25000000, P_GPLL0, 12, 1, 2), + F(50000000, P_GPLL0, 12, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(192000000, P_GPLL4, 2, 0, 0), + F(384000000, P_GPLL4, 1, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc1_apps_clk_src = { + .cmd_rcgr = 0x04d0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_gpll4_map, + .freq_tbl = ftbl_sdcc1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "sdcc1_apps_clk_src", + .parent_names = gcc_xo_gpll0_gpll4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_sdcc2_4_apps_clk_src[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0, 15, 1, 2), + F(25000000, P_GPLL0, 12, 1, 2), + F(50000000, P_GPLL0, 12, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + { } +}; + +static struct clk_rcg2 sdcc2_apps_clk_src = { + .cmd_rcgr = 0x0510, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_sdcc2_4_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "sdcc2_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 sdcc3_apps_clk_src = { + .cmd_rcgr = 0x0550, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_sdcc2_4_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "sdcc3_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 sdcc4_apps_clk_src = { + .cmd_rcgr = 0x0590, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_sdcc2_4_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "sdcc4_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_tsif_ref_clk_src[] = { + F(105500, P_XO, 1, 1, 182), + { } +}; + +static struct clk_rcg2 tsif_ref_clk_src = { + .cmd_rcgr = 0x0d90, + .mnd_width = 8, + .hid_width = 5, + .freq_tbl = ftbl_tsif_ref_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "tsif_ref_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_usb30_mock_utmi_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(60000000, P_GPLL0, 10, 0, 0), + { } +}; + +static struct clk_rcg2 usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0x03e8, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_usb30_mock_utmi_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "usb30_mock_utmi_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_usb3_phy_aux_clk_src[] = { + F(1200000, P_XO, 16, 0, 0), + { } +}; + +static struct clk_rcg2 usb3_phy_aux_clk_src = { + .cmd_rcgr = 0x1414, + .hid_width = 5, + .freq_tbl = ftbl_usb3_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "usb3_phy_aux_clk_src", + .parent_names = (const char *[]) { "xo" }, + .num_parents = 1, + .ops = &clk_rcg2_ops, + }, +}; + +static struct freq_tbl ftbl_usb_hs_system_clk_src[] = { + F(75000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 usb_hs_system_clk_src = { + .cmd_rcgr = 0x0490, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_usb_hs_system_clk_src, + .clkr.hw.init = &(struct clk_init_data) + { + .name = "usb_hs_system_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x05c4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x1484, + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x0648, + .clkr = { + .enable_reg = 0x0648, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x0644, + .clkr = { + .enable_reg = 0x0644, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x06c8, + .clkr = { + .enable_reg = 0x06c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x06c4, + .clkr = { + .enable_reg = 0x06c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x0748, + .clkr = { + .enable_reg = 0x0748, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup3_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x0744, + .clkr = { + .enable_reg = 0x0744, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup3_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x07c8, + .clkr = { + .enable_reg = 0x07c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup4_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x07c4, + .clkr = { + .enable_reg = 0x07c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup4_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup5_i2c_apps_clk = { + .halt_reg = 0x0848, + .clkr = { + .enable_reg = 0x0848, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup5_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup5_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = { + .halt_reg = 0x0844, + .clkr = { + .enable_reg = 0x0844, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup5_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup5_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = { + .halt_reg = 0x08c8, + .clkr = { + .enable_reg = 0x08c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup6_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup6_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = { + .halt_reg = 0x08c4, + .clkr = { + .enable_reg = 0x08c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_qup6_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp1_qup6_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x0684, + .clkr = { + .enable_reg = 0x0684, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart1_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x0704, + .clkr = { + .enable_reg = 0x0704, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart2_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x0784, + .clkr = { + .enable_reg = 0x0784, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart3_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart4_apps_clk = { + .halt_reg = 0x0804, + .clkr = { + .enable_reg = 0x0804, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart4_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart4_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart5_apps_clk = { + .halt_reg = 0x0884, + .clkr = { + .enable_reg = 0x0884, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart5_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart5_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart6_apps_clk = { + .halt_reg = 0x0904, + .clkr = { + .enable_reg = 0x0904, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp1_uart6_apps_clk", + .parent_names = (const char *[]) { + "blsp1_uart6_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_ahb_clk = { + .halt_reg = 0x0944, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x1484, + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup1_i2c_apps_clk = { + .halt_reg = 0x0988, + .clkr = { + .enable_reg = 0x0988, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup1_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup1_spi_apps_clk = { + .halt_reg = 0x0984, + .clkr = { + .enable_reg = 0x0984, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup1_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup2_i2c_apps_clk = { + .halt_reg = 0x0a08, + .clkr = { + .enable_reg = 0x0a08, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup2_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { + .halt_reg = 0x0a04, + .clkr = { + .enable_reg = 0x0a04, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup2_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup3_i2c_apps_clk = { + .halt_reg = 0x0a88, + .clkr = { + .enable_reg = 0x0a88, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup3_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup3_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup3_spi_apps_clk = { + .halt_reg = 0x0a84, + .clkr = { + .enable_reg = 0x0a84, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup3_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup3_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup4_i2c_apps_clk = { + .halt_reg = 0x0b08, + .clkr = { + .enable_reg = 0x0b08, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup4_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup4_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup4_spi_apps_clk = { + .halt_reg = 0x0b04, + .clkr = { + .enable_reg = 0x0b04, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup4_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup4_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup5_i2c_apps_clk = { + .halt_reg = 0x0b88, + .clkr = { + .enable_reg = 0x0b88, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup5_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup5_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup5_spi_apps_clk = { + .halt_reg = 0x0b84, + .clkr = { + .enable_reg = 0x0b84, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup5_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup5_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup6_i2c_apps_clk = { + .halt_reg = 0x0c08, + .clkr = { + .enable_reg = 0x0c08, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup6_i2c_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup6_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_qup6_spi_apps_clk = { + .halt_reg = 0x0c04, + .clkr = { + .enable_reg = 0x0c04, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_qup6_spi_apps_clk", + .parent_names = (const char *[]) { + "blsp2_qup6_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart1_apps_clk = { + .halt_reg = 0x09c4, + .clkr = { + .enable_reg = 0x09c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart1_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart2_apps_clk = { + .halt_reg = 0x0a44, + .clkr = { + .enable_reg = 0x0a44, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart2_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart3_apps_clk = { + .halt_reg = 0x0ac4, + .clkr = { + .enable_reg = 0x0ac4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart3_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart4_apps_clk = { + .halt_reg = 0x0b44, + .clkr = { + .enable_reg = 0x0b44, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart4_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart4_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart5_apps_clk = { + .halt_reg = 0x0bc4, + .clkr = { + .enable_reg = 0x0bc4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart5_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart5_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp2_uart6_apps_clk = { + .halt_reg = 0x0c44, + .clkr = { + .enable_reg = 0x0c44, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_blsp2_uart6_apps_clk", + .parent_names = (const char *[]) { + "blsp2_uart6_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x1900, + .clkr = { + .enable_reg = 0x1900, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_gp1_clk", + .parent_names = (const char *[]) { + "gp1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x1940, + .clkr = { + .enable_reg = 0x1940, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_gp2_clk", + .parent_names = (const char *[]) { + "gp2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x1980, + .clkr = { + .enable_reg = 0x1980, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_gp3_clk", + .parent_names = (const char *[]) { + "gp3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x1ad4, + .clkr = { + .enable_reg = 0x1ad4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_pcie_0_aux_clk", + .parent_names = (const char *[]) { + "pcie_0_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x1ad8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1ad8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_pcie_0_pipe_clk", + .parent_names = (const char *[]) { + "pcie_0_pipe_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x1b54, + .clkr = { + .enable_reg = 0x1b54, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_pcie_1_aux_clk", + .parent_names = (const char *[]) { + "pcie_1_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x1b58, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1b58, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_pcie_1_pipe_clk", + .parent_names = (const char *[]) { + "pcie_1_pipe_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x0ccc, + .clkr = { + .enable_reg = 0x0ccc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_pdm2_clk", + .parent_names = (const char *[]) { + "pdm2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x04c4, + .clkr = { + .enable_reg = 0x04c4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]) { + "sdcc1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x0504, + .clkr = { + .enable_reg = 0x0504, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sdcc2_apps_clk", + .parent_names = (const char *[]) { + "sdcc2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc3_apps_clk = { + .halt_reg = 0x0544, + .clkr = { + .enable_reg = 0x0544, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sdcc3_apps_clk", + .parent_names = (const char *[]) { + "sdcc3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x0584, + .clkr = { + .enable_reg = 0x0584, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sdcc4_apps_clk", + .parent_names = (const char *[]) { + "sdcc4_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_ufs_axi_clk = { + .halt_reg = 0x1d7c, + .clkr = { + .enable_reg = 0x1d7c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sys_noc_ufs_axi_clk", + .parent_names = (const char *[]) { + "ufs_axi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb3_axi_clk = { + .halt_reg = 0x03fc, + .clkr = { + .enable_reg = 0x03fc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_sys_noc_usb3_axi_clk", + .parent_names = (const char *[]) { + "usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_tsif_ref_clk = { + .halt_reg = 0x0d88, + .clkr = { + .enable_reg = 0x0d88, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_tsif_ref_clk", + .parent_names = (const char *[]) { + "tsif_ref_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_axi_clk = { + .halt_reg = 0x1d48, + .clkr = { + .enable_reg = 0x1d48, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_ufs_axi_clk", + .parent_names = (const char *[]) { + "ufs_axi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_rx_cfg_clk = { + .halt_reg = 0x1d54, + .clkr = { + .enable_reg = 0x1d54, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_ufs_rx_cfg_clk", + .parent_names = (const char *[]) { + "ufs_axi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_tx_cfg_clk = { + .halt_reg = 0x1d50, + .clkr = { + .enable_reg = 0x1d50, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_ufs_tx_cfg_clk", + .parent_names = (const char *[]) { + "ufs_axi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_master_clk = { + .halt_reg = 0x03c8, + .clkr = { + .enable_reg = 0x03c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_usb30_master_clk", + .parent_names = (const char *[]) { + "usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mock_utmi_clk = { + .halt_reg = 0x03d0, + .clkr = { + .enable_reg = 0x03d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_usb30_mock_utmi_clk", + .parent_names = (const char *[]) { + "usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_aux_clk = { + .halt_reg = 0x1408, + .clkr = { + .enable_reg = 0x1408, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_usb3_phy_aux_clk", + .parent_names = (const char *[]) { + "usb3_phy_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_hs_system_clk = { + .halt_reg = 0x0484, + .clkr = { + .enable_reg = 0x0484, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data) + { + .name = "gcc_usb_hs_system_clk", + .parent_names = (const char *[]) { + "usb_hs_system_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gcc_msm8994_clocks[] = { + [GPLL0_EARLY] = &gpll0_early.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL4_EARLY] = &gpll4_early.clkr, + [GPLL4] = &gpll4.clkr, + [UFS_AXI_CLK_SRC] = &ufs_axi_clk_src.clkr, + [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr, + [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, + [BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr, + [BLSP1_QUP2_I2C_APPS_CLK_SRC] = &blsp1_qup2_i2c_apps_clk_src.clkr, + [BLSP1_QUP2_SPI_APPS_CLK_SRC] = &blsp1_qup2_spi_apps_clk_src.clkr, + [BLSP1_QUP3_I2C_APPS_CLK_SRC] = &blsp1_qup3_i2c_apps_clk_src.clkr, + [BLSP1_QUP3_SPI_APPS_CLK_SRC] = &blsp1_qup3_spi_apps_clk_src.clkr, + [BLSP1_QUP4_I2C_APPS_CLK_SRC] = &blsp1_qup4_i2c_apps_clk_src.clkr, + [BLSP1_QUP4_SPI_APPS_CLK_SRC] = &blsp1_qup4_spi_apps_clk_src.clkr, + [BLSP1_QUP5_I2C_APPS_CLK_SRC] = &blsp1_qup5_i2c_apps_clk_src.clkr, + [BLSP1_QUP5_SPI_APPS_CLK_SRC] = &blsp1_qup5_spi_apps_clk_src.clkr, + [BLSP1_QUP6_I2C_APPS_CLK_SRC] = &blsp1_qup6_i2c_apps_clk_src.clkr, + [BLSP1_QUP6_SPI_APPS_CLK_SRC] = &blsp1_qup6_spi_apps_clk_src.clkr, + [BLSP1_UART1_APPS_CLK_SRC] = &blsp1_uart1_apps_clk_src.clkr, + [BLSP1_UART2_APPS_CLK_SRC] = &blsp1_uart2_apps_clk_src.clkr, + [BLSP1_UART3_APPS_CLK_SRC] = &blsp1_uart3_apps_clk_src.clkr, + [BLSP1_UART4_APPS_CLK_SRC] = &blsp1_uart4_apps_clk_src.clkr, + [BLSP1_UART5_APPS_CLK_SRC] = &blsp1_uart5_apps_clk_src.clkr, + [BLSP1_UART6_APPS_CLK_SRC] = &blsp1_uart6_apps_clk_src.clkr, + [BLSP2_QUP1_I2C_APPS_CLK_SRC] = &blsp2_qup1_i2c_apps_clk_src.clkr, + [BLSP2_QUP1_SPI_APPS_CLK_SRC] = &blsp2_qup1_spi_apps_clk_src.clkr, + [BLSP2_QUP2_I2C_APPS_CLK_SRC] = &blsp2_qup2_i2c_apps_clk_src.clkr, + [BLSP2_QUP2_SPI_APPS_CLK_SRC] = &blsp2_qup2_spi_apps_clk_src.clkr, + [BLSP2_QUP3_I2C_APPS_CLK_SRC] = &blsp2_qup3_i2c_apps_clk_src.clkr, + [BLSP2_QUP3_SPI_APPS_CLK_SRC] = &blsp2_qup3_spi_apps_clk_src.clkr, + [BLSP2_QUP4_I2C_APPS_CLK_SRC] = &blsp2_qup4_i2c_apps_clk_src.clkr, + [BLSP2_QUP4_SPI_APPS_CLK_SRC] = &blsp2_qup4_spi_apps_clk_src.clkr, + [BLSP2_QUP5_I2C_APPS_CLK_SRC] = &blsp2_qup5_i2c_apps_clk_src.clkr, + [BLSP2_QUP5_SPI_APPS_CLK_SRC] = &blsp2_qup5_spi_apps_clk_src.clkr, + [BLSP2_QUP6_I2C_APPS_CLK_SRC] = &blsp2_qup6_i2c_apps_clk_src.clkr, + [BLSP2_QUP6_SPI_APPS_CLK_SRC] = &blsp2_qup6_spi_apps_clk_src.clkr, + [BLSP2_UART1_APPS_CLK_SRC] = &blsp2_uart1_apps_clk_src.clkr, + [BLSP2_UART2_APPS_CLK_SRC] = &blsp2_uart2_apps_clk_src.clkr, + [BLSP2_UART3_APPS_CLK_SRC] = &blsp2_uart3_apps_clk_src.clkr, + [BLSP2_UART4_APPS_CLK_SRC] = &blsp2_uart4_apps_clk_src.clkr, + [BLSP2_UART5_APPS_CLK_SRC] = &blsp2_uart5_apps_clk_src.clkr, + [BLSP2_UART6_APPS_CLK_SRC] = &blsp2_uart6_apps_clk_src.clkr, + [GP1_CLK_SRC] = &gp1_clk_src.clkr, + [GP2_CLK_SRC] = &gp2_clk_src.clkr, + [GP3_CLK_SRC] = &gp3_clk_src.clkr, + [PCIE_0_AUX_CLK_SRC] = &pcie_0_aux_clk_src.clkr, + [PCIE_0_PIPE_CLK_SRC] = &pcie_0_pipe_clk_src.clkr, + [PCIE_1_AUX_CLK_SRC] = &pcie_1_aux_clk_src.clkr, + [PCIE_1_PIPE_CLK_SRC] = &pcie_1_pipe_clk_src.clkr, + [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, + [SDCC1_APPS_CLK_SRC] = &sdcc1_apps_clk_src.clkr, + [SDCC2_APPS_CLK_SRC] = &sdcc2_apps_clk_src.clkr, + [SDCC3_APPS_CLK_SRC] = &sdcc3_apps_clk_src.clkr, + [SDCC4_APPS_CLK_SRC] = &sdcc4_apps_clk_src.clkr, + [TSIF_REF_CLK_SRC] = &tsif_ref_clk_src.clkr, + [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, + [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, + [USB_HS_SYSTEM_CLK_SRC] = &usb_hs_system_clk_src.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr, + [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr, + [GCC_BLSP1_UART5_APPS_CLK] = &gcc_blsp1_uart5_apps_clk.clkr, + [GCC_BLSP1_UART6_APPS_CLK] = &gcc_blsp1_uart6_apps_clk.clkr, + [GCC_BLSP2_AHB_CLK] = &gcc_blsp2_ahb_clk.clkr, + [GCC_BLSP2_QUP1_I2C_APPS_CLK] = &gcc_blsp2_qup1_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP1_SPI_APPS_CLK] = &gcc_blsp2_qup1_spi_apps_clk.clkr, + [GCC_BLSP2_QUP2_I2C_APPS_CLK] = &gcc_blsp2_qup2_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP2_SPI_APPS_CLK] = &gcc_blsp2_qup2_spi_apps_clk.clkr, + [GCC_BLSP2_QUP3_I2C_APPS_CLK] = &gcc_blsp2_qup3_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP3_SPI_APPS_CLK] = &gcc_blsp2_qup3_spi_apps_clk.clkr, + [GCC_BLSP2_QUP4_I2C_APPS_CLK] = &gcc_blsp2_qup4_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP4_SPI_APPS_CLK] = &gcc_blsp2_qup4_spi_apps_clk.clkr, + [GCC_BLSP2_QUP5_I2C_APPS_CLK] = &gcc_blsp2_qup5_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP5_SPI_APPS_CLK] = &gcc_blsp2_qup5_spi_apps_clk.clkr, + [GCC_BLSP2_QUP6_I2C_APPS_CLK] = &gcc_blsp2_qup6_i2c_apps_clk.clkr, + [GCC_BLSP2_QUP6_SPI_APPS_CLK] = &gcc_blsp2_qup6_spi_apps_clk.clkr, + [GCC_BLSP2_UART1_APPS_CLK] = &gcc_blsp2_uart1_apps_clk.clkr, + [GCC_BLSP2_UART2_APPS_CLK] = &gcc_blsp2_uart2_apps_clk.clkr, + [GCC_BLSP2_UART3_APPS_CLK] = &gcc_blsp2_uart3_apps_clk.clkr, + [GCC_BLSP2_UART4_APPS_CLK] = &gcc_blsp2_uart4_apps_clk.clkr, + [GCC_BLSP2_UART5_APPS_CLK] = &gcc_blsp2_uart5_apps_clk.clkr, + [GCC_BLSP2_UART6_APPS_CLK] = &gcc_blsp2_uart6_apps_clk.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC3_APPS_CLK] = &gcc_sdcc3_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SYS_NOC_UFS_AXI_CLK] = &gcc_sys_noc_ufs_axi_clk.clkr, + [GCC_SYS_NOC_USB3_AXI_CLK] = &gcc_sys_noc_usb3_axi_clk.clkr, + [GCC_TSIF_REF_CLK] = &gcc_tsif_ref_clk.clkr, + [GCC_UFS_AXI_CLK] = &gcc_ufs_axi_clk.clkr, + [GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr, + [GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr, + [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr, + [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr, + [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr, + [GCC_USB_HS_SYSTEM_CLK] = &gcc_usb_hs_system_clk.clkr, +}; + +static const struct regmap_config gcc_msm8994_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x2000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_msm8994_desc = { + .config = &gcc_msm8994_regmap_config, + .clks = gcc_msm8994_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8994_clocks), +}; + +static const struct of_device_id gcc_msm8994_match_table[] = { + { .compatible = "qcom,gcc-msm8994" }, + {} +}; +MODULE_DEVICE_TABLE(of, gcc_msm8994_match_table); + +static int gcc_msm8994_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct clk *clk; + + clk = devm_clk_register(dev, &xo.hw); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + return qcom_cc_probe(pdev, &gcc_msm8994_desc); +} + +static struct platform_driver gcc_msm8994_driver = { + .probe = gcc_msm8994_probe, + .driver = { + .name = "gcc-msm8994", + .of_match_table = gcc_msm8994_match_table, + }, +}; + +static int __init gcc_msm8994_init(void) +{ + return platform_driver_register(&gcc_msm8994_driver); +} +core_initcall(gcc_msm8994_init); + +static void __exit gcc_msm8994_exit(void) +{ + platform_driver_unregister(&gcc_msm8994_driver); +} +module_exit(gcc_msm8994_exit); + +MODULE_DESCRIPTION("Qualcomm GCC MSM8994 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-msm8994"); diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index fe03e6fbc7df..e22bbc27c907 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -464,10 +464,18 @@ static struct clk_rcg2 sdcc1_apps_clk_src = { }, }; +static struct freq_tbl ftbl_sdcc1_ice_core_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(150000000, P_GPLL0, 4, 0, 0), + F(300000000, P_GPLL0, 2, 0, 0), + { } +}; + static struct clk_rcg2 sdcc1_ice_core_clk_src = { .cmd_rcgr = 0x13024, .hid_width = 5, .parent_map = gcc_xo_gpll0_gpll4_gpll0_early_div_map, + .freq_tbl = ftbl_sdcc1_ice_core_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "sdcc1_ice_core_clk_src", .parent_names = gcc_xo_gpll0_gpll4_gpll0_early_div, @@ -1230,10 +1238,18 @@ static struct clk_rcg2 ufs_axi_clk_src = { }, }; +static const struct freq_tbl ftbl_ufs_ice_core_clk_src[] = { + F(19200000, P_XO, 1, 0, 0), + F(150000000, P_GPLL0, 4, 0, 0), + F(300000000, P_GPLL0, 2, 0, 0), + { } +}; + static struct clk_rcg2 ufs_ice_core_clk_src = { .cmd_rcgr = 0x76014, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_ufs_ice_core_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "ufs_ice_core_clk_src", .parent_names = gcc_xo_gpll0, @@ -1242,10 +1258,19 @@ static struct clk_rcg2 ufs_ice_core_clk_src = { }, }; +static const struct freq_tbl ftbl_qspi_ser_clk_src[] = { + F(75000000, P_GPLL0, 8, 0, 0), + F(150000000, P_GPLL0, 4, 0, 0), + F(256000000, P_GPLL4, 1.5, 0, 0), + F(300000000, P_GPLL0, 2, 0, 0), + { } +}; + static struct clk_rcg2 qspi_ser_clk_src = { .cmd_rcgr = 0x8b00c, .hid_width = 5, .parent_map = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map, + .freq_tbl = ftbl_qspi_ser_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "qspi_ser_clk_src", .parent_names = gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div, diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index f12d7b2bddd7..925d178ba675 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -30,6 +30,7 @@ #define SW_OVERRIDE_MASK BIT(2) #define HW_CONTROL_MASK BIT(1) #define SW_COLLAPSE_MASK BIT(0) +#define GMEM_CLAMP_IO_MASK BIT(0) /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ #define EN_REST_WAIT_VAL (0x2 << 20) @@ -140,6 +141,18 @@ static inline void gdsc_clear_mem_on(struct gdsc *sc) regmap_update_bits(sc->regmap, sc->cxcs[i], mask, 0); } +static inline void gdsc_deassert_clamp_io(struct gdsc *sc) +{ + regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, + GMEM_CLAMP_IO_MASK, 0); +} + +static inline void gdsc_assert_clamp_io(struct gdsc *sc) +{ + regmap_update_bits(sc->regmap, sc->clamp_io_ctrl, + GMEM_CLAMP_IO_MASK, 1); +} + static int gdsc_enable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); @@ -148,6 +161,9 @@ static int gdsc_enable(struct generic_pm_domain *domain) if (sc->pwrsts == PWRSTS_ON) return gdsc_deassert_reset(sc); + if (sc->flags & CLAMP_IO) + gdsc_deassert_clamp_io(sc); + ret = gdsc_toggle_logic(sc, true); if (ret) return ret; @@ -170,6 +186,7 @@ static int gdsc_enable(struct generic_pm_domain *domain) static int gdsc_disable(struct generic_pm_domain *domain) { struct gdsc *sc = domain_to_gdsc(domain); + int ret; if (sc->pwrsts == PWRSTS_ON) return gdsc_assert_reset(sc); @@ -177,7 +194,14 @@ static int gdsc_disable(struct generic_pm_domain *domain) if (sc->pwrsts & PWRSTS_OFF) gdsc_clear_mem_on(sc); - return gdsc_toggle_logic(sc, false); + ret = gdsc_toggle_logic(sc, false); + if (ret) + return ret; + + if (sc->flags & CLAMP_IO) + gdsc_assert_clamp_io(sc); + + return 0; } static int gdsc_init(struct gdsc *sc) diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h index 3bf497c36bdf..f011c4957527 100644 --- a/drivers/clk/qcom/gdsc.h +++ b/drivers/clk/qcom/gdsc.h @@ -39,6 +39,7 @@ struct gdsc { struct regmap *regmap; unsigned int gdscr; unsigned int gds_hw_ctrl; + unsigned int clamp_io_ctrl; unsigned int *cxcs; unsigned int cxc_count; const u8 pwrsts; @@ -50,6 +51,7 @@ struct gdsc { #define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) const u8 flags; #define VOTABLE BIT(0) +#define CLAMP_IO BIT(1) struct reset_controller_dev *rcdev; unsigned int *resets; unsigned int reset_count; diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index db3998e5e2d8..977e98eadbeb 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -443,7 +443,7 @@ static int lcc_ipq806x_probe(struct platform_device *pdev) return PTR_ERR(regmap); /* Configure the rate of PLL4 if the bootloader hasn't already */ - val = regmap_read(regmap, 0x0, &val); + regmap_read(regmap, 0x0, &val); if (!val) clk_pll_configure_sr(&pll4, regmap, &pll4_config, true); /* Enable PLL4 source on the LPASS Primary PLL Mux */ diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index ca97e1151797..f77206f549cc 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -3034,6 +3034,28 @@ static struct gdsc mdss_gdsc = { .pwrsts = PWRSTS_OFF_ON, }; +static struct gdsc gpu_gdsc = { + .gdscr = 0x4034, + .gds_hw_ctrl = 0x4038, + .pd = { + .name = "gpu", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x4024, + .clamp_io_ctrl = 0x4300, + .cxcs = (unsigned int []){ 0x4028 }, + .cxc_count = 1, + .pd = { + .name = "gpu_gx", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO, +}; + static struct clk_regmap *mmcc_msm8996_clocks[] = { [MMPLL0_EARLY] = &mmpll0_early.clkr, [MMPLL0_PLL] = &mmpll0.clkr, @@ -3223,6 +3245,8 @@ static struct gdsc *mmcc_msm8996_gdscs[] = { [CPP_GDSC] = &cpp_gdsc, [FD_GDSC] = &fd_gdsc, [MDSS_GDSC] = &mdss_gdsc, + [GPU_GDSC] = &gpu_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, }; static const struct qcom_reset_map mmcc_msm8996_resets[] = { diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c index 8feba93672c5..e8075359366b 100644 --- a/drivers/clk/rockchip/clk-ddr.c +++ b/drivers/clk/rockchip/clk-ddr.c @@ -144,11 +144,8 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, ddrclk->ddr_flag = ddr_flag; clk = clk_register(NULL, &ddrclk->hw); - if (IS_ERR(clk)) { - pr_err("%s: could not register ddrclk %s\n", __func__, name); + if (IS_ERR(clk)) kfree(ddrclk); - return NULL; - } return clk; } diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 9c1373e81683..6ed605776abd 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -319,7 +319,8 @@ static void rockchip_rk3036_pll_init(struct clk_hw *hw) if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 || rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 || - rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) { + rate->dsmpd != cur.dsmpd || + (!cur.dsmpd && (rate->frac != cur.frac))) { struct clk *parent = clk_get_parent(hw->clk); if (!parent) { @@ -795,7 +796,8 @@ static void rockchip_rk3399_pll_init(struct clk_hw *hw) if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 || rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 || - rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) { + rate->dsmpd != cur.dsmpd || + (!cur.dsmpd && (rate->frac != cur.frac))) { struct clk *parent = clk_get_parent(hw->clk); if (!parent) { diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index d0e722a0e8cf..062ef4960244 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -89,6 +89,7 @@ static struct rockchip_pll_rate_table rk3188_pll_rates[] = { RK3066_PLL_RATE( 504000000, 1, 84, 4), 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), @@ -306,14 +307,14 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK2928_CLKGATE_CON(0), 2, GFLAGS), - GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, + GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 3, GFLAGS), GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 6, GFLAGS), - GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, + GATE(PCLK_CPU, "pclk_cpu", "pclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 5, GFLAGS), - GATE(0, "hclk_cpu", "hclk_cpu_pre", CLK_IGNORE_UNUSED, + GATE(HCLK_CPU, "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, CLK_IGNORE_UNUSED, @@ -323,12 +324,12 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { RK2928_CLKSEL_CON(31), 15, 1, MFLAGS, 8, 5, DFLAGS, RK2928_CLKGATE_CON(1), 4, GFLAGS), - GATE(0, "aclk_peri", "aclk_peri_pre", 0, + GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0, RK2928_CLKGATE_CON(2), 1, GFLAGS), - COMPOSITE_NOMUX(0, "hclk_peri", "aclk_peri_pre", 0, + COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_pre", 0, RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK2928_CLKGATE_CON(2), 2, GFLAGS), - COMPOSITE_NOMUX(0, "pclk_peri", "aclk_peri_pre", 0, + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_pre", 0, RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, RK2928_CLKGATE_CON(2), 3, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 8387c7a40bda..828005556376 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -77,7 +77,7 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0), RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), - RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), + RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0), RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0), RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0), @@ -87,12 +87,13 @@ static struct rockchip_pll_rate_table rk3399_pll_rates[] = { RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0), RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0), RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0), - RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0), + RK3036_PLL_RATE( 800000000, 1, 100, 3, 1, 1, 0), RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0), RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0), RK3036_PLL_RATE( 676000000, 3, 169, 2, 1, 1, 0), RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0), RK3036_PLL_RATE( 594000000, 1, 99, 4, 1, 1, 0), + RK3036_PLL_RATE( 533250000, 8, 711, 4, 1, 1, 0), RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0), RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0), RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0), @@ -410,11 +411,11 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(SCLK_USB2PHY1_REF, "clk_usb2phy1_ref", "xin24m", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(6), 6, GFLAGS), - GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", CLK_IGNORE_UNUSED, + GATE(0, "clk_usbphy0_480m_src", "clk_usbphy0_480m", 0, RK3399_CLKGATE_CON(13), 12, GFLAGS), - GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", CLK_IGNORE_UNUSED, + GATE(0, "clk_usbphy1_480m_src", "clk_usbphy1_480m", 0, RK3399_CLKGATE_CON(13), 12, GFLAGS), - MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, CLK_IGNORE_UNUSED, + MUX(0, "clk_usbphy_480m", mux_usbphy_480m_p, 0, RK3399_CLKSEL_CON(14), 6, 1, MFLAGS), MUX(0, "upll", mux_pll_src_24m_usbphy480m_p, 0, @@ -498,7 +499,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { RK3399_CLKGATE_CON(14), 10, GFLAGS), GATE(ACLK_GIC_ADB400_CORE_L_2_GIC, "aclk_core_adb400_core_l_2_gic", "armclkl", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(14), 11, GFLAGS), - GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_PVTM_CORE_L, "clk_pvtm_core_l", "xin24m", 0, RK3399_CLKGATE_CON(0), 7, GFLAGS), /* big core */ @@ -539,7 +540,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(0, "pclk_dbg_cxcs_pd_core_b", "pclk_dbg_core_b", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(14), 2, GFLAGS), - GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_PVTM_CORE_B, "clk_pvtm_core_b", "xin24m", 0, RK3399_CLKGATE_CON(1), 7, GFLAGS), /* gmac */ @@ -675,18 +676,18 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(PCLK_CENTER_MAIN_NOC, "pclk_center_main_noc", "pclk_ddr", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(18), 10, GFLAGS), - GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", CLK_IGNORE_UNUSED, + GATE(PCLK_DDR_MON, "pclk_ddr_mon", "pclk_ddr", 0, RK3399_CLKGATE_CON(18), 12, GFLAGS), GATE(PCLK_CIC, "pclk_cic", "pclk_ddr", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(18), 15, GFLAGS), GATE(PCLK_DDR_SGRF, "pclk_ddr_sgrf", "pclk_ddr", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(19), 2, GFLAGS), - GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_PVTM_DDR, "clk_pvtm_ddr", "xin24m", 0, RK3399_CLKGATE_CON(4), 11, GFLAGS), - GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_DFIMON0_TIMER, "clk_dfimon0_timer", "xin24m", 0, RK3399_CLKGATE_CON(3), 5, GFLAGS), - GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", CLK_IGNORE_UNUSED, + GATE(SCLK_DFIMON1_TIMER, "clk_dfimon1_timer", "xin24m", 0, RK3399_CLKGATE_CON(3), 6, GFLAGS), /* cci */ @@ -966,7 +967,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(SCLK_INTMEM3, "clk_intmem3", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 5, GFLAGS), GATE(SCLK_INTMEM4, "clk_intmem4", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 6, GFLAGS), GATE(SCLK_INTMEM5, "clk_intmem5", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 7, GFLAGS), - GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 8, GFLAGS), + GATE(ACLK_DCF, "aclk_dcf", "aclk_perilp0", 0, RK3399_CLKGATE_CON(23), 8, GFLAGS), GATE(ACLK_DMAC0_PERILP, "aclk_dmac0_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 5, GFLAGS), GATE(ACLK_DMAC1_PERILP, "aclk_dmac1_perilp", "aclk_perilp0", 0, RK3399_CLKGATE_CON(25), 6, GFLAGS), GATE(ACLK_PERILP0_NOC, "aclk_perilp0_noc", "aclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 7, GFLAGS), @@ -980,7 +981,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { GATE(HCLK_PERILP0_NOC, "hclk_perilp0_noc", "hclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(25), 8, GFLAGS), /* pclk_perilp0 gates */ - GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", CLK_IGNORE_UNUSED, RK3399_CLKGATE_CON(23), 9, GFLAGS), + GATE(PCLK_DCF, "pclk_dcf", "pclk_perilp0", 0, RK3399_CLKGATE_CON(23), 9, GFLAGS), /* crypto */ COMPOSITE(SCLK_CRYPTO0, "clk_crypto0", mux_pll_src_cpll_gpll_ppll_p, 0, diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 51d152f735cc..17e68a724945 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -106,6 +106,7 @@ static const struct of_device_id exynos_audss_clk_of_match[] = { }, { }, }; +MODULE_DEVICE_TABLE(of, exynos_audss_clk_of_match); static void exynos_audss_clk_teardown(void) { diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 96fab6cfb202..6c6afb87b4ce 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -132,28 +132,34 @@ free_clkout: pr_err("%s: failed to register clkout clock\n", __func__); } +/* + * We use CLK_OF_DECLARE_DRIVER initialization method to avoid setting + * the OF_POPULATED flag on the pmu device tree node, so later the + * Exynos PMU platform device can be properly probed with PMU driver. + */ + static void __init exynos4_clkout_init(struct device_node *node) { exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK); } -CLK_OF_DECLARE(exynos4210_clkout, "samsung,exynos4210-pmu", +CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu", exynos4_clkout_init); -CLK_OF_DECLARE(exynos4212_clkout, "samsung,exynos4212-pmu", +CLK_OF_DECLARE_DRIVER(exynos4212_clkout, "samsung,exynos4212-pmu", exynos4_clkout_init); -CLK_OF_DECLARE(exynos4412_clkout, "samsung,exynos4412-pmu", +CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu", exynos4_clkout_init); -CLK_OF_DECLARE(exynos3250_clkout, "samsung,exynos3250-pmu", +CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu", exynos4_clkout_init); static void __init exynos5_clkout_init(struct device_node *node) { exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK); } -CLK_OF_DECLARE(exynos5250_clkout, "samsung,exynos5250-pmu", +CLK_OF_DECLARE_DRIVER(exynos5250_clkout, "samsung,exynos5250-pmu", exynos5_clkout_init); -CLK_OF_DECLARE(exynos5410_clkout, "samsung,exynos5410-pmu", +CLK_OF_DECLARE_DRIVER(exynos5410_clkout, "samsung,exynos5410-pmu", exynos5_clkout_init); -CLK_OF_DECLARE(exynos5420_clkout, "samsung,exynos5420-pmu", +CLK_OF_DECLARE_DRIVER(exynos5420_clkout, "samsung,exynos5420-pmu", exynos5_clkout_init); -CLK_OF_DECLARE(exynos5433_clkout, "samsung,exynos5433-pmu", +CLK_OF_DECLARE_DRIVER(exynos5433_clkout, "samsung,exynos5433-pmu", exynos5_clkout_init); diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 254d9526c018..8454c6e3dd65 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -35,17 +35,14 @@ config SUNXI_CCU_NK config SUNXI_CCU_NKM bool - select RATIONAL select SUNXI_CCU_GATE config SUNXI_CCU_NKMP bool - select RATIONAL select SUNXI_CCU_GATE config SUNXI_CCU_NM bool - select RATIONAL select SUNXI_CCU_FRAC select SUNXI_CCU_GATE @@ -56,6 +53,17 @@ config SUNXI_CCU_MP # SoC Drivers +config SUN50I_A64_CCU + bool "Support for the Allwinner A64 CCU" + select SUNXI_CCU_DIV + select SUNXI_CCU_NK + select SUNXI_CCU_NKM + select SUNXI_CCU_NKMP + select SUNXI_CCU_NM + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default ARM64 && ARCH_SUNXI + config SUN6I_A31_CCU bool "Support for the Allwinner A31/A31s CCU" select SUNXI_CCU_DIV diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 106cba27c331..24fbc6e5deb8 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SUNXI_CCU_NM) += ccu_nm.o obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o # SoC support +obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c new file mode 100644 index 000000000000..e3c084cc6da5 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -0,0 +1,915 @@ +/* + * Copyright (c) 2016 Maxime Ripard. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/of_address.h> +#include <linux/platform_device.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" +#include "ccu_phase.h" + +#include "ccu-sun50i-a64.h" + +static struct ccu_nkmp pll_cpux_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT(4, 2), + .m = _SUNXI_CCU_DIV(0, 2), + .p = _SUNXI_CCU_DIV_MAX(16, 2, 4), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT("pll-cpux", + "osc24M", + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from + * the base (2x, 4x and 8x), and one variable divider (the one true + * pll audio). + * + * We don't have any need for the variable divider for now, so we just + * hardcode it to match with the clock names + */ +#define SUN50I_A64_PLL_AUDIO_REG 0x008 + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", + "osc24M", 0x010, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", + "osc24M", 0x018, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr0_clk, "pll-ddr0", + "osc24M", 0x020, + 8, 5, /* N */ + 4, 2, /* K */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static struct ccu_nk pll_periph0_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .fixed_post_div = 2, + .common = { + .reg = 0x028, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph0", "osc24M", + &ccu_nk_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static struct ccu_nk pll_periph1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 5), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .fixed_post_div = 2, + .common = { + .reg = 0x02c, + .features = CCU_FEATURE_FIXED_POSTDIV, + .hw.init = CLK_HW_INIT("pll-periph1", "osc24M", + &ccu_nk_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1", + "osc24M", 0x030, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", + "osc24M", 0x038, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +/* + * The output function can be changed to something more complex that + * we do not handle yet. + * + * Hardcode the mode so that we don't fall in that case. + */ +#define SUN50I_A64_PLL_MIPI_REG 0x040 + +static struct ccu_nkm pll_mipi_clk = { + .enable = BIT(31), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT(8, 4), + .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), + .m = _SUNXI_CCU_DIV(0, 4), + .common = { + .reg = 0x040, + .hw.init = CLK_HW_INIT("pll-mipi", "pll-video0", + &ccu_nkm_ops, CLK_SET_RATE_UNGATE), + }, +}; + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_hsic_clk, "pll-hsic", + "osc24M", 0x044, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", + "osc24M", 0x048, + 8, 7, /* N */ + 0, 4, /* M */ + BIT(24), /* frac enable */ + BIT(25), /* frac select */ + 270000000, /* frac rate 0 */ + 297000000, /* frac rate 1 */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", + "osc24M", 0x04c, + 8, 7, /* N */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); + +static const char * const cpux_parents[] = { "osc32k", "osc24M", + "pll-cpux", "pll-cpux" }; +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents, + 0x050, 16, 2, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0); + +static const char * const ahb1_parents[] = { "osc32k", "osc24M", + "axi", "pll-periph0" }; +static struct ccu_div ahb1_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 12, + .width = 2, + + .variable_prediv = { + .index = 3, + .shift = 6, + .width = 2, + }, + }, + + .common = { + .reg = 0x054, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb1", + ahb1_parents, + &ccu_div_ops, + 0), + }, +}; + +static struct clk_div_table apb1_div_table[] = { + { .val = 0, .div = 2 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 8 }, + { /* Sentinel */ }, +}; +static SUNXI_CCU_DIV_TABLE(apb1_clk, "apb1", "ahb1", + 0x054, 8, 2, apb1_div_table, 0); + +static const char * const apb2_parents[] = { "osc32k", "osc24M", + "pll-periph0-2x", + "pll-periph0-2x" }; +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058, + 0, 5, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const char * const ahb2_parents[] = { "ahb1", "pll-periph0" }; +static const struct ccu_mux_fixed_prediv ahb2_fixed_predivs[] = { + { .index = 1, .div = 2 }, +}; +static struct ccu_mux ahb2_clk = { + .mux = { + .shift = 0, + .width = 1, + .fixed_predivs = ahb2_fixed_predivs, + .n_predivs = ARRAY_SIZE(ahb2_fixed_predivs), + }, + + .common = { + .reg = 0x05c, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ahb2", + ahb2_parents, + &ccu_mux_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1", + 0x060, BIT(1), 0); +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "ahb1", + 0x060, BIT(5), 0); +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1", + 0x060, BIT(6), 0); +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1", + 0x060, BIT(8), 0); +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1", + 0x060, BIT(9), 0); +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1", + 0x060, BIT(10), 0); +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1", + 0x060, BIT(13), 0); +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1", + 0x060, BIT(14), 0); +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2", + 0x060, BIT(17), 0); +static SUNXI_CCU_GATE(bus_ts_clk, "bus-ts", "ahb1", + 0x060, BIT(18), 0); +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1", + 0x060, BIT(19), 0); +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1", + 0x060, BIT(20), 0); +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1", + 0x060, BIT(21), 0); +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1", + 0x060, BIT(23), 0); +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb1", + 0x060, BIT(24), 0); +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2", + 0x060, BIT(25), 0); +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb1", + 0x060, BIT(28), 0); +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb2", + 0x060, BIT(29), 0); + +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1", + 0x064, BIT(0), 0); +static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1", + 0x064, BIT(3), 0); +static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1", + 0x064, BIT(4), 0); +static SUNXI_CCU_GATE(bus_deinterlace_clk, "bus-deinterlace", "ahb1", + 0x064, BIT(5), 0); +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1", + 0x064, BIT(8), 0); +static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1", + 0x064, BIT(11), 0); +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1", + 0x064, BIT(12), 0); +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1", + 0x064, BIT(20), 0); +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1", + 0x064, BIT(21), 0); +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1", + 0x064, BIT(22), 0); + +static SUNXI_CCU_GATE(bus_codec_clk, "bus-codec", "apb1", + 0x068, BIT(0), 0); +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", + 0x068, BIT(1), 0); +static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1", + 0x068, BIT(5), 0); +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", + 0x068, BIT(8), 0); +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", + 0x068, BIT(12), 0); +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", + 0x068, BIT(13), 0); +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", + 0x068, BIT(14), 0); + +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", + 0x06c, BIT(0), 0); +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", + 0x06c, BIT(1), 0); +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", + 0x06c, BIT(2), 0); +static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2", + 0x06c, BIT(5), 0); +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", + 0x06c, BIT(16), 0); +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", + 0x06c, BIT(17), 0); +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", + 0x06c, BIT(18), 0); +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", + 0x06c, BIT(19), 0); +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", + 0x06c, BIT(20), 0); + +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "ahb1", + 0x070, BIT(7), 0); + +static struct clk_div_table ths_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, +}; +static const char * const ths_parents[] = { "osc24M" }; +static struct ccu_div ths_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV_TABLE(0, 2, ths_div_table), + .mux = _SUNXI_CCU_MUX(24, 2), + .common = { + .reg = 0x074, + .hw.init = CLK_HW_INIT_PARENTS("ths", + ths_parents, + &ccu_div_ops, + 0), + }, +}; + +static const char * const mod0_default_parents[] = { "osc24M", "pll-periph0", + "pll-periph1" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x", + "pll-periph1-2x" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const ts_parents[] = { "osc24M", "pll-periph0", }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ts_clk, "ts", ts_parents, 0x098, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 4, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", mmc_default_parents, 0x09c, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents, 0x0a0, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", + "pll-audio-2x", "pll-audio" }; +static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, + 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, + 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s_parents, + 0x0b8, 16, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", + 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", + 0x0cc, BIT(8), 0); +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M", + 0x0cc, BIT(9), 0); +static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic", + 0x0cc, BIT(10), 0); +static SUNXI_CCU_GATE(usb_hsic_12m_clk, "usb-hsic-12M", "osc12M", + 0x0cc, BIT(11), 0); +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", + 0x0cc, BIT(16), 0); +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "usb-ohci0", + 0x0cc, BIT(17), 0); + +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, + 0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL); + +static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram", + 0x100, BIT(0), 0); +static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram", + 0x100, BIT(1), 0); +static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram", + 0x100, BIT(2), 0); +static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "dram", + 0x100, BIT(3), 0); + +static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" }; +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents, + 0x104, 0, 4, 24, 3, BIT(31), 0); + +static const char * const tcon0_parents[] = { "pll-mipi", "pll-video0-2x" }; +static const u8 tcon0_table[] = { 0, 2, }; +static SUNXI_CCU_MUX_TABLE_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents, + tcon0_table, 0x118, 24, 3, BIT(31), + CLK_SET_RATE_PARENT); + +static const char * const tcon1_parents[] = { "pll-video0", "pll-video1" }; +static const u8 tcon1_table[] = { 0, 2, }; +static struct ccu_div tcon1_clk = { + .enable = BIT(31), + .div = _SUNXI_CCU_DIV(0, 4), + .mux = _SUNXI_CCU_MUX_TABLE(24, 2, tcon1_table), + .common = { + .reg = 0x11c, + .hw.init = CLK_HW_INIT_PARENTS("tcon1", + tcon1_parents, + &ccu_div_ops, + CLK_SET_RATE_PARENT), + }, +}; + +static const char * const deinterlace_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(deinterlace_clk, "deinterlace", deinterlace_parents, + 0x124, 0, 4, 24, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", + 0x130, BIT(31), 0); + +static const char * const csi_sclk_parents[] = { "pll-periph0", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_sclk_clk, "csi-sclk", csi_sclk_parents, + 0x134, 16, 4, 24, 3, BIT(31), 0); + +static const char * const csi_mclk_parents[] = { "osc24M", "pll-video1", "pll-periph1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, + 0x134, 0, 5, 8, 3, BIT(15), 0); + +static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", + 0x13c, 16, 3, BIT(31), 0); + +static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", + 0x140, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x", + 0x140, BIT(30), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", + 0x144, BIT(31), 0); + +static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents, + 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", + 0x154, BIT(31), 0); + +static const char * const mbus_parents[] = { "osc24M", "pll-periph0-2x", + "pll-ddr0", "pll-ddr1" }; +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, + 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); + +static const char * const dsi_dphy_parents[] = { "pll-video0", "pll-periph0" }; +static const u8 dsi_dphy_table[] = { 0, 2, }; +static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(dsi_dphy_clk, "dsi-dphy", + dsi_dphy_parents, dsi_dphy_table, + 0x168, 0, 4, 8, 2, BIT(31), CLK_SET_RATE_PARENT); + +static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", + 0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT); + +/* Fixed Factor clocks */ +static CLK_FIXED_FACTOR(osc12M_clk, "osc12M", "osc24M", 1, 2, 0); + +/* We hardcode the divider to 4 for now */ +static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", + "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", + "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", + "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR(pll_periph0_2x_clk, "pll-periph0-2x", + "pll-periph0", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_periph1_2x_clk, "pll-periph1-2x", + "pll-periph1", 1, 2, 0); +static CLK_FIXED_FACTOR(pll_video0_2x_clk, "pll-video0-2x", + "pll-video0", 1, 2, CLK_SET_RATE_PARENT); + +static struct ccu_common *sun50i_a64_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_audio_base_clk.common, + &pll_video0_clk.common, + &pll_ve_clk.common, + &pll_ddr0_clk.common, + &pll_periph0_clk.common, + &pll_periph1_clk.common, + &pll_video1_clk.common, + &pll_gpu_clk.common, + &pll_mipi_clk.common, + &pll_hsic_clk.common, + &pll_de_clk.common, + &pll_ddr1_clk.common, + &cpux_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &ahb2_clk.common, + &bus_mipi_dsi_clk.common, + &bus_ce_clk.common, + &bus_dma_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_nand_clk.common, + &bus_dram_clk.common, + &bus_emac_clk.common, + &bus_ts_clk.common, + &bus_hstimer_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_otg_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ve_clk.common, + &bus_tcon0_clk.common, + &bus_tcon1_clk.common, + &bus_deinterlace_clk.common, + &bus_csi_clk.common, + &bus_hdmi_clk.common, + &bus_de_clk.common, + &bus_gpu_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_codec_clk.common, + &bus_spdif_clk.common, + &bus_pio_clk.common, + &bus_ths_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_scr_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &bus_dbg_clk.common, + &ths_clk.common, + &nand_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &ts_clk.common, + &ce_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &spdif_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_hsic_clk.common, + &usb_hsic_12m_clk.common, + &usb_ohci0_clk.common, + &usb_ohci1_clk.common, + &dram_clk.common, + &dram_ve_clk.common, + &dram_csi_clk.common, + &dram_deinterlace_clk.common, + &dram_ts_clk.common, + &de_clk.common, + &tcon0_clk.common, + &tcon1_clk.common, + &deinterlace_clk.common, + &csi_misc_clk.common, + &csi_sclk_clk.common, + &csi_mclk_clk.common, + &ve_clk.common, + &ac_dig_clk.common, + &ac_dig_4x_clk.common, + &avs_clk.common, + &hdmi_clk.common, + &hdmi_ddc_clk.common, + &mbus_clk.common, + &dsi_dphy_clk.common, + &gpu_clk.common, +}; + +static struct clk_hw_onecell_data sun50i_a64_hw_clks = { + .hws = { + [CLK_OSC_12M] = &osc12M_clk.hw, + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw, + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_MIPI] = &pll_mipi_clk.common.hw, + [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_AHB2] = &ahb2_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_BUS_TS] = &bus_ts_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw, + [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw, + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_CODEC] = &bus_codec_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_BUS_PIO] = &bus_pio_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw, + [CLK_BUS_SCR] = &bus_scr_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_THS] = &ths_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_HSIC] = &usb_hsic_clk.common.hw, + [CLK_USB_HSIC_12M] = &usb_hsic_12m_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI] = &dram_csi_clk.common.hw, + [CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw, + [CLK_DRAM_TS] = &dram_ts_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_TCON0] = &tcon0_clk.common.hw, + [CLK_TCON1] = &tcon1_clk.common.hw, + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, + [CLK_CSI_MISC] = &csi_misc_clk.common.hw, + [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_AC_DIG] = &ac_dig_clk.common.hw, + [CLK_AC_DIG_4X] = &ac_dig_4x_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_DDC] = &hdmi_ddc_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_DSI_DPHY] = &dsi_dphy_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun50i_a64_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_HSIC] = { 0x0cc, BIT(2) }, + + [RST_DRAM] = { 0x0f4, BIT(31) }, + [RST_MBUS] = { 0x0fc, BIT(31) }, + + [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) }, + [RST_BUS_CE] = { 0x2c0, BIT(5) }, + [RST_BUS_DMA] = { 0x2c0, BIT(6) }, + [RST_BUS_MMC0] = { 0x2c0, BIT(8) }, + [RST_BUS_MMC1] = { 0x2c0, BIT(9) }, + [RST_BUS_MMC2] = { 0x2c0, BIT(10) }, + [RST_BUS_NAND] = { 0x2c0, BIT(13) }, + [RST_BUS_DRAM] = { 0x2c0, BIT(14) }, + [RST_BUS_EMAC] = { 0x2c0, BIT(17) }, + [RST_BUS_TS] = { 0x2c0, BIT(18) }, + [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_BUS_SPI0] = { 0x2c0, BIT(20) }, + [RST_BUS_SPI1] = { 0x2c0, BIT(21) }, + [RST_BUS_OTG] = { 0x2c0, BIT(23) }, + [RST_BUS_EHCI0] = { 0x2c0, BIT(24) }, + [RST_BUS_EHCI1] = { 0x2c0, BIT(25) }, + [RST_BUS_OHCI0] = { 0x2c0, BIT(28) }, + [RST_BUS_OHCI1] = { 0x2c0, BIT(29) }, + + [RST_BUS_VE] = { 0x2c4, BIT(0) }, + [RST_BUS_TCON0] = { 0x2c4, BIT(3) }, + [RST_BUS_TCON1] = { 0x2c4, BIT(4) }, + [RST_BUS_DEINTERLACE] = { 0x2c4, BIT(5) }, + [RST_BUS_CSI] = { 0x2c4, BIT(8) }, + [RST_BUS_HDMI0] = { 0x2c4, BIT(10) }, + [RST_BUS_HDMI1] = { 0x2c4, BIT(11) }, + [RST_BUS_DE] = { 0x2c4, BIT(12) }, + [RST_BUS_GPU] = { 0x2c4, BIT(20) }, + [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) }, + [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) }, + [RST_BUS_DBG] = { 0x2c4, BIT(31) }, + + [RST_BUS_LVDS] = { 0x2c8, BIT(0) }, + + [RST_BUS_CODEC] = { 0x2d0, BIT(0) }, + [RST_BUS_SPDIF] = { 0x2d0, BIT(1) }, + [RST_BUS_THS] = { 0x2d0, BIT(8) }, + [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, + [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, + [RST_BUS_I2S2] = { 0x2d0, BIT(14) }, + + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_SCR] = { 0x2d8, BIT(5) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_UART4] = { 0x2d8, BIT(20) }, +}; + +static const struct sunxi_ccu_desc sun50i_a64_ccu_desc = { + .ccu_clks = sun50i_a64_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a64_ccu_clks), + + .hw_clks = &sun50i_a64_hw_clks, + + .resets = sun50i_a64_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_a64_ccu_resets), +}; + +static int sun50i_a64_ccu_probe(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *reg; + u32 val; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* Force the PLL-Audio-1x divider to 4 */ + val = readl(reg + SUN50I_A64_PLL_AUDIO_REG); + val &= ~GENMASK(19, 16); + writel(val | (3 << 16), reg + SUN50I_A64_PLL_AUDIO_REG); + + writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); + + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); +} + +static const struct of_device_id sun50i_a64_ccu_ids[] = { + { .compatible = "allwinner,sun50i-a64-ccu" }, + { } +}; + +static struct platform_driver sun50i_a64_ccu_driver = { + .probe = sun50i_a64_ccu_probe, + .driver = { + .name = "sun50i-a64-ccu", + .of_match_table = sun50i_a64_ccu_ids, + }, +}; +builtin_platform_driver(sun50i_a64_ccu_driver); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.h b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h new file mode 100644 index 000000000000..9b3cd24b78d2 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.h @@ -0,0 +1,72 @@ +/* + * Copyright 2016 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * 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. + */ + +#ifndef _CCU_SUN50I_A64_H_ +#define _CCU_SUN50I_A64_H_ + +#include <dt-bindings/clock/sun50i-a64-ccu.h> +#include <dt-bindings/reset/sun50i-a64-ccu.h> + +#define CLK_OSC_12M 0 +#define CLK_PLL_CPUX 1 +#define CLK_PLL_AUDIO_BASE 2 +#define CLK_PLL_AUDIO 3 +#define CLK_PLL_AUDIO_2X 4 +#define CLK_PLL_AUDIO_4X 5 +#define CLK_PLL_AUDIO_8X 6 +#define CLK_PLL_VIDEO0 7 +#define CLK_PLL_VIDEO0_2X 8 +#define CLK_PLL_VE 9 +#define CLK_PLL_DDR0 10 +#define CLK_PLL_PERIPH0 11 +#define CLK_PLL_PERIPH0_2X 12 +#define CLK_PLL_PERIPH1 13 +#define CLK_PLL_PERIPH1_2X 14 +#define CLK_PLL_VIDEO1 15 +#define CLK_PLL_GPU 16 +#define CLK_PLL_MIPI 17 +#define CLK_PLL_HSIC 18 +#define CLK_PLL_DE 19 +#define CLK_PLL_DDR1 20 +#define CLK_CPUX 21 +#define CLK_AXI 22 +#define CLK_APB 23 +#define CLK_AHB1 24 +#define CLK_APB1 25 +#define CLK_APB2 26 +#define CLK_AHB2 27 + +/* All the bus gates are exported */ + +/* The first bunch of module clocks are exported */ + +#define CLK_USB_OHCI0_12M 90 + +#define CLK_USB_OHCI1_12M 92 + +#define CLK_DRAM 94 + +/* All the DRAM gates are exported */ + +/* Some more module clocks are exported */ + +#define CLK_MBUS 112 + +/* And the DSI and GPU module clock is exported */ + +#define CLK_NUMBER (CLK_GPU + 1) + +#endif /* _CCU_SUN50I_A64_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 79596463e0d9..4a82a49cff5e 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -191,6 +191,8 @@ static struct clk_div_table axi_div_table[] = { static SUNXI_CCU_DIV_TABLE(axi_clk, "axi", "cpu", 0x050, 0, 3, axi_div_table, 0); +#define SUN6I_A31_AHB1_REG 0x054 + static const char * const ahb1_parents[] = { "osc32k", "osc24M", "axi", "pll-periph" }; @@ -1230,6 +1232,16 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node) val &= BIT(16); writel(val, reg + SUN6I_A31_PLL_MIPI_REG); + /* Force AHB1 to PLL6 / 3 */ + val = readl(reg + SUN6I_A31_AHB1_REG); + /* set PLL6 pre-div = 3 */ + val &= ~GENMASK(7, 6); + val |= 0x2 << 6; + /* select PLL6 / pre-div */ + val &= ~GENMASK(13, 12); + val |= 0x3 << 12; + writel(val, reg + SUN6I_A31_AHB1_REG); + sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc); ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk, diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 2646d980087b..5c6d37bdf247 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -344,10 +344,10 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", "pll-audio-2x", "pll-audio" }; static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, - 0x0b0, 16, 2, BIT(31), 0); + 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, - 0x0b4, 16, 2, BIT(31), 0); + 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); /* TODO: the parent for most of the USB clocks is not known */ static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", @@ -415,7 +415,7 @@ static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", 0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", - 0x140, BIT(31), 0); + 0x140, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x144, BIT(31), 0); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 4d70590f05e3..21c427d86f28 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -394,16 +394,16 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents, 0x0a4, static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x", "pll-audio-2x", "pll-audio" }; static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents, - 0x0b0, 16, 2, BIT(31), 0); + 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents, - 0x0b4, 16, 2, BIT(31), 0); + 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_MUX_WITH_GATE(i2s2_clk, "i2s2", i2s_parents, - 0x0b8, 16, 2, BIT(31), 0); + 0x0b8, 16, 2, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio", - 0x0c0, 0, 4, BIT(31), 0); + 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", 0x0cc, BIT(8), 0); @@ -466,7 +466,7 @@ static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", 0x13c, 16, 3, BIT(31), 0); static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio", - 0x140, BIT(31), 0); + 0x140, BIT(31), CLK_SET_RATE_PARENT); static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x144, BIT(31), 0); diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 34c338832c0d..06540f7cf41c 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -20,7 +20,7 @@ #include "ccu_mux.h" /** - * struct _ccu_div - Internal divider description + * struct ccu_div_internal - Internal divider description * @shift: Bit offset of the divider in its register * @width: Width of the divider field in its register * @max: Maximum value allowed for that divider. This is the @@ -36,7 +36,7 @@ * It is basically a wrapper around the clk_divider functions * arguments. */ -struct _ccu_div { +struct ccu_div_internal { u8 shift; u8 width; @@ -78,7 +78,7 @@ struct _ccu_div { struct ccu_div { u32 enable; - struct _ccu_div div; + struct ccu_div_internal div; struct ccu_mux_internal mux; struct ccu_common common; }; diff --git a/drivers/clk/sunxi-ng/ccu_frac.c b/drivers/clk/sunxi-ng/ccu_frac.c index 5c4b10cd15b5..8b5eb7756bf7 100644 --- a/drivers/clk/sunxi-ng/ccu_frac.c +++ b/drivers/clk/sunxi-ng/ccu_frac.c @@ -14,7 +14,7 @@ #include "ccu_frac.h" bool ccu_frac_helper_is_enabled(struct ccu_common *common, - struct _ccu_frac *cf) + struct ccu_frac_internal *cf) { if (!(common->features & CCU_FEATURE_FRACTIONAL)) return false; @@ -23,7 +23,7 @@ bool ccu_frac_helper_is_enabled(struct ccu_common *common, } void ccu_frac_helper_enable(struct ccu_common *common, - struct _ccu_frac *cf) + struct ccu_frac_internal *cf) { unsigned long flags; u32 reg; @@ -38,7 +38,7 @@ void ccu_frac_helper_enable(struct ccu_common *common, } void ccu_frac_helper_disable(struct ccu_common *common, - struct _ccu_frac *cf) + struct ccu_frac_internal *cf) { unsigned long flags; u32 reg; @@ -53,7 +53,7 @@ void ccu_frac_helper_disable(struct ccu_common *common, } bool ccu_frac_helper_has_rate(struct ccu_common *common, - struct _ccu_frac *cf, + struct ccu_frac_internal *cf, unsigned long rate) { if (!(common->features & CCU_FEATURE_FRACTIONAL)) @@ -63,7 +63,7 @@ bool ccu_frac_helper_has_rate(struct ccu_common *common, } unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, - struct _ccu_frac *cf) + struct ccu_frac_internal *cf) { u32 reg; @@ -84,7 +84,7 @@ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, } int ccu_frac_helper_set_rate(struct ccu_common *common, - struct _ccu_frac *cf, + struct ccu_frac_internal *cf, unsigned long rate) { unsigned long flags; diff --git a/drivers/clk/sunxi-ng/ccu_frac.h b/drivers/clk/sunxi-ng/ccu_frac.h index e4c670b1cdfe..7b1ee380156f 100644 --- a/drivers/clk/sunxi-ng/ccu_frac.h +++ b/drivers/clk/sunxi-ng/ccu_frac.h @@ -18,7 +18,7 @@ #include "ccu_common.h" -struct _ccu_frac { +struct ccu_frac_internal { u32 enable; u32 select; @@ -33,21 +33,21 @@ struct _ccu_frac { } bool ccu_frac_helper_is_enabled(struct ccu_common *common, - struct _ccu_frac *cf); + struct ccu_frac_internal *cf); void ccu_frac_helper_enable(struct ccu_common *common, - struct _ccu_frac *cf); + struct ccu_frac_internal *cf); void ccu_frac_helper_disable(struct ccu_common *common, - struct _ccu_frac *cf); + struct ccu_frac_internal *cf); bool ccu_frac_helper_has_rate(struct ccu_common *common, - struct _ccu_frac *cf, + struct ccu_frac_internal *cf, unsigned long rate); unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, - struct _ccu_frac *cf); + struct ccu_frac_internal *cf); int ccu_frac_helper_set_rate(struct ccu_common *common, - struct _ccu_frac *cf, + struct ccu_frac_internal *cf, unsigned long rate); #endif /* _CCU_FRAC_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index edf9215ea8cc..915625e97d98 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -29,8 +29,8 @@ struct ccu_mp { u32 enable; - struct _ccu_div m; - struct _ccu_div p; + struct ccu_div_internal m; + struct ccu_div_internal p; struct ccu_mux_internal mux; struct ccu_common common; }; diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c index 010e9424691d..678b6cb49f01 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.c +++ b/drivers/clk/sunxi-ng/ccu_mult.c @@ -13,10 +13,23 @@ #include "ccu_gate.h" #include "ccu_mult.h" +struct _ccu_mult { + unsigned long mult, min, max; +}; + static void ccu_mult_find_best(unsigned long parent, unsigned long rate, - unsigned int max_n, unsigned int *n) + struct _ccu_mult *mult) { - *n = rate / parent; + int _mult; + + _mult = rate / parent; + if (_mult < mult->min) + _mult = mult->min; + + if (_mult > mult->max) + _mult = mult->max; + + mult->mult = _mult; } static unsigned long ccu_mult_round_rate(struct ccu_mux_internal *mux, @@ -25,11 +38,13 @@ static unsigned long ccu_mult_round_rate(struct ccu_mux_internal *mux, void *data) { struct ccu_mult *cm = data; - unsigned int n; + struct _ccu_mult _cm; - ccu_mult_find_best(parent_rate, rate, 1 << cm->mult.width, &n); + _cm.min = 1; + _cm.max = 1 << cm->mult.width; + ccu_mult_find_best(parent_rate, rate, &_cm); - return parent_rate * n; + return parent_rate * _cm.mult; } static void ccu_mult_disable(struct clk_hw *hw) @@ -83,21 +98,23 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct ccu_mult *cm = hw_to_ccu_mult(hw); + struct _ccu_mult _cm; unsigned long flags; - unsigned int n; u32 reg; ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1, &parent_rate); - ccu_mult_find_best(parent_rate, rate, 1 << cm->mult.width, &n); + _cm.min = cm->mult.min; + _cm.max = 1 << cm->mult.width; + ccu_mult_find_best(parent_rate, rate, &_cm); spin_lock_irqsave(cm->common.lock, flags); reg = readl(cm->common.base + cm->common.reg); reg &= ~GENMASK(cm->mult.width + cm->mult.shift - 1, cm->mult.shift); - writel(reg | ((n - 1) << cm->mult.shift), + writel(reg | ((_cm.mult - 1) << cm->mult.shift), cm->common.base + cm->common.reg); spin_unlock_irqrestore(cm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_mult.h b/drivers/clk/sunxi-ng/ccu_mult.h index 5d2c8dc14073..c1a2134bdc71 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.h +++ b/drivers/clk/sunxi-ng/ccu_mult.h @@ -4,21 +4,26 @@ #include "ccu_common.h" #include "ccu_mux.h" -struct _ccu_mult { +struct ccu_mult_internal { u8 shift; u8 width; + u8 min; }; -#define _SUNXI_CCU_MULT(_shift, _width) \ - { \ - .shift = _shift, \ - .width = _width, \ +#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min) \ + { \ + .shift = _shift, \ + .width = _width, \ + .min = _min, \ } +#define _SUNXI_CCU_MULT(_shift, _width) \ + _SUNXI_CCU_MULT_MIN(_shift, _width, 1) + struct ccu_mult { u32 enable; - struct _ccu_mult mult; + struct ccu_mult_internal mult; struct ccu_mux_internal mux; struct ccu_common common; }; diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c index d6fafb397489..eaf0fdf78d2b 100644 --- a/drivers/clk/sunxi-ng/ccu_nk.c +++ b/drivers/clk/sunxi-ng/ccu_nk.c @@ -9,21 +9,24 @@ */ #include <linux/clk-provider.h> -#include <linux/rational.h> #include "ccu_gate.h" #include "ccu_nk.h" +struct _ccu_nk { + unsigned long n, min_n, max_n; + unsigned long k, min_k, max_k; +}; + static void ccu_nk_find_best(unsigned long parent, unsigned long rate, - unsigned int max_n, unsigned int max_k, - unsigned int *n, unsigned int *k) + struct _ccu_nk *nk) { unsigned long best_rate = 0; unsigned int best_k = 0, best_n = 0; unsigned int _k, _n; - for (_k = 1; _k <= max_k; _k++) { - for (_n = 1; _n <= max_n; _n++) { + for (_k = nk->min_k; _k <= nk->max_k; _k++) { + for (_n = nk->min_n; _n <= nk->max_n; _n++) { unsigned long tmp_rate = parent * _n * _k; if (tmp_rate > rate) @@ -37,8 +40,8 @@ static void ccu_nk_find_best(unsigned long parent, unsigned long rate, } } - *k = best_k; - *n = best_n; + nk->k = best_k; + nk->n = best_n; } static void ccu_nk_disable(struct clk_hw *hw) @@ -89,16 +92,19 @@ static long ccu_nk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct ccu_nk *nk = hw_to_ccu_nk(hw); - unsigned int n, k; + struct _ccu_nk _nk; if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV) rate *= nk->fixed_post_div; - ccu_nk_find_best(*parent_rate, rate, - 1 << nk->n.width, 1 << nk->k.width, - &n, &k); + _nk.min_n = nk->n.min; + _nk.max_n = 1 << nk->n.width; + _nk.min_k = nk->k.min; + _nk.max_k = 1 << nk->k.width; + + ccu_nk_find_best(*parent_rate, rate, &_nk); + rate = *parent_rate * _nk.n * _nk.k; - rate = *parent_rate * n * k; if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV) rate = rate / nk->fixed_post_div; @@ -110,15 +116,18 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate, { struct ccu_nk *nk = hw_to_ccu_nk(hw); unsigned long flags; - unsigned int n, k; + struct _ccu_nk _nk; u32 reg; if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV) rate = rate * nk->fixed_post_div; - ccu_nk_find_best(parent_rate, rate, - 1 << nk->n.width, 1 << nk->k.width, - &n, &k); + _nk.min_n = nk->n.min; + _nk.max_n = 1 << nk->n.width; + _nk.min_k = nk->k.min; + _nk.max_k = 1 << nk->k.width; + + ccu_nk_find_best(parent_rate, rate, &_nk); spin_lock_irqsave(nk->common.lock, flags); @@ -126,7 +135,7 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate, reg &= ~GENMASK(nk->n.width + nk->n.shift - 1, nk->n.shift); reg &= ~GENMASK(nk->k.width + nk->k.shift - 1, nk->k.shift); - writel(reg | ((k - 1) << nk->k.shift) | ((n - 1) << nk->n.shift), + writel(reg | ((_nk.k - 1) << nk->k.shift) | ((_nk.n - 1) << nk->n.shift), nk->common.base + nk->common.reg); spin_unlock_irqrestore(nk->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nk.h b/drivers/clk/sunxi-ng/ccu_nk.h index 4b52da0c29fe..437836b80696 100644 --- a/drivers/clk/sunxi-ng/ccu_nk.h +++ b/drivers/clk/sunxi-ng/ccu_nk.h @@ -30,8 +30,8 @@ struct ccu_nk { u32 enable; u32 lock; - struct _ccu_mult n; - struct _ccu_mult k; + struct ccu_mult_internal n; + struct ccu_mult_internal k; unsigned int fixed_post_div; diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 059fdc3b4f96..9b840a47a94d 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -9,15 +9,14 @@ */ #include <linux/clk-provider.h> -#include <linux/rational.h> #include "ccu_gate.h" #include "ccu_nkm.h" struct _ccu_nkm { - unsigned long n, max_n; - unsigned long k, max_k; - unsigned long m, max_m; + unsigned long n, min_n, max_n; + unsigned long k, min_k, max_k; + unsigned long m, min_m, max_m; }; static void ccu_nkm_find_best(unsigned long parent, unsigned long rate, @@ -27,22 +26,22 @@ static void ccu_nkm_find_best(unsigned long parent, unsigned long rate, unsigned long best_n = 0, best_k = 0, best_m = 0; unsigned long _n, _k, _m; - for (_k = 1; _k <= nkm->max_k; _k++) { - unsigned long tmp_rate; - - rational_best_approximation(rate / _k, parent, - nkm->max_n, nkm->max_m, &_n, &_m); - - tmp_rate = parent * _n * _k / _m; - - if (tmp_rate > rate) - continue; - - if ((rate - tmp_rate) < (rate - best_rate)) { - best_rate = tmp_rate; - best_n = _n; - best_k = _k; - best_m = _m; + for (_k = nkm->min_k; _k <= nkm->max_k; _k++) { + for (_n = nkm->min_n; _n <= nkm->max_n; _n++) { + for (_m = nkm->min_m; _m <= nkm->max_m; _m++) { + unsigned long tmp_rate; + + tmp_rate = parent * _n * _k / _m; + + if (tmp_rate > rate) + continue; + if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_k = _k; + best_m = _m; + } + } } } @@ -101,8 +100,11 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, struct ccu_nkm *nkm = data; struct _ccu_nkm _nkm; + _nkm.min_n = nkm->n.min; _nkm.max_n = 1 << nkm->n.width; + _nkm.min_k = nkm->k.min; _nkm.max_k = 1 << nkm->k.width; + _nkm.min_m = 1; _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); @@ -127,8 +129,11 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + _nkm.min_n = nkm->n.min; _nkm.max_n = 1 << nkm->n.width; + _nkm.min_k = nkm->k.min; _nkm.max_k = 1 << nkm->k.width; + _nkm.min_m = 1; _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; ccu_nkm_find_best(parent_rate, rate, &_nkm); diff --git a/drivers/clk/sunxi-ng/ccu_nkm.h b/drivers/clk/sunxi-ng/ccu_nkm.h index 35493fddd8ab..34580894f4d1 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.h +++ b/drivers/clk/sunxi-ng/ccu_nkm.h @@ -29,9 +29,9 @@ struct ccu_nkm { u32 enable; u32 lock; - struct _ccu_mult n; - struct _ccu_mult k; - struct _ccu_div m; + struct ccu_mult_internal n; + struct ccu_mult_internal k; + struct ccu_div_internal m; struct ccu_mux_internal mux; struct ccu_common common; diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index 9769dee99511..684c42da3ebb 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -9,16 +9,15 @@ */ #include <linux/clk-provider.h> -#include <linux/rational.h> #include "ccu_gate.h" #include "ccu_nkmp.h" struct _ccu_nkmp { - unsigned long n, max_n; - unsigned long k, max_k; - unsigned long m, max_m; - unsigned long p, max_p; + unsigned long n, min_n, max_n; + unsigned long k, min_k, max_k; + unsigned long m, min_m, max_m; + unsigned long p, min_p, max_p; }; static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, @@ -28,25 +27,25 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate, unsigned long best_n = 0, best_k = 0, best_m = 0, best_p = 0; unsigned long _n, _k, _m, _p; - for (_k = 1; _k <= nkmp->max_k; _k++) { - for (_p = 1; _p <= nkmp->max_p; _p <<= 1) { - unsigned long tmp_rate; - - rational_best_approximation(rate / _k, parent / _p, - nkmp->max_n, nkmp->max_m, - &_n, &_m); - - tmp_rate = parent * _n * _k / (_m * _p); - - if (tmp_rate > rate) - continue; - - if ((rate - tmp_rate) < (rate - best_rate)) { - best_rate = tmp_rate; - best_n = _n; - best_k = _k; - best_m = _m; - best_p = _p; + for (_k = nkmp->min_k; _k <= nkmp->max_k; _k++) { + for (_n = nkmp->min_n; _n <= nkmp->max_n; _n++) { + for (_m = nkmp->min_m; _m <= nkmp->max_m; _m++) { + for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) { + unsigned long tmp_rate; + + tmp_rate = parent * _n * _k / (_m * _p); + + if (tmp_rate > rate) + continue; + + if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_k = _k; + best_m = _m; + best_p = _p; + } + } } } } @@ -108,9 +107,13 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw); struct _ccu_nkmp _nkmp; + _nkmp.min_n = nkmp->n.min; _nkmp.max_n = 1 << nkmp->n.width; + _nkmp.min_k = nkmp->k.min; _nkmp.max_k = 1 << nkmp->k.width; + _nkmp.min_m = 1; _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.min_p = 1; _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); ccu_nkmp_find_best(*parent_rate, rate, &_nkmp); @@ -126,9 +129,13 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags; u32 reg; + _nkmp.min_n = 1; _nkmp.max_n = 1 << nkmp->n.width; + _nkmp.min_k = 1; _nkmp.max_k = 1 << nkmp->k.width; + _nkmp.min_m = 1; _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; + _nkmp.min_p = 1; _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1); ccu_nkmp_find_best(parent_rate, rate, &_nkmp); diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h index 5adb0c92a614..a82facbc6144 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.h +++ b/drivers/clk/sunxi-ng/ccu_nkmp.h @@ -29,10 +29,10 @@ struct ccu_nkmp { u32 enable; u32 lock; - struct _ccu_mult n; - struct _ccu_mult k; - struct _ccu_div m; - struct _ccu_div p; + struct ccu_mult_internal n; + struct ccu_mult_internal k; + struct ccu_div_internal m; + struct ccu_div_internal p; struct ccu_common common; }; diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index b61bdd8c7a7f..c9f3b6c982f0 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -9,12 +9,42 @@ */ #include <linux/clk-provider.h> -#include <linux/rational.h> #include "ccu_frac.h" #include "ccu_gate.h" #include "ccu_nm.h" +struct _ccu_nm { + unsigned long n, min_n, max_n; + unsigned long m, min_m, max_m; +}; + +static void ccu_nm_find_best(unsigned long parent, unsigned long rate, + struct _ccu_nm *nm) +{ + unsigned long best_rate = 0; + unsigned long best_n = 0, best_m = 0; + unsigned long _n, _m; + + for (_n = nm->min_n; _n <= nm->max_n; _n++) { + for (_m = nm->min_m; _m <= nm->max_m; _m++) { + unsigned long tmp_rate = parent * _n / _m; + + if (tmp_rate > rate) + continue; + + if ((rate - tmp_rate) < (rate - best_rate)) { + best_rate = tmp_rate; + best_n = _n; + best_m = _m; + } + } + } + + nm->n = best_n; + nm->m = best_m; +} + static void ccu_nm_disable(struct clk_hw *hw) { struct ccu_nm *nm = hw_to_ccu_nm(hw); @@ -61,24 +91,24 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); - unsigned long max_n, max_m; - unsigned long n, m; + struct _ccu_nm _nm; - max_n = 1 << nm->n.width; - max_m = nm->m.max ?: 1 << nm->m.width; + _nm.min_n = nm->n.min; + _nm.max_n = 1 << nm->n.width; + _nm.min_m = 1; + _nm.max_m = nm->m.max ?: 1 << nm->m.width; - rational_best_approximation(rate, *parent_rate, max_n, max_m, &n, &m); + ccu_nm_find_best(*parent_rate, rate, &_nm); - return *parent_rate * n / m; + return *parent_rate * _nm.n / _nm.m; } static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct ccu_nm *nm = hw_to_ccu_nm(hw); + struct _ccu_nm _nm; unsigned long flags; - unsigned long max_n, max_m; - unsigned long n, m; u32 reg; if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) @@ -86,10 +116,12 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, else ccu_frac_helper_disable(&nm->common, &nm->frac); - max_n = 1 << nm->n.width; - max_m = nm->m.max ?: 1 << nm->m.width; + _nm.min_n = 1; + _nm.max_n = 1 << nm->n.width; + _nm.min_m = 1; + _nm.max_m = nm->m.max ?: 1 << nm->m.width; - rational_best_approximation(rate, parent_rate, max_n, max_m, &n, &m); + ccu_nm_find_best(parent_rate, rate, &_nm); spin_lock_irqsave(nm->common.lock, flags); @@ -97,7 +129,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, reg &= ~GENMASK(nm->n.width + nm->n.shift - 1, nm->n.shift); reg &= ~GENMASK(nm->m.width + nm->m.shift - 1, nm->m.shift); - writel(reg | ((m - 1) << nm->m.shift) | ((n - 1) << nm->n.shift), + writel(reg | ((_nm.m - 1) << nm->m.shift) | ((_nm.n - 1) << nm->n.shift), nm->common.base + nm->common.reg); spin_unlock_irqrestore(nm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index 0b7bcd33a2df..e87fd186da78 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -30,9 +30,9 @@ struct ccu_nm { u32 enable; u32 lock; - struct _ccu_mult n; - struct _ccu_div m; - struct _ccu_frac frac; + struct ccu_mult_internal n; + struct ccu_div_internal m; + struct ccu_frac_internal frac; struct ccu_common common; }; diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index e54266cc1c51..4417ae129ac7 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -24,7 +24,7 @@ #include "clk-factors.h" /** - * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks + * sun4i_a10_get_mod0_factors() - calculates m, n factors for MOD0-style clocks * MOD0 rate is calculated as follows * rate = (parent_rate >> p) / (m + 1); */ diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 838b22aa8b67..f2c9274b8bd5 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -373,7 +373,7 @@ static void sun4i_get_apb1_factors(struct factors_request *req) else calcp = 3; - calcm = (req->parent_rate >> calcp) - 1; + calcm = (div >> calcp) - 1; req->rate = (req->parent_rate >> calcp) / (calcm + 1); req->m = calcm; diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index c205809ba580..ad1c1cc829cb 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -20,7 +20,7 @@ #include <linux/cpu.h> #include <linux/err.h> #include <linux/kernel.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/platform_device.h> #include <soc/tegra/fuse.h> @@ -148,7 +148,6 @@ static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { { .compatible = "nvidia,tegra124-dfll", }, { }, }; -MODULE_DEVICE_TABLE(of, tegra124_dfll_fcpu_of_match); static const struct dev_pm_ops tegra124_dfll_pm_ops = { SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend, @@ -164,20 +163,4 @@ static struct platform_driver tegra124_dfll_fcpu_driver = { .pm = &tegra124_dfll_pm_ops, }, }; - -static int __init tegra124_dfll_fcpu_init(void) -{ - return platform_driver_register(&tegra124_dfll_fcpu_driver); -} -module_init(tegra124_dfll_fcpu_init); - -static void __exit tegra124_dfll_fcpu_exit(void) -{ - platform_driver_unregister(&tegra124_dfll_fcpu_driver); -} -module_exit(tegra124_dfll_fcpu_exit); - -MODULE_DESCRIPTION("Tegra124 DFLL clock source driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Aleksandr Frid <afrid@nvidia.com>"); -MODULE_AUTHOR("Paul Walmsley <pwalmsley@nvidia.com>"); +builtin_platform_driver(tegra124_dfll_fcpu_driver); diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c index 624115e82ff9..da9e8e7b5ce5 100644 --- a/drivers/clk/tegra/cvb.c +++ b/drivers/clk/tegra/cvb.c @@ -92,19 +92,19 @@ static int build_opp_table(struct device *dev, const struct cvb_table *table, /** * tegra_cvb_add_opp_table - build OPP table from Tegra CVB tables - * @cvb_tables: array of CVB tables - * @sz: size of the previously mentioned array + * @dev: the struct device * for which the OPP table is built + * @tables: array of CVB tables + * @count: size of the previously mentioned array * @process_id: process id of the HW module * @speedo_id: speedo id of the HW module * @speedo_value: speedo value of the HW module - * @max_rate: highest safe clock rate - * @opp_dev: the struct device * for which the OPP table is built + * @max_freq: highest safe clock rate * * On Tegra, a CVB table encodes the relationship between operating voltage * and safe maximal frequency for a given module (e.g. GPU or CPU). This * function calculates the optimal voltage-frequency operating points * for the given arguments and exports them via the OPP library for the - * given @opp_dev. Returns a pointer to the struct cvb_table that matched + * given @dev. Returns a pointer to the struct cvb_table that matched * or an ERR_PTR on failure. */ const struct cvb_table * diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index c77333230bdf..45d05339d583 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include <linux/module.h> +#include <linux/init.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/slab.h> @@ -295,31 +295,17 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) return ret; } -static int of_dra7_atl_clk_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); - - return 0; -} - static const struct of_device_id of_dra7_atl_clk_match_tbl[] = { { .compatible = "ti,dra7-atl", }, {}, }; -MODULE_DEVICE_TABLE(of, of_dra7_atl_clk_match_tbl); static struct platform_driver dra7_atl_clk_driver = { .driver = { .name = "dra7-atl", + .suppress_bind_attrs = true, .of_match_table = of_dra7_atl_clk_match_tbl, }, .probe = of_dra7_atl_clk_probe, - .remove = of_dra7_atl_clk_remove, }; - -module_platform_driver(dra7_atl_clk_driver); - -MODULE_DESCRIPTION("Clock driver for DRA7 Audio Tracking Logic"); -MODULE_ALIAS("platform:dra7-atl-clock"); -MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(dra7_atl_clk_driver); diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 5ffb898d0839..26c53f7963a4 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -79,7 +79,7 @@ static int uniphier_clk_probe(struct platform_device *pdev) hw_data->num = clk_num; /* avoid returning NULL for unused idx */ - for (; clk_num >= 0; clk_num--) + while (--clk_num >= 0) hw_data->hws[clk_num] = ERR_PTR(-EINVAL); for (p = data; p->name; p++) { @@ -111,6 +111,10 @@ static int uniphier_clk_remove(struct platform_device *pdev) static const struct of_device_id uniphier_clk_match[] = { /* System clock */ { + .compatible = "socionext,uniphier-sld3-clock", + .data = uniphier_sld3_sys_clk_data, + }, + { .compatible = "socionext,uniphier-ld4-clock", .data = uniphier_ld4_sys_clk_data, }, @@ -138,7 +142,7 @@ static const struct of_device_id uniphier_clk_match[] = { .compatible = "socionext,uniphier-ld20-clock", .data = uniphier_ld20_sys_clk_data, }, - /* Media I/O clock */ + /* Media I/O clock, SD clock */ { .compatible = "socionext,uniphier-sld3-mio-clock", .data = uniphier_sld3_mio_clk_data, @@ -156,20 +160,20 @@ static const struct of_device_id uniphier_clk_match[] = { .data = uniphier_sld3_mio_clk_data, }, { - .compatible = "socionext,uniphier-pro5-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-pro5-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, { - .compatible = "socionext,uniphier-pxs2-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-pxs2-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, { .compatible = "socionext,uniphier-ld11-mio-clock", .data = uniphier_sld3_mio_clk_data, }, { - .compatible = "socionext,uniphier-ld20-mio-clock", - .data = uniphier_pro5_mio_clk_data, + .compatible = "socionext,uniphier-ld20-sd-clock", + .data = uniphier_pro5_sd_clk_data, }, /* Peripheral clock */ { diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c index 6aa7ec768d0b..218d20f099ce 100644 --- a/drivers/clk/uniphier/clk-uniphier-mio.c +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -93,7 +93,7 @@ const struct uniphier_clk_data uniphier_sld3_mio_clk_data[] = { { /* sentinel */ } }; -const struct uniphier_clk_data uniphier_pro5_mio_clk_data[] = { +const struct uniphier_clk_data uniphier_pro5_sd_clk_data[] = { UNIPHIER_MIO_CLK_SD_FIXED, UNIPHIER_MIO_CLK_SD(0, 0), UNIPHIER_MIO_CLK_SD(1, 1), diff --git a/drivers/clk/uniphier/clk-uniphier-mux.c b/drivers/clk/uniphier/clk-uniphier-mux.c index 15a2f2cbe0d9..2c243a894f3b 100644 --- a/drivers/clk/uniphier/clk-uniphier-mux.c +++ b/drivers/clk/uniphier/clk-uniphier-mux.c @@ -42,7 +42,7 @@ static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw) struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw); int num_parents = clk_hw_get_num_parents(hw); int ret; - u32 val; + unsigned int val; u8 i; ret = regmap_read(mux->regmap, mux->reg, &val); diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h index 3ae184062388..0244dba1f4cf 100644 --- a/drivers/clk/uniphier/clk-uniphier.h +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -115,7 +115,7 @@ extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[]; extern const struct uniphier_clk_data uniphier_sld3_mio_clk_data[]; -extern const struct uniphier_clk_data uniphier_pro5_mio_clk_data[]; +extern const struct uniphier_clk_data uniphier_pro5_sd_clk_data[]; extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[]; extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[]; |