diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2014-01-15 10:47:29 -0800 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-16 12:01:03 -0800 |
commit | 6d00b56fe8c6f10076c9477e1cce99caf4568760 (patch) | |
tree | ed9acf11a5b7c316a70eac4bf3a4686d70926cb0 | |
parent | 2ec941304df9e1cd5e2f2404303a5fab0929969a (diff) |
clk: qcom: Add support for MSM8960's multimedia clock controller (MMCC)
Add a driver for the multimedia clock controller found on MSM
8960 based platforms. This should allow multimedia device drivers
to probe and control their clocks.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/qcom/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8960.c | 2321 | ||||
-rw-r--r-- | include/dt-bindings/clock/qcom,mmcc-msm8960.h | 137 | ||||
-rw-r--r-- | include/dt-bindings/reset/qcom,mmcc-msm8960.h | 93 |
5 files changed, 2561 insertions, 0 deletions
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 8b39761dc9fb..715269381cca 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -11,3 +11,12 @@ config MSM_GCC_8960 Support for the global clock controller on msm8960 devices. Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, SATA, PCIe, etc. + +config MSM_MMCC_8960 + tristate "MSM8960 Multimedia Clock Controller" + select MSM_GCC_8960 + depends on COMMON_CLK_QCOM + help + Support for the multimedia clock controller on msm8960 devices. + Say Y if you want to support multimedia devices such as display, + graphics, video encode/decode, camera, etc. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 1fb673c4f786..52efa954ed3e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -8,3 +8,4 @@ clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-branch.o clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += reset.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o +obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c new file mode 100644 index 000000000000..f9b59c7e48e9 --- /dev/null +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -0,0 +1,2321 @@ +/* + * Copyright (c) 2013, 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/kernel.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk-provider.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#include <dt-bindings/clock/qcom,mmcc-msm8960.h> +#include <dt-bindings/reset/qcom,mmcc-msm8960.h> + +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" + +#define P_PXO 0 +#define P_PLL8 1 +#define P_PLL2 2 +#define P_PLL3 3 + +static u8 mmcc_pxo_pll8_pll2_map[] = { + [P_PXO] = 0, + [P_PLL8] = 2, + [P_PLL2] = 1, +}; + +static const char *mmcc_pxo_pll8_pll2[] = { + "pxo", + "pll8_vote", + "pll2", +}; + +static u8 mmcc_pxo_pll8_pll2_pll3_map[] = { + [P_PXO] = 0, + [P_PLL8] = 2, + [P_PLL2] = 1, + [P_PLL3] = 3, +}; + +static const char *mmcc_pxo_pll8_pll2_pll3[] = { + "pxo", + "pll2", + "pll8_vote", + "pll3", +}; + +static struct clk_pll pll2 = { + .l_reg = 0x320, + .m_reg = 0x324, + .n_reg = 0x328, + .config_reg = 0x32c, + .mode_reg = 0x31c, + .status_reg = 0x334, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll2", + .parent_names = (const char *[]){ "pxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct freq_tbl clk_tbl_cam[] = { + { 6000000, P_PLL8, 4, 1, 16 }, + { 8000000, P_PLL8, 4, 1, 12 }, + { 12000000, P_PLL8, 4, 1, 8 }, + { 16000000, P_PLL8, 4, 1, 6 }, + { 19200000, P_PLL8, 4, 1, 5 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 32000000, P_PLL8, 4, 1, 3 }, + { 48000000, P_PLL8, 4, 1, 2 }, + { 64000000, P_PLL8, 3, 1, 2 }, + { 96000000, P_PLL8, 4, 0, 0 }, + { 128000000, P_PLL8, 3, 0, 0 }, + { } +}; + +static struct clk_rcg camclk0_src = { + .ns_reg = 0x0148, + .md_reg = 0x0144, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 8, + .reset_in_cc = true, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_cam, + .clkr = { + .enable_reg = 0x0140, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "camclk0_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch camclk0_clk = { + .halt_reg = 0x01e8, + .halt_bit = 15, + .clkr = { + .enable_reg = 0x0140, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camclk0_clk", + .parent_names = (const char *[]){ "camclk0_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, + }, + +}; + +static struct clk_rcg camclk1_src = { + .ns_reg = 0x015c, + .md_reg = 0x0158, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 8, + .reset_in_cc = true, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_cam, + .clkr = { + .enable_reg = 0x0154, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "camclk1_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch camclk1_clk = { + .halt_reg = 0x01e8, + .halt_bit = 16, + .clkr = { + .enable_reg = 0x0154, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camclk1_clk", + .parent_names = (const char *[]){ "camclk1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, + }, + +}; + +static struct clk_rcg camclk2_src = { + .ns_reg = 0x0228, + .md_reg = 0x0224, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 8, + .reset_in_cc = true, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_cam, + .clkr = { + .enable_reg = 0x0220, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "camclk2_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch camclk2_clk = { + .halt_reg = 0x01e8, + .halt_bit = 16, + .clkr = { + .enable_reg = 0x0220, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camclk2_clk", + .parent_names = (const char *[]){ "camclk2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, + }, + +}; + +static struct freq_tbl clk_tbl_csi[] = { + { 27000000, P_PXO, 1, 0, 0 }, + { 85330000, P_PLL8, 1, 2, 9 }, + { 177780000, P_PLL2, 1, 2, 9 }, + { } +}; + +static struct clk_rcg csi0_src = { + .ns_reg = 0x0048, + .md_reg = 0x0044, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_csi, + .clkr = { + .enable_reg = 0x0040, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "csi0_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch csi0_clk = { + .halt_reg = 0x01cc, + .halt_bit = 13, + .clkr = { + .enable_reg = 0x0040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi0_src" }, + .num_parents = 1, + .name = "csi0_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch csi0_phy_clk = { + .halt_reg = 0x01e8, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x0040, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi0_src" }, + .num_parents = 1, + .name = "csi0_phy_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg csi1_src = { + .ns_reg = 0x0010, + .md_reg = 0x0028, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_csi, + .clkr = { + .enable_reg = 0x0024, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "csi1_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch csi1_clk = { + .halt_reg = 0x01cc, + .halt_bit = 14, + .clkr = { + .enable_reg = 0x0024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi1_src" }, + .num_parents = 1, + .name = "csi1_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch csi1_phy_clk = { + .halt_reg = 0x01e8, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x0024, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi1_src" }, + .num_parents = 1, + .name = "csi1_phy_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg csi2_src = { + .ns_reg = 0x0234, + .md_reg = 0x022c, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_csi, + .clkr = { + .enable_reg = 0x022c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "csi2_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch csi2_clk = { + .halt_reg = 0x01cc, + .halt_bit = 29, + .clkr = { + .enable_reg = 0x022c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi2_src" }, + .num_parents = 1, + .name = "csi2_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch csi2_phy_clk = { + .halt_reg = 0x01e8, + .halt_bit = 29, + .clkr = { + .enable_reg = 0x022c, + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "csi2_src" }, + .num_parents = 1, + .name = "csi2_phy_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +struct clk_pix_rdi { + u32 s_reg; + u32 s_mask; + u32 s2_reg; + u32 s2_mask; + struct clk_regmap clkr; +}; + +#define to_clk_pix_rdi(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_pix_rdi, clkr) + +static int pix_rdi_set_parent(struct clk_hw *hw, u8 index) +{ + int i; + int ret = 0; + u32 val; + struct clk_pix_rdi *rdi = to_clk_pix_rdi(hw); + struct clk *clk = hw->clk; + int num_parents = __clk_get_num_parents(hw->clk); + + /* + * These clocks select three inputs via two muxes. One mux selects + * between csi0 and csi1 and the second mux selects between that mux's + * output and csi2. The source and destination selections for each + * mux must be clocking for the switch to succeed so just turn on + * all three sources because it's easier than figuring out what source + * needs to be on at what time. + */ + for (i = 0; i < num_parents; i++) { + ret = clk_prepare_enable(clk_get_parent_by_index(clk, i)); + if (ret) + goto err; + } + + if (index == 2) + val = rdi->s2_mask; + else + val = 0; + regmap_update_bits(rdi->clkr.regmap, rdi->s2_reg, rdi->s2_mask, val); + /* + * Wait at least 6 cycles of slowest clock + * for the glitch-free MUX to fully switch sources. + */ + udelay(1); + + if (index == 1) + val = rdi->s_mask; + else + val = 0; + regmap_update_bits(rdi->clkr.regmap, rdi->s_reg, rdi->s_mask, val); + /* + * Wait at least 6 cycles of slowest clock + * for the glitch-free MUX to fully switch sources. + */ + udelay(1); + +err: + for (i--; i >= 0; i--) + clk_disable_unprepare(clk_get_parent_by_index(clk, i)); + + return ret; +} + +static u8 pix_rdi_get_parent(struct clk_hw *hw) +{ + u32 val; + struct clk_pix_rdi *rdi = to_clk_pix_rdi(hw); + + + regmap_read(rdi->clkr.regmap, rdi->s2_reg, &val); + if (val & rdi->s2_mask) + return 2; + + regmap_read(rdi->clkr.regmap, rdi->s_reg, &val); + if (val & rdi->s_mask) + return 1; + + return 0; +} + +static const struct clk_ops clk_ops_pix_rdi = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, + .set_parent = pix_rdi_set_parent, + .get_parent = pix_rdi_get_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +static const char *pix_rdi_parents[] = { + "csi0_clk", + "csi1_clk", + "csi2_clk", +}; + +static struct clk_pix_rdi csi_pix_clk = { + .s_reg = 0x0058, + .s_mask = BIT(25), + .s2_reg = 0x0238, + .s2_mask = BIT(13), + .clkr = { + .enable_reg = 0x0058, + .enable_mask = BIT(26), + .hw.init = &(struct clk_init_data){ + .name = "csi_pix_clk", + .parent_names = pix_rdi_parents, + .num_parents = 3, + .ops = &clk_ops_pix_rdi, + }, + }, +}; + +static struct clk_pix_rdi csi_pix1_clk = { + .s_reg = 0x0238, + .s_mask = BIT(8), + .s2_reg = 0x0238, + .s2_mask = BIT(9), + .clkr = { + .enable_reg = 0x0238, + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "csi_pix1_clk", + .parent_names = pix_rdi_parents, + .num_parents = 3, + .ops = &clk_ops_pix_rdi, + }, + }, +}; + +static struct clk_pix_rdi csi_rdi_clk = { + .s_reg = 0x0058, + .s_mask = BIT(12), + .s2_reg = 0x0238, + .s2_mask = BIT(12), + .clkr = { + .enable_reg = 0x0058, + .enable_mask = BIT(13), + .hw.init = &(struct clk_init_data){ + .name = "csi_rdi_clk", + .parent_names = pix_rdi_parents, + .num_parents = 3, + .ops = &clk_ops_pix_rdi, + }, + }, +}; + +static struct clk_pix_rdi csi_rdi1_clk = { + .s_reg = 0x0238, + .s_mask = BIT(0), + .s2_reg = 0x0238, + .s2_mask = BIT(1), + .clkr = { + .enable_reg = 0x0238, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "csi_rdi1_clk", + .parent_names = pix_rdi_parents, + .num_parents = 3, + .ops = &clk_ops_pix_rdi, + }, + }, +}; + +static struct clk_pix_rdi csi_rdi2_clk = { + .s_reg = 0x0238, + .s_mask = BIT(4), + .s2_reg = 0x0238, + .s2_mask = BIT(5), + .clkr = { + .enable_reg = 0x0238, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "csi_rdi2_clk", + .parent_names = pix_rdi_parents, + .num_parents = 3, + .ops = &clk_ops_pix_rdi, + }, + }, +}; + +static struct freq_tbl clk_tbl_csiphytimer[] = { + { 85330000, P_PLL8, 1, 2, 9 }, + { 177780000, P_PLL2, 1, 2, 9 }, + { } +}; + +static struct clk_rcg csiphytimer_src = { + .ns_reg = 0x0168, + .md_reg = 0x0164, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 8, + .reset_in_cc = true, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_csiphytimer, + .clkr = { + .enable_reg = 0x0160, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "csiphytimer_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static const char *csixphy_timer_src[] = { "csiphytimer_src" }; + +static struct clk_branch csiphy0_timer_clk = { + .halt_reg = 0x01e8, + .halt_bit = 17, + .clkr = { + .enable_reg = 0x0160, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = csixphy_timer_src, + .num_parents = 1, + .name = "csiphy0_timer_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch csiphy1_timer_clk = { + .halt_reg = 0x01e8, + .halt_bit = 18, + .clkr = { + .enable_reg = 0x0160, + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .parent_names = csixphy_timer_src, + .num_parents = 1, + .name = "csiphy1_timer_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch csiphy2_timer_clk = { + .halt_reg = 0x01e8, + .halt_bit = 30, + .clkr = { + .enable_reg = 0x0160, + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .parent_names = csixphy_timer_src, + .num_parents = 1, + .name = "csiphy2_timer_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_gfx2d[] = { + { 27000000, P_PXO, 1, 0 }, + { 48000000, P_PLL8, 1, 8 }, + { 54857000, P_PLL8, 1, 7 }, + { 64000000, P_PLL8, 1, 6 }, + { 76800000, P_PLL8, 1, 5 }, + { 96000000, P_PLL8, 1, 4 }, + { 128000000, P_PLL8, 1, 3 }, + { 145455000, P_PLL2, 2, 11 }, + { 160000000, P_PLL2, 1, 5 }, + { 177778000, P_PLL2, 2, 9 }, + { 200000000, P_PLL2, 1, 4 }, + { 228571000, P_PLL2, 2, 7 }, + { } +}; + +static struct clk_dyn_rcg gfx2d0_src = { + .ns_reg = 0x0070, + .md_reg[0] = 0x0064, + .md_reg[1] = 0x0068, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 25, + .mnctr_mode_shift = 9, + .n_val_shift = 20, + .m_val_shift = 4, + .width = 4, + }, + .mn[1] = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 24, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 4, + .width = 4, + }, + .s[0] = { + .src_sel_shift = 3, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .mux_sel_bit = 11, + .freq_tbl = clk_tbl_gfx2d, + .clkr = { + .enable_reg = 0x0060, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gfx2d0_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gfx2d0_clk = { + .halt_reg = 0x01c8, + .halt_bit = 9, + .clkr = { + .enable_reg = 0x0060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gfx2d0_clk", + .parent_names = (const char *[]){ "gfx2d0_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_dyn_rcg gfx2d1_src = { + .ns_reg = 0x007c, + .md_reg[0] = 0x0078, + .md_reg[1] = 0x006c, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 25, + .mnctr_mode_shift = 9, + .n_val_shift = 20, + .m_val_shift = 4, + .width = 4, + }, + .mn[1] = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 24, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 4, + .width = 4, + }, + .s[0] = { + .src_sel_shift = 3, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .mux_sel_bit = 11, + .freq_tbl = clk_tbl_gfx2d, + .clkr = { + .enable_reg = 0x0074, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gfx2d1_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gfx2d1_clk = { + .halt_reg = 0x01c8, + .halt_bit = 14, + .clkr = { + .enable_reg = 0x0074, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gfx2d1_clk", + .parent_names = (const char *[]){ "gfx2d1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_gfx3d[] = { + { 27000000, P_PXO, 1, 0 }, + { 48000000, P_PLL8, 1, 8 }, + { 54857000, P_PLL8, 1, 7 }, + { 64000000, P_PLL8, 1, 6 }, + { 76800000, P_PLL8, 1, 5 }, + { 96000000, P_PLL8, 1, 4 }, + { 128000000, P_PLL8, 1, 3 }, + { 145455000, P_PLL2, 2, 11 }, + { 160000000, P_PLL2, 1, 5 }, + { 177778000, P_PLL2, 2, 9 }, + { 200000000, P_PLL2, 1, 4 }, + { 228571000, P_PLL2, 2, 7 }, + { 266667000, P_PLL2, 1, 3 }, + { 300000000, P_PLL3, 1, 4 }, + { 320000000, P_PLL2, 2, 5 }, + { 400000000, P_PLL2, 1, 2 }, + { } +}; + +static struct clk_dyn_rcg gfx3d_src = { + .ns_reg = 0x008c, + .md_reg[0] = 0x0084, + .md_reg[1] = 0x0088, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 25, + .mnctr_mode_shift = 9, + .n_val_shift = 18, + .m_val_shift = 4, + .width = 4, + }, + .mn[1] = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 24, + .mnctr_mode_shift = 6, + .n_val_shift = 14, + .m_val_shift = 4, + .width = 4, + }, + .s[0] = { + .src_sel_shift = 3, + .parent_map = mmcc_pxo_pll8_pll2_pll3_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_pll3_map, + }, + .mux_sel_bit = 11, + .freq_tbl = clk_tbl_gfx3d, + .clkr = { + .enable_reg = 0x0080, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gfx3d_src", + .parent_names = mmcc_pxo_pll8_pll2_pll3, + .num_parents = 3, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch gfx3d_clk = { + .halt_reg = 0x01c8, + .halt_bit = 4, + .clkr = { + .enable_reg = 0x0080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gfx3d_clk", + .parent_names = (const char *[]){ "gfx3d_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_ijpeg[] = { + { 27000000, P_PXO, 1, 0, 0 }, + { 36570000, P_PLL8, 1, 2, 21 }, + { 54860000, P_PLL8, 7, 0, 0 }, + { 96000000, P_PLL8, 4, 0, 0 }, + { 109710000, P_PLL8, 1, 2, 7 }, + { 128000000, P_PLL8, 3, 0, 0 }, + { 153600000, P_PLL8, 1, 2, 5 }, + { 200000000, P_PLL2, 4, 0, 0 }, + { 228571000, P_PLL2, 1, 2, 7 }, + { 266667000, P_PLL2, 1, 1, 3 }, + { 320000000, P_PLL2, 1, 2, 5 }, + { } +}; + +static struct clk_rcg ijpeg_src = { + .ns_reg = 0x00a0, + .md_reg = 0x009c, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 12, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_ijpeg, + .clkr = { + .enable_reg = 0x0098, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "ijpeg_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch ijpeg_clk = { + .halt_reg = 0x01c8, + .halt_bit = 24, + .clkr = { + .enable_reg = 0x0098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "ijpeg_clk", + .parent_names = (const char *[]){ "ijpeg_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_jpegd[] = { + { 64000000, P_PLL8, 6 }, + { 76800000, P_PLL8, 5 }, + { 96000000, P_PLL8, 4 }, + { 160000000, P_PLL2, 5 }, + { 200000000, P_PLL2, 4 }, + { } +}; + +static struct clk_rcg jpegd_src = { + .ns_reg = 0x00ac, + .p = { + .pre_div_shift = 12, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .freq_tbl = clk_tbl_jpegd, + .clkr = { + .enable_reg = 0x00a4, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "jpegd_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_rcg_ops, + }, + }, +}; + +static struct clk_branch jpegd_clk = { + .halt_reg = 0x01c8, + .halt_bit = 19, + .clkr = { + .enable_reg = 0x00a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "jpegd_clk", + .parent_names = (const char *[]){ "jpegd_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct freq_tbl clk_tbl_mdp[] = { + { 9600000, P_PLL8, 1, 1, 40 }, + { 13710000, P_PLL8, 1, 1, 28 }, + { 27000000, P_PXO, 1, 0, 0 }, + { 29540000, P_PLL8, 1, 1, 13 }, + { 34910000, P_PLL8, 1, 1, 11 }, + { 38400000, P_PLL8, 1, 1, 10 }, + { 59080000, P_PLL8, 1, 2, 13 }, + { 76800000, P_PLL8, 1, 1, 5 }, + { 85330000, P_PLL8, 1, 2, 9 }, + { 96000000, P_PLL8, 1, 1, 4 }, + { 128000000, P_PLL8, 1, 1, 3 }, + { 160000000, P_PLL2, 1, 1, 5 }, + { 177780000, P_PLL2, 1, 2, 9 }, + { 200000000, P_PLL2, 1, 1, 4 }, + { 228571000, P_PLL2, 1, 2, 7 }, + { 266667000, P_PLL2, 1, 1, 3 }, + { } +}; + +static struct clk_dyn_rcg mdp_src = { + .ns_reg = 0x00d0, + .md_reg[0] = 0x00c4, + .md_reg[1] = 0x00c8, + .mn[0] = { + .mnctr_en_bit = 8, + .mnctr_reset_bit = 31, + .mnctr_mode_shift = 9, + .n_val_shift = 22, + .m_val_shift = 8, + .width = 8, + }, + .mn[1] = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 30, + .mnctr_mode_shift = 6, + .n_val_shift = 14, + .m_val_shift = 8, + .width = 8, + }, + .s[0] = { + .src_sel_shift = 3, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .s[1] = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .mux_sel_bit = 11, + .freq_tbl = clk_tbl_mdp, + .clkr = { + .enable_reg = 0x00c0, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "mdp_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch mdp_clk = { + .halt_reg = 0x01d0, + .halt_bit = 10, + .clkr = { + .enable_reg = 0x00c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mdp_clk", + .parent_names = (const char *[]){ "mdp_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch mdp_lut_clk = { + .halt_reg = 0x01e8, + .halt_bit = 13, + .clkr = { + .enable_reg = 0x016c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .parent_names = (const char *[]){ "mdp_clk" }, + .num_parents = 1, + .name = "mdp_lut_clk", + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch mdp_vsync_clk = { + .halt_reg = 0x01cc, + .halt_bit = 22, + .clkr = { + .enable_reg = 0x0058, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "mdp_vsync_clk", + .parent_names = (const char *[]){ "pxo" }, + .num_parents = 1, + .ops = &clk_branch_ops + }, + }, +}; + +static struct freq_tbl clk_tbl_rot[] = { + { 27000000, P_PXO, 1 }, + { 29540000, P_PLL8, 13 }, + { 32000000, P_PLL8, 12 }, + { 38400000, P_PLL8, 10 }, + { 48000000, P_PLL8, 8 }, + { 54860000, P_PLL8, 7 }, + { 64000000, P_PLL8, 6 }, + { 76800000, P_PLL8, 5 }, + { 96000000, P_PLL8, 4 }, + { 100000000, P_PLL2, 8 }, + { 114290000, P_PLL2, 7 }, + { 133330000, P_PLL2, 6 }, + { 160000000, P_PLL2, 5 }, + { 200000000, P_PLL2, 4 }, + { } +}; + +static struct clk_dyn_rcg rot_src = { + .ns_reg = 0x00e8, + .p[0] = { + .pre_div_shift = 22, + .pre_div_width = 4, + }, + .p[1] = { + .pre_div_shift = 26, + .pre_div_width = 4, + }, + .s[0] = { + .src_sel_shift = 16, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .s[1] = { + .src_sel_shift = 19, + .parent_map = mmcc_pxo_pll8_pll2_map, + }, + .mux_sel_bit = 30, + .freq_tbl = clk_tbl_rot, + .clkr = { + .enable_reg = 0x00e0, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "rot_src", + .parent_names = mmcc_pxo_pll8_pll2, + .num_parents = 3, + .ops = &clk_dyn_rcg_ops, + }, + }, +}; + +static struct clk_branch rot_clk = { + .halt_reg = 0x01d0, + .halt_bit = 15, + .clkr = { + .enable_reg = 0x00e0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "rot_clk", + .parent_names = (const char *[]){ "rot_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +#define P_HDMI_PLL 1 + +static u8 mmcc_pxo_hdmi_map[] = { + [P_PXO] = 0, + [P_HDMI_PLL] = 2, +}; + +static const char *mmcc_pxo_hdmi[] = { + "pxo", + "hdmi_pll", +}; + +static struct freq_tbl clk_tbl_tv[] = { + { 25200000, P_HDMI_PLL, 1, 0, 0 }, + { 27000000, P_HDMI_PLL, 1, 0, 0 }, + { 27030000, P_HDMI_PLL, 1, 0, 0 }, + { 74250000, P_HDMI_PLL, 1, 0, 0 }, + { 108000000, P_HDMI_PLL, 1, 0, 0 }, + { 148500000, P_HDMI_PLL, 1, 0, 0 }, + { } +}; + +static struct clk_rcg tv_src = { + .ns_reg = 0x00f4, + .md_reg = 0x00f0, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_hdmi_map, + }, + .freq_tbl = clk_tbl_tv, + .clkr = { + .enable_reg = 0x00ec, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ |