| /* |
| * (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; |
| } |
| |