]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ARM: imx6q: add BYPASS support for PLL clocks
authorShawn Guo <shawn.guo@freescale.com>
Mon, 1 Sep 2014 06:17:48 +0000 (14:17 +0800)
committerNitin Garg <nitin.garg@freescale.com>
Fri, 16 Jan 2015 03:17:15 +0000 (21:17 -0600)
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>
(cherry-picked from commit 1a829f632c30732ea0dca90e55815284c98d7ea3)

arch/arm/mach-imx/clk-imx6q.c
include/dt-bindings/clock/imx6qdl-clock.h

index 876ec21df8b5884cbaa8802a948e3f3f814a544a..e4ff9943f7930cc969cf0bd12081bdafdd42d9b2 100644 (file)
@@ -75,7 +75,15 @@ static const char *lvds_sels[] = {
        "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
        "pcie_ref", "sata_ref",
 };
-
+static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
+static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
+static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
+static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
+static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
+static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
+static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
 static struct clk *clk[IMX6QDL_CLK_END];
 static struct clk_onecell_data clk_data;
 
@@ -125,6 +133,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
        clk[IMX6QDL_CLK_CKIH] = imx_obtain_fixed_clock("ckih1", 0);
        clk[IMX6QDL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0);
+       /* Clock source from external clock via CLK1/2 PADs */
+       clk[IMX6QDL_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+       clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
 
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
        base = of_iomap(np, 0);
@@ -138,15 +149,48 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                video_div_table[2].div = 1;
        };
 
-       /*                                             type             name         parent_name  base     div_mask */
-       clk[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_pllv3(IMX_PLLV3_SYS,   "pll1_sys",     "osc", base,        0x7f);
-       clk[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_pllv3(IMX_PLLV3_GENERIC,       "pll2_bus",     "osc", base + 0x30, 0x1);
-       clk[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_pllv3(IMX_PLLV3_USB,   "pll3_usb_otg", "osc", base + 0x10, 0x3);
-       clk[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_pllv3(IMX_PLLV3_AV,    "pll4_audio",   "osc", base + 0x70, 0x7f);
-       clk[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_pllv3(IMX_PLLV3_AV,    "pll5_video",   "osc", base + 0xa0, 0x7f);
-       clk[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_pllv3(IMX_PLLV3_ENET,  "pll6_enet",    "osc", base + 0xe0, 0x3);
-       clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB,   "pll7_usb_host","osc", base + 0x20, 0x3);
-
+       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));
+       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));
+       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));
+       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));
+       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));
+       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));
+       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));
+
+       /*                                    type               name    parent_name        base         div_mask */
+       clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS,     "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+       clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+       clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+       clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+       clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+       clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+       clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB,     "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+       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);
+       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);
+       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);
+       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);
+       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);
+       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);
+       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);
+
+       /* Do not bypass PLLs initially */
+       clk_set_parent(clk[IMX6QDL_PLL1_BYPASS], clk[IMX6QDL_CLK_PLL1]);
+       clk_set_parent(clk[IMX6QDL_PLL2_BYPASS], clk[IMX6QDL_CLK_PLL2]);
+       clk_set_parent(clk[IMX6QDL_PLL3_BYPASS], clk[IMX6QDL_CLK_PLL3]);
+       clk_set_parent(clk[IMX6QDL_PLL4_BYPASS], clk[IMX6QDL_CLK_PLL4]);
+       clk_set_parent(clk[IMX6QDL_PLL5_BYPASS], clk[IMX6QDL_CLK_PLL5]);
+       clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
+       clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
+
+       clk[IMX6QDL_CLK_PLL1_SYS]      = imx_clk_gate("pll1_sys",      "pll1_bypass", base + 0x00, 13);
+       clk[IMX6QDL_CLK_PLL2_BUS]      = imx_clk_gate("pll2_bus",      "pll2_bypass", base + 0x30, 13);
+       clk[IMX6QDL_CLK_PLL3_USB_OTG]  = imx_clk_gate("pll3_usb_otg",  "pll3_bypass", base + 0x10, 13);
+       clk[IMX6QDL_CLK_PLL4_AUDIO]    = imx_clk_gate("pll4_audio",    "pll4_bypass", base + 0x70, 13);
+       clk[IMX6QDL_CLK_PLL5_VIDEO]    = imx_clk_gate("pll5_video",    "pll5_bypass", base + 0xa0, 13);
+       clk[IMX6QDL_CLK_PLL6_ENET]     = imx_clk_gate("pll6_enet",     "pll6_bypass", base + 0xe0, 13);
+       clk[IMX6QDL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0xe0, 13);
        /*
         * Bit 20 is the reserved and read-only bit, we do this only for:
         * - Do nothing for usbphy clk_enable/disable
@@ -182,9 +226,12 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
         * the "output_enable" bit as a gate, even though it's really just
         * enabling clock output.
         */
-       clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate("lvds1_gate", "lvds1_sel", base + 0x160, 10);
-       clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate("lvds2_gate", "lvds2_sel", base + 0x160, 11);
+       clk[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+       clk[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
 
+       clk[IMX6QDL_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+       clk[IMX6QDL_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
        /*                                            name              parent_name        reg       idx */
        clk[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
        clk[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
index c0802e78f1074c394f5565e557758769a3f7d259..a730f8b2c8272785a5914384aa7ec645b19dcf46 100644 (file)
 #define IMX6QDL_CLK_ESAI_IPG                   217
 #define IMX6QDL_CLK_ASRC_IPG                   218
 #define IMX6QDL_CLK_ASRC_MEM                   219
-#define IMX6QDL_CLK_END                                220
-
+#define IMX6QDL_CLK_LVDS1_IN                   220
+#define IMX6QDL_CLK_LVDS2_IN                   221
+#define IMX6QDL_CLK_ANACLK1                    222
+#define IMX6QDL_CLK_ANACLK2                    223
+#define IMX6QDL_PLL1_BYPASS_SRC                        224
+#define IMX6QDL_PLL2_BYPASS_SRC                        225
+#define IMX6QDL_PLL3_BYPASS_SRC                        226
+#define IMX6QDL_PLL4_BYPASS_SRC                        227
+#define IMX6QDL_PLL5_BYPASS_SRC                        228
+#define IMX6QDL_PLL6_BYPASS_SRC                        229
+#define IMX6QDL_PLL7_BYPASS_SRC                        230
+#define IMX6QDL_CLK_PLL1                       231
+#define IMX6QDL_CLK_PLL2                       232
+#define IMX6QDL_CLK_PLL3                       233
+#define IMX6QDL_CLK_PLL4                       234
+#define IMX6QDL_CLK_PLL5                       235
+#define IMX6QDL_CLK_PLL6                       236
+#define IMX6QDL_CLK_PLL7                       237
+#define IMX6QDL_PLL1_BYPASS                    238
+#define IMX6QDL_PLL2_BYPASS                    239
+#define IMX6QDL_PLL3_BYPASS                    240
+#define IMX6QDL_PLL4_BYPASS                    241
+#define IMX6QDL_PLL5_BYPASS                    242
+#define IMX6QDL_PLL6_BYPASS                    243
+#define IMX6QDL_PLL7_BYPASS                    244
+#define IMX6QDL_CLK_END                                245
 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */