From: 黄涛 Date: Wed, 15 Jan 2014 08:40:50 +0000 (+0800) Subject: ARM: rockchip: rk3188 add restart support X-Git-Tag: firefly_0821_release~6390 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=75180cac611adb2d8baa50cab3a341870c052693;p=firefly-linux-kernel-4.4.55.git ARM: rockchip: rk3188 add restart support --- diff --git a/arch/arm/mach-rockchip/common.c b/arch/arm/mach-rockchip/common.c index 93adf5dadcf0..9bf34cc7bb2b 100644 --- a/arch/arm/mach-rockchip/common.c +++ b/arch/arm/mach-rockchip/common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 ROCKCHIP, Inc. + * Copyright (C) 2013-2014 ROCKCHIP, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,10 @@ #include #include #include +#include "common.h" #include "cpu_axi.h" +#include "loader.h" +#include "pmu.h" #include "sram.h" static int __init rockchip_cpu_axi_init(void) @@ -130,3 +133,85 @@ int __init rockchip_pie_init(void) return 0; } + +static bool is_panic = false; + +static int panic_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + is_panic = true; + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + .notifier_call = panic_event, +}; + +static int boot_mode; + +int rockchip_boot_mode(void) +{ + return boot_mode; +} +EXPORT_SYMBOL(rockchip_boot_mode); + +static inline const char *boot_flag_name(u32 flag) +{ + flag -= SYS_KERNRL_REBOOT_FLAG; + switch (flag) { + case BOOT_NORMAL: return "NORMAL"; + case BOOT_LOADER: return "LOADER"; + case BOOT_MASKROM: return "MASKROM"; + case BOOT_RECOVER: return "RECOVER"; + case BOOT_NORECOVER: return "NORECOVER"; + case BOOT_SECONDOS: return "SECONDOS"; + case BOOT_WIPEDATA: return "WIPEDATA"; + case BOOT_WIPEALL: return "WIPEALL"; + case BOOT_CHECKIMG: return "CHECKIMG"; + case BOOT_FASTBOOT: return "FASTBOOT"; + default: return ""; + } +} + +static inline const char *boot_mode_name(u32 mode) +{ + switch (mode) { + case BOOT_MODE_NORMAL: return "NORMAL"; + case BOOT_MODE_FACTORY2: return "FACTORY2"; + case BOOT_MODE_RECOVERY: return "RECOVERY"; + case BOOT_MODE_CHARGE: return "CHARGE"; + case BOOT_MODE_POWER_TEST: return "POWER_TEST"; + case BOOT_MODE_OFFMODE_CHARGING: return "OFFMODE_CHARGING"; + case BOOT_MODE_REBOOT: return "REBOOT"; + case BOOT_MODE_PANIC: return "PANIC"; + case BOOT_MODE_WATCHDOG: return "WATCHDOG"; + default: return ""; + } +} + +void __init rockchip_boot_mode_init(u32 flag, u32 mode) +{ + boot_mode = mode; + if (mode || ((flag & 0xff) && ((flag & 0xffffff00) == SYS_KERNRL_REBOOT_FLAG))) + printk("Boot mode: %s (%d) flag: %s (0x%08x)\n", boot_mode_name(mode), mode, boot_flag_name(flag), flag); + atomic_notifier_chain_register(&panic_notifier_list, &panic_block); +} + +void rockchip_restart_get_boot_mode(const char *cmd, u32 *flag, u32 *mode) +{ + *flag = 0; + *mode = BOOT_MODE_REBOOT; + + if (cmd) { + if (!strcmp(cmd, "loader") || !strcmp(cmd, "bootloader")) + *flag = SYS_LOADER_REBOOT_FLAG + BOOT_LOADER; + else if(!strcmp(cmd, "recovery")) + *flag = SYS_LOADER_REBOOT_FLAG + BOOT_RECOVER; + else if (!strcmp(cmd, "charge")) + *mode = BOOT_MODE_CHARGE; + } else { + if (is_panic) + *mode = BOOT_MODE_PANIC; + } +} + +struct rockchip_pmu_operations rockchip_pmu_ops; diff --git a/arch/arm/mach-rockchip/common.h b/arch/arm/mach-rockchip/common.h new file mode 100644 index 000000000000..e4fec0bd0233 --- /dev/null +++ b/arch/arm/mach-rockchip/common.h @@ -0,0 +1,21 @@ +#ifndef __MACH_ROCKCHIP_COMMON_H +#define __MACH_ROCKCHIP_COMMON_H + +extern unsigned long rockchip_boot_fn; +extern struct smp_operations rockchip_smp_ops; + +#define BOOT_MODE_NORMAL 0 +#define BOOT_MODE_FACTORY2 1 +#define BOOT_MODE_RECOVERY 2 +#define BOOT_MODE_CHARGE 3 +#define BOOT_MODE_POWER_TEST 4 +#define BOOT_MODE_OFFMODE_CHARGING 5 +#define BOOT_MODE_REBOOT 6 +#define BOOT_MODE_PANIC 7 +#define BOOT_MODE_WATCHDOG 8 + +extern int rockchip_boot_mode(void); +extern void __init rockchip_boot_mode_init(u32 flag, u32 mode); +extern void rockchip_restart_get_boot_mode(const char *cmd, u32 *flag, u32 *mode); + +#endif diff --git a/arch/arm/mach-rockchip/core.h b/arch/arm/mach-rockchip/core.h deleted file mode 100644 index a23568585e6f..000000000000 --- a/arch/arm/mach-rockchip/core.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2013 ROCKCHIP, Inc. - * Copyright (c) 2013 MundoReader S.L. - * Author: Heiko Stuebner - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __MACH_CORE_H -#define __MACH_CORE_H - -extern unsigned long rockchip_boot_fn; - -extern struct smp_operations rockchip_smp_ops; - -#endif diff --git a/arch/arm/mach-rockchip/cpu_axi.h b/arch/arm/mach-rockchip/cpu_axi.h index 0523be5a4557..e3beedfef471 100644 --- a/arch/arm/mach-rockchip/cpu_axi.h +++ b/arch/arm/mach-rockchip/cpu_axi.h @@ -38,4 +38,18 @@ writel_relaxed(array[3], base + CPU_AXI_QOS_SATURATION); \ } while (0) +#define RK3188_CPU_AXI_DMAC_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x1000) +#define RK3188_CPU_AXI_CPU0_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x2000) +#define RK3188_CPU_AXI_CPU1R_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x2080) +#define RK3188_CPU_AXI_CPU1W_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x2100) +#define RK3188_CPU_AXI_PERI_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x4000) +#define RK3188_CPU_AXI_GPU_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x5000) +#define RK3188_CPU_AXI_VPU_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x6000) +#define RK3188_CPU_AXI_LCDC0_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7000) +#define RK3188_CPU_AXI_CIF0_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7080) +#define RK3188_CPU_AXI_IPP_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7100) +#define RK3188_CPU_AXI_LCDC1_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7180) +#define RK3188_CPU_AXI_CIF1_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7200) +#define RK3188_CPU_AXI_RGA_QOS_BASE (RK_CPU_AXI_BUS_VIRT + 0x7280) + #endif diff --git a/arch/arm/mach-rockchip/cru.h b/arch/arm/mach-rockchip/cru.h new file mode 100644 index 000000000000..15092a2c9a1f --- /dev/null +++ b/arch/arm/mach-rockchip/cru.h @@ -0,0 +1,40 @@ +#ifndef __MACH_ROCKCHIP_CRU_H +#define __MACH_ROCKCHIP_CRU_H + +enum { + RK3188_APLL_ID = 0, + RK3188_DPLL_ID, + RK3188_CPLL_ID, + RK3188_GPLL_ID, + RK3188_END_PLL_ID, +}; + +#define RK3188_CRU_MODE_CON 0x40 +#define RK3188_CRU_CLKSEL_CON 0x44 +#define RK3188_CRU_CLKGATE_CON 0xd0 +#define RK3188_CRU_GLB_SRST_FST 0x100 +#define RK3188_CRU_GLB_SRST_SND 0x104 +#define RK3188_CRU_SOFTRST_CON 0x110 + +#define RK3188_PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) + +#define RK3188_CRU_CLKSELS_CON_CNT (35) +#define RK3188_CRU_CLKSELS_CON(i) (RK3188_CRU_CLKSEL_CON + ((i) * 4)) + +#define RK3188_CRU_CLKGATES_CON_CNT (10) +#define RK3188_CRU_CLKGATES_CON(i) (RK3188_CRU_CLKGATE_CON + ((i) * 4)) + +#define RK3188_CRU_SOFTRSTS_CON_CNT (9) +#define RK3188_CRU_SOFTRSTS_CON(i) (RK3188_CRU_SOFTRST_CON + ((i) * 4)) + +#define RK3188_CRU_MISC_CON (0x134) +#define RK3188_CRU_GLB_CNT_TH (0x140) + +/*******************MODE BITS***************************/ + +#define RK3188_PLL_MODE_MSK(id) (0x3 << ((id) * 4)) +#define RK3188_PLL_MODE_SLOW(id) ((0x0<<((id)*4))|(0x3<<(16+(id)*4))) +#define RK3188_PLL_MODE_NORM(id) ((0x1<<((id)*4))|(0x3<<(16+(id)*4))) +#define RK3188_PLL_MODE_DEEP(id) ((0x2<<((id)*4))|(0x3<<(16+(id)*4))) + +#endif diff --git a/arch/arm/mach-rockchip/loader.h b/arch/arm/mach-rockchip/loader.h new file mode 100644 index 000000000000..9eaa790f710d --- /dev/null +++ b/arch/arm/mach-rockchip/loader.h @@ -0,0 +1,21 @@ +#ifndef __MACH_ROCKCHIP_LOADER_H +#define __MACH_ROCKCHIP_LOADER_H + +#define SYS_LOADER_REBOOT_FLAG 0x5242C300 //high 24 bits is tag, low 8 bits is type +#define SYS_KERNRL_REBOOT_FLAG 0xC3524200 //high 24 bits is tag, low 8 bits is type + +enum { + BOOT_NORMAL = 0, /* normal boot */ + BOOT_LOADER, /* enter loader rockusb mode */ + BOOT_MASKROM, /* enter maskrom rockusb mode (not support now) */ + BOOT_RECOVER, /* enter recover */ + BOOT_NORECOVER, /* do not enter recover */ + BOOT_SECONDOS, /* boot second OS (not support now)*/ + BOOT_WIPEDATA, /* enter recover and wipe data. */ + BOOT_WIPEALL, /* enter recover and wipe all data. */ + BOOT_CHECKIMG, /* check firmware img with backup part(in loader mode)*/ + BOOT_FASTBOOT, /* enter fast boot mode (not support now) */ + BOOT_MAX /* MAX VALID BOOT TYPE.*/ +}; + +#endif diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 1c43e5df5812..fb31bb47ff65 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 ROCKCHIP, Inc. + * Copyright (C) 2013-2014 ROCKCHIP, Inc. * Copyright (c) 2013 MundoReader S.L. * Author: Heiko Stuebner * @@ -26,22 +26,14 @@ #include #include -#include "core.h" +#include "common.h" +#include "pmu.h" #define SCU_CTRL 0x00 #define SCU_STANDBY_EN (1 << 5) static int ncores; -/* - * temporary PMU handling - */ - -#define PMU_PWRDN_CON 0x08 -#define PMU_PWRDN_ST 0x0c - -static void __iomem *pmu_base_addr; - extern void secondary_startup(void); extern void v7_invalidate_l1(void); @@ -61,23 +53,6 @@ static void __naked rockchip_secondary_trampoline(void) ); } -static inline bool pmu_power_domain_is_on(int pd) -{ - return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd)); -} - -static void pmu_set_power_domain(int pd, bool on) -{ - u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON); - if (on) - val &= ~BIT(pd); - else - val |= BIT(pd); - writel(val, pmu_base_addr + PMU_PWRDN_CON); - - while (pmu_power_domain_is_on(pd) != on) { } -} - /* * Handling of CPU cores */ @@ -92,7 +67,7 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, } /* start the core */ - pmu_set_power_domain(0 + cpu, true); + rockchip_pmu_ops.set_power_domain(PD_CPU_0 + cpu, true); return 0; } @@ -158,8 +133,6 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) return; } - pmu_base_addr = of_iomap(node, 0); - /* * While the number of cpus is gathered from dt, also get the number * of cores from the scu to verify this value when booting the cores. @@ -174,7 +147,7 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) for (i = 0; i < ncores; i++) { if (i == cpu) continue; - pmu_set_power_domain(i, false); + rockchip_pmu_ops.set_power_domain(PD_CPU_0 + i, false); } iounmap(scu_base_addr); diff --git a/arch/arm/mach-rockchip/pmu.h b/arch/arm/mach-rockchip/pmu.h new file mode 100644 index 000000000000..2224faec112e --- /dev/null +++ b/arch/arm/mach-rockchip/pmu.h @@ -0,0 +1,65 @@ +#ifndef __MACH_ROCKCHIP_PMU_H +#define __MACH_ROCKCHIP_PMU_H + +#define RK3188_PMU_WAKEUP_CFG0 0x00 +#define RK3188_PMU_WAKEUP_CFG1 0x04 +#define RK3188_PMU_PWRDN_CON 0x08 +#define RK3188_PMU_PWRDN_ST 0x0c +#define RK3188_PMU_INT_CON 0x10 +#define RK3188_PMU_INT_ST 0x14 +#define RK3188_PMU_MISC_CON 0x18 +#define RK3188_PMU_OSC_CNT 0x1c +#define RK3188_PMU_PLL_CNT 0x20 +#define RK3188_PMU_PMU_CNT 0x24 +#define RK3188_PMU_DDRIO_PWRON_CNT 0x28 +#define RK3188_PMU_WAKEUP_RST_CLR_CNT 0x2c +#define RK3188_PMU_SCU_PWRDWN_CNT 0x30 +#define RK3188_PMU_SCU_PWRUP_CNT 0x34 +#define RK3188_PMU_MISC_CON1 0x38 +#define RK3188_PMU_GPIO0_CON 0x3c +#define RK3188_PMU_SYS_REG0 0x40 +#define RK3188_PMU_SYS_REG1 0x44 +#define RK3188_PMU_SYS_REG2 0x48 +#define RK3188_PMU_SYS_REG3 0x4c +#define RK3188_PMU_STOP_INT_DLY 0x60 +#define RK3188_PMU_GPIO0A_PULL 0x64 +#define RK3188_PMU_GPIO0B_PULL 0x68 + +enum pmu_power_domain { + PD_BCPU, + PD_BDSP, + PD_BUS, + PD_CPU_0, + PD_CPU_1, + PD_CPU_2, + PD_CPU_3, + PD_CS, + PD_GPU, + PD_PERI, + PD_SCU, + PD_VIDEO, + PD_VIO, +}; + +enum pmu_idle_req { + IDLE_REQ_ALIVE, + IDLE_REQ_AP2BP, + IDLE_REQ_BP2AP, + IDLE_REQ_BUS, + IDLE_REQ_CORE, + IDLE_REQ_DMA, + IDLE_REQ_GPU, + IDLE_REQ_PERI, + IDLE_REQ_VIDEO, + IDLE_REQ_VIO, +}; + +struct rockchip_pmu_operations { + int (*set_power_domain)(enum pmu_power_domain pd, bool on); + bool (*power_domain_is_on)(enum pmu_power_domain pd); + int (*set_idle_request)(enum pmu_idle_req req, bool idle); +}; + +extern struct rockchip_pmu_operations rockchip_pmu_ops; + +#endif diff --git a/arch/arm/mach-rockchip/rk3188.c b/arch/arm/mach-rockchip/rk3188.c index 1dc806d9d5ea..23b5db53b980 100644 --- a/arch/arm/mach-rockchip/rk3188.c +++ b/arch/arm/mach-rockchip/rk3188.c @@ -1,7 +1,7 @@ /* * Device Tree support for Rockchip RK3188 * - * Copyright (C) 2013 ROCKCHIP, Inc. + * Copyright (C) 2013-2014 ROCKCHIP, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +23,14 @@ #include #include #include -#include "core.h" +#include "common.h" #include "cpu.h" #include "cpu_axi.h" +#include "cru.h" #include "grf.h" #include "iomap.h" +#include "loader.h" +#include "pmu.h" #include "sram.h" #define RK3188_DEVICE(name) \ @@ -89,6 +92,20 @@ static struct map_desc rk3188_io_desc[] __initdata = { }, }; +static void __init rk3188_boot_mode_init(void) +{ + u32 flag = readl_relaxed(RK_PMU_VIRT + RK3188_PMU_SYS_REG0); + u32 mode = readl_relaxed(RK_PMU_VIRT + RK3188_PMU_SYS_REG1); + + if (flag == (SYS_KERNRL_REBOOT_FLAG | BOOT_RECOVER)) { + mode = BOOT_MODE_RECOVERY; + } + rockchip_boot_mode_init(flag, mode); +#ifdef CONFIG_RK29_WATCHDOG + writel_relaxed(BOOT_MODE_WATCHDOG, RK_PMU_VIRT + RK3188_PMU_SYS_REG1); +#endif +} + static void __init rk3188_dt_map_io(void) { preset_lpj = 11996091ULL / 2; @@ -104,24 +121,214 @@ static void __init rk3188_dt_map_io(void) /* rki2c is used instead of old i2c */ writel_relaxed(0xF800F800, RK_GRF_VIRT + RK3188_GRF_SOC_CON1); + + rk3188_boot_mode_init(); +} + +static const u8 pmu_pd_map[] = { + [PD_CPU_0] = 0, + [PD_CPU_1] = 1, + [PD_CPU_2] = 2, + [PD_CPU_3] = 3, + [PD_SCU] = 4, + [PD_BUS] = 5, + [PD_PERI] = 6, + [PD_VIO] = 7, + [PD_VIDEO] = 8, + [PD_GPU] = 9, + [PD_CS] = 10, +}; + +static bool rk3188_pmu_power_domain_is_on(enum pmu_power_domain pd) +{ + /* 1'b0: power on, 1'b1: power off */ + return !(readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_ST) & BIT(pmu_pd_map[pd])); +} + +static noinline void do_pmu_set_power_domain(enum pmu_power_domain domain, bool on) +{ + u8 pd = pmu_pd_map[domain]; + u32 val = readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_CON); + if (on) + val &= ~BIT(pd); + else + val |= BIT(pd); + writel_relaxed(val, RK_PMU_VIRT + RK3188_PMU_PWRDN_CON); + dsb(); + + while ((readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_ST) & BIT(pd)) == on) + ; +} + +static DEFINE_SPINLOCK(pmu_misc_con1_lock); + +static const u8 pmu_req_map[] = { + [IDLE_REQ_BUS] = 1, + [IDLE_REQ_PERI] = 2, + [IDLE_REQ_GPU] = 3, + [IDLE_REQ_VIDEO] = 4, + [IDLE_REQ_VIO] = 5, +}; + +static const u8 pmu_idle_map[] = { + [IDLE_REQ_DMA] = 14, + [IDLE_REQ_CORE] = 15, + [IDLE_REQ_VIO] = 22, + [IDLE_REQ_VIDEO] = 23, + [IDLE_REQ_GPU] = 24, + [IDLE_REQ_PERI] = 25, + [IDLE_REQ_BUS] = 26, +}; + +static const u8 pmu_ack_map[] = { + [IDLE_REQ_DMA] = 17, + [IDLE_REQ_CORE] = 18, + [IDLE_REQ_VIO] = 27, + [IDLE_REQ_VIDEO] = 28, + [IDLE_REQ_GPU] = 29, + [IDLE_REQ_PERI] = 30, + [IDLE_REQ_BUS] = 31, +}; + +static int rk3188_pmu_set_idle_request(enum pmu_idle_req req, bool idle) +{ + u32 idle_mask = BIT(pmu_idle_map[req]); + u32 idle_target = idle << pmu_idle_map[req]; + u32 ack_mask = BIT(pmu_ack_map[req]); + u32 ack_target = idle << pmu_ack_map[req]; + u32 mask = BIT(pmu_req_map[req]); + u32 val; + unsigned long flags; + + spin_lock_irqsave(&pmu_misc_con1_lock, flags); + val = readl_relaxed(RK_PMU_VIRT + RK3188_PMU_MISC_CON1); + if (idle) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, RK_PMU_VIRT + RK3188_PMU_MISC_CON1); + dsb(); + + while ((readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_ST) & ack_mask) != ack_target) + ; + while ((readl_relaxed(RK_PMU_VIRT + RK3188_PMU_PWRDN_ST) & idle_mask) != idle_target) + ; + spin_unlock_irqrestore(&pmu_misc_con1_lock, flags); + + return 0; +} + +/* + * software should power down or power up power domain one by one. Power down or + * power up multiple power domains simultaneously will result in chip electric current + * change dramatically which will affect the chip function. + */ +static DEFINE_SPINLOCK(pmu_pd_lock); +static u32 lcdc0_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 lcdc1_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 cif0_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 cif1_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 ipp_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 rga_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 gpu_qos[CPU_AXI_QOS_NUM_REGS]; +static u32 vpu_qos[CPU_AXI_QOS_NUM_REGS]; + +#define SAVE_QOS(array, NAME) CPU_AXI_SAVE_QOS(array, RK3188_CPU_AXI_##NAME##_QOS_BASE) +#define RESTORE_QOS(array, NAME) CPU_AXI_RESTORE_QOS(array, RK3188_CPU_AXI_##NAME##_QOS_BASE) + +static int rk3188_pmu_set_power_domain(enum pmu_power_domain pd, bool on) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_pd_lock, flags); + if (rk3188_pmu_power_domain_is_on(pd) == on) { + spin_unlock_irqrestore(&pmu_pd_lock, flags); + return 0; + } + if (!on) { + /* if power down, idle request to NIU first */ + if (pd == PD_VIO) { + SAVE_QOS(lcdc0_qos, LCDC0); + SAVE_QOS(lcdc1_qos, LCDC1); + SAVE_QOS(cif0_qos, CIF0); + SAVE_QOS(cif1_qos, CIF1); + SAVE_QOS(ipp_qos, IPP); + SAVE_QOS(rga_qos, RGA); + rk3188_pmu_set_idle_request(IDLE_REQ_VIO, true); + } else if (pd == PD_VIDEO) { + SAVE_QOS(vpu_qos, VPU); + rk3188_pmu_set_idle_request(IDLE_REQ_VIDEO, true); + } else if (pd == PD_GPU) { + SAVE_QOS(gpu_qos, GPU); + rk3188_pmu_set_idle_request(IDLE_REQ_GPU, true); + } + } + do_pmu_set_power_domain(pd, on); + if (on) { + /* if power up, idle request release to NIU */ + if (pd == PD_VIO) { + rk3188_pmu_set_idle_request(IDLE_REQ_VIO, false); + RESTORE_QOS(lcdc0_qos, LCDC0); + RESTORE_QOS(lcdc1_qos, LCDC1); + RESTORE_QOS(cif0_qos, CIF0); + RESTORE_QOS(cif1_qos, CIF1); + RESTORE_QOS(ipp_qos, IPP); + RESTORE_QOS(rga_qos, RGA); + } else if (pd == PD_VIDEO) { + rk3188_pmu_set_idle_request(IDLE_REQ_VIDEO, false); + RESTORE_QOS(vpu_qos, VPU); + } else if (pd == PD_GPU) { + rk3188_pmu_set_idle_request(IDLE_REQ_GPU, false); + RESTORE_QOS(gpu_qos, GPU); + } + } + spin_unlock_irqrestore(&pmu_pd_lock, flags); + + return 0; } static void __init rk3188_dt_init_timer(void) { + rockchip_pmu_ops.set_power_domain = rk3188_pmu_set_power_domain; + rockchip_pmu_ops.power_domain_is_on = rk3188_pmu_power_domain_is_on; + rockchip_pmu_ops.set_idle_request = rk3188_pmu_set_idle_request; of_clk_init(NULL); clocksource_of_init(); } -static const char * const rk3188_dt_compat[] = { +static const char * const rk3188_dt_compat[] __initconst = { "rockchip,rk3188", NULL, }; +static void rk3188_restart(char mode, const char *cmd) +{ + u32 boot_flag, boot_mode; + + rockchip_restart_get_boot_mode(cmd, &boot_flag, &boot_mode); + + writel_relaxed(boot_flag, RK_PMU_VIRT + RK3188_PMU_SYS_REG0); // for loader + writel_relaxed(boot_mode, RK_PMU_VIRT + RK3188_PMU_SYS_REG1); // for linux + dsb(); + + /* disable remap */ + writel_relaxed(1 << (12 + 16), RK_GRF_VIRT + RK3188_GRF_SOC_CON0); + /* pll enter slow mode */ + writel_relaxed(RK3188_PLL_MODE_SLOW(RK3188_APLL_ID) | + RK3188_PLL_MODE_SLOW(RK3188_CPLL_ID) | + RK3188_PLL_MODE_SLOW(RK3188_GPLL_ID), + RK_CRU_VIRT + RK3188_CRU_MODE_CON); + dsb(); + writel_relaxed(0xeca8, RK_CRU_VIRT + RK3188_CRU_GLB_SRST_SND); + dsb(); +} + DT_MACHINE_START(RK3188_DT, "Rockchip RK3188 (Flattened Device Tree)") .smp = smp_ops(rockchip_smp_ops), .map_io = rk3188_dt_map_io, .init_time = rk3188_dt_init_timer, .dt_compat = rk3188_dt_compat, + .restart = rk3188_restart, MACHINE_END #define CPU 3188 @@ -161,7 +368,7 @@ arch_initcall(rk3188_pie_init); #define sram_printascii(s) do {} while (0) /* FIXME */ #include "ddr_rk30.c" -static int rk3188_ddr_init(void) +static int __init rk3188_ddr_init(void) { if (cpu_is_rk3188()) ddr_init(DDR3_DEFAULT, 300);