asuswrt-merlin.ng/release/src-rt-5.02axhnd.675x/router-sysdep.rt-ax58u/bcmdrv/shared/hndarm_ca9.c
2022-05-26 14:16:11 -04:00

572 lines
16 KiB
C

/*
* BCM43XX Sonics SiliconBackplane ARM core routines
*
* Copyright (C) 2021, Broadcom. All Rights Reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: hndarm_ca9.c 678682 2017-01-10 16:37:04Z $
*/
#include <typedefs.h>
#include <bcm_math.h>
#include <bcmutils.h>
#include <siutils.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <sbhndarm.h>
#include <sbgci.h>
#include <bcmdevs.h>
#include <hndpmu.h>
#include <chipcommonb.h>
#include <armca9_core.h>
#include <ddr_core.h>
#define PLL_SUP_4708 0x00000001
#define PLL_SUP_4709 0x00000002
#define PLL_SUP_47092 0x00000004
#define PLL_SUP_47094 0x00000008
#define PLL_SUP_NS_ALL (PLL_SUP_4708 | PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094)
#define PLL_SUP_53573 0x00000010
#define PLL_SUP_DDR2 0x00000001
#define PLL_SUP_DDR3 0x00000002
struct arm_pll {
uint32 clk;
uint32 reg_val;
uint32 flag;
};
struct arm_ca7_pll {
uint32 cpu;
uint32 cci;
uint32 nic;
uint32 pll_ctrl_1; /* ndiv_nfrac */
uint32 pll_ctrl_2; /* mdiv */
uint32 clkratioarm;
uint32 clkratiocci;
};
struct ddr_clk {
uint32 clk;
uint32 pll_ctrl_1;
uint32 pll_ctrl_2;
uint32 type_flag;
uint32 flag;
};
static struct arm_pll arm_pll_table[] = {
{ 600, 0x1003001, PLL_SUP_NS_ALL},
{ 800, 0x1004001, PLL_SUP_NS_ALL},
{ 900, 0, PLL_SUP_53573},
{ 1000, 0x1005001, PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094},
{ 1200, 0x1006001, PLL_SUP_47094},
{ 1400, 0x1007001, PLL_SUP_47094},
{0}
};
static struct arm_ca7_pll arm_pll_ca7_table[] = {
{600, 300, 150, 0x01680000, 0x010c0603, 1, 1},
{0}
};
static struct ddr_clk ddr_clock_pll_table[] = {
{ 286, 0, 0, PLL_SUP_DDR2, PLL_SUP_53573},
{ 318, 0, 0, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_53573},
{ 333, 0x17800000, 0x1e0f1219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
{ 358, 0, 0, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_53573},
{ 389, 0x18c00000, 0x23121219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
{ 392, 0, 0, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_53573},
{ 400, 0x18000000, 0x20101019, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL},
{ 533, 0x18000000, 0x20100c19, PLL_SUP_DDR3, PLL_SUP_NS_ALL | PLL_SUP_53573},
{ 666, 0x17800000, 0x1e0f0919, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
{ 775, 0x17c00000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
{ 800, 0x18000000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094},
{0}
};
uint
BCMINITFN(si_irq)(si_t *sih)
{
return 0;
}
/*
* Initializes clocks and interrupts. SB and NVRAM access must be
* initialized prior to calling.
*/
void
BCMATTACHFN(si_arm_init)(si_t *sih)
{
return;
}
uint32
BCMINITFN(si_cpu_clock)(si_t *sih)
{
uint32 val;
osl_t *osh;
osh = si_osh(sih);
if (BCM4707_CHIP(CHIPID(sih->chip))) {
/* Return 100 MHz if we are in default value policy 2 */
val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ);
if ((val & 0x7070707) == 0x2020202)
return 100000000;
val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA);
val = (val >> 8) & 0x2ff;
val = (val * 25 * 1000000) / 2;
return val;
}
#ifdef _CFE_ /* only compile tailed 53573 block in cfe, to avoid impact 4708 cfez size \
*/
if (PMUCTL_ENAB(sih))
#endif // endif
if (BCM53573_CHIP(CHIPID(sih->chip))) {
pmuregs_t *pmu;
uint origidx;
uint32 fvco, pdiv, pll_ctrl_20, mdiv, ndiv_nfrac, clkout, r_high, r_low;
uint32 xtal_freq = si_alp_clock(sih);
origidx = si_coreidx(sih);
pmu = si_setcore(sih, PMU_CORE_ID, 0);
ASSERT(pmu != NULL);
/* Read mdiv, pdiv from pllcontrol[13] */
W_REG(osh, &pmu->pllcontrol_addr, 13);
mdiv = R_REG(osh, &pmu->pllcontrol_data) & 0xff;
ASSERT(mdiv);
pdiv = (R_REG(osh, &pmu->pllcontrol_data) >> 24) & 0x7;
ASSERT(pdiv);
/* Read ndiv[29:20], ndiv_frac[19:0] from pllcontrol[14] */
W_REG(osh, &pmu->pllcontrol_addr, 14);
ndiv_nfrac = R_REG(osh, &pmu->pllcontrol_data) & 0x3fffffff;
/* Read pll_ctrl_20 from pllcontrol[15] */
W_REG(osh, &pmu->pllcontrol_addr, 15);
pll_ctrl_20 = 1 << ((R_REG(osh, &pmu->pllcontrol_data) >> 20) & 0x1);
math_uint64_multiple_add(&r_high, &r_low, ndiv_nfrac, (xtal_freq * pll_ctrl_20), 0);
math_uint64_right_shift(&fvco, r_high, r_low, 20);
clkout = (fvco / pdiv)/ mdiv;
/* Return to original core */
si_setcoreidx(sih, origidx);
return clkout;
}
return si_clock(sih);
}
uint32
BCMINITFN(si_mem_clock)(si_t *sih)
{
osl_t *osh;
uint idx;
chipcommonbregs_t *chipcb;
uint32 control1, control2, val;
osh = si_osh(sih);
if (BCM4707_CHIP(CHIPID(sih->chip))) {
chipcb = si_setcore(sih, NS_CCB_CORE_ID, 0);
if (chipcb) {
control1 = R_REG(osh, &chipcb->cru_lcpll_control1);
control2 = R_REG(osh, &chipcb->cru_lcpll_control2);
for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
if ((control1 == ddr_clock_pll_table[idx].pll_ctrl_1) &&
(control2 == ddr_clock_pll_table[idx].pll_ctrl_2)) {
val = ddr_clock_pll_table[idx].clk;
return (val * 1000000);
}
}
}
}
#ifdef _CFE_ /* only compile tailed 53573 block in cfe, to avoid impact 4708 cfez size \
*/
if (PMUCTL_ENAB(sih))
#endif // endif
if (BCM53573_CHIP(CHIPID(sih->chip))) {
pmuregs_t *pmu;
uint origidx;
uint32 fvco, pdiv, pll_ctrl_20, mdiv, ndiv_nfrac, clkout, r_high, r_low;
uint32 xtal_freq = si_alp_clock(sih);
origidx = si_coreidx(sih);
pmu = si_setcore(sih, PMU_CORE_ID, 0);
ASSERT(pmu != NULL);
/* Read mdiv from pllcontrol[25] */
W_REG(osh, &pmu->pllcontrol_addr, 25);
mdiv = (R_REG(osh, &pmu->pllcontrol_data) >> 16) & 0xff;
ASSERT(mdiv);
/* Read pdiv[18:16], ndiv[29:20], ndiv_frac[31] from pllcontrol[26] */
W_REG(osh, &pmu->pllcontrol_addr, 26);
pdiv = (R_REG(osh, &pmu->pllcontrol_data) >> 16) & 0x7;
ndiv_nfrac = R_REG(osh, &pmu->pllcontrol_data) & 0x3ff00000;
ndiv_nfrac |= (R_REG(osh, &pmu->pllcontrol_data) & 0x80000000)? 1: 0;
ASSERT(pdiv);
/* Read ndiv_frac[19:1] from pllcontrol[27] */
W_REG(osh, &pmu->pllcontrol_addr, 27);
ndiv_nfrac |= ((R_REG(osh, &pmu->pllcontrol_data) << 1) & 0xffffe);
/* Read pll_ctrl_20 from pllcontrol[28] */
W_REG(osh, &pmu->pllcontrol_addr, 28);
pll_ctrl_20 = 1 << ((R_REG(osh, &pmu->pllcontrol_data) >> 20) & 0x1);
math_uint64_multiple_add(&r_high, &r_low, ndiv_nfrac, (xtal_freq * pll_ctrl_20), 0);
math_uint64_right_shift(&fvco, r_high, r_low, 20);
clkout = (fvco / pdiv)/ mdiv;
/* Return to original core */
si_setcoreidx(sih, origidx);
return clkout;
}
return si_clock(sih);
}
bool
BCMINITFN(si_arm_setclock)(si_t *sih, uint32 armclock, uint32 ddrclock,
uint32 axi_cciclock, uint32 nicclock)
{
osl_t *osh;
uint32 val;
bool ret = TRUE;
int idx;
int bootdev;
uint32 *ddrclk;
osh = si_osh(sih);
if (BCM4707_CHIP(CHIPID(sih->chip))) {
uint32 platform_flag = 0, ddr_flag = 0;
void *regs = (void *)si_setcore(sih, NS_DDR23_CORE_ID, 0);
if (regs) {
ddr_flag = ((si_core_sflags(sih, 0, 0) & DDR_TYPE_MASK)
== DDR_STAT_DDR3)? PLL_SUP_DDR3 : PLL_SUP_DDR2;
}
switch (sih->chippkg) {
case BCM4708_PKG_ID:
if (CHIPID(sih->chip) == BCM47094_CHIP_ID) {
platform_flag = PLL_SUP_47092;
} else {
platform_flag = PLL_SUP_4708;
}
break;
case BCM4709_PKG_ID:
if (CHIPID(sih->chip) == BCM47094_CHIP_ID) {
platform_flag = PLL_SUP_47094;
} else {
platform_flag = PLL_SUP_4709;
}
break;
}
/* Check CPU CLK table */
for (idx = 0; arm_pll_table[idx].clk != 0; idx++) {
if ((arm_pll_table[idx].flag & platform_flag) == 0)
arm_pll_table[idx].clk = 0;
}
/* Check DDR CLK table */
for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
if ((ddr_clock_pll_table[idx].type_flag & ddr_flag) == 0 ||
(ddr_clock_pll_table[idx].flag & platform_flag) == 0) {
ddr_clock_pll_table[idx].clk = 0;
break;
}
}
/* Check DDR clock */
if (ddrclock && si_mem_clock(sih) != ddrclock) {
ddrclock /= 1000000;
for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx ++) {
if (ddrclock == ddr_clock_pll_table[idx].clk)
break;
}
if (ddr_clock_pll_table[idx].clk != 0) {
ddrclk = (uint32 *)(0x1000 + BISZ_OFFSET - 4);
*ddrclk = ddrclock;
bootdev = soc_boot_dev((void *)sih);
if (bootdev == SOC_BOOTDEV_NANDFLASH) {
__asm__ __volatile__("ldr\tpc,=0x1c000000\n\t");
} else if (bootdev == SOC_BOOTDEV_SFLASH) {
__asm__ __volatile__("ldr\tpc,=0x1e000000\n\t");
}
}
}
/* Set CPU clock */
armclock /= 1000000;
/* The password */
W_REG(osh, (uint32 *)IHOST_PROC_CLK_WR_ACCESS, 0xa5a501);
/* Bypass ARM clock and run on the default sysclk */
W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ, 0x82020202);
val = (1 << IHOST_PROC_CLK_POLICY_CTL__GO) |
(1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL, val);
do {
val = R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL);
if ((val & (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) == 0)
break;
} while (1);
/* Now it is safe to program the ARM PLL.
* ndiv_int
*/
for (idx = 0; arm_pll_table[idx].clk != 0; idx++) {
if (armclock <= arm_pll_table[idx].clk)
break;
}
if (arm_pll_table[idx].clk == 0) {
ret = FALSE;
goto done;
}
val = arm_pll_table[idx].reg_val;
W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val);
do {
val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA);
if (val & (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK))
break;
} while (1);
val |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ, 0x87070707);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE0_CLKGATE, 0x00010303);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE1_CLKGATE, 0x00000303);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_SWITCH_CLKGATE, 0x00010303);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_PERIPH_CLKGATE, 0x00010303);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_APB0_CLKGATE, 0x00010303);
val = (1 << IHOST_PROC_CLK_POLICY_CTL__GO) |
(1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC);
W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL, val);
do {
val = R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL);
if ((val & (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) == 0)
break;
} while (1);
}
#ifdef _CFE_ /* only compile tailed 53573 block in cfe, to avoid impact 4708 cfez size \
*/
if (PMUCTL_ENAB(sih))
#endif /* _CFE */
if (BCM53573_CHIP(CHIPID(sih->chip))) {
/* Check DDR clock */
ddrclock /= 1000000;
if (ddrclock && (si_mem_clock(sih)/1000000 != ddrclock)) {
uint32 ddr_flag = 0;
gciregs_t *gci = (gciregs_t *)si_setcore(sih, GCI_CORE_ID, 0);
/* check strap_ddr_type: 0: ddr2, 1: ddr3 */
W_REG(osh, (uint32 *)&gci->gci_indirect_addr, 7);
ddr_flag = ((R_REG(osh, &gci->gci_chipsts) & SI_BCM53573_DDRTYPE_MASK)
== SI_BCM53573_DDRTYPE_DDR3)? PLL_SUP_DDR3 : PLL_SUP_DDR2;
for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx ++) {
if (ddrclock == ddr_clock_pll_table[idx].clk &&
ddr_clock_pll_table[idx].type_flag & ddr_flag &&
ddr_clock_pll_table[idx].flag & PLL_SUP_53573)
break;
}
if (ddr_clock_pll_table[idx].clk != 0) {
ddrclk = (uint32 *)(0x1000 + BISZ_OFFSET - 4);
*ddrclk = ddrclock;
bootdev = soc_boot_dev((void *)sih);
if (bootdev == SOC_BOOTDEV_SFLASH) {
__asm__ __volatile__("ldr\tpc,=0x1c000000\n\t");
} else if (bootdev == SOC_BOOTDEV_NANDFLASH) {
__asm__ __volatile__("ldr\tpc,=0x30000000\n\t");
}
}
}
/* 53573B0 have issue when it change CPU clock frequency. bypass it */
if (CHIPREV(sih->chiprev) >= 2) {
goto done;
}
/* Set CPU clock */
armclock /= 1000000;
axi_cciclock /= 1000000;
nicclock /= 1000000;
if ((armclock && (si_cpu_clock(sih)/1000000 != armclock)) ||
(axi_cciclock != 0 && nicclock != 0)) {
chipcregs_t *cc = si_setcoreidx(sih, SI_CC_IDX);
pmuregs_t *pmu = (pmuregs_t *)si_setcore(sih, PMU_CORE_ID, 0);
ca7regs_t *ca7 = (ca7regs_t*)si_setcore(sih, ARMCA7_CORE_ID, 0);
for (idx = 0; arm_pll_ca7_table[idx].cpu != 0; idx ++) {
if (armclock == arm_pll_ca7_table[idx].cpu &&
axi_cciclock == arm_pll_ca7_table[idx].cci &&
nicclock == arm_pll_ca7_table[idx].nic) {
printf("set CPU:CCI:NIC to %d:%d:%d \n", armclock,
axi_cciclock, nicclock);
break;
}
}
if (arm_pll_ca7_table[idx].cpu != 0) {
/* Set CPU:CCI:NICclock ratio to 2:2:1 */
AND_REG(osh, (uint32 *)&ca7->corecontrol, ~(0x7<<9));
/* Set CPU:CCI:NICclock ratio to 1:1:1 */
AND_REG(osh, (uint32 *)&ca7->corecontrol, ~(0x3<<12));
/* change Fvco */
W_REG(osh, (uint32 *)&pmu->pllcontrol_addr, 0xe);
W_REG(osh, (uint32 *)&pmu->pllcontrol_data,
arm_pll_ca7_table[idx].pll_ctrl_1);
/* change 3 channel mdiv */
W_REG(osh, (uint32 *)&pmu->pllcontrol_addr, 0xd);
W_REG(osh, (uint32 *)&pmu->pllcontrol_data,
arm_pll_ca7_table[idx].pll_ctrl_2);
/* clear load_en_ch bits */
W_REG(osh, (uint32 *)&pmu->pllcontrol_addr, 0xc);
AND_REG(osh, (uint32 *)&pmu->pllcontrol_data, ~0x7000);
/* set PLL control update bit */
OR_REG(osh, (uint32 *)&pmu->pmucontrol, 0x400);
/* wait until CPU PLL being locked */
do {
val = R_REG(osh, (uint32 *)&cc->chipstatus);
if (val & SI_BCM53573_LOCKED_CPUPLL)
break;
} while (1);
/* set load_en_ch bits */
W_REG(osh, (uint32 *)&pmu->pllcontrol_addr, 0xc);
OR_REG(osh, (uint32 *)&pmu->pllcontrol_data, 0x7000);
/* set PLL control update bit */
OR_REG(osh, (uint32 *)&pmu->pmucontrol, 0x400);
/* wait until CPU PLL being locked */
do {
val = R_REG(osh, (uint32 *)&cc->chipstatus);
if (val & SI_BCM53573_LOCKED_CPUPLL)
break;
} while (1);
/* clear load_en_ch bits */
W_REG(osh, (uint32 *)&pmu->pllcontrol_addr, 0xc);
AND_REG(osh, (uint32 *)&pmu->pllcontrol_data, ~0x7000);
/* set PLL control update bit */
OR_REG(osh, (uint32 *)&pmu->pmucontrol, 0x400);
/* wait until CPU PLL being locked */
do {
val = R_REG(osh, (uint32 *)&cc->chipstatus);
if (val & SI_BCM53573_LOCKED_CPUPLL)
break;
} while (1);
/* Set CCI:NIC clock ratio */
OR_REG(osh, (uint32 *)&ca7->corecontrol,
arm_pll_ca7_table[idx].clkratiocci << 12);
/* Set CPU:CCI clock ratio */
OR_REG(osh, (uint32 *)&ca7->corecontrol,
arm_pll_ca7_table[idx].clkratioarm << 9);
}
}
}
done:
return (ret);
}
void si_mem_setclock(si_t *sih, uint32 ddrclock)
{
osl_t *osh;
chipcommonbregs_t *chipcb;
uint32 val;
int idx;
if (BCM4707_CHIP(CHIPID(sih->chip))) {
for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) {
if (ddr_clock_pll_table[idx].clk == ddrclock)
break;
}
if (ddr_clock_pll_table[idx].clk == 0)
return;
osh = si_osh(sih);
chipcb = (chipcommonbregs_t *)si_setcore(sih, NS_CCB_CORE_ID, 0);
if (chipcb) {
val = 0xea68;
W_REG(osh, &chipcb->cru_clkset_key, val);
val = R_REG(osh, &chipcb->cru_lcpll_control1);
val &= ~0x0ff00000;
val |= (ddr_clock_pll_table[idx].pll_ctrl_1 & 0x0ff00000);
W_REG(osh, &chipcb->cru_lcpll_control1, val);
val = R_REG(osh, &chipcb->cru_lcpll_control2);
val &= ~0xffffff00;
val |= (ddr_clock_pll_table[idx].pll_ctrl_2 & 0xffffff00);
W_REG(osh, &chipcb->cru_lcpll_control2, val);
/* Enable change */
val = R_REG(osh, &chipcb->cru_lcpll_control0);
val |= 0x7;
W_REG(osh, &chipcb->cru_lcpll_control0, val);
val &= ~0x7;
W_REG(osh, &chipcb->cru_lcpll_control0, val);
val = 0;
W_REG(osh, &chipcb->cru_clkset_key, val);
}
}
if (BCM53573_CHIP(CHIPID(sih->chip))) {
}
}
/* Start chipc watchdog timer and wait till reset */
void
hnd_cpu_reset(si_t *sih)
{
si_watchdog(sih, 1);
while (1);
}
void
hnd_cpu_jumpto(void *addr)
{
void (*jumpto)(void) = addr;
(jumpto)();
}