tegra: Init clocks even when SPL did not run
[platform/kernel/u-boot.git] / arch / arm / mach-tegra / tegra124 / clock.c
index fc8bd19..5ae718b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2013
+ * (C) Copyright 2013-2015
  * NVIDIA Corporation <www.nvidia.com>
  *
  * SPDX-License-Identifier:     GPL-2.0+
@@ -42,6 +42,7 @@ enum clock_type_id {
        CLOCK_TYPE_ASPTE,
        CLOCK_TYPE_PMDACD2T,
        CLOCK_TYPE_PCST,
+       CLOCK_TYPE_DP,
 
        CLOCK_TYPE_PC2CC3M,
        CLOCK_TYPE_PC2CC3S_T,
@@ -101,6 +102,10 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
        { CLK(PERIPH),  CLK(CGENERAL),  CLK(SFROM32KHZ),        CLK(OSC),
                CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
                MASK_BITS_31_28},
+       /* CLOCK_TYPE_DP */
+       { CLK(NONE),    CLK(NONE),      CLK(NONE),      CLK(NONE),
+               CLK(NONE),      CLK(NONE),      CLK(NONE),      CLK(NONE),
+               MASK_BITS_31_28},
 
        /* Additional clock types on Tegra114+ */
        /* CLOCK_TYPE_PC2CC3M */
@@ -259,7 +264,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
 
        /* 0x58 */
        TYPE(PERIPHC_58h,       CLOCK_TYPE_NONE),
-       TYPE(PERIPHC_59h,       CLOCK_TYPE_NONE),
+       TYPE(PERIPHC_SOR,       CLOCK_TYPE_NONE),
        TYPE(PERIPHC_5ah,       CLOCK_TYPE_NONE),
        TYPE(PERIPHC_5bh,       CLOCK_TYPE_NONE),
        TYPE(PERIPHC_SATAOOB,   CLOCK_TYPE_PCMT),
@@ -470,7 +475,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
        PERIPHC_ACTMON,
 
        /* 120 */
-       NONE(EXTPERIPH1),
+       PERIPHC_EXTPERIPH1,
        NONE(EXTPERIPH2),
        NONE(EXTPERIPH3),
        NONE(OOB),
@@ -546,7 +551,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
        NONE(X_RESERVED19),
        NONE(ADX1),
        NONE(DPAUX),
-       NONE(SOR0),
+       PERIPHC_SOR,
        NONE(X_RESERVED23),
 
        /* 184 */
@@ -561,6 +566,38 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
 };
 
 /*
+ * PLL divider shift/mask tables for all PLL IDs.
+ */
+struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
+       /*
+        * T124: same as T114, some deviations from T2x/T30. Adds PLLDP.
+        * NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLX, etc.)
+        *       If lock_ena or lock_det are >31, they're not used in that PLL.
+        */
+
+       { .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF,  .p_shift = 20, .p_mask = 0x0F,
+         .lock_ena = 24, .lock_det = 27, .kcp_shift = 28, .kcp_mask = 3, .kvco_shift = 27, .kvco_mask = 1 },   /* PLLC */
+       { .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF,  .p_shift = 0,  .p_mask = 0,
+         .lock_ena = 0,  .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 },     /* PLLM */
+       { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
+         .lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLP */
+       { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
+         .lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLA */
+       { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x01,
+         .lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLU */
+       { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
+         .lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD */
+       { .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF,  .p_shift = 20, .p_mask = 0x0F,
+         .lock_ena = 18, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 },     /* PLLX */
+       { .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF,  .p_shift = 0,  .p_mask = 0,
+         .lock_ena = 9,  .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 },     /* PLLE */
+       { .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07,
+         .lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */
+       { .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF,  .p_shift = 20,  .p_mask = 0xF,
+         .lock_ena = 30, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 },   /* PLLDP */
+};
+
+/*
  * Get the oscillator frequency, from the corresponding hardware configuration
  * field. Note that Tegra30+ support 3 new higher freqs, but we map back
  * to the old T20 freqs. Support for the higher oscillators is TBD.
@@ -594,7 +631,10 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
        assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
        internal_id = periph_id_to_internal_id[periph_id];
        assert(internal_id != -1);
-       if (internal_id >= PERIPHC_VW_FIRST) {
+       if (internal_id >= PERIPHC_X_FIRST) {
+               internal_id -= PERIPHC_X_FIRST;
+               return &clkrst->crc_clk_src_x[internal_id];
+       } else if (internal_id >= PERIPHC_VW_FIRST) {
                internal_id -= PERIPHC_VW_FIRST;
                return &clkrst->crc_clk_src_vw[internal_id];
        } else {
@@ -602,6 +642,51 @@ u32 *get_periph_source_reg(enum periph_id periph_id)
        }
 }
 
+int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
+                         int *divider_bits, int *type)
+{
+       enum periphc_internal_id internal_id;
+
+       if (!clock_periph_id_isvalid(periph_id))
+               return -1;
+
+       internal_id = periph_id_to_internal_id[periph_id];
+       if (!periphc_internal_id_isvalid(internal_id))
+               return -1;
+
+       *type = clock_periph_type[internal_id];
+       if (!clock_type_id_isvalid(*type))
+               return -1;
+
+       *mux_bits = clock_source[*type][CLOCK_MAX_MUX];
+
+       if (*type == CLOCK_TYPE_PC2CC3M_T16)
+               *divider_bits = 16;
+       else
+               *divider_bits = 8;
+
+       return 0;
+}
+
+enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
+{
+       enum periphc_internal_id internal_id;
+       int type;
+
+       if (!clock_periph_id_isvalid(periph_id))
+               return CLOCK_ID_NONE;
+
+       internal_id = periph_id_to_internal_id[periph_id];
+       if (!periphc_internal_id_isvalid(internal_id))
+               return CLOCK_ID_NONE;
+
+       type = clock_periph_type[internal_id];
+       if (!clock_type_id_isvalid(type))
+               return CLOCK_ID_NONE;
+
+       return clock_source[type][source];
+}
+
 /**
  * Given a peripheral ID and the required source clock, this returns which
  * value should be programmed into the source mux for that peripheral.
@@ -618,23 +703,10 @@ int get_periph_clock_source(enum periph_id periph_id,
        enum clock_id parent, int *mux_bits, int *divider_bits)
 {
        enum clock_type_id type;
-       enum periphc_internal_id internal_id;
-       int mux;
+       int mux, err;
 
-       assert(clock_periph_id_isvalid(periph_id));
-
-       internal_id = periph_id_to_internal_id[periph_id];
-       assert(periphc_internal_id_isvalid(internal_id));
-
-       type = clock_periph_type[internal_id];
-       assert(clock_type_id_isvalid(type));
-
-       *mux_bits = clock_source[type][CLOCK_MAX_MUX];
-
-       if (type == CLOCK_TYPE_PC2CC3M_T16)
-               *divider_bits = 16;
-       else
-               *divider_bits = 8;
+       err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
+       assert(!err);
 
        for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
                if (clock_source[type][mux] == parent)
@@ -657,8 +729,10 @@ void clock_set_enable(enum periph_id periph_id, int enable)
        assert(clock_periph_id_isvalid(periph_id));
        if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
                clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
-       else
+       else if ((int)periph_id < PERIPH_ID_X_FIRST)
                clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
+       else
+               clk = &clkrst->crc_clk_out_enb_x;
        reg = readl(clk);
        if (enable)
                reg |= PERIPH_MASK(periph_id);
@@ -678,8 +752,10 @@ void reset_set_enable(enum periph_id periph_id, int enable)
        assert(clock_periph_id_isvalid(periph_id));
        if (periph_id < PERIPH_ID_VW_FIRST)
                reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
-       else
+       else if ((int)periph_id < PERIPH_ID_X_FIRST)
                reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
+       else
+               reset = &clkrst->crc_rst_devices_x;
        reg = readl(reset);
        if (enable)
                reg |= PERIPH_MASK(periph_id);
@@ -688,7 +764,7 @@ void reset_set_enable(enum periph_id periph_id, int enable)
        writel(reg, reset);
 }
 
-#ifdef CONFIG_OF_CONTROL
+#if CONFIG_IS_ENABLED(OF_CONTROL)
 /*
  * Convert a device tree clock ID to our peripheral ID. They are mostly
  * the same but we are very cautious so we check that a valid clock ID is
@@ -754,15 +830,22 @@ enum periph_id clk_id_to_periph_id(int clk_id)
                return clk_id;
        }
 }
-#endif /* CONFIG_OF_CONTROL */
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 void clock_early_init(void)
 {
        struct clk_rst_ctlr *clkrst =
                (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       struct clk_pll_info *pllinfo;
+       u32 data;
 
        tegra30_set_up_pllp();
 
+       /* clear IDDQ before accessing any other PLLC registers */
+       pllinfo = &tegra_pll_info_table[CLOCK_ID_CGENERAL];
+       clrbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc, PLLC_IDDQ);
+       udelay(2);
+
        /*
         * PLLC output frequency set to 600Mhz
         * PLLD output frequency set to 925Mhz
@@ -796,21 +879,43 @@ void clock_early_init(void)
        writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
 
        /* PLLC_MISC: Set LOCK_ENABLE */
-       writel(0x01000000, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc);
+       pllinfo = &tegra_pll_info_table[CLOCK_ID_CGENERAL];
+       setbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc, (1 << pllinfo->lock_ena));
        udelay(2);
 
-       /* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1 */
-       writel(0x40000C10, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
+       /* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */
+       pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
+       data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift);
+       data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena);
+       writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
        udelay(2);
 }
 
+/*
+ * clock_early_init_done - Check if clock_early_init() has been called
+ *
+ * Check a register that we set up to see if clock_early_init() has already
+ * been called.
+ *
+ * @return true if clock_early_init() was called, false if not
+ */
+bool clock_early_init_done(void)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 val;
+
+       val = readl(&clkrst->crc_sclk_brst_pol);
+
+       return val == 0x20002222;
+}
+
 void arch_timer_init(void)
 {
        struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;
        u32 freq, val;
 
-       freq = clock_get_rate(CLOCK_ID_OSC);
-       debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq);
+       freq = clock_get_rate(CLOCK_ID_CLK_M);
+       debug("%s: clk_m freq is %dHz [0x%08X]\n", __func__, freq, freq);
 
        /* ARM CNTFRQ */
        asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq));
@@ -933,3 +1038,145 @@ int tegra_plle_enable(void)
 
        return 0;
 }
+
+void clock_sor_enable_edp_clock(void)
+{
+       u32 *reg;
+
+       /* uses PLLP, has a non-standard bit layout. */
+       reg = get_periph_source_reg(PERIPH_ID_SOR0);
+       setbits_le32(reg, SOR0_CLK_SEL0);
+}
+
+u32 clock_set_display_rate(u32 frequency)
+{
+       /**
+        * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz
+        *           = (cf * n) >> p, where 1MHz < cf < 6MHz
+        *           = ((ref / m) * n) >> p
+        *
+        * Iterate the possible values of p (3 bits, 2^7) to find out a minimum
+        * safe vco, then find best (m, n). since m has only 5 bits, we can
+        * iterate all possible values.  Note Tegra 124 supports 11 bits for n,
+        * but our pll_fields has only 10 bits for n.
+        *
+        * Note values undershoot or overshoot target output frequency may not
+        * work if the values are not in "safe" range by panel specification.
+        */
+       u32 ref = clock_get_rate(CLOCK_ID_OSC);
+       u32 divm, divn, divp, cpcon;
+       u32 cf, vco, rounded_rate = frequency;
+       u32 diff, best_diff, best_m = 0, best_n = 0, best_p;
+       const u32 max_m = 1 << 5, max_n = 1 << 10, max_p = 1 << 3,
+                 mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz,
+                 min_cf = 1 * mhz, max_cf = 6 * mhz;
+       int mux_bits, divider_bits, source;
+
+       for (divp = 0, vco = frequency; vco < min_vco && divp < max_p; divp++)
+               vco <<= 1;
+
+       if (vco < min_vco || vco > max_vco) {
+               printf("%s: Cannot find out a supported VCO for Frequency (%u)\n",
+                      __func__, frequency);
+               return 0;
+       }
+
+       best_p = divp;
+       best_diff = vco;
+
+       for (divm = 1; divm < max_m && best_diff; divm++) {
+               cf = ref / divm;
+               if (cf < min_cf)
+                       break;
+               if (cf > max_cf)
+                       continue;
+
+               divn = vco / cf;
+               if (divn >= max_n)
+                       continue;
+
+               diff = vco - divn * cf;
+               if (divn + 1 < max_n && diff > cf / 2) {
+                       divn++;
+                       diff = cf - diff;
+               }
+
+               if (diff >= best_diff)
+                       continue;
+
+               best_diff = diff;
+               best_m = divm;
+               best_n = divn;
+       }
+
+       if (best_n < 50)
+               cpcon = 2;
+       else if (best_n < 300)
+               cpcon = 3;
+       else if (best_n < 600)
+               cpcon = 8;
+       else
+               cpcon = 12;
+
+       if (best_diff) {
+               printf("%s: Failed to match output frequency %u, best difference is %u\n",
+                      __func__, frequency, best_diff);
+               rounded_rate = (ref / best_m * best_n) >> best_p;
+       }
+
+       debug("%s: PLLD=%u ref=%u, m/n/p/cpcon=%u/%u/%u/%u\n",
+             __func__, rounded_rate, ref, best_m, best_n, best_p, cpcon);
+
+       source = get_periph_clock_source(PERIPH_ID_DISP1, CLOCK_ID_DISPLAY,
+                                        &mux_bits, &divider_bits);
+       clock_ll_set_source_bits(PERIPH_ID_DISP1, mux_bits, source);
+       clock_set_rate(CLOCK_ID_DISPLAY, best_n, best_m, best_p, cpcon);
+
+       return rounded_rate;
+}
+
+void clock_set_up_plldp(void)
+{
+       struct clk_rst_ctlr *clkrst =
+                       (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 value;
+
+       value = PLLDP_SS_CFG_UNDOCUMENTED | PLLDP_SS_CFG_DITHER;
+       writel(value | PLLDP_SS_CFG_CLAMP, &clkrst->crc_plldp_ss_cfg);
+       clock_start_pll(CLOCK_ID_DP, 1, 90, 3, 0, 0);
+       writel(value, &clkrst->crc_plldp_ss_cfg);
+}
+
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid)
+{
+       struct clk_rst_ctlr *clkrst =
+                       (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+       if (clkid == CLOCK_ID_DP)
+               return &clkrst->plldp;
+
+       return NULL;
+}
+
+struct periph_clk_init periph_clk_init_table[] = {
+       { PERIPH_ID_SBC1, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SBC2, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SBC3, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SBC4, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SBC5, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SBC6, CLOCK_ID_PERIPH },
+       { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH },
+       { PERIPH_ID_DISP1, CLOCK_ID_CGENERAL },
+       { PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
+       { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
+       { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
+       { PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
+       { PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
+       { PERIPH_ID_I2C3, CLOCK_ID_PERIPH },
+       { PERIPH_ID_I2C4, CLOCK_ID_PERIPH },
+       { PERIPH_ID_I2C5, CLOCK_ID_PERIPH },
+       { PERIPH_ID_I2C6, CLOCK_ID_PERIPH },
+       { -1, },
+};