Skip to content

Commit b1f156d

Browse files
author
Shawn Guo
committed
ARM: imx6q: add BYPASS support for PLL clocks
The imx6q clock driver currently hard-codes all PLL clocks to source from OSC24M without BYPASS support. The patch adds the missing lvds_in clock which is mutually exclusive with lvds_gate, and implements BYPASS and BYPASS_CLK_SRC selection for PLL clocks as per Figure 10-3. Primary Clock Generation in IMX6DQRM, i.e. both BYPASS_CLK_SRC and BYPASS bits are implemented as mux clocks, and ENABLE bit of PLL clocks is implemented as a gate clock after BYPASS mux. Signed-off-by: Shawn Guo <[email protected]>
1 parent 19d8634 commit b1f156d

File tree

2 files changed

+83
-11
lines changed

2 files changed

+83
-11
lines changed

arch/arm/mach-imx/clk-imx6q.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ static const char *lvds_sels[] = {
7373
"pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
7474
"pcie_ref_125m", "sata_ref_100m",
7575
};
76+
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
77+
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
78+
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
79+
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
80+
static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
81+
static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
82+
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
83+
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
7684

7785
static struct clk *clk[IMX6QDL_CLK_END];
7886
static struct clk_onecell_data clk_data;
@@ -123,6 +131,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
123131
clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
124132
clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
125133
clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
134+
/* Clock source from external clock via CLK1/2 PADs */
135+
clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
136+
clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
126137

127138
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
128139
base = of_iomap(np, 0);
@@ -136,14 +147,47 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
136147
video_div_table[2].div = 1;
137148
};
138149

139-
/* type name parent_name base div_mask */
140-
clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f);
141-
clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1);
142-
clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3);
143-
clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f);
144-
clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f);
145-
clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3);
146-
clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3);
150+
clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
151+
clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
152+
clk[IMX6QDL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
153+
clk[IMX6QDL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
154+
clk[IMX6QDL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
155+
clk[IMX6QDL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
156+
clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
157+
158+
/* type name parent_name base div_mask */
159+
clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
160+
clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
161+
clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
162+
clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
163+
clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
164+
clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
165+
clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
166+
167+
clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
168+
clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
169+
clk[IMX6QDL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
170+
clk[IMX6QDL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
171+
clk[IMX6QDL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
172+
clk[IMX6QDL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
173+
clk[IMX6QDL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
174+
175+
/* Do not bypass PLLs initially */
176+
clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
177+
clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
178+
clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
179+
clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
180+
clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
181+
clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
182+
clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
183+
184+
clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
185+
clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
186+
clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
187+
clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
188+
clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
189+
clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
190+
clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0xe0, 13);
147191

148192
/*
149193
* Bit 20 is the reserved and read-only bit, we do this only for:
@@ -180,8 +224,11 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
180224
* the "output_enable" bit as a gate, even though it's really just
181225
* enabling clock output.
182226
*/
183-
clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate("lvds1_gate", "lvds1_sel", base + 0x160, 10);
184-
clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate("lvds2_gate", "lvds2_sel", base + 0x160, 11);
227+
clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
228+
clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
229+
230+
clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
231+
clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
185232

186233
/* name parent_name reg idx */
187234
clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);

include/dt-bindings/clock/imx6qdl-clock.h

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,31 @@
222222
#define IMX6QDL_CLK_ESAI_MEM 209
223223
#define IMX6QDL_CLK_ASRC_IPG 210
224224
#define IMX6QDL_CLK_ASRC_MEM 211
225-
#define IMX6QDL_CLK_END 212
225+
#define IMX6QDL_CLK_LVDS1_IN 212
226+
#define IMX6QDL_CLK_LVDS2_IN 213
227+
#define IMX6QDL_CLK_ANACLK1 214
228+
#define IMX6QDL_CLK_ANACLK2 215
229+
#define IMX6QDL_PLL1_BYPASS_SRC 216
230+
#define IMX6QDL_PLL2_BYPASS_SRC 217
231+
#define IMX6QDL_PLL3_BYPASS_SRC 218
232+
#define IMX6QDL_PLL4_BYPASS_SRC 219
233+
#define IMX6QDL_PLL5_BYPASS_SRC 220
234+
#define IMX6QDL_PLL6_BYPASS_SRC 221
235+
#define IMX6QDL_PLL7_BYPASS_SRC 222
236+
#define IMX6QDL_CLK_PLL1 223
237+
#define IMX6QDL_CLK_PLL2 224
238+
#define IMX6QDL_CLK_PLL3 225
239+
#define IMX6QDL_CLK_PLL4 226
240+
#define IMX6QDL_CLK_PLL5 227
241+
#define IMX6QDL_CLK_PLL6 228
242+
#define IMX6QDL_CLK_PLL7 229
243+
#define IMX6QDL_PLL1_BYPASS 230
244+
#define IMX6QDL_PLL2_BYPASS 231
245+
#define IMX6QDL_PLL3_BYPASS 232
246+
#define IMX6QDL_PLL4_BYPASS 233
247+
#define IMX6QDL_PLL5_BYPASS 234
248+
#define IMX6QDL_PLL6_BYPASS 235
249+
#define IMX6QDL_PLL7_BYPASS 236
250+
#define IMX6QDL_CLK_END 237
226251

227252
#endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */

0 commit comments

Comments
 (0)