clk: tl1: add clk81 mux clock [1/1]
authorJian Hu <jian.hu@amlogic.com>
Wed, 8 May 2019 11:52:28 +0000 (19:52 +0800)
committerJian Hu <jian.hu@amlogic.com>
Thu, 1 Aug 2019 11:29:39 +0000 (04:29 -0700)
PD#SWPL-8215

Problem:
1.clk81 can not switch to 24M
2.fixed pll can set rate
  call clk_prepare_enable to open it
  call clk_disable_unprepare to close it

Solution:
1.add clk81 mux clock
2.change fixed pll callback Read only to R/W

Verify:
test passed on tm2 ab301

Change-Id: I426d4307f19647afcb0166a23c1988df1b504807
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
drivers/amlogic/clk/clkc.h
drivers/amlogic/clk/tl1/tl1.c
drivers/amlogic/clk/tl1/tl1_ao.c
drivers/amlogic/clk/tl1/tl1_clk-pll.c
include/dt-bindings/clock/amlogic,tl1-clkc.h

index 7deac3e..b23fd61 100644 (file)
@@ -53,7 +53,7 @@ struct pll_rate_table {
        u16             n;
        u16             od;
        u16             od2;
-       u16             frac;
+       u32             frac;
 };
 
 struct fclk_rate_table {
index 86207a9..ee90068 100644 (file)
@@ -185,6 +185,10 @@ static struct meson_clk_pll tl1_adc_pll = {
 };
 #endif
 
+static const struct pll_rate_table tl1_fixed_pll_rate_table[] = {
+       PLL_FRAC_RATE(2000000000ULL, 166, 1, 1, 0, 0x3F15555),
+};
+
 static struct meson_clk_pll tl1_fixed_pll = {
        .m = {
                .reg_off = HHI_FIX_PLL_CNTL0,
@@ -207,12 +211,14 @@ static struct meson_clk_pll tl1_fixed_pll = {
                .width   = 19,
        },
        .lock = &clk_lock,
+       .rate_table = tl1_fixed_pll_rate_table,
+       .rate_count = ARRAY_SIZE(tl1_fixed_pll_rate_table),
        .hw.init = &(struct clk_init_data){
                .name = "fixed_pll",
-               .ops = &meson_tl1_pll_ro_ops,
+               .ops = &meson_tl1_pll_ops,
                .parent_names = (const char *[]){ "xtal" },
                .num_parents = 1,
-               .flags = CLK_GET_RATE_NOCACHE,
+               .flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED,
        },
 };
 
@@ -676,6 +682,19 @@ static struct clk_gate tl1_clk81 = {
        },
 };
 
+static struct clk_mux tl1_switch_clk81 = {
+       .reg = (void *)HHI_MPEG_CLK_CNTL,
+       .mask = 0x1,
+       .shift = 8,
+       .lock = &clk_lock,
+       .hw.init = &(struct clk_init_data){
+               .name = "switch_clk81",
+               .ops = &clk_mux_ops,
+               .parent_names = (const char *[]){ "xtal", "clk81" },
+               .num_parents = 2,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 /* HHI_GCLK_MPEG0 26 bits valid */
 static MESON_GATE_TL1(tl1_ddr, HHI_GCLK_MPEG0,         0);
@@ -881,6 +900,7 @@ static struct clk_hw *tl1_clk_hws[] = {
        [CLKID_DSU_PRE_PARENT0] = &tl1_dsu_pre0_clk.hw,
        [CLKID_DSU_PRE_CLK]     = &tl1_dsu_pre_clk.hw,
        [CLKID_DSU_CLK]         = &tl1_dsu_clk.hw,
+       [CLKID_SWITCH_CLK81] = &tl1_switch_clk81.hw,
 };
 /* Convenience tables to populate base addresses in .probe */
 
@@ -1101,6 +1121,9 @@ static void __init tl1_clkc_init(struct device_node *np)
        tl1_dsu_clk.reg = clk_base
                        + (unsigned long)tl1_dsu_clk.reg;
 
+       tl1_switch_clk81.reg = clk_base
+                       + (unsigned long)tl1_switch_clk81.reg;
+
        /* Populate base address for gates */
        for (i = 0; i < ARRAY_SIZE(tl1_clk_gates); i++)
                tl1_clk_gates[i]->reg = clk_base +
@@ -1127,6 +1150,8 @@ static void __init tl1_clkc_init(struct device_node *np)
                        WARN_ON(IS_ERR(clks[clkid]));
                }
        }
+       clks[CLKID_SWITCH_CLK81] = clk_register(NULL, &tl1_switch_clk81.hw);
+       WARN_ON(IS_ERR(clks[CLKID_SWITCH_CLK81]));
 
        meson_tl1_sdemmc_init();
        meson_tl1_media_init();
index b3c099c..ab6bca5 100644 (file)
@@ -172,7 +172,7 @@ static int tl1_aoclkc_probe(struct platform_device *pdev)
        tl1_saradc_div.reg = aoclk_base + (unsigned long)tl1_saradc_div.reg;
        tl1_saradc_gate.reg = aoclk_base + (unsigned long)tl1_saradc_gate.reg;
 
-       for (clkid = CLKID_AO_BASE; clkid < NR_CLKS; clkid++) {
+       for (clkid = CLKID_AO_BASE; clkid < CLKID_AO_END; clkid++) {
                if (tl1_ao_clk_hws[clkid-CLKID_AO_BASE]) {
                        clks[clkid] = clk_register(NULL,
                        tl1_ao_clk_hws[clkid-CLKID_AO_BASE]);
index 69eac78..473e644 100644 (file)
 #define TL1_SYS_PLL_CNTL4 0x88770290
 #define TL1_SYS_PLL_CNTL5 0x39272000
 
+#define TL1_FIXED_PLL_CNTL0 0xD00104A6
+#define TL1_FIXED_PLL_CNTL1 0x3F15555
+#define TL1_FIXED_PLL_CNTL2 0x00000000
+#define TL1_FIXED_PLL_CNTL3 0x6A285C60
+#define TL1_FIXED_PLL_CNTL4 0x65771290
+#define TL1_FIXED_PLL_CNTL5 0x39272000
+#define TL1_FIXED_PLL_CNTL6 0x56540000
+#define TL1_FIXED_PLL_TST   0xA000004F
 
 #define TL1_GP0_PLL_CNTL1 0x00000000
 #define TL1_GP0_PLL_CNTL2 0x00000000
@@ -165,16 +173,20 @@ static long meson_tl1_pll_round_rate(struct clk_hw *hw, unsigned long rate,
        for (i = 0; i < pll->rate_count; i++) {
                if (rate <= rate_table[i].rate) {
                        ret_rate = rate_table[i].rate;
-                       if (!strcmp(clk_hw_get_name(hw), "sys_pll"))
+                       if (!strcmp(clk_hw_get_name(hw), "sys_pll")
+                               || !strcmp(clk_hw_get_name(hw), "fixed_pll"))
                                do_div(ret_rate, 1000);
+
                        return ret_rate;
                }
        }
 
        /* else return the smallest value */
        ret_rate = rate_table[0].rate;
-       if (!strcmp(clk_hw_get_name(hw), "sys_pll"))
+       if (!strcmp(clk_hw_get_name(hw), "sys_pll")
+               || !strcmp(clk_hw_get_name(hw), "fixed_pll"))
                do_div(ret_rate, 1000);
+
        return ret_rate;
 }
 
@@ -223,7 +235,8 @@ static int meson_tl1_pll_set_rate(struct clk_hw *hw, unsigned long rate,
        if (parent_rate == 0 || rate == 0)
                return -EINVAL;
 
-       if (!strcmp(clk_hw_get_name(hw), "sys_pll"))
+       if (!strcmp(clk_hw_get_name(hw), "sys_pll")
+               || !strcmp(clk_hw_get_name(hw), "fixed_pll"))
                rate *= 1000;
 
        old_rate = rate;
@@ -331,14 +344,30 @@ static int meson_tl1_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                        cntlbase + (unsigned long)(0*4));
                writel(TM2_PCIE_PLL_CNTL2_,
                        cntlbase + (unsigned long)(7*4));
+       } else if (!strcmp(clk_hw_get_name(hw), "fixed_pll")) {
+               writel((readl(cntlbase) | MESON_PLL_RESET)
+                       & (~MESON_PLL_ENABLE), cntlbase);
+
+               udelay(100);
+               writel(TL1_FIXED_PLL_CNTL1,
+                               cntlbase + (unsigned long)(1*4));
+               writel(TL1_FIXED_PLL_CNTL2,
+                               cntlbase + (unsigned long)(2*4));
+               writel(TL1_FIXED_PLL_CNTL3,
+                               cntlbase + (unsigned long)(3*4));
+               writel(TL1_FIXED_PLL_CNTL4,
+                               cntlbase + (unsigned long)(4*4));
+               writel(TL1_FIXED_PLL_CNTL5,
+                               cntlbase + (unsigned long)(5*4));
+               writel(TL1_FIXED_PLL_CNTL6,
+                               cntlbase + (unsigned long)(6*4));
+               udelay(10);
        } else {
                pr_err("%s: %s pll not found!!!\n",
                        __func__, clk_hw_get_name(hw));
                return -EINVAL;
        }
 
-       /* when set rate for pcie pll, do not set M/N/OD/frac registers bit */
-       if (strcmp(clk_hw_get_name(hw), "pcie_pll")) {
        reg = readl(pll->base + p->reg_off);
 
        tmp = rate_set->n;
@@ -379,7 +408,6 @@ static int meson_tl1_pll_set_rate(struct clk_hw *hw, unsigned long rate,
                reg = PARM_SET(p->width, p->shift, reg, tmp);
                writel(reg, pll->base + p->reg_off);
        }
-       }
        p = &pll->n;
 
        /* PLL reset */
@@ -427,7 +455,8 @@ static int meson_tl1_pll_enable(struct clk_hw *hw)
        if (!strcmp(clk_hw_get_name(hw), "gp0_pll")
                || !strcmp(clk_hw_get_name(hw), "gp1_pll")
                || !strcmp(clk_hw_get_name(hw), "hifi_pll")
-               || !strcmp(clk_hw_get_name(hw), "sys_pll")) {
+               || !strcmp(clk_hw_get_name(hw), "sys_pll")
+               || !strcmp(clk_hw_get_name(hw), "fixed_pll")) {
                void *cntlbase = pll->base + p->reg_off;
 
                        if (readl(cntlbase + (unsigned long)(6*4))
@@ -435,7 +464,6 @@ static int meson_tl1_pll_enable(struct clk_hw *hw)
                                first_set = 0;
 
        }
-
        parent = clk_hw_get_parent(hw);
 
        /*First init, just set minimal rate.*/
index 733d470..a37705b 100644 (file)
 #define CLKID_VCLK2_VENCLMMC                   (GATE_OTHER + 14)
 #define CLKID_VCLK2_VENCL                      (GATE_OTHER + 15)
 #define CLKID_VCLK2_OTHER1                     (GATE_OTHER + 16)
-
 /*HHI_GCLK_OTHER: 0x55*/
 #define GATE_AO_BASE                           (GATE_OTHER + 17)
 
 #define CLKID_AO_UART2                         (CLKID_AO_BASE + 10)
 #define CLKID_AO_IR_BLASTER                    (CLKID_AO_BASE + 11)
 #define CLKID_AO_SAR_ADC                       (CLKID_AO_BASE + 12)
-#define NR_CLKS                                        (CLKID_AO_BASE + 13)
+#define CLKID_AO_END                           (CLKID_AO_BASE + 13)
+#define CLKID_SWITCH_CLK81                     (CLKID_AO_BASE + 13)
+#define NR_CLKS                                        (CLKID_AO_BASE + 14)
+
 #endif /* __DT_BINDINGS_TL1_CLKC_H */