Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
[oweals/u-boot.git] / arch / arm / cpu / armv7 / tegra2 / clock.c
index 11d2346d83b0fda80052b79f68ac3583779ba990..ccad3516398cd9d781902d3c5c070c8c0490a66d 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/arch/tegra2.h>
 #include <common.h>
 #include <div64.h>
+#include <fdtdec.h>
 
 /*
  * This is our record of the current clock rate of each clock. We don't
@@ -67,6 +68,7 @@ enum clock_type_id {
        CLOCK_TYPE_MCPT,
        CLOCK_TYPE_PCM,
        CLOCK_TYPE_PCMT,
+       CLOCK_TYPE_PCMT16,      /* CLOCK_TYPE_PCMT with 16-bit divider */
        CLOCK_TYPE_PCXTS,
        CLOCK_TYPE_PDCT,
 
@@ -98,6 +100,7 @@ static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = {
        { CLK(MEMORY),  CLK(CGENERAL),  CLK(PERIPH),    CLK(OSC)        },
        { CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(NONE)       },
        { CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(OSC)        },
+       { CLK(PERIPH),  CLK(CGENERAL),  CLK(MEMORY),    CLK(OSC)        },
        { CLK(PERIPH),  CLK(CGENERAL),  CLK(XCPU),      CLK(OSC)        },
        { CLK(PERIPH),  CLK(DISPLAY),   CLK(CGENERAL),  CLK(OSC)        },
 };
@@ -211,8 +214,8 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
 
        /* 0x08 */
        TYPE(PERIPHC_XIO,       CLOCK_TYPE_PCMT),
-       TYPE(PERIPHC_I2C1,      CLOCK_TYPE_PCMT),
-       TYPE(PERIPHC_DVC_I2C,   CLOCK_TYPE_PCMT),
+       TYPE(PERIPHC_I2C1,      CLOCK_TYPE_PCMT16),
+       TYPE(PERIPHC_DVC_I2C,   CLOCK_TYPE_PCMT16),
        TYPE(PERIPHC_TWC,       CLOCK_TYPE_PCMT),
        TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
        TYPE(PERIPHC_SPI1,      CLOCK_TYPE_PCMT),
@@ -246,7 +249,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
        TYPE(PERIPHC_HDMI,      CLOCK_TYPE_PDCT),
        TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
        TYPE(PERIPHC_TVDAC,     CLOCK_TYPE_PDCT),
-       TYPE(PERIPHC_I2C2,      CLOCK_TYPE_PCMT),
+       TYPE(PERIPHC_I2C2,      CLOCK_TYPE_PCMT16),
        TYPE(PERIPHC_EMC,       CLOCK_TYPE_MCPT),
 
        /* 0x28 */
@@ -256,7 +259,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
        TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
        TYPE(PERIPHC_NONE,      CLOCK_TYPE_NONE),
        TYPE(PERIPHC_SPI4,      CLOCK_TYPE_PCMT),
-       TYPE(PERIPHC_I2C3,      CLOCK_TYPE_PCMT),
+       TYPE(PERIPHC_I2C3,      CLOCK_TYPE_PCMT16),
        TYPE(PERIPHC_SDMMC3,    CLOCK_TYPE_PCMT),
 
        /* 0x30 */
@@ -407,6 +410,16 @@ enum clock_osc_freq clock_get_osc_freq(void)
        return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
 }
 
+int clock_get_osc_bypass(void)
+{
+       struct clk_rst_ctlr *clkrst =
+                       (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 reg;
+
+       reg = readl(&clkrst->crc_osc_ctrl);
+       return (reg & OSC_XOBP_MASK) >> OSC_XOBP_SHIFT;
+}
+
 /* Returns a pointer to the registers of the given pll */
 static struct clk_pll *get_pll(enum clock_id clkid)
 {
@@ -417,6 +430,28 @@ static struct clk_pll *get_pll(enum clock_id clkid)
        return &clkrst->crc_pll[clkid];
 }
 
+int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
+               u32 *divp, u32 *cpcon, u32 *lfcon)
+{
+       struct clk_pll *pll = get_pll(clkid);
+       u32 data;
+
+       assert(clkid != CLOCK_ID_USB);
+
+       /* Safety check, adds to code size but is small */
+       if (!clock_id_isvalid(clkid) || clkid == CLOCK_ID_USB)
+               return -1;
+       data = readl(&pll->pll_base);
+       *divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT;
+       *divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT;
+       *divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT;
+       data = readl(&pll->pll_misc);
+       *cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT;
+       *lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT;
+
+       return 0;
+}
+
 unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
                u32 divp, u32 cpcon, u32 lfcon)
 {
@@ -518,14 +553,16 @@ void clock_ll_set_source(enum periph_id periph_id, unsigned source)
  * Given the parent's rate and the required rate for the children, this works
  * out the peripheral clock divider to use, in 7.1 binary format.
  *
+ * @param divider_bits number of divider bits (8 or 16)
  * @param parent_rate  clock rate of parent clock in Hz
  * @param rate         required clock rate for this clock
  * @return divider which should be used
  */
-static int clk_div7_1_get_divider(unsigned long parent_rate,
-                                 unsigned long rate)
+static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate,
+                          unsigned long rate)
 {
        u64 divider = parent_rate * 2;
+       unsigned max_divider = 1 << divider_bits;
 
        divider += rate - 1;
        do_div(divider, rate);
@@ -533,7 +570,7 @@ static int clk_div7_1_get_divider(unsigned long parent_rate,
        if ((s64)divider - 2 < 0)
                return 0;
 
-       if ((s64)divider - 2 > 255)
+       if ((s64)divider - 2 >= max_divider)
                return -1;
 
        return divider - 2;
@@ -571,6 +608,7 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id,
  * required child clock rate. This function assumes that a second-stage
  * divisor is available which can divide by powers of 2 from 1 to 256.
  *
+ * @param divider_bits number of divider bits (8 or 16)
  * @param parent_rate  clock rate of parent clock in Hz
  * @param rate         required clock rate for this clock
  * @param extra_div    value for the second-stage divisor (not set if this
@@ -578,8 +616,8 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id,
  * @return divider which should be used, or -1 if nothing is valid
  *
  */
-static int find_best_divider(unsigned long parent_rate, unsigned long rate,
-               int *extra_div)
+static int find_best_divider(unsigned divider_bits, unsigned long parent_rate,
+                            unsigned long rate, int *extra_div)
 {
        int shift;
        int best_divider = -1;
@@ -588,7 +626,8 @@ static int find_best_divider(unsigned long parent_rate, unsigned long rate,
        /* try dividers from 1 to 256 and find closest match */
        for (shift = 0; shift <= 8 && best_error > 0; shift++) {
                unsigned divided_parent = parent_rate >> shift;
-               int divider = clk_div7_1_get_divider(divided_parent, rate);
+               int divider = clk_get_divider(divider_bits, divided_parent,
+                                             rate);
                unsigned effective_rate = get_rate_from_divider(divided_parent,
                                                       divider);
                int error = rate - effective_rate;
@@ -614,10 +653,11 @@ static int find_best_divider(unsigned long parent_rate, unsigned long rate,
  * @param periph_id    peripheral to start
  * @param source       PLL id of required parent clock
  * @param mux_bits     Set to number of bits in mux register: 2 or 4
+ * @param divider_bits Set to number of divider bits (8 or 16)
  * @return mux value (0-4, or -1 if not found)
  */
 static int get_periph_clock_source(enum periph_id periph_id,
-               enum clock_id parent, int *mux_bits)
+               enum clock_id parent, int *mux_bits, int *divider_bits)
 {
        enum clock_type_id type;
        enum periphc_internal_id internal_id;
@@ -631,11 +671,18 @@ static int get_periph_clock_source(enum periph_id periph_id,
        type = clock_periph_type[internal_id];
        assert(clock_type_id_isvalid(type));
 
-       /* Special case here for the clock with a 4-bit source mux */
+       /*
+        * Special cases here for the clock with a 4-bit source mux and I2C
+        * with its 16-bit divisor
+        */
        if (type == CLOCK_TYPE_PCXTS)
                *mux_bits = 4;
        else
                *mux_bits = 2;
+       if (type == CLOCK_TYPE_PCMT16)
+               *divider_bits = 16;
+       else
+               *divider_bits = 8;
 
        for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
                if (clock_source[type][mux] == parent)
@@ -661,24 +708,22 @@ static int get_periph_clock_source(enum periph_id periph_id,
  * Adjust peripheral PLL to use the given divider and source.
  *
  * @param periph_id    peripheral to adjust
- * @param parent       Required parent clock (for source mux)
- * @param divider      Required divider in 7.1 format
+ * @param source       Source number (0-3 or 0-7)
+ * @param mux_bits     Number of mux bits (2 or 4)
+ * @param divider      Required divider in 7.1 or 15.1 format
  * @return 0 if ok, -1 on error (requesting a parent clock which is not valid
  *             for this peripheral)
  */
-static int adjust_periph_pll(enum periph_id periph_id,
-               enum clock_id parent, unsigned divider)
+static int adjust_periph_pll(enum periph_id periph_id, int source,
+                            int mux_bits, unsigned divider)
 {
        u32 *reg = get_periph_source_reg(periph_id);
-       unsigned source;
-       int mux_bits;
 
        clrsetbits_le32(reg, OUT_CLK_DIVISOR_MASK,
                        divider << OUT_CLK_DIVISOR_SHIFT);
        udelay(1);
 
        /* work out the source clock and set it */
-       source = get_periph_clock_source(periph_id, parent, &mux_bits);
        if (source < 0)
                return -1;
        if (mux_bits == 4) {
@@ -696,14 +741,21 @@ unsigned clock_adjust_periph_pll_div(enum periph_id periph_id,
                enum clock_id parent, unsigned rate, int *extra_div)
 {
        unsigned effective_rate;
+       int mux_bits, divider_bits, source;
        int divider;
 
+       /* work out the source clock and set it */
+       source = get_periph_clock_source(periph_id, parent, &mux_bits,
+                                        &divider_bits);
+
        if (extra_div)
-               divider = find_best_divider(pll_rate[parent], rate, extra_div);
+               divider = find_best_divider(divider_bits, pll_rate[parent],
+                                           rate, extra_div);
        else
-               divider = clk_div7_1_get_divider(pll_rate[parent], rate);
+               divider = clk_get_divider(divider_bits, pll_rate[parent],
+                                         rate);
        assert(divider >= 0);
-       if (adjust_periph_pll(periph_id, parent, divider))
+       if (adjust_periph_pll(periph_id, source, mux_bits, divider))
                return -1U;
        debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate,
                get_periph_source_reg(periph_id),
@@ -918,6 +970,63 @@ void clock_ll_start_uart(enum periph_id periph_id)
        reset_set_enable(periph_id, 0);
 }
 
+#ifdef CONFIG_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
+ * provided.
+ *
+ * @param clk_id       Clock ID according to tegra2 device tree binding
+ * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
+ */
+static enum periph_id clk_id_to_periph_id(int clk_id)
+{
+       if (clk_id > 95)
+               return PERIPH_ID_NONE;
+
+       switch (clk_id) {
+       case 1:
+       case 2:
+       case 7:
+       case 10:
+       case 20:
+       case 30:
+       case 35:
+       case 49:
+       case 56:
+       case 74:
+       case 76:
+       case 77:
+       case 78:
+       case 79:
+       case 80:
+       case 81:
+       case 82:
+       case 83:
+       case 91:
+       case 95:
+               return PERIPH_ID_NONE;
+       default:
+               return clk_id;
+       }
+}
+
+int clock_decode_periph_id(const void *blob, int node)
+{
+       enum periph_id id;
+       u32 cell[2];
+       int err;
+
+       err = fdtdec_get_int_array(blob, node, "clocks", cell,
+                                  ARRAY_SIZE(cell));
+       if (err)
+               return -1;
+       id = clk_id_to_periph_id(cell[1]);
+       assert(clock_periph_id_isvalid(id));
+       return id;
+}
+#endif /* CONFIG_OF_CONTROL */
+
 int clock_verify(void)
 {
        struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH);
@@ -950,7 +1059,10 @@ void clock_early_init(void)
                clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
                break;
 
-       case CLOCK_OSC_FREQ_13_0:
+       case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
+               clock_set_rate(CLOCK_ID_PERIPH, 432, 13, 1, 8);
+               clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
+               break;
        case CLOCK_OSC_FREQ_19_2:
        default:
                /*