blob: 9da7c27a884c4d6e5e1149563c7432081854c5e3 [file] [log] [blame]
/*
* (C) Copyright 2012
* Marvell Semiconductor <www.marvell.com>
* Written-by: Neil Zhang <zhangwm@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <serial.h>
#include <asm/arch/cpu.h>
#include <asm/arch/pxa182x.h>
#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1))
#define SET_MRVL_ID (1<<8)
#define L2C_RAM_SEL (1<<4)
#define PXA182X_WDT_BASE 0xD4080000
#define CIU_CA7_WARM_RESET_VECTOR (0xd4282cd8)
#define REBOOT_TIME (0x20)
#define MPMU_WDTPCR (0x200)
#define MPMU_APRR (0x1020)
#define MPMU_APRR_WDTR (1<<4)
/* Watchdog Timer Registers Offset */
#define TMR_WMER (0x0064)
#define TMR_WMR (0x0068)
#define TMR_WVR (0x006c)
#define TMR_WCR (0x0098)
#define TMR_WSR (0x0070)
#define TMR_WFAR (0x009c)
#define TMR_WSAR (0x00A0)
int d2forsysen(void)
{
u32 icu_msk;
u32 vector_asflag = readl(CIU_CA7_WARM_RESET_VECTOR);
int ramdump_boot = get_ramdump_flag_f();
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;
struct pxa182xcpu_registers *cpuregs =
(struct pxa182xcpu_registers *)PXA182X_CIU_BASE;
struct pxa182xapbc_registers *apbclkres =
(struct pxa182xapbc_registers *)PXA182X_APBC_BASE;
#if defined(CONFIG_PXA182X_AMP_SUPPORT) || defined(CONFIG_I2C_MV)
struct pxa182xapbcp_registers *apbcpclkres =
(struct pxa182xapbcp_registers *)PXA182X_APBCP_BASE;
#endif
struct pxa182xmpmu_registers *mpmu =
(struct pxa182xmpmu_registers *)PXA182X_MPMU_BASE;
#if defined(CONFIG_MMP_DISP) || defined(CONFIG_MV_SDHCI) || \
defined(CONFIG_MV_UDC)
struct pxa182xapmu_registers *apmu =
(struct pxa182xapmu_registers *)PXA182X_APMU_BASE;
#endif
/* set SEL_MRVL_ID bit in PANTHEON_CPU_CONF register */
val = readl(&cpuregs->cpu_conf);
val = val | SET_MRVL_ID;
writel(val, &cpuregs->cpu_conf);
/* Turn on clock gating (PMUM_CCGR) */
writel(0xFFFFFFFF, &mpmu->ccgr);
/* Turn on clock gating (PMUM_ACGR) */
writel(0xFFFFFFFF, &mpmu->acgr);
/* Turn on uart1 (AP) clock */
writel(UARTCLK14745KHZ, &apbclkres->uart1);
#ifdef CONFIG_PXA182X_AMP_SUPPORT
/* Turn on uart0 clock */
writel(UARTCLK14745KHZ, &apbcpclkres->uart0);
#endif /* CONFIG_PXA182X_AMP_SUPPORT */
/* Enable GPIO clock */
writel(APBC_APBCLK, &apbclkres->gpio);
#ifdef CONFIG_I2C_MV
/* Enable I2C clock */
writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi0);
writel(APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi0);
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, &apbclkres->twsi1);
writel(APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi1);
#endif
#ifdef CONFIG_MMP_DISP
/* Enable LCD_AXI/AHB/DSI/FCLK clock, 416MHz source FCLK as default */
val = readl(&apmu->lcd_dsi);
/* Enable lcd AXI clock control */
val |= LCD_CI_ISP_ACLK_EN | LCD_CI_ISP_ACLK_RST;
writel(val, &apmu->lcd_dsi);
/* Set LCD AXI clock as 208MHZ freq */
val &= ~(LCD_CI_ISP_ACLK_DIV_MSK | LCD_CI_ISP_ACLK_SEL_MSK);
val |= LCD_CI_ISP_ACLK_REQ | LCD_CI_ISP_ACLK_DIV(1) |
LCD_CI_ISP_ACLK_SEL(0);
writel(val, &apmu->lcd_dsi);
/* Enable LCD function clock */
val |= LCD_CI_HCLK_EN | LCD_CI_HCLK_RST;
val |= LCD_FCLK_EN | LCD_FCLK_RST | LCD_DEF_FCLK_SEL;
writel(val, &apmu->lcd_dsi);
val = readl(&apmu->dsi);
/* Enable DSI PHY/ESC clock */
val &= ~DSI_PHYESC_SELDIV_MSK;
val |= DSI_PHYESC_SELDIV | DSI_PHY_CLK_EN | DSI_PHY_CLK_RST;
writel(val, &apmu->dsi);
#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->sd0);
writel(sdh_clk | APMU_PERIPH_CLK_EN | APMU_AXI_CLK_EN |
APMU_PERIPH_RESET, &apmu->sd2);
#endif
#ifdef CONFIG_MV_UDC
/* Enable usb clock */
writel(APMU_PERIPH_CLK_EN | APMU_AXI_CLK_EN | APMU_PERIPH_RESET |
APMU_AXI_RESET, &apmu->usb);
#endif
icache_enable();
return 0;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
u32 id;
struct pxa182xcpu_registers *cpuregs =
(struct pxa182xcpu_registers *)PXA182X_CIU_BASE;
id = readl(&cpuregs->chip_id);
printf("SoC: PXA 88AP%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
#ifdef CONFIG_PXA_AMP_SUPPORT
#define PMU_CC2_AP (PXA182X_APMU_BASE + 0x100)
/* For PXA182X */
#define PXA182X_CPU_CORE_RST(n) (1 << ((n) * 4 + 16))
#define PXA182X_CPU_DBG_RST(n) (1 << ((n) * 4 + 18))
#define PXA182X_CPU_WDOG_RST(n) (1 << ((n) * 4 + 19))
#define CPU_WARM_RESET_VECTOR (PXA182X_CIU_BASE + 0xD8)
void pxa_cpu_reset(int cpu, u32 addr)
{
unsigned int tmp;
if (!cpu) {
printf("Wrong CPU number. Should be 1\n");
return;
}
writel(addr, CPU_WARM_RESET_VECTOR);
tmp = readl(PMU_CC2_AP);
tmp &= ~(PXA182X_CPU_CORE_RST(cpu) | PXA182X_CPU_DBG_RST(cpu) |
PXA182X_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, (PXA182X_MPMU_BASE + MPMU_WDTPCR));
udelay(10);
writel(0x3, (PXA182X_MPMU_BASE + MPMU_WDTPCR));
udelay(100);
/* reset counter */
writel(0xbaba, PXA182X_WDT_BASE + TMR_WFAR);
writel(0xeb10, PXA182X_WDT_BASE + TMR_WSAR);
writel(0x1, PXA182X_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, PXA182X_WDT_BASE + TMR_WFAR);
writel(0xeb10, PXA182X_WDT_BASE + TMR_WSAR);
writel(0x3, PXA182X_WDT_BASE + TMR_WMER);
reg = readl(PXA182X_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((PXA182X_MPMU_BASE + MPMU_APRR)) | MPMU_APRR_WDTR;
writel(reg, (PXA182X_MPMU_BASE + MPMU_APRR));
/* clear previous WDT status */
writel(0xbaba, PXA182X_WDT_BASE + TMR_WFAR);
writel(0xeb10, PXA182X_WDT_BASE + TMR_WSAR);
writel(0, PXA182X_WDT_BASE + TMR_WSR);
writel(0xbaba, PXA182X_WDT_BASE + TMR_WFAR);
writel(0xeb10, PXA182X_WDT_BASE + TMR_WSAR);
writel(REBOOT_TIME, PXA182X_WDT_BASE + TMR_WMR);
udelay(1000);
return;
}