diff options
author | Stephen Boyd <sboyd@kernel.org> | 2018-12-13 01:05:44 -0800 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2018-12-13 01:05:44 -0800 |
commit | e74581b79ddd9b49b8c61e2791fc4dffc0245afb (patch) | |
tree | 5ab61c8c9120ff519d6e4802555962d4c1ec7619 /drivers | |
parent | 8913e8a73d03470b7aeaeab9c4f4fd3b50a0e2ec (diff) | |
parent | f03566d0aa79f9e09a288936980741c479a22fdb (diff) |
Merge tag 'meson-clk-4.21-2' of https://github.com/BayLibre/clk-meson into clk-meson
Pull more meson clk driver updates from Neil Armstrong:
- Fix GXL HDMI Pll fractional bits (from first round)
- Add the Meson8/Meson8b video clocks
- Add clk-input helper and use it for axg-audio clock driver
* tag 'meson-clk-4.21-2' of https://github.com/BayLibre/clk-meson:
clk: meson: axg-audio: use the clk input helper function
clk: meson: add clk-input helper function
clk: meson: meson8b: add the read-only video clock trees
clk: meson: meson8b: add the fractional divider for vid_pll_dco
clk: meson: meson8b: fix the offset of vid_pll_dco's N value
clk: meson: Fix GXL HDMI PLL fractional bits width
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/meson/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/meson/axg-audio.c | 83 | ||||
-rw-r--r-- | drivers/clk/meson/clk-input.c | 44 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 5 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 8 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.c | 746 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.h | 54 |
7 files changed, 870 insertions, 71 deletions
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 0234767f6cfc..a849aa809825 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index 5f6c860aa122..8ac3a2295473 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -631,22 +631,23 @@ static struct clk_regmap *const axg_audio_clk_regmaps[] = { &axg_tdmout_c_lrclk, }; -static struct clk *devm_clk_get_enable(struct device *dev, char *id) +static int devm_clk_get_enable(struct device *dev, char *id) { struct clk *clk; int ret; clk = devm_clk_get(dev, id); if (IS_ERR(clk)) { - if (PTR_ERR(clk) != -EPROBE_DEFER) + ret = PTR_ERR(clk); + if (ret != -EPROBE_DEFER) dev_err(dev, "failed to get %s", id); - return clk; + return ret; } ret = clk_prepare_enable(clk); if (ret) { dev_err(dev, "failed to enable %s", id); - return ERR_PTR(ret); + return ret; } ret = devm_add_action_or_reset(dev, @@ -654,74 +655,40 @@ static struct clk *devm_clk_get_enable(struct device *dev, char *id) clk); if (ret) { dev_err(dev, "failed to add reset action on %s", id); - return ERR_PTR(ret); + return ret; } - return clk; -} - -static const struct clk_ops axg_clk_no_ops = {}; - -static struct clk_hw *axg_clk_hw_register_bypass(struct device *dev, - const char *name, - const char *parent_name) -{ - struct clk_hw *hw; - struct clk_init_data init; - char *clk_name; - int ret; - - hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); - if (!hw) - return ERR_PTR(-ENOMEM); - - clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); - if (!clk_name) - return ERR_PTR(-ENOMEM); - - init.name = clk_name; - init.ops = &axg_clk_no_ops; - init.flags = 0; - init.parent_names = parent_name ? &parent_name : NULL; - init.num_parents = parent_name ? 1 : 0; - hw->init = &init; - - ret = devm_clk_hw_register(dev, hw); - kfree(clk_name); - - return ret ? ERR_PTR(ret) : hw; + return 0; } static int axg_register_clk_hw_input(struct device *dev, const char *name, unsigned int clkid) { - struct clk *parent_clk = devm_clk_get(dev, name); - struct clk_hw *hw = NULL; + char *clk_name; + struct clk_hw *hw; + int err = 0; - if (IS_ERR(parent_clk)) { - int err = PTR_ERR(parent_clk); + clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); + if (!clk_name) + return -ENOMEM; + hw = meson_clk_hw_register_input(dev, name, clk_name, 0); + if (IS_ERR(hw)) { /* It is ok if an input clock is missing */ - if (err == -ENOENT) { + if (PTR_ERR(hw) == -ENOENT) { dev_dbg(dev, "%s not provided", name); } else { + err = PTR_ERR(hw); if (err != -EPROBE_DEFER) dev_err(dev, "failed to get %s clock", name); - return err; } } else { - hw = axg_clk_hw_register_bypass(dev, name, - __clk_get_name(parent_clk)); - } - - if (IS_ERR(hw)) { - dev_err(dev, "failed to register %s clock", name); - return PTR_ERR(hw); + axg_audio_hw_onecell_data.hws[clkid] = hw; } - axg_audio_hw_onecell_data.hws[clkid] = hw; - return 0; + kfree(clk_name); + return err; } static int axg_register_clk_hw_inputs(struct device *dev, @@ -759,7 +726,6 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) struct regmap *map; struct resource *res; void __iomem *regs; - struct clk *clk; struct clk_hw *hw; int ret, i; @@ -775,9 +741,9 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) } /* Get the mandatory peripheral clock */ - clk = devm_clk_get_enable(dev, "pclk"); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ret = devm_clk_get_enable(dev, "pclk"); + if (ret) + return ret; ret = device_reset(dev); if (ret) { @@ -786,8 +752,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) } /* Register the peripheral input clock */ - hw = axg_clk_hw_register_bypass(dev, "audio_pclk", - __clk_get_name(clk)); + hw = meson_clk_hw_register_input(dev, "pclk", "axg_audio_pclk", 0); if (IS_ERR(hw)) return PTR_ERR(hw); diff --git a/drivers/clk/meson/clk-input.c b/drivers/clk/meson/clk-input.c new file mode 100644 index 000000000000..06b3e3bb6a66 --- /dev/null +++ b/drivers/clk/meson/clk-input.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (c) 2018 BayLibre, SAS. + * Author: Jerome Brunet <jbrunet@baylibre.com> + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/device.h> +#include "clkc.h" + +static const struct clk_ops meson_clk_no_ops = {}; + +struct clk_hw *meson_clk_hw_register_input(struct device *dev, + const char *of_name, + const char *clk_name, + unsigned long flags) +{ + struct clk *parent_clk = devm_clk_get(dev, of_name); + struct clk_init_data init; + const char *parent_name; + struct clk_hw *hw; + int ret; + + if (IS_ERR(parent_clk)) + return (struct clk_hw *)parent_clk; + + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return ERR_PTR(-ENOMEM); + + parent_name = __clk_get_name(parent_clk); + init.name = clk_name; + init.ops = &meson_clk_no_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + hw->init = &init; + + ret = devm_clk_hw_register(dev, hw); + + return ret ? ERR_PTR(ret) : hw; +} +EXPORT_SYMBOL_GPL(meson_clk_hw_register_input); diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 91666055c75a..6183b22c4bf2 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -119,4 +119,9 @@ extern const struct clk_ops meson_clk_mpll_ops; extern const struct clk_ops meson_clk_phase_ops; extern const struct clk_ops meson_vid_pll_div_ro_ops; +struct clk_hw *meson_clk_hw_register_input(struct device *dev, + const char *of_name, + const char *clk_name, + unsigned long flags); + #endif /* __CLKC_H */ diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index b92df222f553..9290465c0589 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -216,10 +216,16 @@ static struct clk_regmap gxl_hdmi_pll_dco = { .shift = 9, .width = 5, }, + /* + * On gxl, there is a register shift due to + * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, + * so we use the HHI_HDMI_PLL_CNTL2 define from GXBB + * instead which is defined at the same offset. + */ .frac = { .reg_off = HHI_HDMI_PLL_CNTL2, .shift = 0, - .width = 12, + .width = 10, }, .l = { .reg_off = HHI_HDMI_PLL_CNTL, diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index f906a9f0eefd..950d0e548c75 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -120,7 +120,7 @@ static struct clk_regmap meson8b_fixed_pll = { }, }; -static struct clk_regmap meson8b_vid_pll_dco = { +static struct clk_regmap meson8b_hdmi_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { .reg_off = HHI_VID_PLL_CNTL, @@ -134,9 +134,14 @@ static struct clk_regmap meson8b_vid_pll_dco = { }, .n = { .reg_off = HHI_VID_PLL_CNTL, - .shift = 9, + .shift = 10, .width = 5, }, + .frac = { + .reg_off = HHI_VID_PLL_CNTL2, + .shift = 0, + .width = 12, + }, .l = { .reg_off = HHI_VID_PLL_CNTL, .shift = 31, @@ -149,14 +154,15 @@ static struct clk_regmap meson8b_vid_pll_dco = { }, }, .hw.init = &(struct clk_init_data){ - .name = "vid_pll_dco", + /* sometimes also called "HPLL" or "HPLL PLL" */ + .name = "hdmi_pll_dco", .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, }, }; -static struct clk_regmap meson8b_vid_pll = { +static struct clk_regmap meson8b_hdmi_pll_lvds_out = { .data = &(struct clk_regmap_div_data){ .offset = HHI_VID_PLL_CNTL, .shift = 16, @@ -164,9 +170,25 @@ static struct clk_regmap meson8b_vid_pll = { .flags = CLK_DIVIDER_POWER_OF_TWO, }, .hw.init = &(struct clk_init_data){ - .name = "vid_pll", + .name = "hdmi_pll_lvds_out", .ops = &clk_regmap_divider_ro_ops, - .parent_names = (const char *[]){ "vid_pll_dco" }, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_pll_hdmi_out = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_PLL_CNTL, + .shift = 18, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_hdmi_out", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_dco" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -925,6 +947,632 @@ static struct clk_regmap meson8b_l2_dram_clk_gate = { }, }; +static struct clk_regmap meson8b_vid_pll_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_in_sel", + .ops = &clk_regmap_mux_ro_ops, + /* + * TODO: depending on the SoC there is also a second parent: + * Meson8: unknown + * Meson8b: hdmi_pll_dco + * Meson8m2: vid2_pll + */ + .parent_names = (const char *[]){ "hdmi_pll_dco" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_in_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vid_pll_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_pre_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .shift = 4, + .width = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_pre_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_post_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .shift = 12, + .width = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_post_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll_pre_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_DIVIDER_CNTL, + .mask = 0x3, + .shift = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll", + .ops = &clk_regmap_mux_ro_ops, + /* TODO: parent 0x2 is vid_pll_pre_div_mult7_div2 */ + .parent_names = (const char *[]){ "vid_pll_pre_div", + "vid_pll_post_div" }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vid_pll_final_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_final_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "vid_pll" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const char * const meson8b_vclk_mux_parents[] = { + "vid_pll_final_div", "fclk_div4", "fclk_div3", "fclk_div5", + "vid_pll_final_div", "fclk_div7", "mpll1" +}; + +static struct clk_regmap meson8b_vclk_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_in_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk_div1_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div1_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div2_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_div2" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div4_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_div4" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div6_div = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div6_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_div6" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk_div12_div = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk_div12_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_DIV, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk_div12" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_CNTL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_clk_in_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_in_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_vclk2_div1_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div1_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div2_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_div2" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div4_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_div4" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div6_div = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div6_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_div6" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_vclk2_div12_div = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "vclk2_in_en" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static struct clk_regmap meson8b_vclk2_div12_div_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VIID_CLK_DIV, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "vclk2_div12" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const char * const meson8b_vclk_enc_mux_parents[] = { + "vclk_div1_en", "vclk_div2_en", "vclk_div4_en", "vclk_div6_en", + "vclk_div12_en", +}; + +static struct clk_regmap meson8b_cts_enct_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enct_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enct = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enct", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cts_enct_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cts_encp_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cts_enci_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_tx_pixel_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0xf, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_tx_pixel = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_pixel", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "hdmi_tx_pixel_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const char * const meson8b_vclk2_enc_mux_parents[] = { + "vclk2_div1_en", "vclk2_div2_en", "vclk2_div4_en", "vclk2_div6_en", + "vclk2_div12_en", +}; + +static struct clk_regmap meson8b_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk2_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cts_encl_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_vdac0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = meson8b_vclk2_enc_mux_parents, + .num_parents = ARRAY_SIZE(meson8b_vclk2_enc_mux_parents), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cts_vdac0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac0", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "cts_vdac0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_HDMI_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sys_sel", + .ops = &clk_regmap_mux_ro_ops, + /* FIXME: all other parents are unknown */ + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_HDMI_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sys_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "hdmi_sys_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_hdmi_sys = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_HDMI_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_sys", + .ops = &clk_regmap_gate_ro_ops, + .parent_names = (const char *[]){ "hdmi_sys_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0); @@ -1124,7 +1772,7 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_NAND_DIV] = &meson8b_nand_clk_div.hw, [CLKID_NAND_CLK] = &meson8b_nand_clk_gate.hw, [CLKID_PLL_FIXED_DCO] = &meson8b_fixed_pll_dco.hw, - [CLKID_PLL_VID_DCO] = &meson8b_vid_pll_dco.hw, + [CLKID_HDMI_PLL_DCO] = &meson8b_hdmi_pll_dco.hw, [CLKID_PLL_SYS_DCO] = &meson8b_sys_pll_dco.hw, [CLKID_CPU_CLK_DIV2] = &meson8b_cpu_clk_div2.hw, [CLKID_CPU_CLK_DIV3] = &meson8b_cpu_clk_div3.hw, @@ -1141,6 +1789,50 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_AXI] = &meson8b_axi_clk_gate.hw, [CLKID_L2_DRAM_SEL] = &meson8b_l2_dram_clk_sel.hw, [CLKID_L2_DRAM] = &meson8b_l2_dram_clk_gate.hw, + [CLKID_HDMI_PLL_LVDS_OUT] = &meson8b_hdmi_pll_lvds_out.hw, + [CLKID_HDMI_PLL_HDMI_OUT] = &meson8b_hdmi_pll_hdmi_out.hw, + [CLKID_VID_PLL_IN_SEL] = &meson8b_vid_pll_in_sel.hw, + [CLKID_VID_PLL_IN_EN] = &meson8b_vid_pll_in_en.hw, + [CLKID_VID_PLL_PRE_DIV] = &meson8b_vid_pll_pre_div.hw, + [CLKID_VID_PLL_POST_DIV] = &meson8b_vid_pll_post_div.hw, + [CLKID_VID_PLL_FINAL_DIV] = &meson8b_vid_pll_final_div.hw, + [CLKID_VCLK_IN_SEL] = &meson8b_vclk_in_sel.hw, + [CLKID_VCLK_IN_EN] = &meson8b_vclk_in_en.hw, + [CLKID_VCLK_DIV1] = &meson8b_vclk_div1_gate.hw, + [CLKID_VCLK_DIV2_DIV] = &meson8b_vclk_div2_div.hw, + [CLKID_VCLK_DIV2] = &meson8b_vclk_div2_div_gate.hw, + [CLKID_VCLK_DIV4_DIV] = &meson8b_vclk_div4_div.hw, + [CLKID_VCLK_DIV4] = &meson8b_vclk_div4_div_gate.hw, + [CLKID_VCLK_DIV6_DIV] = &meson8b_vclk_div6_div.hw, + [CLKID_VCLK_DIV6] = &meson8b_vclk_div6_div_gate.hw, + [CLKID_VCLK_DIV12_DIV] = &meson8b_vclk_div12_div.hw, + [CLKID_VCLK_DIV12] = &meson8b_vclk_div12_div_gate.hw, + [CLKID_VCLK2_IN_SEL] = &meson8b_vclk2_in_sel.hw, + [CLKID_VCLK2_IN_EN] = &meson8b_vclk2_clk_in_en.hw, + [CLKID_VCLK2_DIV1] = &meson8b_vclk2_div1_gate.hw, + [CLKID_VCLK2_DIV2_DIV] = &meson8b_vclk2_div2_div.hw, + [CLKID_VCLK2_DIV2] = &meson8b_vclk2_div2_div_gate.hw, + [CLKID_VCLK2_DIV4_DIV] = &meson8b_vclk2_div4_div.hw, + [CLKID_VCLK2_DIV4] = &meson8b_vclk2_div4_div_gate.hw, + [CLKID_VCLK2_DIV6_DIV] = &meson8b_vclk2_div6_div.hw, + [CLKID_VCLK2_DIV6] = &meson8b_vclk2_div6_div_gate.hw, + [CLKID_VCLK2_DIV12_DIV] = &meson8b_vclk2_div12_div.hw, + [CLKID_VCLK2_DIV12] = &meson8b_vclk2_div12_div_gate.hw, + [CLKID_CTS_ENCT_SEL] = &meson8b_cts_enct_sel.hw, + [CLKID_CTS_ENCT] = &meson8b_cts_enct.hw, + [CLKID_CTS_ENCP_SEL] = &meson8b_cts_encp_sel.hw, + [CLKID_CTS_ENCP] = &meson8b_cts_encp.hw, + [CLKID_CTS_ENCI_SEL] = &meson8b_cts_enci_sel.hw, + [CLKID_CTS_ENCI] = &meson8b_cts_enci.hw, + [CLKID_HDMI_TX_PIXEL_SEL] = &meson8b_hdmi_tx_pixel_sel.hw, + [CLKID_HDMI_TX_PIXEL] = &meson8b_hdmi_tx_pixel.hw, + [CLKID_CTS_ENCL_SEL] = &meson8b_cts_encl_sel.hw, + [CLKID_CTS_ENCL] = &meson8b_cts_encl.hw, + [CLKID_CTS_VDAC0_SEL] = &meson8b_cts_vdac0_sel.hw, + [CLKID_CTS_VDAC0] = &meson8b_cts_vdac0.hw, + [CLKID_HDMI_SYS_SEL] = &meson8b_hdmi_sys_sel.hw, + [CLKID_HDMI_SYS_DIV] = &meson8b_hdmi_sys_div.hw, + [CLKID_HDMI_SYS] = &meson8b_hdmi_sys.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, @@ -1234,7 +1926,6 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_mpll1_div, &meson8b_mpll2_div, &meson8b_fixed_pll, - &meson8b_vid_pll, &meson8b_sys_pll, &meson8b_cpu_in_sel, &meson8b_cpu_scale_div, @@ -1250,7 +1941,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_nand_clk_div, &meson8b_nand_clk_gate, &meson8b_fixed_pll_dco, - &meson8b_vid_pll_dco, + &meson8b_hdmi_pll_dco, &meson8b_sys_pll_dco, &meson8b_abp_clk_sel, &meson8b_abp_clk_gate, @@ -1260,6 +1951,43 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_axi_clk_gate, &meson8b_l2_dram_clk_sel, &meson8b_l2_dram_clk_gate, + &meson8b_hdmi_pll_lvds_out, + &meson8b_hdmi_pll_hdmi_out, + &meson8b_vid_pll_in_sel, + &meson8b_vid_pll_in_en, + &meson8b_vid_pll_pre_div, + &meson8b_vid_pll_post_div, + &meson8b_vid_pll, + &meson8b_vid_pll_final_div, + &meson8b_vclk_in_sel, + &meson8b_vclk_in_en, + &meson8b_vclk_div1_gate, + &meson8b_vclk_div2_div_gate, + &meson8b_vclk_div4_div_gate, + &meson8b_vclk_div6_div_gate, + &meson8b_vclk_div12_div_gate, + &meson8b_vclk2_in_sel, + &meson8b_vclk2_clk_in_en, + &meson8b_vclk2_div1_gate, + &meson8b_vclk2_div2_div_gate, + &meson8b_vclk2_div4_div_gate, + &meson8b_vclk2_div6_div_gate, + &meson8b_vclk2_div12_div_gate, + &meson8b_cts_enct_sel, + &meson8b_cts_enct, + &meson8b_cts_encp_sel, + &meson8b_cts_encp, + &meson8b_cts_enci_sel, + &meson8b_cts_enci, + &meson8b_hdmi_tx_pixel_sel, + &meson8b_hdmi_tx_pixel, + &meson8b_cts_encl_sel, + &meson8b_cts_encl, + &meson8b_cts_vdac0_sel, + &meson8b_cts_vdac0, + &meson8b_hdmi_sys_sel, + &meson8b_hdmi_sys_div, + &meson8b_hdmi_sys, }; static const struct meson8b_clk_reset_line { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 0abb331162ab..87fba739af81 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -19,20 +19,26 @@ * * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf */ +#define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ +#define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ #define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ #define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ #define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ #define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ +#define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ #define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ +#define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ #define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */ #define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ +#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */ #define HHI_NAND_CLK_CNTL 0x25c /* 0x97 offset in data sheet */ #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ #define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ +#define HHI_VID_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ /* * MPLL register offeset taken from the S905 datasheet. Vendor kernel source @@ -76,7 +82,7 @@ #define CLKID_NAND_SEL 110 #define CLKID_NAND_DIV 111 #define CLKID_PLL_FIXED_DCO 113 -#define CLKID_PLL_VID_DCO 114 +#define CLKID_HDMI_PLL_DCO 114 #define CLKID_PLL_SYS_DCO 115 #define CLKID_CPU_CLK_DIV2 116 #define CLKID_CPU_CLK_DIV3 117 @@ -89,8 +95,52 @@ #define CLKID_PERIPH_SEL 125 #define CLKID_AXI_SEL 127 #define CLKID_L2_DRAM_SEL 129 +#define CLKID_HDMI_PLL_LVDS_OUT 131 +#define CLKID_HDMI_PLL_HDMI_OUT 132 +#define CLKID_VID_PLL_IN_SEL 133 +#define CLKID_VID_PLL_IN_EN 134 +#define CLKID_VID_PLL_PRE_DIV 135 +#define CLKID_VID_PLL_POST_DIV 136 +#define CLKID_VID_PLL_FINAL_DIV 137 +#define CLKID_VCLK_IN_SEL 138 +#define CLKID_VCLK_IN_EN 139 +#define CLKID_VCLK_DIV1 140 +#define CLKID_VCLK_DIV2_DIV 141 +#define CLKID_VCLK_DIV2 142 +#define CLKID_VCLK_DIV4_DIV 143 +#define CLKID_VCLK_DIV4 144 +#define CLKID_VCLK_DIV6_DIV 145 +#define CLKID_VCLK_DIV6 146 +#define CLKID_VCLK_DIV12_DIV 147 +#define CLKID_VCLK_DIV12 148 +#define CLKID_VCLK2_IN_SEL 149 +#define CLKID_VCLK2_IN_EN 150 +#define CLKID_VCLK2_DIV1 151 +#define CLKID_VCLK2_DIV2_DIV 152 +#define CLKID_VCLK2_DIV2 153 +#define CLKID_VCLK2_DIV4_DIV 154 +#define CLKID_VCLK2_DIV4 155 +#define CLKID_VCLK2_DIV6_DIV 156 +#define CLKID_VCLK2_DIV6 157 +#define CLKID_VCLK2_DIV12_DIV 158 +#define CLKID_VCLK2_DIV12 159 +#define CLKID_CTS_ENCT_SEL 160 +#define CLKID_CTS_ENCT 161 +#define CLKID_CTS_ENCP_SEL 162 +#define CLKID_CTS_ENCP 163 +#define CLKID_CTS_ENCI_SEL 164 +#define CLKID_CTS_ENCI 165 +#define CLKID_HDMI_TX_PIXEL_SEL 166 +#define CLKID_HDMI_TX_PIXEL 167 +#define CLKID_CTS_ENCL_SEL 168 +#define CLKID_CTS_ENCL 169 +#define CLKID_CTS_VDAC0_SEL 170 +#define CLKID_CTS_VDAC0 171 +#define CLKID_HDMI_SYS_SEL 172 +#define CLKID_HDMI_SYS_DIV 173 +#define CLKID_HDMI_SYS 174 -#define CLK_NR_CLKS 131 +#define CLK_NR_CLKS 175 /* * include the CLKID and RESETID that have |