Patchwork [U-Boot,2/7] Tegra114: Add AVP (arm720t) files

login
register
mail settings
Submitter Tom Warren
Date Jan. 16, 2013, 9:14 p.m.
Message ID <1358370848-29469-3-git-send-email-twarren@nvidia.com>
Download mbox | patch
Permalink /patch/213059/
State Superseded
Delegated to: Tom Warren
Headers show

Comments

Tom Warren - Jan. 16, 2013, 9:14 p.m.
This provides SPL support for T114 boards - AVP early init, plus
CPU (A15) init/jump to main U-Boot.

Signed-off-by: Tom Warren <twarren@nvidia.com>
---
 arch/arm/cpu/arm720t/tegra-common/cpu.c |   23 ++-
 arch/arm/cpu/arm720t/tegra-common/cpu.h |   13 +-
 arch/arm/cpu/arm720t/tegra114/Makefile  |   42 ++++
 arch/arm/cpu/arm720t/tegra114/config.mk |   19 ++
 arch/arm/cpu/arm720t/tegra114/cpu.c     |  328 +++++++++++++++++++++++++++++++
 5 files changed, 411 insertions(+), 14 deletions(-)
 create mode 100644 arch/arm/cpu/arm720t/tegra114/Makefile
 create mode 100644 arch/arm/cpu/arm720t/tegra114/config.mk
 create mode 100644 arch/arm/cpu/arm720t/tegra114/cpu.c
Stephen Warren - Jan. 16, 2013, 10:42 p.m.
On 01/16/2013 02:14 PM, Tom Warren wrote:
> This provides SPL support for T114 boards - AVP early init, plus
> CPU (A15) init/jump to main U-Boot.

> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c

> -	if (chip_id == 0x30)
> +	if (chip_id >= 0x30)
>  		return TEGRA_FAMILY_T3x;
>  	else
>  		return TEGRA_FAMILY_T2x;

Shouldn't that comparison use CHIPID_TEGRA30?

Shouldn't there be a TEGRA_FAMILY_T11x for Tegra114; anything that cares
about >=Tegra30 can compare the family with >= not ==.

Hmm. It seems the only use of the FAMILY value is get_num_cpus() right
below; why not have that just switch on the same chip_id variable that
everything else uses?

> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h

> +#ifndef TRUE
> +#define TRUE	1
> +#endif
> +#ifndef FALSE
> +#define FALSE	0
> +#endif

Surely those are in a standard header somewhere; we shouldn't create yet
another duplicate of them.

> diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c

> +static int is_partition_powered(u32 mask)

> +	reg = readl(&pmc->pmc_pwrgate_status);
> +	if ((reg & mask) == mask)
> +		return TRUE;
> +
> +	return FALSE;

The last 4 lines are just "return reg & mask;" or "return (reg & mask)
== mask;". Same in the next function.

> +void powerup_cpus(void)
> +{
> +	debug("powerup_cpus entry\n");
> +
> +	/* Are we booting to the fast cluster? */
> +	if (get_cluster_id() == 0) {

Why would we ever boot on anything other than the fast cluster? I would
assume that the kernel assume it will always get booted on the fast
cluster, which would then imply that U-Boot had to boot on or switch to
the fast cluster.
Allen Martin - Jan. 16, 2013, 11:01 p.m.
On Wed, Jan 16, 2013 at 01:14:03PM -0800, Tom Warren wrote:
> This provides SPL support for T114 boards - AVP early init, plus
> CPU (A15) init/jump to main U-Boot.
> 
> Signed-off-by: Tom Warren <twarren@nvidia.com>
> ---
>  arch/arm/cpu/arm720t/tegra-common/cpu.c |   23 ++-
>  arch/arm/cpu/arm720t/tegra-common/cpu.h |   13 +-
>  arch/arm/cpu/arm720t/tegra114/Makefile  |   42 ++++
>  arch/arm/cpu/arm720t/tegra114/config.mk |   19 ++
>  arch/arm/cpu/arm720t/tegra114/cpu.c     |  328 +++++++++++++++++++++++++++++++
>  5 files changed, 411 insertions(+), 14 deletions(-)
>  create mode 100644 arch/arm/cpu/arm720t/tegra114/Makefile
>  create mode 100644 arch/arm/cpu/arm720t/tegra114/config.mk
>  create mode 100644 arch/arm/cpu/arm720t/tegra114/cpu.c
> 
> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c
> index 693d584..846163c 100644
> --- a/arch/arm/cpu/arm720t/tegra-common/cpu.c
> +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c
> @@ -40,7 +40,7 @@ enum tegra_family_t get_family(void)
>         chip_id = reg >> 8;
>         chip_id &= 0xff;
>         debug("  tegra_get_family: chip_id = %x\n", chip_id);
> -       if (chip_id == 0x30)
> +       if (chip_id >= 0x30)

Should this be CHIPID_TEGRA30?  And it would probably be better to do:

if (chipid == CHIPID_TEGRA30 || chipid == CHIPID_TEGRA114)
         return TEGRA_FAMILY_T3x;
else if (chipid == CHIPID_TEGRA20)
         return TEGRA_FAMILY_T2x;
else
         fail;


That forces the person doing the support for the next tegra chip to
have to make a conscious decision about what to do here.


>                 return TEGRA_FAMILY_T3x;
>         else
>                 return TEGRA_FAMILY_T2x;
> @@ -56,6 +56,7 @@ int get_num_cpus(void)
>   */
>  struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
>         /* T20: 1 GHz */
> +       /*  n,  m, p, cpcon */
>         {{ 1000, 13, 0, 12},    /* OSC 13M */
>          { 625,  12, 0, 8},     /* OSC 19.2M */
>          { 1000, 12, 0, 12},    /* OSC 12M */
> @@ -76,11 +77,11 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
>          { 700, 13, 0, 8},
>         },
> 
> -       /* 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 */

Removing TEGRA_SOC2_SLOW should probably be a separate patch, since it
doesn't hae anything to do with t114.

> +       /* T114: 1.4 GHz */
> +       {{ 862, 8, 0, 8},
> +        { 583, 8, 0, 4},
> +        { 696, 12, 0, 8},
> +        { 700, 13, 0, 8},
>         },
>  };
> 
> @@ -166,8 +167,8 @@ void init_pllx(void)
>         sel = &tegra_pll_x_table[chip_type][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) {
> +       /* adjust PLLP_out1-4 on T30/T114 */
> +       if (chip_type >= TEGRA_SOC_T30) {

same comment here about >= T30

>                 debug("  init_pllx: adjusting PLLP out freqs\n");
>                 adjust_pllp_out_freqs();
>         }
> @@ -203,7 +204,7 @@ void enable_cpu_clock(int enable)
>          */
>         clk = readl(&clkrst->crc_clk_cpu_cmplx);
>         clk |= 1 << CPU1_CLK_STP_SHIFT;
> -#if defined(CONFIG_TEGRA30)
> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)

Can this be runtime instead of #ifdef?

>         clk |= 1 << CPU2_CLK_STP_SHIFT;
>         clk |= 1 << CPU3_CLK_STP_SHIFT;
>  #endif
> @@ -308,7 +309,7 @@ void clock_enable_coresight(int enable)
>                  * Clock divider request for 204MHz would setup CSITE clock as
>                  * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
>                  */
> -               if (tegra_get_chip_type() == TEGRA_SOC_T30)
> +               if (tegra_get_chip_type() >= TEGRA_SOC_T30)

same comment here about >= T30

>                         src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
>                 else
>                         src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
> @@ -318,7 +319,7 @@ void clock_enable_coresight(int enable)
>                 rst = CORESIGHT_UNLOCK;
>                 writel(rst, CSITE_CPU_DBG0_LAR);
>                 writel(rst, CSITE_CPU_DBG1_LAR);
> -#if defined(CONFIG_TEGRA30)
> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)

same comment here about runtime vs ifdef

>                 writel(rst, CSITE_CPU_DBG2_LAR);
>                 writel(rst, CSITE_CPU_DBG3_LAR);
>  #endif
> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
> index 3e2ea3a..45b346d 100644
> --- a/arch/arm/cpu/arm720t/tegra-common/cpu.h
> +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.h
> @@ -22,14 +22,21 @@
>   */
>  #include <asm/types.h>
> 
> +#ifndef TRUE
> +#define TRUE   1
> +#endif
> +#ifndef FALSE
> +#define FALSE  0
> +#endif
> +

u-boot seems a little inconsistent here, but it looks like most of
u-boot uses C99 "true" and "false"


>  /* Stabilization delays, in usec */
>  #define PLL_STABILIZATION_DELAY (300)
>  #define IO_STABILIZATION_DELAY (1000)
> 
> -#if defined(CONFIG_TEGRA30)
> -#define NVBL_PLLP_KHZ  (408000)
> -#else  /* Tegra20 */
> +#if defined(CONFIG_TEGRA20)
>  #define NVBL_PLLP_KHZ  (216000)
> +#else  /* Tegra30/Tegra114 */
> +#define NVBL_PLLP_KHZ  (408000)
>  #endif

Again here it's probably better to explicitly do:

#if defined(CONFIG_TEGRA20)
...
#elsif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
...
#else
#error "unknown tegra chip"
#endif

Or better yet, make it runtime if possible.

> +
> +       /* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
> +       reg = readl(&pmc->pmc_cntrl);
> +       reg &= ~(CPUPWRREQ_POL);
> +       reg |= CPUPWRREQ_OE;
> +       writel(reg, &pmc->pmc_cntrl);

clrsetbits_le32() instead?

> +
> +       /*
> +        * Set CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0_CAR2PMC_CPU_ACK_WIDTH
> +        * to 408 to satisfy the requirement of having at least 16 CPU clock
> +        * cycles before clamp removal.
> +        */
> +
> +       reg = readl(&clkrst->crc_cpu_softrst_ctrl2);
> +       reg &= 0xFFFFF000;      /* bits 11:0 */
> +       reg |= 408;
> +       writel(reg, &clkrst->crc_cpu_softrst_ctrl2);

clrsetbits_le32() instead?


> +       val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
> +               (1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
> +               (0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
> +               (0 << CLK_SYS_RATE_APB_RATE_SHIFT);

Remove the 0's?

> +       writel(val, &clkrst->crc_clk_sys_rate);
> +

-Allen
Tom Warren - Jan. 17, 2013, 7:15 p.m.
Stephen,

On Wed, Jan 16, 2013 at 3:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 01/16/2013 02:14 PM, Tom Warren wrote:
>> This provides SPL support for T114 boards - AVP early init, plus
>> CPU (A15) init/jump to main U-Boot.
>
>> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c
>
>> -     if (chip_id == 0x30)
>> +     if (chip_id >= 0x30)
>>               return TEGRA_FAMILY_T3x;
>>       else
>>               return TEGRA_FAMILY_T2x;
>
> Shouldn't that comparison use CHIPID_TEGRA30?
>
> Shouldn't there be a TEGRA_FAMILY_T11x for Tegra114; anything that cares
> about >=Tegra30 can compare the family with >= not ==.
>
> Hmm. It seems the only use of the FAMILY value is get_num_cpus() right
> below; why not have that just switch on the same chip_id variable that
> everything else uses?

Sure, I can refine this code.  I didn't want to spend too much time
obsessively polishing my 'precious' and miss the upstreaming dates I'd
committed to.

But it's worth a look for V2.

>
>> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
>
>> +#ifndef TRUE
>> +#define TRUE 1
>> +#endif
>> +#ifndef FALSE
>> +#define FALSE        0
>> +#endif
>
> Surely those are in a standard header somewhere; we shouldn't create yet
> another duplicate of them.

Couldn't find 'em on a quick search (grep define.TRUE) except in
places like scsi.h and ext4_common.h and fpga.h. If you have a
standard header that you know of, let me know.

>
>> diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c
>
>> +static int is_partition_powered(u32 mask)
>
>> +     reg = readl(&pmc->pmc_pwrgate_status);
>> +     if ((reg & mask) == mask)
>> +             return TRUE;
>> +
>> +     return FALSE;
>
> The last 4 lines are just "return reg & mask;" or "return (reg & mask)
> == mask;". Same in the next function.

I'm porting internal bootloader bringup code here, and trying to avoid
unnecessary changes, but I can modify these to remove the TRUE/FALSE
in V2.

>
>> +void powerup_cpus(void)
>> +{
>> +     debug("powerup_cpus entry\n");
>> +
>> +     /* Are we booting to the fast cluster? */
>> +     if (get_cluster_id() == 0) {
>
> Why would we ever boot on anything other than the fast cluster? I would
> assume that the kernel assume it will always get booted on the fast
> cluster, which would then imply that U-Boot had to boot on or switch to
> the fast cluster.
>

Again, this is from internal NV bootloader code that I know works. I
don't know the circumstances where we might be booted on the LP
cluster, but I figured if the internal bootloader code thought it
worth checking, so should I.  If you have unimpeachable evidence to
the contrary, I can optimize this out.

Tom
Tom Warren - Jan. 17, 2013, 7:28 p.m.
Allen,

On Wed, Jan 16, 2013 at 4:01 PM, Allen Martin <amartin@nvidia.com> wrote:
> On Wed, Jan 16, 2013 at 01:14:03PM -0800, Tom Warren wrote:
>> This provides SPL support for T114 boards - AVP early init, plus
>> CPU (A15) init/jump to main U-Boot.
>>
>> Signed-off-by: Tom Warren <twarren@nvidia.com>
>> ---
>>  arch/arm/cpu/arm720t/tegra-common/cpu.c |   23 ++-
>>  arch/arm/cpu/arm720t/tegra-common/cpu.h |   13 +-
>>  arch/arm/cpu/arm720t/tegra114/Makefile  |   42 ++++
>>  arch/arm/cpu/arm720t/tegra114/config.mk |   19 ++
>>  arch/arm/cpu/arm720t/tegra114/cpu.c     |  328 +++++++++++++++++++++++++++++++
>>  5 files changed, 411 insertions(+), 14 deletions(-)
>>  create mode 100644 arch/arm/cpu/arm720t/tegra114/Makefile
>>  create mode 100644 arch/arm/cpu/arm720t/tegra114/config.mk
>>  create mode 100644 arch/arm/cpu/arm720t/tegra114/cpu.c
>>
>> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c
>> index 693d584..846163c 100644
>> --- a/arch/arm/cpu/arm720t/tegra-common/cpu.c
>> +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c
>> @@ -40,7 +40,7 @@ enum tegra_family_t get_family(void)
>>         chip_id = reg >> 8;
>>         chip_id &= 0xff;
>>         debug("  tegra_get_family: chip_id = %x\n", chip_id);
>> -       if (chip_id == 0x30)
>> +       if (chip_id >= 0x30)
>
> Should this be CHIPID_TEGRA30?  And it would probably be better to do:
>
> if (chipid == CHIPID_TEGRA30 || chipid == CHIPID_TEGRA114)
>          return TEGRA_FAMILY_T3x;
> else if (chipid == CHIPID_TEGRA20)
>          return TEGRA_FAMILY_T2x;
> else
>          fail;
>
>
> That forces the person doing the support for the next tegra chip to
> have to make a conscious decision about what to do here.

Sounds good, will do in V2.

>
>
>>                 return TEGRA_FAMILY_T3x;
>>         else
>>                 return TEGRA_FAMILY_T2x;
>> @@ -56,6 +56,7 @@ int get_num_cpus(void)
>>   */
>>  struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
>>         /* T20: 1 GHz */
>> +       /*  n,  m, p, cpcon */
>>         {{ 1000, 13, 0, 12},    /* OSC 13M */
>>          { 625,  12, 0, 8},     /* OSC 19.2M */
>>          { 1000, 12, 0, 12},    /* OSC 12M */
>> @@ -76,11 +77,11 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
>>          { 700, 13, 0, 8},
>>         },
>>
>> -       /* 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 */
>
> Removing TEGRA_SOC2_SLOW should probably be a separate patch, since it
> doesn't hae anything to do with t114.

I did this in one of my patchset revisions for the T30 baseline code,
but it crept back in somehow when I got around to looking at T114
support.

I can make a separate patch and slip it in the /next on top of the
current commits, before I apply the T114 stuff if it's cleaner for
you.

>
>> +       /* T114: 1.4 GHz */
>> +       {{ 862, 8, 0, 8},
>> +        { 583, 8, 0, 4},
>> +        { 696, 12, 0, 8},
>> +        { 700, 13, 0, 8},
>>         },
>>  };
>>
>> @@ -166,8 +167,8 @@ void init_pllx(void)
>>         sel = &tegra_pll_x_table[chip_type][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) {
>> +       /* adjust PLLP_out1-4 on T30/T114 */
>> +       if (chip_type >= TEGRA_SOC_T30) {
>
> same comment here about >= T30

Will do.

>
>>                 debug("  init_pllx: adjusting PLLP out freqs\n");
>>                 adjust_pllp_out_freqs();
>>         }
>> @@ -203,7 +204,7 @@ void enable_cpu_clock(int enable)
>>          */
>>         clk = readl(&clkrst->crc_clk_cpu_cmplx);
>>         clk |= 1 << CPU1_CLK_STP_SHIFT;
>> -#if defined(CONFIG_TEGRA30)
>> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
>
> Can this be runtime instead of #ifdef?

Not sure what you mean by runtime - this is common code. Are you
asking to make it based on a num_cpus variable, etc.?

if (num_cpus > 2)
    clk |= (1 << CPU2_CLK_STP_SHIFT) + (1 << CPU3_CLK_STP_SHIFT);


>
>>         clk |= 1 << CPU2_CLK_STP_SHIFT;
>>         clk |= 1 << CPU3_CLK_STP_SHIFT;
>>  #endif
>> @@ -308,7 +309,7 @@ void clock_enable_coresight(int enable)
>>                  * Clock divider request for 204MHz would setup CSITE clock as
>>                  * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
>>                  */
>> -               if (tegra_get_chip_type() == TEGRA_SOC_T30)
>> +               if (tegra_get_chip_type() >= TEGRA_SOC_T30)
>
> same comment here about >= T30

Will do.

>
>>                         src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
>>                 else
>>                         src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
>> @@ -318,7 +319,7 @@ void clock_enable_coresight(int enable)
>>                 rst = CORESIGHT_UNLOCK;
>>                 writel(rst, CSITE_CPU_DBG0_LAR);
>>                 writel(rst, CSITE_CPU_DBG1_LAR);
>> -#if defined(CONFIG_TEGRA30)
>> +#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
>
> same comment here about runtime vs ifdef
>
>>                 writel(rst, CSITE_CPU_DBG2_LAR);
>>                 writel(rst, CSITE_CPU_DBG3_LAR);
>>  #endif
>> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
>> index 3e2ea3a..45b346d 100644
>> --- a/arch/arm/cpu/arm720t/tegra-common/cpu.h
>> +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.h
>> @@ -22,14 +22,21 @@
>>   */
>>  #include <asm/types.h>
>>
>> +#ifndef TRUE
>> +#define TRUE   1
>> +#endif
>> +#ifndef FALSE
>> +#define FALSE  0
>> +#endif
>> +
>
> u-boot seems a little inconsistent here, but it looks like most of
> u-boot uses C99 "true" and "false"

Can you point to a header to include to get this? Or same code? Thanks.

>
>
>>  /* Stabilization delays, in usec */
>>  #define PLL_STABILIZATION_DELAY (300)
>>  #define IO_STABILIZATION_DELAY (1000)
>>
>> -#if defined(CONFIG_TEGRA30)
>> -#define NVBL_PLLP_KHZ  (408000)
>> -#else  /* Tegra20 */
>> +#if defined(CONFIG_TEGRA20)
>>  #define NVBL_PLLP_KHZ  (216000)
>> +#else  /* Tegra30/Tegra114 */
>> +#define NVBL_PLLP_KHZ  (408000)
>>  #endif
>
> Again here it's probably better to explicitly do:
>
> #if defined(CONFIG_TEGRA20)
> ...
> #elsif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
> ...
> #else
> #error "unknown tegra chip"
> #endif
>
> Or better yet, make it runtime if possible.

Again, I always try to make changes as minimally as possible, but I
haven't thought too much about the next SoC port (probably because
I'll likely be doing it, too).

But it's probably worth changing this to flag things like that, so
I'll do it in V2.

>
>> +
>> +       /* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
>> +       reg = readl(&pmc->pmc_cntrl);
>> +       reg &= ~(CPUPWRREQ_POL);
>> +       reg |= CPUPWRREQ_OE;
>> +       writel(reg, &pmc->pmc_cntrl);
>
> clrsetbits_le32() instead?

Yeah, I have a note to go thru the T30/T114 init code and change all
of these to set/clrbits_le32() where possible. I'll do that for V2 for
T114 and if any crop up in T30-only code, I'll submit a new patch for
that.

>
>> +
>> +       /*
>> +        * Set CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0_CAR2PMC_CPU_ACK_WIDTH
>> +        * to 408 to satisfy the requirement of having at least 16 CPU clock
>> +        * cycles before clamp removal.
>> +        */
>> +
>> +       reg = readl(&clkrst->crc_cpu_softrst_ctrl2);
>> +       reg &= 0xFFFFF000;      /* bits 11:0 */
>> +       reg |= 408;
>> +       writel(reg, &clkrst->crc_cpu_softrst_ctrl2);
>
> clrsetbits_le32() instead?
>
>
>> +       val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
>> +               (1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
>> +               (0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
>> +               (0 << CLK_SYS_RATE_APB_RATE_SHIFT);
>
> Remove the 0's?

Yeah, that'd be cleaner. Again, ported from internal bootloader code.

>
>> +       writel(val, &clkrst->crc_clk_sys_rate);
>> +
>
> -Allen
> --
> nvpublic
Thanks,

Tom
Stephen Warren - Jan. 17, 2013, 10:42 p.m.
On 01/17/2013 12:15 PM, Tom Warren wrote:
> Stephen,
> 
> On Wed, Jan 16, 2013 at 3:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 01/16/2013 02:14 PM, Tom Warren wrote:
>>> This provides SPL support for T114 boards - AVP early init, plus
>>> CPU (A15) init/jump to main U-Boot.

>>> diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
>>
>>> +#ifndef TRUE
>>> +#define TRUE 1
>>> +#endif
>>> +#ifndef FALSE
>>> +#define FALSE        0
>>> +#endif
>>
>> Surely those are in a standard header somewhere; we shouldn't create yet
>> another duplicate of them.
> 
> Couldn't find 'em on a quick search (grep define.TRUE) except in
> places like scsi.h and ext4_common.h and fpga.h. If you have a
> standard header that you know of, let me know.

Hmmm. Further investigation shows it is indeed once of those standard
things that isn't actually defined anywhere standard:-(

>>> diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c
>>
>>> +static int is_partition_powered(u32 mask)
>>
>>> +     reg = readl(&pmc->pmc_pwrgate_status);
>>> +     if ((reg & mask) == mask)
>>> +             return TRUE;
>>> +
>>> +     return FALSE;
>>
>> The last 4 lines are just "return reg & mask;" or "return (reg & mask)
>> == mask;". Same in the next function.
> 
> I'm porting internal bootloader bringup code here, and trying to avoid
> unnecessary changes, but I can modify these to remove the TRUE/FALSE
> in V2.

I don't think our downstream code is relevant for upstreaming; changes
sent upstream should be clean/minimal/standalone. In fact, I find
upstreaming a good time to explicitly remove/clean-up all the cruft that
has accumulated downstream, which wasn't always thought through thoroughly.

>>> +void powerup_cpus(void)
>>> +{
>>> +     debug("powerup_cpus entry\n");
>>> +
>>> +     /* Are we booting to the fast cluster? */
>>> +     if (get_cluster_id() == 0) {
>>
>> Why would we ever boot on anything other than the fast cluster? I would
>> assume that the kernel assume it will always get booted on the fast
>> cluster, which would then imply that U-Boot had to boot on or switch to
>> the fast cluster.
> 
> Again, this is from internal NV bootloader code that I know works. I
> don't know the circumstances where we might be booted on the LP
> cluster, but I figured if the internal bootloader code thought it
> worth checking, so should I.  If you have unimpeachable evidence to
> the contrary, I can optimize this out.

I think it's more that if we don't have concrete evidence that the code
is needed, we shouldn't bloat usptream with cruft.

Patch

diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c
index 693d584..846163c 100644
--- a/arch/arm/cpu/arm720t/tegra-common/cpu.c
+++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c
@@ -40,7 +40,7 @@  enum tegra_family_t get_family(void)
 	chip_id = reg >> 8;
 	chip_id &= 0xff;
 	debug("  tegra_get_family: chip_id = %x\n", chip_id);
-	if (chip_id == 0x30)
+	if (chip_id >= 0x30)
 		return TEGRA_FAMILY_T3x;
 	else
 		return TEGRA_FAMILY_T2x;
@@ -56,6 +56,7 @@  int get_num_cpus(void)
  */
 struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
 	/* T20: 1 GHz */
+	/*  n,  m, p, cpcon */
 	{{ 1000, 13, 0, 12},	/* OSC 13M */
 	 { 625,  12, 0, 8},	/* OSC 19.2M */
 	 { 1000, 12, 0, 12},	/* OSC 12M */
@@ -76,11 +77,11 @@  struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
 	 { 700, 13, 0, 8},
 	},
 
-	/* 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 */
+	/* T114: 1.4 GHz */
+	{{ 862, 8, 0, 8},
+	 { 583, 8, 0, 4},
+	 { 696, 12, 0, 8},
+	 { 700, 13, 0, 8},
 	},
 };
 
@@ -166,8 +167,8 @@  void init_pllx(void)
 	sel = &tegra_pll_x_table[chip_type][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) {
+	/* adjust PLLP_out1-4 on T30/T114 */
+	if (chip_type >= TEGRA_SOC_T30) {
 		debug("  init_pllx: adjusting PLLP out freqs\n");
 		adjust_pllp_out_freqs();
 	}
@@ -203,7 +204,7 @@  void enable_cpu_clock(int enable)
 	 */
 	clk = readl(&clkrst->crc_clk_cpu_cmplx);
 	clk |= 1 << CPU1_CLK_STP_SHIFT;
-#if defined(CONFIG_TEGRA30)
+#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
 	clk |= 1 << CPU2_CLK_STP_SHIFT;
 	clk |= 1 << CPU3_CLK_STP_SHIFT;
 #endif
@@ -308,7 +309,7 @@  void clock_enable_coresight(int enable)
 		 * Clock divider request for 204MHz would setup CSITE clock as
 		 * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
 		 */
-		if (tegra_get_chip_type() == TEGRA_SOC_T30)
+		if (tegra_get_chip_type() >= TEGRA_SOC_T30)
 			src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
 		else
 			src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
@@ -318,7 +319,7 @@  void clock_enable_coresight(int enable)
 		rst = CORESIGHT_UNLOCK;
 		writel(rst, CSITE_CPU_DBG0_LAR);
 		writel(rst, CSITE_CPU_DBG1_LAR);
-#if defined(CONFIG_TEGRA30)
+#if defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
 		writel(rst, CSITE_CPU_DBG2_LAR);
 		writel(rst, CSITE_CPU_DBG3_LAR);
 #endif
diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
index 3e2ea3a..45b346d 100644
--- a/arch/arm/cpu/arm720t/tegra-common/cpu.h
+++ b/arch/arm/cpu/arm720t/tegra-common/cpu.h
@@ -22,14 +22,21 @@ 
  */
 #include <asm/types.h>
 
+#ifndef TRUE
+#define TRUE	1
+#endif
+#ifndef FALSE
+#define FALSE	0
+#endif
+
 /* Stabilization delays, in usec */
 #define PLL_STABILIZATION_DELAY (300)
 #define IO_STABILIZATION_DELAY	(1000)
 
-#if defined(CONFIG_TEGRA30)
-#define NVBL_PLLP_KHZ	(408000)
-#else	/* Tegra20 */
+#if defined(CONFIG_TEGRA20)
 #define NVBL_PLLP_KHZ	(216000)
+#else	/* Tegra30/Tegra114 */
+#define NVBL_PLLP_KHZ	(408000)
 #endif
 
 #define PLLX_ENABLED		(1 << 30)
diff --git a/arch/arm/cpu/arm720t/tegra114/Makefile b/arch/arm/cpu/arm720t/tegra114/Makefile
new file mode 100644
index 0000000..157d85a
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra114/Makefile
@@ -0,0 +1,42 @@ 
+#
+# Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+#COBJS-y	+= cpu.o t11x.o
+COBJS-y	+= cpu.o
+
+SRCS	:= $(COBJS-y:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS-y))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/arm720t/tegra114/config.mk b/arch/arm/cpu/arm720t/tegra114/config.mk
new file mode 100644
index 0000000..2388c56
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra114/config.mk
@@ -0,0 +1,19 @@ 
+#
+# Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+USE_PRIVATE_LIBGCC = yes
diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c
new file mode 100644
index 0000000..9527495
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra114/cpu.c
@@ -0,0 +1,328 @@ 
+/*
+ * Copyright (c) 2010-2012, 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,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include "../tegra-common/cpu.h"
+
+/* Tegra114-specific CPU init code */
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_power_rail entry\n");
+
+	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
+	pinmux_tristate_disable(PINGRP_PWR_I2C_SCL);
+	pinmux_tristate_disable(PINGRP_PWR_I2C_SDA);
+
+	/*
+	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz),
+	 * set it for 25ms (102MHz * .025)
+	 */
+	reg = 0x26E8F0;
+	writel(reg, &pmc->pmc_cpupwrgood_timer);
+
+	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
+	reg = readl(&pmc->pmc_cntrl);
+	reg &= ~(CPUPWRREQ_POL);
+	reg |= CPUPWRREQ_OE;
+	writel(reg, &pmc->pmc_cntrl);
+
+	/*
+	 * Set CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0_CAR2PMC_CPU_ACK_WIDTH
+	 * to 408 to satisfy the requirement of having at least 16 CPU clock
+	 * cycles before clamp removal.
+	 */
+
+	reg = readl(&clkrst->crc_cpu_softrst_ctrl2);
+	reg &= 0xFFFFF000;	/* bits 11:0 */
+	reg |= 408;
+	writel(reg, &clkrst->crc_cpu_softrst_ctrl2);
+}
+
+static void enable_cpu_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_clocks entry\n");
+
+	/* Wait for PLL-X to lock */
+	do {
+		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+	} while ((reg & (1 << 27)) == 0);
+
+	/* Wait until all clocks are stable */
+	udelay(PLL_STABILIZATION_DELAY);
+
+	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+
+	/* Always enable the main CPU complex clocks */
+	clock_enable(PERIPH_ID_CPU);
+	clock_enable(PERIPH_ID_CPULP);
+	clock_enable(PERIPH_ID_CPUG);
+}
+
+static void remove_cpu_resets(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("remove_cpu_resets entry\n");
+	/* Take the slow non-CPU partition out of reset */
+	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr);
+	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Take the fast non-CPU partition out of reset */
+	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr);
+	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpug_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the slow cluster */
+	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr);
+	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0);
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the fast cluster */
+	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr);
+	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0);
+	reg |= (CLR_CPURESET1+CLR_DBGRESET1+CLR_CORERESET1+CLR_CXRESET1);
+	reg |= (CLR_CPURESET2+CLR_DBGRESET2+CLR_CORERESET2+CLR_CXRESET2);
+	reg |= (CLR_CPURESET3+CLR_DBGRESET3+CLR_CORERESET3+CLR_CXRESET3);
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+}
+
+/**
+ * The T114 requires some special clock initialization, including setting up
+ * the DVC I2C, turning on MSELECT and selecting the G CPU cluster
+ */
+void t114_init_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	u32 val;
+
+	debug("t114_init_clocks entry\n");
+
+	/* Set active CPU cluster to G */
+	clrbits_le32(&flow->cluster_control, 1);
+
+	/*
+	 * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
+	 * at 108 MHz. This is glitch free as only the source is changed, no
+	 * special precaution needed.
+	 */
+	val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+	writel(val, &clkrst->crc_sclk_brst_pol);
+
+	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
+
+	debug("Setting up PLLX\n");
+	init_pllx();
+
+	val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
+		(1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
+		(0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
+		(0 << CLK_SYS_RATE_APB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Enable clocks to required peripherals. TBD - minimize this list */
+	debug("Enabling clocks\n");
+
+	clock_set_enable(PERIPH_ID_CACHE2, 1);
+	clock_set_enable(PERIPH_ID_GPIO, 1);
+	clock_set_enable(PERIPH_ID_TMR, 1);
+	clock_set_enable(PERIPH_ID_RTC, 1);
+	clock_set_enable(PERIPH_ID_CPU, 1);
+	clock_set_enable(PERIPH_ID_EMC, 1);
+	clock_set_enable(PERIPH_ID_I2C5, 1);
+	clock_set_enable(PERIPH_ID_FUSE, 1);
+	clock_set_enable(PERIPH_ID_PMC, 1);
+	clock_set_enable(PERIPH_ID_APBDMA, 1);
+	clock_set_enable(PERIPH_ID_MEM, 1);
+	clock_set_enable(PERIPH_ID_IRAMA, 1);
+	clock_set_enable(PERIPH_ID_IRAMB, 1);
+	clock_set_enable(PERIPH_ID_IRAMC, 1);
+	clock_set_enable(PERIPH_ID_IRAMD, 1);
+	clock_set_enable(PERIPH_ID_CORESIGHT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_EMC1, 1);
+	clock_set_enable(PERIPH_ID_MC1, 1);
+	clock_set_enable(PERIPH_ID_DVFS, 1);
+
+	/* Switch MSELECT clock to PLLP (00) */
+	clock_ll_set_source(PERIPH_ID_MSELECT, 0);
+
+	/*
+	 * Clock divider request for 102MHz would setup MSELECT clock as
+	 * 102MHz for PLLP base 408MHz
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0,
+		(NVBL_PLLP_KHZ/102000));
+
+	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */
+	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16);
+
+	/* Give clocks time to stabilize */
+	udelay(1000);
+
+	/* Take required peripherals out of reset */
+	debug("Taking periphs out of reset\n");
+	reset_set_enable(PERIPH_ID_CACHE2, 0);
+	reset_set_enable(PERIPH_ID_GPIO, 0);
+	reset_set_enable(PERIPH_ID_TMR, 0);
+	reset_set_enable(PERIPH_ID_COP, 0);
+	reset_set_enable(PERIPH_ID_EMC, 0);
+	reset_set_enable(PERIPH_ID_I2C5, 0);
+	reset_set_enable(PERIPH_ID_FUSE, 0);
+	reset_set_enable(PERIPH_ID_APBDMA, 0);
+	reset_set_enable(PERIPH_ID_MEM, 0);
+	reset_set_enable(PERIPH_ID_CORESIGHT, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+	reset_set_enable(PERIPH_ID_EMC1, 0);
+	reset_set_enable(PERIPH_ID_MC1, 0);
+
+	debug("t114_init_clocks exit\n");
+}
+
+static int get_cluster_id(void)
+{
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+
+	debug("%s: id = %08X\n", __func__, readl(&flow->cluster_control));
+	/* Return ACTIVE bit (bit0) which is 0 for G and 1 for LP */
+	return readl(&flow->cluster_control) & 1;
+}
+
+static int is_partition_powered(u32 mask)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get power gate status */
+	reg = readl(&pmc->pmc_pwrgate_status);
+	if ((reg & mask) == mask)
+		return TRUE;
+
+	return FALSE;
+}
+
+static int is_clamp_removed(u32 mask)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get clamp status. TODO: Add pmc_clamp_status alias to pmc.h */
+	reg = readl(&pmc->pmc_pwrgate_timer_on);
+	if ((reg & mask) == mask)
+		return FALSE;
+
+	return TRUE;
+}
+
+static void power_partition(u32 status, u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("%s: status = %08X, part ID = %08X\n", __func__, status, partid);
+	/* Is the partition already on? */
+	if (!is_partition_powered(status)) {
+		/* No, toggle the partition power state (OFF -> ON) */
+		debug("power_partition, toggling state\n");
+		clrbits_le32(&pmc->pmc_pwrgate_toggle, 0x1F);
+		setbits_le32(&pmc->pmc_pwrgate_toggle, partid);
+		setbits_le32(&pmc->pmc_pwrgate_toggle, START_CP);
+
+		/* Wait for the power to come up */
+		while (!is_partition_powered(status))
+			;
+
+		/* Wait for the clamp status to be cleared */
+		while (!is_clamp_removed(status))
+			;
+
+		/* Give I/O signals time to stabilize */
+		udelay(IO_STABILIZATION_DELAY);
+	}
+}
+
+void powerup_cpus(void)
+{
+	debug("powerup_cpus entry\n");
+
+	/* Are we booting to the fast cluster? */
+	if (get_cluster_id() == 0) {
+		debug("powerup_cpus entry: G cluster\n");
+		/* Power up the fast cluster rail partition */
+		power_partition(CRAIL, CRAILID);
+
+		/* Power up the fast cluster non-CPU partition */
+		power_partition(C0NC, C0NCID);
+
+		/* Power up the fast cluster CPU0 partition */
+		power_partition(CE0, CE0ID);
+	} else {
+		debug("powerup_cpus entry: LP cluster\n");
+		/* Power up the slow cluster non-CPU partition */
+		power_partition(C1NC, C1NCID);
+
+		/* Power up the slow cluster CPU partition */
+		power_partition(CELP, CELPID);
+	}
+}
+
+void start_cpu(u32 reset_vector)
+{
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+
+	t114_init_clocks();
+
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	/* Get the CPU(s) running */
+	enable_cpu_clocks();
+
+	/* Enable CoreSight */
+	clock_enable_coresight(1);
+
+	/* Take CPU(s) out of reset */
+	remove_cpu_resets();
+
+	/*
+	 * Set the entry point for CPU execution from reset,
+	 *  if it's a non-zero value.
+	 */
+	if (reset_vector)
+		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+	/* If the CPU(s) don't already have power, power 'em up */
+	powerup_cpus();
+}