diff options
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/bcm/clk-bcm2835.c | 23 | ||||
-rw-r--r-- | drivers/clk/clk-divider.c | 2 | ||||
-rw-r--r-- | drivers/clk/clk-qoriq.c | 6 | ||||
-rw-r--r-- | drivers/clk/clk.c | 14 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx35.c | 2 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx6q.c | 46 | ||||
-rw-r--r-- | drivers/clk/qcom/Kconfig | 2 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8996.c | 4 |
8 files changed, 73 insertions, 26 deletions
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 7a7970865..0fc71cbaa 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1006,16 +1006,28 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw, return 0; } +static bool +bcm2835_clk_is_pllc(struct clk_hw *hw) +{ + if (!hw) + return false; + + return strncmp(clk_hw_get_name(hw), "pllc", 4) == 0; +} + static int bcm2835_clock_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); struct clk_hw *parent, *best_parent = NULL; + bool current_parent_is_pllc; unsigned long rate, best_rate = 0; unsigned long prate, best_prate = 0; size_t i; u32 div; + current_parent_is_pllc = bcm2835_clk_is_pllc(clk_hw_get_parent(hw)); + /* * Select parent clock that results in the closest but lower rate */ @@ -1023,6 +1035,17 @@ static int bcm2835_clock_determine_rate(struct clk_hw *hw, parent = clk_hw_get_parent_by_index(hw, i); if (!parent) continue; + + /* + * Don't choose a PLLC-derived clock as our parent + * unless it had been manually set that way. PLLC's + * frequency gets adjusted by the firmware due to + * over-temp or under-voltage conditions, without + * prior notification to our clock consumer. + */ + if (bcm2835_clk_is_pllc(parent) && !current_parent_is_pllc) + continue; + prate = clk_hw_get_rate(parent); div = bcm2835_clock_choose_div(hw, req->rate, prate, true); rate = bcm2835_clock_rate_from_divisor(clock, prate, div); diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a0f55bc1a..96386ffc8 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -352,7 +352,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = readl(divider->reg) >> divider->shift; + bestdiv = clk_readl(divider->reg) >> divider->shift; bestdiv &= div_mask(divider->width); bestdiv = _get_div(divider->table, bestdiv, divider->flags, divider->width); diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 58566a179..20b105584 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -766,7 +766,11 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx) if (!hwc) return NULL; - hwc->reg = cg->regs + 0x20 * idx; + if (cg->info.flags & CG_VER3) + hwc->reg = cg->regs + 0x70000 + 0x20 * idx; + else + hwc->reg = cg->regs + 0x20 * idx; + hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]]; /* diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 820a939fb..2877a4dde 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1908,10 +1908,6 @@ int clk_set_phase(struct clk *clk, int degrees) clk_prepare_lock(); - /* bail early if nothing to do */ - if (degrees == clk->core->phase) - goto out; - trace_clk_set_phase(clk->core, degrees); if (clk->core->ops->set_phase) @@ -1922,7 +1918,6 @@ int clk_set_phase(struct clk *clk, int degrees) if (!ret) clk->core->phase = degrees; -out: clk_prepare_unlock(); return ret; @@ -3186,7 +3181,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); - struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER); + struct clk_hw *hw; if (!clkspec) return ERR_PTR(-EINVAL); @@ -3194,12 +3189,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, /* Check if we have such a provider in our array */ mutex_lock(&of_clk_mutex); list_for_each_entry(provider, &of_clk_providers, link) { - if (provider->node == clkspec->np) + if (provider->node == clkspec->np) { hw = __of_clk_get_hw_from_provider(provider, clkspec); - if (!IS_ERR(hw)) { clk = __clk_create_clk(hw, dev_id, con_id); + } - if (!IS_ERR(clk) && !__clk_get(clk)) { + if (!IS_ERR(clk)) { + if (!__clk_get(clk)) { __clk_free_clk(clk); clk = ERR_PTR(-ENOENT); } diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index b0978d3b8..d302ed3b8 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -115,7 +115,7 @@ static void __init _mx35_clocks_init(void) } clk[ckih] = imx_clk_fixed("ckih", 24000000); - clk[ckil] = imx_clk_fixed("ckih", 32768); + clk[ckil] = imx_clk_fixed("ckil", 32768); clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL); clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL); diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index ba1c1ae72..ce8ea1040 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -318,11 +318,16 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_IPG_PER_SEL] = imx_clk_mux("ipg_per_sel", base + 0x1c, 6, 1, ipg_per_sels, ARRAY_SIZE(ipg_per_sels)); clk[IMX6QDL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels_2, ARRAY_SIZE(gpu2d_core_sels_2)); + } else if (clk_on_imx6dl()) { + clk[IMX6QDL_CLK_MLB_SEL] = imx_clk_mux("mlb_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); } else { clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); } clk[IMX6QDL_CLK_GPU3D_CORE_SEL] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); - clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_GPU2D_CORE_SEL] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + else + 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); @@ -400,9 +405,15 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); } - clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_MLB_PODF] = imx_clk_divider("mlb_podf", "mlb_sel", base + 0x18, 23, 3); + else + clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); clk[IMX6QDL_CLK_GPU3D_CORE_PODF] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); - clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); + if (clk_on_imx6dl()) + clk[IMX6QDL_CLK_GPU2D_CORE_PODF] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 29, 3); + else + clk[IMX6QDL_CLK_GPU3D_SHADER] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); clk[IMX6QDL_CLK_IPU1_PODF] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); clk[IMX6QDL_CLK_IPU2_PODF] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); clk[IMX6QDL_CLK_LDB_DI0_PODF] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0); @@ -473,14 +484,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x6c, 16, &share_count_esai); clk[IMX6QDL_CLK_GPT_IPG] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); clk[IMX6QDL_CLK_GPT_IPG_PER] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); - if (clk_on_imx6dl()) - /* - * The multiplexer and divider of imx6q clock gpu3d_shader get - * redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl. - */ - clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24); - else - clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); + clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4); @@ -511,7 +515,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) * The multiplexer and divider of the imx6q clock gpu2d get * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl. */ - clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18); + clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "mlb_podf", base + 0x74, 18); else clk[IMX6QDL_CLK_MLB] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); clk[IMX6QDL_CLK_MMDC_CH0_AXI] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); @@ -629,6 +633,24 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]); + /* + * Initialize the GPU clock muxes, so that the maximum specified clock + * rates for the respective SoC are not exceeded. + */ + if (clk_on_imx6dl()) { + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + } else if (clk_on_imx6q()) { + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], + clk[IMX6QDL_CLK_MMDC_CH0_AXI]); + clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], + clk[IMX6QDL_CLK_PLL2_PFD1_594M]); + clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], + clk[IMX6QDL_CLK_PLL3_USB_OTG]); + } + imx_register_uart_clocks(uart_clks); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 95e3b3e0f..98909b184 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -117,6 +117,7 @@ config MSM_MMCC_8974 config MSM_GCC_8996 tristate "MSM8996 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on msm8996 devices. @@ -126,6 +127,7 @@ config MSM_GCC_8996 config MSM_MMCC_8996 tristate "MSM8996 Multimedia Clock Controller" select MSM_GCC_8996 + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the multimedia clock controller on msm8996 devices. diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index bbf732bbc..9f643cca8 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2592,9 +2592,9 @@ static struct clk_branch gcc_pcie_2_aux_clk = { }; static struct clk_branch gcc_pcie_2_pipe_clk = { - .halt_reg = 0x6e108, + .halt_reg = 0x6e018, .clkr = { - .enable_reg = 0x6e108, + .enable_reg = 0x6e018, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_pipe_clk", |