10e9b1141SJustin Chen /* 20e9b1141SJustin Chen * MIPS-specific support for Broadcom STB S2/S3/S5 power management 30e9b1141SJustin Chen * 40e9b1141SJustin Chen * Copyright (C) 2016-2017 Broadcom 50e9b1141SJustin Chen * 60e9b1141SJustin Chen * This program is free software; you can redistribute it and/or modify 70e9b1141SJustin Chen * it under the terms of the GNU General Public License version 2 as 80e9b1141SJustin Chen * published by the Free Software Foundation. 90e9b1141SJustin Chen * 100e9b1141SJustin Chen * This program is distributed in the hope that it will be useful, 110e9b1141SJustin Chen * but WITHOUT ANY WARRANTY; without even the implied warranty of 120e9b1141SJustin Chen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 130e9b1141SJustin Chen * GNU General Public License for more details. 140e9b1141SJustin Chen */ 150e9b1141SJustin Chen 160e9b1141SJustin Chen #include <linux/kernel.h> 170e9b1141SJustin Chen #include <linux/printk.h> 180e9b1141SJustin Chen #include <linux/io.h> 190e9b1141SJustin Chen #include <linux/of.h> 200e9b1141SJustin Chen #include <linux/of_address.h> 210e9b1141SJustin Chen #include <linux/delay.h> 220e9b1141SJustin Chen #include <linux/suspend.h> 230e9b1141SJustin Chen #include <asm/bmips.h> 240e9b1141SJustin Chen #include <asm/tlbflush.h> 250e9b1141SJustin Chen 260e9b1141SJustin Chen #include "pm.h" 270e9b1141SJustin Chen 280e9b1141SJustin Chen #define S2_NUM_PARAMS 6 290e9b1141SJustin Chen #define MAX_NUM_MEMC 3 300e9b1141SJustin Chen 310e9b1141SJustin Chen /* S3 constants */ 320e9b1141SJustin Chen #define MAX_GP_REGS 16 330e9b1141SJustin Chen #define MAX_CP0_REGS 32 340e9b1141SJustin Chen #define NUM_MEMC_CLIENTS 128 350e9b1141SJustin Chen #define AON_CTRL_RAM_SIZE 128 360e9b1141SJustin Chen #define BRCMSTB_S3_MAGIC 0x5AFEB007 370e9b1141SJustin Chen 380e9b1141SJustin Chen #define CLEAR_RESET_MASK 0x01 390e9b1141SJustin Chen 400e9b1141SJustin Chen /* Index each CP0 register that needs to be saved */ 410e9b1141SJustin Chen #define CONTEXT 0 420e9b1141SJustin Chen #define USER_LOCAL 1 430e9b1141SJustin Chen #define PGMK 2 440e9b1141SJustin Chen #define HWRENA 3 450e9b1141SJustin Chen #define COMPARE 4 460e9b1141SJustin Chen #define STATUS 5 470e9b1141SJustin Chen #define CONFIG 6 480e9b1141SJustin Chen #define MODE 7 490e9b1141SJustin Chen #define EDSP 8 500e9b1141SJustin Chen #define BOOT_VEC 9 510e9b1141SJustin Chen #define EBASE 10 520e9b1141SJustin Chen 530e9b1141SJustin Chen struct brcmstb_memc { 540e9b1141SJustin Chen void __iomem *ddr_phy_base; 550e9b1141SJustin Chen void __iomem *arb_base; 560e9b1141SJustin Chen }; 570e9b1141SJustin Chen 580e9b1141SJustin Chen struct brcmstb_pm_control { 590e9b1141SJustin Chen void __iomem *aon_ctrl_base; 600e9b1141SJustin Chen void __iomem *aon_sram_base; 610e9b1141SJustin Chen void __iomem *timers_base; 620e9b1141SJustin Chen struct brcmstb_memc memcs[MAX_NUM_MEMC]; 630e9b1141SJustin Chen int num_memc; 640e9b1141SJustin Chen }; 650e9b1141SJustin Chen 660e9b1141SJustin Chen struct brcm_pm_s3_context { 670e9b1141SJustin Chen u32 cp0_regs[MAX_CP0_REGS]; 680e9b1141SJustin Chen u32 memc0_rts[NUM_MEMC_CLIENTS]; 690e9b1141SJustin Chen u32 sc_boot_vec; 700e9b1141SJustin Chen }; 710e9b1141SJustin Chen 720e9b1141SJustin Chen struct brcmstb_mem_transfer; 730e9b1141SJustin Chen 740e9b1141SJustin Chen struct brcmstb_mem_transfer { 750e9b1141SJustin Chen struct brcmstb_mem_transfer *next; 760e9b1141SJustin Chen void *src; 770e9b1141SJustin Chen void *dst; 780e9b1141SJustin Chen dma_addr_t pa_src; 790e9b1141SJustin Chen dma_addr_t pa_dst; 800e9b1141SJustin Chen u32 len; 810e9b1141SJustin Chen u8 key; 820e9b1141SJustin Chen u8 mode; 830e9b1141SJustin Chen u8 src_remapped; 840e9b1141SJustin Chen u8 dst_remapped; 850e9b1141SJustin Chen u8 src_dst_remapped; 860e9b1141SJustin Chen }; 870e9b1141SJustin Chen 880e9b1141SJustin Chen #define AON_SAVE_SRAM(base, idx, val) \ 890e9b1141SJustin Chen __raw_writel(val, base + (idx << 2)) 900e9b1141SJustin Chen 910e9b1141SJustin Chen /* Used for saving registers in asm */ 920e9b1141SJustin Chen u32 gp_regs[MAX_GP_REGS]; 930e9b1141SJustin Chen 940e9b1141SJustin Chen #define BSP_CLOCK_STOP 0x00 950e9b1141SJustin Chen #define PM_INITIATE 0x01 960e9b1141SJustin Chen 970e9b1141SJustin Chen static struct brcmstb_pm_control ctrl; 980e9b1141SJustin Chen 990e9b1141SJustin Chen static void brcm_pm_save_cp0_context(struct brcm_pm_s3_context *ctx) 1000e9b1141SJustin Chen { 1010e9b1141SJustin Chen /* Generic MIPS */ 1020e9b1141SJustin Chen ctx->cp0_regs[CONTEXT] = read_c0_context(); 1030e9b1141SJustin Chen ctx->cp0_regs[USER_LOCAL] = read_c0_userlocal(); 1040e9b1141SJustin Chen ctx->cp0_regs[PGMK] = read_c0_pagemask(); 1050e9b1141SJustin Chen ctx->cp0_regs[HWRENA] = read_c0_cache(); 1060e9b1141SJustin Chen ctx->cp0_regs[COMPARE] = read_c0_compare(); 1070e9b1141SJustin Chen ctx->cp0_regs[STATUS] = read_c0_status(); 1080e9b1141SJustin Chen 1090e9b1141SJustin Chen /* Broadcom specific */ 1100e9b1141SJustin Chen ctx->cp0_regs[CONFIG] = read_c0_brcm_config(); 1110e9b1141SJustin Chen ctx->cp0_regs[MODE] = read_c0_brcm_mode(); 1120e9b1141SJustin Chen ctx->cp0_regs[EDSP] = read_c0_brcm_edsp(); 1130e9b1141SJustin Chen ctx->cp0_regs[BOOT_VEC] = read_c0_brcm_bootvec(); 1140e9b1141SJustin Chen ctx->cp0_regs[EBASE] = read_c0_ebase(); 1150e9b1141SJustin Chen 1160e9b1141SJustin Chen ctx->sc_boot_vec = bmips_read_zscm_reg(0xa0); 1170e9b1141SJustin Chen } 1180e9b1141SJustin Chen 1190e9b1141SJustin Chen static void brcm_pm_restore_cp0_context(struct brcm_pm_s3_context *ctx) 1200e9b1141SJustin Chen { 1210e9b1141SJustin Chen /* Restore cp0 state */ 1220e9b1141SJustin Chen bmips_write_zscm_reg(0xa0, ctx->sc_boot_vec); 1230e9b1141SJustin Chen 1240e9b1141SJustin Chen /* Generic MIPS */ 1250e9b1141SJustin Chen write_c0_context(ctx->cp0_regs[CONTEXT]); 1260e9b1141SJustin Chen write_c0_userlocal(ctx->cp0_regs[USER_LOCAL]); 1270e9b1141SJustin Chen write_c0_pagemask(ctx->cp0_regs[PGMK]); 1280e9b1141SJustin Chen write_c0_cache(ctx->cp0_regs[HWRENA]); 1290e9b1141SJustin Chen write_c0_compare(ctx->cp0_regs[COMPARE]); 1300e9b1141SJustin Chen write_c0_status(ctx->cp0_regs[STATUS]); 1310e9b1141SJustin Chen 1320e9b1141SJustin Chen /* Broadcom specific */ 1330e9b1141SJustin Chen write_c0_brcm_config(ctx->cp0_regs[CONFIG]); 1340e9b1141SJustin Chen write_c0_brcm_mode(ctx->cp0_regs[MODE]); 1350e9b1141SJustin Chen write_c0_brcm_edsp(ctx->cp0_regs[EDSP]); 1360e9b1141SJustin Chen write_c0_brcm_bootvec(ctx->cp0_regs[BOOT_VEC]); 1370e9b1141SJustin Chen write_c0_ebase(ctx->cp0_regs[EBASE]); 1380e9b1141SJustin Chen } 1390e9b1141SJustin Chen 1400e9b1141SJustin Chen static void brcmstb_pm_handshake(void) 1410e9b1141SJustin Chen { 1420e9b1141SJustin Chen void __iomem *base = ctrl.aon_ctrl_base; 1430e9b1141SJustin Chen u32 tmp; 1440e9b1141SJustin Chen 1450e9b1141SJustin Chen /* BSP power handshake, v1 */ 1460e9b1141SJustin Chen tmp = __raw_readl(base + AON_CTRL_HOST_MISC_CMDS); 1470e9b1141SJustin Chen tmp &= ~1UL; 1480e9b1141SJustin Chen __raw_writel(tmp, base + AON_CTRL_HOST_MISC_CMDS); 1490e9b1141SJustin Chen (void)__raw_readl(base + AON_CTRL_HOST_MISC_CMDS); 1500e9b1141SJustin Chen 1510e9b1141SJustin Chen __raw_writel(0, base + AON_CTRL_PM_INITIATE); 1520e9b1141SJustin Chen (void)__raw_readl(base + AON_CTRL_PM_INITIATE); 1530e9b1141SJustin Chen __raw_writel(BSP_CLOCK_STOP | PM_INITIATE, 1540e9b1141SJustin Chen base + AON_CTRL_PM_INITIATE); 1550e9b1141SJustin Chen /* 1560e9b1141SJustin Chen * HACK: BSP may have internal race on the CLOCK_STOP command. 1570e9b1141SJustin Chen * Avoid touching the BSP for a few milliseconds. 1580e9b1141SJustin Chen */ 1590e9b1141SJustin Chen mdelay(3); 1600e9b1141SJustin Chen } 1610e9b1141SJustin Chen 1620e9b1141SJustin Chen static void brcmstb_pm_s5(void) 1630e9b1141SJustin Chen { 1640e9b1141SJustin Chen void __iomem *base = ctrl.aon_ctrl_base; 1650e9b1141SJustin Chen 1660e9b1141SJustin Chen brcmstb_pm_handshake(); 1670e9b1141SJustin Chen 1680e9b1141SJustin Chen /* Clear magic s3 warm-boot value */ 1690e9b1141SJustin Chen AON_SAVE_SRAM(ctrl.aon_sram_base, 0, 0); 1700e9b1141SJustin Chen 1710e9b1141SJustin Chen /* Set the countdown */ 1720e9b1141SJustin Chen __raw_writel(0x10, base + AON_CTRL_PM_CPU_WAIT_COUNT); 1730e9b1141SJustin Chen (void)__raw_readl(base + AON_CTRL_PM_CPU_WAIT_COUNT); 1740e9b1141SJustin Chen 1750e9b1141SJustin Chen /* Prepare to S5 cold boot */ 1760e9b1141SJustin Chen __raw_writel(PM_COLD_CONFIG, base + AON_CTRL_PM_CTRL); 1770e9b1141SJustin Chen (void)__raw_readl(base + AON_CTRL_PM_CTRL); 1780e9b1141SJustin Chen 1790e9b1141SJustin Chen __raw_writel((PM_COLD_CONFIG | PM_PWR_DOWN), base + 1800e9b1141SJustin Chen AON_CTRL_PM_CTRL); 1810e9b1141SJustin Chen (void)__raw_readl(base + AON_CTRL_PM_CTRL); 1820e9b1141SJustin Chen 1830e9b1141SJustin Chen __asm__ __volatile__( 1840e9b1141SJustin Chen " wait\n" 1850e9b1141SJustin Chen : : : "memory"); 1860e9b1141SJustin Chen } 1870e9b1141SJustin Chen 1880e9b1141SJustin Chen static int brcmstb_pm_s3(void) 1890e9b1141SJustin Chen { 1900e9b1141SJustin Chen struct brcm_pm_s3_context s3_context; 1910e9b1141SJustin Chen void __iomem *memc_arb_base; 1920e9b1141SJustin Chen unsigned long flags; 1930e9b1141SJustin Chen u32 tmp; 1940e9b1141SJustin Chen int i; 1950e9b1141SJustin Chen 1960e9b1141SJustin Chen /* Prepare for s3 */ 1970e9b1141SJustin Chen AON_SAVE_SRAM(ctrl.aon_sram_base, 0, BRCMSTB_S3_MAGIC); 1980e9b1141SJustin Chen AON_SAVE_SRAM(ctrl.aon_sram_base, 1, (u32)&s3_reentry); 1990e9b1141SJustin Chen AON_SAVE_SRAM(ctrl.aon_sram_base, 2, 0); 2000e9b1141SJustin Chen 2010e9b1141SJustin Chen /* Clear RESET_HISTORY */ 2020e9b1141SJustin Chen tmp = __raw_readl(ctrl.aon_ctrl_base + AON_CTRL_RESET_CTRL); 2030e9b1141SJustin Chen tmp &= ~CLEAR_RESET_MASK; 2040e9b1141SJustin Chen __raw_writel(tmp, ctrl.aon_ctrl_base + AON_CTRL_RESET_CTRL); 2050e9b1141SJustin Chen 2060e9b1141SJustin Chen local_irq_save(flags); 2070e9b1141SJustin Chen 2080e9b1141SJustin Chen /* Inhibit DDR_RSTb pulse for both MMCs*/ 2090e9b1141SJustin Chen for (i = 0; i < ctrl.num_memc; i++) { 2100e9b1141SJustin Chen tmp = __raw_readl(ctrl.memcs[i].ddr_phy_base + 2110e9b1141SJustin Chen DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL); 2120e9b1141SJustin Chen 2130e9b1141SJustin Chen tmp &= ~0x0f; 2140e9b1141SJustin Chen __raw_writel(tmp, ctrl.memcs[i].ddr_phy_base + 2150e9b1141SJustin Chen DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL); 2160e9b1141SJustin Chen tmp |= (0x05 | BIT(5)); 2170e9b1141SJustin Chen __raw_writel(tmp, ctrl.memcs[i].ddr_phy_base + 2180e9b1141SJustin Chen DDR40_PHY_CONTROL_REGS_0_STANDBY_CTRL); 2190e9b1141SJustin Chen } 2200e9b1141SJustin Chen 2210e9b1141SJustin Chen /* Save CP0 context */ 2220e9b1141SJustin Chen brcm_pm_save_cp0_context(&s3_context); 2230e9b1141SJustin Chen 2240e9b1141SJustin Chen /* Save RTS(skip debug register) */ 2250e9b1141SJustin Chen memc_arb_base = ctrl.memcs[0].arb_base + 4; 2260e9b1141SJustin Chen for (i = 0; i < NUM_MEMC_CLIENTS; i++) { 2270e9b1141SJustin Chen s3_context.memc0_rts[i] = __raw_readl(memc_arb_base); 2280e9b1141SJustin Chen memc_arb_base += 4; 2290e9b1141SJustin Chen } 2300e9b1141SJustin Chen 2310e9b1141SJustin Chen /* Save I/O context */ 2320e9b1141SJustin Chen local_flush_tlb_all(); 2330e9b1141SJustin Chen _dma_cache_wback_inv(0, ~0); 2340e9b1141SJustin Chen 2350e9b1141SJustin Chen brcm_pm_do_s3(ctrl.aon_ctrl_base, current_cpu_data.dcache.linesz); 2360e9b1141SJustin Chen 2370e9b1141SJustin Chen /* CPU reconfiguration */ 2380e9b1141SJustin Chen local_flush_tlb_all(); 2390e9b1141SJustin Chen bmips_cpu_setup(); 2400e9b1141SJustin Chen cpumask_clear(&bmips_booted_mask); 2410e9b1141SJustin Chen 2420e9b1141SJustin Chen /* Restore RTS (skip debug register) */ 2430e9b1141SJustin Chen memc_arb_base = ctrl.memcs[0].arb_base + 4; 2440e9b1141SJustin Chen for (i = 0; i < NUM_MEMC_CLIENTS; i++) { 2450e9b1141SJustin Chen __raw_writel(s3_context.memc0_rts[i], memc_arb_base); 2460e9b1141SJustin Chen memc_arb_base += 4; 2470e9b1141SJustin Chen } 2480e9b1141SJustin Chen 2490e9b1141SJustin Chen /* restore CP0 context */ 2500e9b1141SJustin Chen brcm_pm_restore_cp0_context(&s3_context); 2510e9b1141SJustin Chen 2520e9b1141SJustin Chen local_irq_restore(flags); 2530e9b1141SJustin Chen 2540e9b1141SJustin Chen return 0; 2550e9b1141SJustin Chen } 2560e9b1141SJustin Chen 2570e9b1141SJustin Chen static int brcmstb_pm_s2(void) 2580e9b1141SJustin Chen { 2590e9b1141SJustin Chen /* 2600e9b1141SJustin Chen * We need to pass 6 arguments to an assembly function. Lets avoid the 2610e9b1141SJustin Chen * stack and pass arguments in a explicit 4 byte array. The assembly 2620e9b1141SJustin Chen * code assumes all arguments are 4 bytes and arguments are ordered 2630e9b1141SJustin Chen * like so: 2640e9b1141SJustin Chen * 2650e9b1141SJustin Chen * 0: AON_CTRl base register 2660e9b1141SJustin Chen * 1: DDR_PHY base register 2670e9b1141SJustin Chen * 2: TIMERS base resgister 2680e9b1141SJustin Chen * 3: I-Cache line size 2690e9b1141SJustin Chen * 4: Restart vector address 2700e9b1141SJustin Chen * 5: Restart vector size 2710e9b1141SJustin Chen */ 2720e9b1141SJustin Chen u32 s2_params[6]; 2730e9b1141SJustin Chen 2740e9b1141SJustin Chen /* Prepare s2 parameters */ 2750e9b1141SJustin Chen s2_params[0] = (u32)ctrl.aon_ctrl_base; 2760e9b1141SJustin Chen s2_params[1] = (u32)ctrl.memcs[0].ddr_phy_base; 2770e9b1141SJustin Chen s2_params[2] = (u32)ctrl.timers_base; 2780e9b1141SJustin Chen s2_params[3] = (u32)current_cpu_data.icache.linesz; 2790e9b1141SJustin Chen s2_params[4] = (u32)BMIPS_WARM_RESTART_VEC; 2800e9b1141SJustin Chen s2_params[5] = (u32)(bmips_smp_int_vec_end - 2810e9b1141SJustin Chen bmips_smp_int_vec); 2820e9b1141SJustin Chen 2830e9b1141SJustin Chen /* Drop to standby */ 2840e9b1141SJustin Chen brcm_pm_do_s2(s2_params); 2850e9b1141SJustin Chen 2860e9b1141SJustin Chen return 0; 2870e9b1141SJustin Chen } 2880e9b1141SJustin Chen 2890e9b1141SJustin Chen static int brcmstb_pm_standby(bool deep_standby) 2900e9b1141SJustin Chen { 2910e9b1141SJustin Chen brcmstb_pm_handshake(); 2920e9b1141SJustin Chen 2930e9b1141SJustin Chen /* Send IRQs to BMIPS_WARM_RESTART_VEC */ 2940e9b1141SJustin Chen clear_c0_cause(CAUSEF_IV); 2950e9b1141SJustin Chen irq_disable_hazard(); 2960e9b1141SJustin Chen set_c0_status(ST0_BEV); 2970e9b1141SJustin Chen irq_disable_hazard(); 2980e9b1141SJustin Chen 2990e9b1141SJustin Chen if (deep_standby) 3000e9b1141SJustin Chen brcmstb_pm_s3(); 3010e9b1141SJustin Chen else 3020e9b1141SJustin Chen brcmstb_pm_s2(); 3030e9b1141SJustin Chen 3040e9b1141SJustin Chen /* Send IRQs to normal runtime vectors */ 3050e9b1141SJustin Chen clear_c0_status(ST0_BEV); 3060e9b1141SJustin Chen irq_disable_hazard(); 3070e9b1141SJustin Chen set_c0_cause(CAUSEF_IV); 3080e9b1141SJustin Chen irq_disable_hazard(); 3090e9b1141SJustin Chen 3100e9b1141SJustin Chen return 0; 3110e9b1141SJustin Chen } 3120e9b1141SJustin Chen 3130e9b1141SJustin Chen static int brcmstb_pm_enter(suspend_state_t state) 3140e9b1141SJustin Chen { 3150e9b1141SJustin Chen int ret = -EINVAL; 3160e9b1141SJustin Chen 3170e9b1141SJustin Chen switch (state) { 3180e9b1141SJustin Chen case PM_SUSPEND_STANDBY: 3190e9b1141SJustin Chen ret = brcmstb_pm_standby(false); 3200e9b1141SJustin Chen break; 3210e9b1141SJustin Chen case PM_SUSPEND_MEM: 3220e9b1141SJustin Chen ret = brcmstb_pm_standby(true); 3230e9b1141SJustin Chen break; 3240e9b1141SJustin Chen } 3250e9b1141SJustin Chen 3260e9b1141SJustin Chen return ret; 3270e9b1141SJustin Chen } 3280e9b1141SJustin Chen 3290e9b1141SJustin Chen static int brcmstb_pm_valid(suspend_state_t state) 3300e9b1141SJustin Chen { 3310e9b1141SJustin Chen switch (state) { 3320e9b1141SJustin Chen case PM_SUSPEND_STANDBY: 3330e9b1141SJustin Chen return true; 3340e9b1141SJustin Chen case PM_SUSPEND_MEM: 3350e9b1141SJustin Chen return true; 3360e9b1141SJustin Chen default: 3370e9b1141SJustin Chen return false; 3380e9b1141SJustin Chen } 3390e9b1141SJustin Chen } 3400e9b1141SJustin Chen 3410e9b1141SJustin Chen static const struct platform_suspend_ops brcmstb_pm_ops = { 3420e9b1141SJustin Chen .enter = brcmstb_pm_enter, 3430e9b1141SJustin Chen .valid = brcmstb_pm_valid, 3440e9b1141SJustin Chen }; 3450e9b1141SJustin Chen 3460e9b1141SJustin Chen static const struct of_device_id aon_ctrl_dt_ids[] = { 3470e9b1141SJustin Chen { .compatible = "brcm,brcmstb-aon-ctrl" }, 3480e9b1141SJustin Chen { /* sentinel */ } 3490e9b1141SJustin Chen }; 3500e9b1141SJustin Chen 3510e9b1141SJustin Chen static const struct of_device_id ddr_phy_dt_ids[] = { 3520e9b1141SJustin Chen { .compatible = "brcm,brcmstb-ddr-phy" }, 3530e9b1141SJustin Chen { /* sentinel */ } 3540e9b1141SJustin Chen }; 3550e9b1141SJustin Chen 3560e9b1141SJustin Chen static const struct of_device_id arb_dt_ids[] = { 3570e9b1141SJustin Chen { .compatible = "brcm,brcmstb-memc-arb" }, 3580e9b1141SJustin Chen { /* sentinel */ } 3590e9b1141SJustin Chen }; 3600e9b1141SJustin Chen 3610e9b1141SJustin Chen static const struct of_device_id timers_ids[] = { 3620e9b1141SJustin Chen { .compatible = "brcm,brcmstb-timers" }, 3630e9b1141SJustin Chen { /* sentinel */ } 3640e9b1141SJustin Chen }; 3650e9b1141SJustin Chen 3660e9b1141SJustin Chen static inline void __iomem *brcmstb_ioremap_node(struct device_node *dn, 3670e9b1141SJustin Chen int index) 3680e9b1141SJustin Chen { 3690e9b1141SJustin Chen return of_io_request_and_map(dn, index, dn->full_name); 3700e9b1141SJustin Chen } 3710e9b1141SJustin Chen 3720e9b1141SJustin Chen static void __iomem *brcmstb_ioremap_match(const struct of_device_id *matches, 3730e9b1141SJustin Chen int index, const void **ofdata) 3740e9b1141SJustin Chen { 3750e9b1141SJustin Chen struct device_node *dn; 3760e9b1141SJustin Chen const struct of_device_id *match; 3770e9b1141SJustin Chen 3780e9b1141SJustin Chen dn = of_find_matching_node_and_match(NULL, matches, &match); 3790e9b1141SJustin Chen if (!dn) 3800e9b1141SJustin Chen return ERR_PTR(-EINVAL); 3810e9b1141SJustin Chen 3820e9b1141SJustin Chen if (ofdata) 3830e9b1141SJustin Chen *ofdata = match->data; 3840e9b1141SJustin Chen 3850e9b1141SJustin Chen return brcmstb_ioremap_node(dn, index); 3860e9b1141SJustin Chen } 3870e9b1141SJustin Chen 3880e9b1141SJustin Chen static int brcmstb_pm_init(void) 3890e9b1141SJustin Chen { 3900e9b1141SJustin Chen struct device_node *dn; 3910e9b1141SJustin Chen void __iomem *base; 3920e9b1141SJustin Chen int i; 3930e9b1141SJustin Chen 3940e9b1141SJustin Chen /* AON ctrl registers */ 3950e9b1141SJustin Chen base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 0, NULL); 3960e9b1141SJustin Chen if (IS_ERR(base)) { 3970e9b1141SJustin Chen pr_err("error mapping AON_CTRL\n"); 3980e9b1141SJustin Chen goto aon_err; 3990e9b1141SJustin Chen } 4000e9b1141SJustin Chen ctrl.aon_ctrl_base = base; 4010e9b1141SJustin Chen 4020e9b1141SJustin Chen /* AON SRAM registers */ 4030e9b1141SJustin Chen base = brcmstb_ioremap_match(aon_ctrl_dt_ids, 1, NULL); 4040e9b1141SJustin Chen if (IS_ERR(base)) { 4050e9b1141SJustin Chen pr_err("error mapping AON_SRAM\n"); 4060e9b1141SJustin Chen goto sram_err; 4070e9b1141SJustin Chen } 4080e9b1141SJustin Chen ctrl.aon_sram_base = base; 4090e9b1141SJustin Chen 4100e9b1141SJustin Chen ctrl.num_memc = 0; 4110e9b1141SJustin Chen /* Map MEMC DDR PHY registers */ 4120e9b1141SJustin Chen for_each_matching_node(dn, ddr_phy_dt_ids) { 4130e9b1141SJustin Chen i = ctrl.num_memc; 4140e9b1141SJustin Chen if (i >= MAX_NUM_MEMC) { 4150e9b1141SJustin Chen pr_warn("Too many MEMCs (max %d)\n", MAX_NUM_MEMC); 4160e9b1141SJustin Chen break; 4170e9b1141SJustin Chen } 4180e9b1141SJustin Chen base = brcmstb_ioremap_node(dn, 0); 4190e9b1141SJustin Chen if (IS_ERR(base)) 4200e9b1141SJustin Chen goto ddr_err; 4210e9b1141SJustin Chen 4220e9b1141SJustin Chen ctrl.memcs[i].ddr_phy_base = base; 4230e9b1141SJustin Chen ctrl.num_memc++; 4240e9b1141SJustin Chen } 4250e9b1141SJustin Chen 4260e9b1141SJustin Chen /* MEMC ARB registers */ 4270e9b1141SJustin Chen base = brcmstb_ioremap_match(arb_dt_ids, 0, NULL); 4280e9b1141SJustin Chen if (IS_ERR(base)) { 4290e9b1141SJustin Chen pr_err("error mapping MEMC ARB\n"); 4300e9b1141SJustin Chen goto ddr_err; 4310e9b1141SJustin Chen } 4320e9b1141SJustin Chen ctrl.memcs[0].arb_base = base; 4330e9b1141SJustin Chen 4340e9b1141SJustin Chen /* Timer registers */ 4350e9b1141SJustin Chen base = brcmstb_ioremap_match(timers_ids, 0, NULL); 4360e9b1141SJustin Chen if (IS_ERR(base)) { 4370e9b1141SJustin Chen pr_err("error mapping timers\n"); 4380e9b1141SJustin Chen goto tmr_err; 4390e9b1141SJustin Chen } 4400e9b1141SJustin Chen ctrl.timers_base = base; 4410e9b1141SJustin Chen 4420e9b1141SJustin Chen /* s3 cold boot aka s5 */ 4430e9b1141SJustin Chen pm_power_off = brcmstb_pm_s5; 4440e9b1141SJustin Chen 4450e9b1141SJustin Chen suspend_set_ops(&brcmstb_pm_ops); 4460e9b1141SJustin Chen 4470e9b1141SJustin Chen return 0; 4480e9b1141SJustin Chen 4490e9b1141SJustin Chen tmr_err: 4500e9b1141SJustin Chen iounmap(ctrl.memcs[0].arb_base); 4510e9b1141SJustin Chen ddr_err: 4520e9b1141SJustin Chen for (i = 0; i < ctrl.num_memc; i++) 4530e9b1141SJustin Chen iounmap(ctrl.memcs[i].ddr_phy_base); 4540e9b1141SJustin Chen 4550e9b1141SJustin Chen iounmap(ctrl.aon_sram_base); 4560e9b1141SJustin Chen sram_err: 4570e9b1141SJustin Chen iounmap(ctrl.aon_ctrl_base); 4580e9b1141SJustin Chen aon_err: 4590e9b1141SJustin Chen return PTR_ERR(base); 4600e9b1141SJustin Chen } 4610e9b1141SJustin Chen arch_initcall(brcmstb_pm_init); 462