ARM: DRA7: Add support for IO delay configuration
[oweals/u-boot.git] / arch / arm / mach-tegra / clock.c
index e07f11d0901941e6b1026607ba165749f9f751ef..24047b8c82f0c0efe5b084535bd492e9c8b2d4ff 100644 (file)
 /* Tegra SoC common clock control functions */
 
 #include <common.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/tegra.h>
 #include <asm/arch-tegra/ap.h>
 #include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
 #include <asm/arch-tegra/timer.h>
 #include <div64.h>
 #include <fdtdec.h>
@@ -82,7 +84,7 @@ static struct clk_pll *get_pll(enum clock_id clkid)
 
        assert(clock_id_is_pll(clkid));
        if (clkid >= (enum clock_id)TEGRA_CLK_PLLS) {
-               debug("%s: Invalid PLL\n", __func__);
+               debug("%s: Invalid PLL %d\n", __func__, clkid);
                return NULL;
        }
        return &clkrst->crc_pll[clkid];
@@ -118,9 +120,12 @@ int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn,
 unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn,
                u32 divp, u32 cpcon, u32 lfcon)
 {
-       struct clk_pll *pll = get_pll(clkid);
+       struct clk_pll *pll = NULL;
        u32 misc_data, data;
 
+       if (clkid < (enum clock_id)TEGRA_CLK_PLLS)
+               pll = get_pll(clkid);
+
        /*
         * We cheat by treating all PLL (except PLLU) in the same fashion.
         * This works only because:
@@ -172,12 +177,37 @@ void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source,
        writel(value, reg);
 }
 
-void clock_ll_set_source(enum periph_id periph_id, unsigned source)
+int clock_ll_set_source_bits(enum periph_id periph_id, int mux_bits,
+                            unsigned source)
 {
        u32 *reg = get_periph_source_reg(periph_id);
 
-       clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK,
-                       source << OUT_CLK_SOURCE_31_30_SHIFT);
+       switch (mux_bits) {
+       case MASK_BITS_31_30:
+               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK,
+                               source << OUT_CLK_SOURCE_31_30_SHIFT);
+               break;
+
+       case MASK_BITS_31_29:
+               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_29_MASK,
+                               source << OUT_CLK_SOURCE_31_29_SHIFT);
+               break;
+
+       case MASK_BITS_31_28:
+               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_28_MASK,
+                               source << OUT_CLK_SOURCE_31_28_SHIFT);
+               break;
+
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+void clock_ll_set_source(enum periph_id periph_id, unsigned source)
+{
+       clock_ll_set_source_bits(periph_id, MASK_BITS_31_30, source);
 }
 
 /**
@@ -326,25 +356,7 @@ static int adjust_periph_pll(enum periph_id periph_id, int source,
        if (source < 0)
                return -1;
 
-       switch (mux_bits) {
-       case MASK_BITS_31_30:
-               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK,
-                               source << OUT_CLK_SOURCE_31_30_SHIFT);
-               break;
-
-       case MASK_BITS_31_29:
-               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_29_MASK,
-                               source << OUT_CLK_SOURCE_31_29_SHIFT);
-               break;
-
-       case MASK_BITS_31_28:
-               clrsetbits_le32(reg, OUT_CLK_SOURCE_31_28_MASK,
-                               source << OUT_CLK_SOURCE_31_28_SHIFT);
-               break;
-
-       default:
-               return -1;
-       }
+       clock_ll_set_source_bits(periph_id, mux_bits, source);
 
        udelay(2);
        return 0;
@@ -586,6 +598,7 @@ void clock_init(void)
        pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY);
        pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH);
        pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL);
+       pll_rate[CLOCK_ID_DISPLAY] = clock_get_rate(CLOCK_ID_DISPLAY);
        pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC);
        pll_rate[CLOCK_ID_SFROM32KHZ] = 32768;
        pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU);
@@ -593,6 +606,7 @@ void clock_init(void)
        debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]);
        debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]);
        debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]);
+       debug("PLLD = %d\n", pll_rate[CLOCK_ID_DISPLAY]);
        debug("PLLX = %d\n", pll_rate[CLOCK_ID_XCPU]);
 
        /* Do any special system timer/TSC setup */
@@ -693,3 +707,18 @@ void tegra30_set_up_pllp(void)
 
        set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4);
 }
+
+int clock_external_output(int clk_id)
+{
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+       if (clk_id >= 1 && clk_id <= 3) {
+               setbits_le32(&pmc->pmc_clk_out_cntrl,
+                            1 << (2 + (clk_id - 1) * 8));
+       } else {
+               printf("%s: Unknown output clock id %d\n", __func__, clk_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}