blob: c31f024c730e4690ad0ea316247c0f5e94d8bd61 [file] [log] [blame]
/*
* (C) Copyright 2018
* ASR Microelectronics (Shanghai) Co., Ltd.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <serial.h>
#include <asm/arch/cpu.h>
#include <asm/arch/asr1802.h>
#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1))
#define SET_MRVL_ID (1<<8)
#define L2C_RAM_SEL (1<<4)
#define REBOOT_TIME (0x20)
#define SOC_SEL_RTC32K (0x1 << 30)
int d2forsysen(void)
{
u32 icu_msk;
u32 vector_asflag = readl(CIU_CA7_WARM_RESET_VECTOR);
int ramdump_boot = get_ramdump_flag_f();
//asr1802s only now
if (!cpu_is_asr1802s())
return 0;
if (ramdump_boot)
return 0;
if (vector_asflag != CONFIG_SYS_TEXT_BASE) {
cp_msa_sleep();
do_d2_test(32);
} else {
do_d2_restore();
}
return 0;
}
int arch_cpu_init(void)
{
u32 val, val2;
#if defined(CONFIG_ASR1802S_AMP_SUPPORT) || defined(CONFIG_I2C_MV)
struct asr1802apbcp_registers *apbcpclkres =
(struct asr1802apbcp_registers *)ASR1802_APBCP_BASE;
#endif
struct scsrtc_registers *scsrtcregs =
(struct scsrtc_registers *)ASR1802_SCSRTC_BASE;
/* set SEL_MRVL_ID bit in PANTHEON_CPU_CONF register */
val = asr_ciu_read(MOHAWK_CPU_CONF);
val = val | SET_MRVL_ID;
asr_ciu_write(MOHAWK_CPU_CONF, val);
/* Turn on clock gating (PMUM_CCGR) */
writel(0xFFFFFFFF, MPMU_CCGR);
/* Turn on clock gating (PMUM_ACGR) */
writel(0xFFFFFFFF, MPMU_ACGR);
if (cpu_is_asr1903()) {
/* Turn on uart3 (AP) clock */
writel(UARTCLK14745KHZ, APBC_UART3_CLK_RST);
} else {
/* Turn on uart1 (AP) clock */
writel(UARTCLK14745KHZ, APBC_UART0_CLK_RST);
}
#ifdef CONFIG_ASR1802S_AMP_SUPPORT
/* Turn on uart0 clock */
writel(UARTCLK14745KHZ, &apbcpclkres->uart0);
#endif /* CONFIG_ASR1802S_AMP_SUPPORT */
/* Enable GPIO clock */
writel(APBC_APBCLK, APBC_GPIO_CLK_RST);
#ifdef CONFIG_I2C_MV
/* Enable I2C clock */
writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, APBC_TWSI0_CLK_RST);
writel(APBC_FNCLK | APBC_APBCLK, APBC_TWSI0_CLK_RST);
writel(APBCP_RST | CLK_32MHZ | APBCP_FNCLK | APBCP_APBCCLK,
&apbcpclkres->twsi);
writel(CLK_32MHZ | APBCP_FNCLK | APBCP_APBCCLK, &apbcpclkres->twsi);
writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, APBC_TWSI1_CLK_RST);
writel(APBC_FNCLK | APBC_APBCLK, APBC_TWSI0_CLK_RST);
#endif
#ifdef CONFIG_MV_SDHCI
/* Enable mmc clock */
u32 sdh_clk;
/* 104MHz CLK default */
sdh_clk = SDH_CLK_FC_REQ | SDH_CLK_SEL_416MHZ | SDH_CLK_DIV(3);
writel(sdh_clk | APMU_PERIPH_CLK_EN | APMU_AXI_CLK_EN |
APMU_PERIPH_RESET | APMU_AXI_RESET, APMU_SDH0_CLK_RES_CTRL);
writel(sdh_clk | APMU_PERIPH_CLK_EN | APMU_AXI_CLK_EN |
APMU_PERIPH_RESET, APMU_SDH1_CLK_RES_CTRL);
#endif
#if defined(CONFIG_MV_UDC) || defined(CONFIG_USB_GADGET_DWC2_OTG)
/* Enable usb clock */
writel(APMU_PERIPH_CLK_EN | APMU_AXI_CLK_EN | APMU_PERIPH_RESET |
APMU_AXI_RESET, APMU_USB_CLK_RES_CTRL);
#endif
#ifdef CONFIG_ASR_UDC
/* Enable usb clock */
if(cpu_is_asr1826s())
writel(0x1E000, APMU_USB3PHY0_CTRL0);
else if(cpu_is_asr1903())
writel(0xF, APMU_USB_CLK_RES_CTRL);
#endif
if (cpu_is_asr1806() || (cpu_is_asr1803() && (!cpu_is_asr1803_z1()))) {
/* single crystal mode for falcon a0 */
val = readl(&scsrtcregs->dcs_mode);
if (0x0 == val) {
/* SCCR[0] = 0,APBSPARE5_SW_VCXO_EN = 1 */
if (cpu_is_asr1803_a0()) {
writel((APBSPARE5_SW_VCXO_EN | readl(APB_SPARE5_REG)),
APB_SPARE5_REG);
} else { /* SSCR[0] = 1,SW_DEBUG_REG2[30] = 1 */
asr_ciu_write(SW_DEBUG_REG2, asr_ciu_read(SW_DEBUG_REG2) | SOC_SEL_RTC32K);
}
} else {
/* make sure the 32k sel is correct */
if (cpu_is_asr1803_a0())
writel(readl(APB_SPARE5_REG) & (~APBSPARE5_EXT32_SEL),
APB_SPARE5_REG);
else
asr_ciu_write(SW_DEBUG_REG2, asr_ciu_read(SW_DEBUG_REG2) & (~SOC_SEL_RTC32K));
}
}
/* update reg_bg, it's for tsen/audio etc modules */
if (cpu_is_asr1806() || cpu_is_asr1903()) {
val = readl(APB_SPARE2_REG);
val &= ~(0x3 << 28);
writel(val, APB_SPARE2_REG);
if (cpu_is_asr1806()) {
val = asr_geu_read(ASR1806_GEU_BANK0_159_128);
val = (val >> 1) & 0xf;
} else {
val = asr_geu_read(ASR1903_GEU_BANK0_240_208);
val = (val >> (218 - 208)) & 0xf;
}
if (val) {
val2 = readl(APB_SPARE2_REG);
val2 &= ~(0xf << 24);
val2 |= (val << 24);
writel(val2, APB_SPARE2_REG);
}
if (cpu_is_asr1903() && (!cpu_is_asr1903_z1())) {
val = asr_geu_read(ASR1903_GEU_BANK3_255_224);
if ((val >> (236 - 224)) & 0x3) {
val = (val >> (230 - 224)) & 0x3f;
} else {
val = asr_geu_read(ASR1903_GEU_BANK0_240_208);
val = (val >> (222 - 208)) & 0x3f;
}
if (val) {
val2 = readl(APB_SPARE14_REG);
val2 &= ~(0x3f << 0);
val2 |= (val << 0);
writel(val2, APB_SPARE14_REG);
}
}
}
icache_enable();
return 0;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
u32 id;
id = asr_ciu_read(CIU_CHIP_ID);
printf("SoC: ASR%X-%X\n", (id & 0xFFFF), (id >> 0x10));
return 0;
}
#endif
#ifdef CONFIG_I2C_MV
void i2c_clk_enable(void)
{
}
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
/* Enable D-cache. I-cache is already enabled in start.S */
dcache_enable();
}
#endif
#if defined(CONFIG_ARCH_MISC_INIT)
int arch_misc_init(void)
{
#if defined(CONFIG_TEE_OS)
optee_tz_init();
#endif
}
#endif
#ifdef CONFIG_PXA_AMP_SUPPORT
#define PMU_CC2_AP (ASR1802_APMU_BASE + 0x100)
/* For ASR1802 */
#define ASR1802_CPU_CORE_RST(n) (1 << ((n) * 4 + 16))
#define ASR1802_CPU_DBG_RST(n) (1 << ((n) * 4 + 18))
#define ASR1802_CPU_WDOG_RST(n) (1 << ((n) * 4 + 19))
void pxa_cpu_reset(int cpu, u32 addr)
{
unsigned int tmp;
if (!cpu) {
printf("Wrong CPU number. Should be 1\n");
return;
}
writel(addr, CIU_CA7_WARM_RESET_VECTOR);
tmp = readl(PMU_CC2_AP);
tmp &= ~(ASR1802_CPU_CORE_RST(cpu) | ASR1802_CPU_DBG_RST(cpu) |
ASR1802_CPU_WDOG_RST(cpu));
writel(tmp, PMU_CC2_AP);
}
#endif
/*Todo - check if relevant*/
#if defined(CONFIG_ARM_ERRATA_802022)
#define WFI_BIT(n) (5 + 3 * n)
#define CORE_N_WFI(n) (1 << (WFI_BIT(n)))
#define AXI_PHYS_BASE 0xd4200000
#define APMU_PHYS_BASE (AXI_PHYS_BASE + 0x82800)
#define APMU_REG(x) (APMU_PHYS_BASE + (x))
#define PMU_CORE_STATUS APMU_REG(0x0090)
#define CPU_POR_RST(n) (1 << ((n) * 3 + 16))
#define CPU_CORE_RST(n) (1 << ((n) * 3 + 17))
#define CPU_DBG_RST(n) (1 << ((n) * 3 + 18))
void cpu_oor(void)
{
u32 tmp, cpu, core_active_status, core_tmp_status;
/* Wakeup all other cores */
tmp = __raw_readl(PMU_CC2_AP);
for (cpu = 1; cpu < CONFIG_NR_CPUS; cpu++)
if ((tmp & CPU_CORE_RST(cpu)) == CPU_CORE_RST(cpu))
tmp &= ~(CPU_CORE_RST(cpu) | CPU_DBG_RST(cpu) |
CPU_POR_RST(cpu));
__raw_writel(tmp, PMU_CC2_AP);
/* Polling until all other cores are all in C12 */
core_tmp_status = CORE_N_WFI(1) | CORE_N_WFI(2) | CORE_N_WFI(3);
do {
core_active_status = __raw_readl(PMU_CORE_STATUS);
} while ((core_tmp_status & core_active_status) != core_tmp_status);
/* Put all other cores into reset */
for (cpu = 1; cpu < CONFIG_NR_CPUS; cpu++)
tmp |= (CPU_CORE_RST(cpu) | CPU_DBG_RST(cpu) |
CPU_POR_RST(cpu));
__raw_writel(tmp, PMU_CC2_AP);
}
#endif
extern void pmic_prepare_for_soc_reboot(void);
void pxa_wdt_reset(void)
{
u32 reg;
int i;
pmic_prepare_for_soc_reboot();
writel(0x7, MPMU_WDTPCR);
udelay(10);
writel(0x3, MPMU_WDTPCR);
udelay(100);
/* reset counter */
writel(0xbaba, ASR1802_WDT_BASE + TMR_WFAR);
writel(0xeb10, ASR1802_WDT_BASE + TMR_WSAR);
writel(0x1, ASR1802_WDT_BASE + TMR_WCR);
/*
* enable WDT
* 1. write 0xbaba to match 1st key
* 2. write 0xeb10 to match 2nd key
* 3. enable wdt count, generate interrupt when experies
*/
for (i = 0; i < 10; i++) {
writel(0xbaba, ASR1802_WDT_BASE + TMR_WFAR);
writel(0xeb10, ASR1802_WDT_BASE + TMR_WSAR);
writel(0x3, ASR1802_WDT_BASE + TMR_WMER);
reg = readl(ASR1802_WDT_BASE + TMR_WMER);
if (reg != 0x3)
printf("Watchdog reset&count enable set fail, TMR_WMER is 0x%x\n", reg);
else
break;
}
reg = readl(MPMU_APRR) | MPMU_APRR_WDTR;
writel(reg, MPMU_APRR);
/* clear previous WDT status */
writel(0xbaba, ASR1802_WDT_BASE + TMR_WFAR);
writel(0xeb10, ASR1802_WDT_BASE + TMR_WSAR);
writel(0, ASR1802_WDT_BASE + TMR_WSR);
writel(0xbaba, ASR1802_WDT_BASE + TMR_WFAR);
writel(0xeb10, ASR1802_WDT_BASE + TMR_WSAR);
writel(REBOOT_TIME, ASR1802_WDT_BASE + TMR_WMR);
udelay(1000);
return;
}
bool board_is_scs_mode(void)
{
struct scsrtc_registers *scsrtcregs = (struct scsrtc_registers *)ASR1802_SCSRTC_BASE;
if (cpu_is_asr1903())
scsrtcregs = (struct scsrtc_registers *)ASR1903_SCSRTC_BASE;
if (scsrtcregs->dcs_mode == 0x0)
return true;
else
return false;
}