/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "sunxi_def.h" #include "sunxi_private.h" #define SUN50I_PRCM_PBASE (0x01F01400) #define SUN50I_CPUCFG_PBASE (0x01700000) #define SUN50I_RCPUCFG_PBASE (0x01F01C00) #define SUNXI_CPU_PWR_CLAMP(cluster, cpu) (0x140 + (cluster*4 + cpu)*0x04) #define SUNXI_CLUSTER_PWROFF_GATING(cluster) (0x100 + (cluster)*0x04) #define SUNXI_CLUSTER_PWRON_RESET(cluster) (0x30 + (cluster)*0x04) #define SUNXI_DBG_REG0 (0x20) #define SUNXI_CLUSTER_CPU_STATUS(cluster) (0x30 + (cluster)*0x4) #define SUNXI_CPU_RST_CTRL(cluster) (0x80 + (cluster)*0x4) #define SUNXI_CLUSTER_CTRL0(cluster) (0x00 + (cluster)*0x10) #define SUNXI_CPU_RVBA_L(cpu) (0xA0 + (cpu)*0x8) #define SUNXI_CPU_RVBA_H(cpu) (0xA4 + (cpu)*0x8) #define readl(x) mmio_read_32((x)) #define writel(v, a) mmio_write_32((a), (v)) typedef unsigned int bool; static unsigned int sun50i_cpucfg_base = SUN50I_CPUCFG_PBASE; static unsigned int sun50i_prcm_base = SUN50I_PRCM_PBASE; static unsigned int sun50i_r_cpucfg_base = SUN50I_RCPUCFG_PBASE; extern bakery_lock_t plat_console_lock; void udelay(unsigned int delay) { if (!delay) return; __asm__ volatile ( "1:\tsubs %0, %0, #1\n" "\tb.ne 1b" :: "r" (delay * 1000UL) ); } #ifdef SUNXI_CPUOPS_REAL_DELAY #define CPU_DELAY_SHORT 10 #define CPU_DELAY_MEDIUM 20 #define CPU_DELAY_LONG 30 #else #define CPU_DELAY_SHORT 0 #define CPU_DELAY_MEDIUM 0 #define CPU_DELAY_LONG 0 #endif void sun50i_set_secondary_entry(unsigned long entry, unsigned int cpu) { mmio_write_32(sun50i_cpucfg_base + SUNXI_CPU_RVBA_L(cpu) ,entry); mmio_write_32(sun50i_cpucfg_base + SUNXI_CPU_RVBA_H(cpu), 0); } void sun50i_set_AA32nAA64(unsigned int cluster, unsigned int cpu, bool is_aa64) { volatile unsigned int value; value = readl(sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); value &= ~(1<<(cpu + 24)); value |= (is_aa64 <<(cpu + 24)); writel(value, sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); value = readl(sun50i_cpucfg_base + SUNXI_CLUSTER_CTRL0(cluster)); } int sun50i_power_switch_set(unsigned int cluster, unsigned int cpu, bool enable) { if (enable) { if (0x00 == readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))) return 0; /* de-active cpu power clamp */ writel(0xFE, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_MEDIUM); writel(0xF8, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_SHORT); writel(0xE0, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_SHORT); writel(0x80, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_SHORT); writel(0x00, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_MEDIUM); while (0x00 != readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))); } else { if (0xFF == readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))) return 0; writel(0xFF, sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu)); udelay(CPU_DELAY_LONG); while (0xFF != readl(sun50i_prcm_base + SUNXI_CPU_PWR_CLAMP(cluster, cpu))); } return 0; } void sun50i_cpu_power_up(unsigned int cluster, unsigned int cpu) { unsigned int value; /* Assert nCPUPORESET LOW */ value = readl(sun50i_cpucfg_base + SUNXI_CPU_RST_CTRL(cluster)); value &= (~(1<