Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <shawn.guo@freescale.com>

Shawn Guo b1f156db 19d86344

+83 -11
+57 -10
arch/arm/mach-imx/clk-imx6q.c
··· 73 73 "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref", 74 74 "pcie_ref_125m", "sata_ref_100m", 75 75 }; 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", }; 76 84 77 85 static struct clk *clk[IMX6QDL_CLK_END]; 78 86 static struct clk_onecell_data clk_data; ··· 131 123 clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); 132 124 clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0); 133 125 clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0); 126 + /* Clock source from external clock via CLK1/2 PADs */ 127 + clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0); 128 + clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0); 134 129 135 130 np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); 136 131 base = of_iomap(np, 0); ··· 147 136 video_div_table[2].div = 1; 148 137 }; 149 138 150 - /* type name parent_name base div_mask */ 151 - clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); 152 - clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1); 153 - clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3); 154 - clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f); 155 - clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f); 156 - clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3); 157 - clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3); 139 + 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)); 140 + 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)); 141 + 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)); 142 + 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)); 143 + 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)); 144 + 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)); 145 + 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)); 146 + 147 + /* type name parent_name base div_mask */ 148 + clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); 149 + clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); 150 + clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); 151 + clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); 152 + clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); 153 + clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); 154 + clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); 155 + 156 + 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); 157 + 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); 158 + 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); 159 + 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); 160 + 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); 161 + 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); 162 + 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); 163 + 164 + /* Do not bypass PLLs initially */ 165 + clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]); 166 + clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]); 167 + clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]); 168 + clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]); 169 + clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]); 170 + clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]); 171 + clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]); 172 + 173 + clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13); 174 + clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); 175 + clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); 176 + clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); 177 + clk[IMX6QDL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); 178 + clk[IMX6QDL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); 179 + clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0xe0, 13); 158 180 159 181 /* 160 182 * Bit 20 is the reserved and read-only bit, we do this only for: ··· 224 180 * the "output_enable" bit as a gate, even though it's really just 225 181 * enabling clock output. 226 182 */ 227 - clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate("lvds1_gate", "lvds1_sel", base + 0x160, 10); 228 - clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate("lvds2_gate", "lvds2_sel", base + 0x160, 11); 183 + clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12)); 184 + clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13)); 185 + 186 + clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10)); 187 + clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11)); 229 188 230 189 /* name parent_name reg idx */ 231 190 clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+26 -1
include/dt-bindings/clock/imx6qdl-clock.h
··· 222 222 #define IMX6QDL_CLK_ESAI_MEM 209 223 223 #define IMX6QDL_CLK_ASRC_IPG 210 224 224 #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 226 251 227 252 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */