aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/clk-imx6sl.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/clk-imx6sl.c')
-rw-r--r--arch/arm/mach-imx/clk-imx6sl.c159
1 files changed, 137 insertions, 22 deletions
diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c
index 4c86f3035205..f7073c0782fb 100644
--- a/arch/arm/mach-imx/clk-imx6sl.c
+++ b/arch/arm/mach-imx/clk-imx6sl.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright 2013 Freescale Semiconductor, Inc. 2 * Copyright 2013-2014 Freescale Semiconductor, Inc.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -18,27 +18,43 @@
18#include "clk.h" 18#include "clk.h"
19#include "common.h" 19#include "common.h"
20 20
21static const char const *step_sels[] = { "osc", "pll2_pfd2", }; 21#define CCSR 0xc
22static const char const *pll1_sw_sels[] = { "pll1_sys", "step", }; 22#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
23static const char const *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; 23#define CACRR 0x10
24static const char const *ocram_sels[] = { "periph", "ocram_alt_sels", }; 24#define CDHIPR 0x48
25static const char const *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; 25#define BM_CDHIPR_ARM_PODF_BUSY (1 << 16)
26static const char const *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; 26#define ARM_WAIT_DIV_396M 2
27static const char const *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; 27#define ARM_WAIT_DIV_792M 4
28static const char const *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", }; 28#define ARM_WAIT_DIV_996M 6
29static const char const *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; 29
30static const char const *csi_lcdif_sels[] = { "mmdc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", }; 30#define PLL_ARM 0x0
31static const char const *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", }; 31#define BM_PLL_ARM_DIV_SELECT (0x7f << 0)
32static const char const *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", }; 32#define BM_PLL_ARM_POWERDOWN (1 << 12)
33static const char const *perclk_sels[] = { "ipg", "osc", }; 33#define BM_PLL_ARM_ENABLE (1 << 13)
34static const char const *epdc_pxp_sels[] = { "mmdc", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd1", }; 34#define BM_PLL_ARM_LOCK (1 << 31)
35static const char const *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; 35#define PLL_ARM_DIV_792M 66
36static const char const *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; 36
37static const char const *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; 37static const char *step_sels[] = { "osc", "pll2_pfd2", };
38static const char const *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; 38static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
39static const char const *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; 39static const char *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", };
40static const char const *ecspi_sels[] = { "pll3_60m", "osc", }; 40static const char *ocram_sels[] = { "periph", "ocram_alt_sels", };
41static const char const *uart_sels[] = { "pll3_80m", "osc", }; 41static const char *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", };
42static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", };
43static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
44static const char *periph_sels[] = { "pre_periph_sel", "periph_clk2_podf", };
45static const char *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", };
46static const char *csi_lcdif_sels[] = { "mmdc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", };
47static const char *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", };
48static const char *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", };
49static const char *perclk_sels[] = { "ipg", "osc", };
50static const char *epdc_pxp_sels[] = { "mmdc", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd1", };
51static const char *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", };
52static const char *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", };
53static const char *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", };
54static const char *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", };
55static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", };
56static const char *ecspi_sels[] = { "pll3_60m", "osc", };
57static const char *uart_sels[] = { "pll3_80m", "osc", };
42 58
43static struct clk_div_table clk_enet_ref_table[] = { 59static struct clk_div_table clk_enet_ref_table[] = {
44 { .val = 0, .div = 20, }, 60 { .val = 0, .div = 20, },
@@ -65,6 +81,89 @@ static struct clk_div_table video_div_table[] = {
65 81
66static struct clk *clks[IMX6SL_CLK_END]; 82static struct clk *clks[IMX6SL_CLK_END];
67static struct clk_onecell_data clk_data; 83static struct clk_onecell_data clk_data;
84static void __iomem *ccm_base;
85static void __iomem *anatop_base;
86
87static const u32 clks_init_on[] __initconst = {
88 IMX6SL_CLK_IPG, IMX6SL_CLK_ARM, IMX6SL_CLK_MMDC_ROOT,
89};
90
91/*
92 * ERR005311 CCM: After exit from WAIT mode, unwanted interrupt(s) taken
93 * during WAIT mode entry process could cause cache memory
94 * corruption.
95 *
96 * Software workaround:
97 * To prevent this issue from occurring, software should ensure that the
98 * ARM to IPG clock ratio is less than 12:5 (that is < 2.4x), before
99 * entering WAIT mode.
100 *
101 * This function will set the ARM clk to max value within the 12:5 limit.
102 * As IPG clock is fixed at 66MHz(so ARM freq must not exceed 158.4MHz),
103 * ARM freq are one of below setpoints: 396MHz, 792MHz and 996MHz, since
104 * the clk APIs can NOT be called in idle thread(may cause kernel schedule
105 * as there is sleep function in PLL wait function), so here we just slow
106 * down ARM to below freq according to previous freq:
107 *
108 * run mode wait mode
109 * 396MHz -> 132MHz;
110 * 792MHz -> 158.4MHz;
111 * 996MHz -> 142.3MHz;
112 */
113static int imx6sl_get_arm_divider_for_wait(void)
114{
115 if (readl_relaxed(ccm_base + CCSR) & BM_CCSR_PLL1_SW_CLK_SEL) {
116 return ARM_WAIT_DIV_396M;
117 } else {
118 if ((readl_relaxed(anatop_base + PLL_ARM) &
119 BM_PLL_ARM_DIV_SELECT) == PLL_ARM_DIV_792M)
120 return ARM_WAIT_DIV_792M;
121 else
122 return ARM_WAIT_DIV_996M;
123 }
124}
125
126static void imx6sl_enable_pll_arm(bool enable)
127{
128 static u32 saved_pll_arm;
129 u32 val;
130
131 if (enable) {
132 saved_pll_arm = val = readl_relaxed(anatop_base + PLL_ARM);
133 val |= BM_PLL_ARM_ENABLE;
134 val &= ~BM_PLL_ARM_POWERDOWN;
135 writel_relaxed(val, anatop_base + PLL_ARM);
136 while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
137 ;
138 } else {
139 writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM);
140 }
141}
142
143void imx6sl_set_wait_clk(bool enter)
144{
145 static unsigned long saved_arm_div;
146 int arm_div_for_wait = imx6sl_get_arm_divider_for_wait();
147
148 /*
149 * According to hardware design, arm podf change need
150 * PLL1 clock enabled.
151 */
152 if (arm_div_for_wait == ARM_WAIT_DIV_396M)
153 imx6sl_enable_pll_arm(true);
154
155 if (enter) {
156 saved_arm_div = readl_relaxed(ccm_base + CACRR);
157 writel_relaxed(arm_div_for_wait, ccm_base + CACRR);
158 } else {
159 writel_relaxed(saved_arm_div, ccm_base + CACRR);
160 }
161 while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY)
162 ;
163
164 if (arm_div_for_wait == ARM_WAIT_DIV_396M)
165 imx6sl_enable_pll_arm(false);
166}
68 167
69static void __init imx6sl_clocks_init(struct device_node *ccm_node) 168static void __init imx6sl_clocks_init(struct device_node *ccm_node)
70{ 169{
@@ -72,6 +171,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
72 void __iomem *base; 171 void __iomem *base;
73 int irq; 172 int irq;
74 int i; 173 int i;
174 int ret;
75 175
76 clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); 176 clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
77 clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); 177 clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
@@ -80,6 +180,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
80 np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); 180 np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop");
81 base = of_iomap(np, 0); 181 base = of_iomap(np, 0);
82 WARN_ON(!base); 182 WARN_ON(!base);
183 anatop_base = base;
83 184
84 /* type name parent base div_mask */ 185 /* type name parent base div_mask */
85 clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); 186 clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f);
@@ -127,6 +228,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
127 np = ccm_node; 228 np = ccm_node;
128 base = of_iomap(np, 0); 229 base = of_iomap(np, 0);
129 WARN_ON(!base); 230 WARN_ON(!base);
231 ccm_base = base;
130 232
131 /* Reuse imx6q pm code */ 233 /* Reuse imx6q pm code */
132 imx6q_pm_set_ccm_base(base); 234 imx6q_pm_set_ccm_base(base);
@@ -258,6 +360,19 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
258 clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); 360 clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0");
259 clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); 361 clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0");
260 362
363 /* Ensure the AHB clk is at 132MHz. */
364 ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
365 if (ret)
366 pr_warn("%s: failed to set AHB clock rate %d!\n",
367 __func__, ret);
368
369 /*
370 * Make sure those always on clocks are enabled to maintain the correct
371 * usecount and enabling/disabling of parent PLLs.
372 */
373 for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
374 clk_prepare_enable(clks[clks_init_on[i]]);
375
261 if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { 376 if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
262 clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); 377 clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]);
263 clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); 378 clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]);