ARM: tegra: simplify halt_avp()
[platform/kernel/u-boot.git] / arch / arm / cpu / arm720t / tegra-common / cpu.c
index 693d584..168f525 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
 #include <asm/arch-tegra/scu.h>
 #include "cpu.h"
 
-enum tegra_family_t {
-       TEGRA_FAMILY_T2x,
-       TEGRA_FAMILY_T3x,
-};
-
-
-enum tegra_family_t get_family(void)
-{
-       u32 reg, chip_id;
-
-       reg = readl(NV_PA_APB_MISC_BASE + GP_HIDREV);
-
-       chip_id = reg >> 8;
-       chip_id &= 0xff;
-       debug("  tegra_get_family: chip_id = %x\n", chip_id);
-       if (chip_id == 0x30)
-               return TEGRA_FAMILY_T3x;
-       else
-               return TEGRA_FAMILY_T2x;
-}
-
 int get_num_cpus(void)
 {
-       return get_family() == TEGRA_FAMILY_T3x ? 4 : 2;
+       struct apb_misc_gp_ctlr *gp;
+       uint rev;
+
+       gp = (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
+       rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+
+       switch (rev) {
+       case CHIPID_TEGRA20:
+               return 2;
+               break;
+       case CHIPID_TEGRA30:
+       case CHIPID_TEGRA114:
+       default:
+               return 4;
+               break;
+       }
 }
 
 /*
  * Timing tables for each SOC for all four oscillator options.
  */
 struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
-       /* T20: 1 GHz */
-       {{ 1000, 13, 0, 12},    /* OSC 13M */
-        { 625,  12, 0, 8},     /* OSC 19.2M */
-        { 1000, 12, 0, 12},    /* OSC 12M */
-        { 1000, 26, 0, 12},    /* OSC 26M */
+       /*
+        * T20: 1 GHz
+        *
+        * Register   Field  Bits   Width
+        * ------------------------------
+        * PLLX_BASE  p      22:20    3
+        * PLLX_BASE  n      17: 8   10
+        * PLLX_BASE  m       4: 0    5
+        * PLLX_MISC  cpcon  11: 8    4
+        */
+       {
+               { .n = 1000, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+               { .n =  625, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+               { .n = 1000, .m = 12, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+               { .n = 1000, .m = 26, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
        },
-
-       /* T25: 1.2 GHz */
-       {{ 923, 10, 0, 12},
-        { 750, 12, 0, 8},
-        { 600,  6, 0, 12},
-        { 600, 13, 0, 12},
+       /*
+        * T25: 1.2 GHz
+        *
+        * Register   Field  Bits   Width
+        * ------------------------------
+        * PLLX_BASE  p      22:20    3
+        * PLLX_BASE  n      17: 8   10
+        * PLLX_BASE  m       4: 0    5
+        * PLLX_MISC  cpcon  11: 8    4
+        */
+       {
+               { .n = 923, .m = 10, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */
+               { .n = 750, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */
+               { .n = 600, .m =  6, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */
+               { .n = 600, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */
        },
-
-       /* T30: 1.4 GHz */
-       {{ 862, 8, 0, 8},
-        { 583, 8, 0, 4},
-        { 700, 6, 0, 8},
-        { 700, 13, 0, 8},
+       /*
+        * T30: 1.4 GHz
+        *
+        * Register   Field  Bits   Width
+        * ------------------------------
+        * PLLX_BASE  p      22:20    3
+        * PLLX_BASE  n      17: 8   10
+        * PLLX_BASE  m       4: 0    5
+        * PLLX_MISC  cpcon  11: 8    4
+        */
+       {
+               { .n = 862, .m =  8, .p = 0, .cpcon = 8 }, /* OSC: 13.0 MHz */
+               { .n = 583, .m =  8, .p = 0, .cpcon = 4 }, /* OSC: 19.2 MHz */
+               { .n = 700, .m =  6, .p = 0, .cpcon = 8 }, /* OSC: 12.0 MHz */
+               { .n = 700, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 26.0 MHz */
+       },
+       /*
+        * T114: 700 MHz
+        *
+        * Register   Field  Bits   Width
+        * ------------------------------
+        * PLLX_BASE  p      23:20    4
+        * PLLX_BASE  n      15: 8    8
+        * PLLX_BASE  m       7: 0    8
+        */
+       {
+               { .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+               { .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+               { .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+               { .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
        },
 
-       /* TEGRA_SOC2_SLOW: 312 MHz */
-       {{ 312, 13, 0, 12},     /* OSC 13M */
-        { 260, 16, 0, 8},      /* OSC 19.2M */
-        { 312, 12, 0, 12},     /* OSC 12M */
-        { 312, 26, 0, 12},     /* OSC 26M */
+       /*
+        * T124: 700 MHz
+        *
+        * Register   Field  Bits   Width
+        * ------------------------------
+        * PLLX_BASE  p      23:20    4
+        * PLLX_BASE  n      15: 8    8
+        * PLLX_BASE  m       7: 0    8
+        */
+       {
+               { .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+               { .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+               { .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+               { .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
        },
 };
 
-void adjust_pllp_out_freqs(void)
+static inline void pllx_set_iddq(void)
 {
+#if defined(CONFIG_TEGRA124)
        struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
-       struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH];
        u32 reg;
 
-       /* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
-       reg = readl(&pll->pll_out[0]);  /* OUTA, contains OUT2 / OUT1 */
-       reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR
-               | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR;
-       writel(reg, &pll->pll_out[0]);
-
-       reg = readl(&pll->pll_out[1]);   /* OUTB, contains OUT4 / OUT3 */
-       reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR
-               | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR;
-       writel(reg, &pll->pll_out[1]);
+       /* Disable IDDQ */
+       reg = readl(&clkrst->crc_pllx_misc3);
+       reg &= ~PLLX_IDDQ_MASK;
+       writel(reg, &clkrst->crc_pllx_misc3);
+       udelay(2);
+       debug("%s: IDDQ: PLLX IDDQ = 0x%08X\n", __func__,
+             readl(&clkrst->crc_pllx_misc3));
+#endif
 }
 
 int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
                u32 divp, u32 cpcon)
 {
+       int chip = tegra_get_chip();
        u32 reg;
 
        /* If PLLX is already enabled, just return */
@@ -115,31 +160,41 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
 
        debug(" pllx_set_rate entry\n");
 
+       pllx_set_iddq();
+
        /* Set BYPASS, m, n and p to PLLX_BASE */
        reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT);
        reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT));
        writel(reg, &pll->pll_base);
 
        /* Set cpcon to PLLX_MISC */
-       reg = (cpcon << PLL_CPCON_SHIFT);
+       if (chip == CHIPID_TEGRA20 || chip == CHIPID_TEGRA30)
+               reg = (cpcon << PLL_CPCON_SHIFT);
+       else
+               reg = 0;
 
        /* Set dccon to PLLX_MISC if freq > 600MHz */
        if (divn > 600)
                reg |= (1 << PLL_DCCON_SHIFT);
        writel(reg, &pll->pll_misc);
 
-       /* Enable PLLX */
-       reg = readl(&pll->pll_base);
-       reg |= PLL_ENABLE_MASK;
-
        /* Disable BYPASS */
+       reg = readl(&pll->pll_base);
        reg &= ~PLL_BYPASS_MASK;
        writel(reg, &pll->pll_base);
+       debug("pllx_set_rate: base = 0x%08X\n", reg);
 
        /* Set lock_enable to PLLX_MISC */
        reg = readl(&pll->pll_misc);
        reg |= PLL_LOCK_ENABLE_MASK;
        writel(reg, &pll->pll_misc);
+       debug("pllx_set_rate: misc = 0x%08X\n", reg);
+
+       /* Enable PLLX last, once it's all configured */
+       reg = readl(&pll->pll_base);
+       reg |= PLL_ENABLE_MASK;
+       writel(reg, &pll->pll_base);
+       debug("pllx_set_rate: base final = 0x%08X\n", reg);
 
        return 0;
 }
@@ -148,29 +203,31 @@ void init_pllx(void)
 {
        struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
        struct clk_pll_simple *pll = &clkrst->crc_pll_simple[SIMPLE_PLLX];
-       int chip_type;
+       int soc_type, sku_info, chip_sku;
        enum clock_osc_freq osc;
        struct clk_pll_table *sel;
 
        debug("init_pllx entry\n");
 
-       /* get chip type */
-       chip_type = tegra_get_chip_type();
-       debug(" init_pllx: chip_type = %d\n", chip_type);
+       /* get SOC (chip) type */
+       soc_type = tegra_get_chip();
+       debug(" init_pllx: SoC = 0x%02X\n", soc_type);
+
+       /* get SKU info */
+       sku_info = tegra_get_sku_info();
+       debug(" init_pllx: SKU info byte = 0x%02X\n", sku_info);
+
+       /* get chip SKU, combo of the above info */
+       chip_sku = tegra_get_chip_sku();
+       debug(" init_pllx: Chip SKU = %d\n", chip_sku);
 
        /* get osc freq */
        osc = clock_get_osc_freq();
-       debug("  init_pllx: osc = %d\n", osc);
+       debug(" init_pllx: osc = %d\n", osc);
 
        /* set pllx */
-       sel = &tegra_pll_x_table[chip_type][osc];
+       sel = &tegra_pll_x_table[chip_sku][osc];
        pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
-
-       /* adjust PLLP_out1-4 on T30 */
-       if (chip_type == TEGRA_SOC_T30) {
-               debug("  init_pllx: adjusting PLLP out freqs\n");
-               adjust_pllp_out_freqs();
-       }
 }
 
 void enable_cpu_clock(int enable)
@@ -203,10 +260,9 @@ void enable_cpu_clock(int enable)
         */
        clk = readl(&clkrst->crc_clk_cpu_cmplx);
        clk |= 1 << CPU1_CLK_STP_SHIFT;
-#if defined(CONFIG_TEGRA30)
-       clk |= 1 << CPU2_CLK_STP_SHIFT;
-       clk |= 1 << CPU3_CLK_STP_SHIFT;
-#endif
+       if (get_num_cpus() == 4)
+               clk |= (1 << CPU2_CLK_STP_SHIFT) + (1 << CPU3_CLK_STP_SHIFT);
+
        /* Stop/Unstop the CPU clock */
        clk &= ~CPU0_CLK_STP_MASK;
        clk |= !enable << CPU0_CLK_STP_SHIFT;
@@ -292,7 +348,7 @@ void reset_A9_cpu(int reset)
 
 void clock_enable_coresight(int enable)
 {
-       u32 rst, src;
+       u32 rst, src = 2;
 
        debug("clock_enable_coresight entry\n");
        clock_set_enable(PERIPH_ID_CORESIGHT, enable);
@@ -300,36 +356,29 @@ void clock_enable_coresight(int enable)
 
        if (enable) {
                /*
-                * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
-                *  1.5, giving an effective frequency of 144MHz.
-                * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
-                *  (bits 7:0), so 00000001b == 1.5 (n+1 + .5)
-                *
-                * Clock divider request for 204MHz would setup CSITE clock as
-                * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
+                * Put CoreSight on PLLP_OUT0 and divide it down as per
+                * PLLP base frequency based on SoC type (T20/T30+).
+                * Clock divider request would setup CSITE clock as 144MHz
+                * for PLLP base 216MHz and 204MHz for PLLP base 408MHz
                 */
-               if (tegra_get_chip_type() == TEGRA_SOC_T30)
-                       src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
-               else
-                       src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+               src = CLK_DIVIDER(NVBL_PLLP_KHZ, CSITE_KHZ);
                clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src);
 
                /* Unlock the CPU CoreSight interfaces */
                rst = CORESIGHT_UNLOCK;
                writel(rst, CSITE_CPU_DBG0_LAR);
                writel(rst, CSITE_CPU_DBG1_LAR);
-#if defined(CONFIG_TEGRA30)
-               writel(rst, CSITE_CPU_DBG2_LAR);
-               writel(rst, CSITE_CPU_DBG3_LAR);
-#endif
+               if (get_num_cpus() == 4) {
+                       writel(rst, CSITE_CPU_DBG2_LAR);
+                       writel(rst, CSITE_CPU_DBG3_LAR);
+               }
        }
 }
 
 void halt_avp(void)
 {
        for (;;) {
-               writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
-                       | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)),
-                       FLOW_CTLR_HALT_COP_EVENTS);
+               writel(HALT_COP_EVENT_JTAG | (FLOW_MODE_STOP << 29),
+                      FLOW_CTLR_HALT_COP_EVENTS);
        }
 }