bcm63xx_pmb.c (4958B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Broadcom BCM63138 PMB initialization for secondary CPU(s) 4 * 5 * Copyright (C) 2015 Broadcom Corporation 6 * Author: Florian Fainelli <f.fainelli@gmail.com> 7 */ 8#include <linux/kernel.h> 9#include <linux/io.h> 10#include <linux/spinlock.h> 11#include <linux/reset/bcm63xx_pmb.h> 12#include <linux/of.h> 13#include <linux/of_address.h> 14 15#include "bcm63xx_smp.h" 16 17/* ARM Control register definitions */ 18#define CORE_PWR_CTRL_SHIFT 0 19#define CORE_PWR_CTRL_MASK 0x3 20#define PLL_PWR_ON BIT(8) 21#define PLL_LDO_PWR_ON BIT(9) 22#define PLL_CLAMP_ON BIT(10) 23#define CPU_RESET_N(x) BIT(13 + (x)) 24#define NEON_RESET_N BIT(15) 25#define PWR_CTRL_STATUS_SHIFT 28 26#define PWR_CTRL_STATUS_MASK 0x3 27#define PWR_DOWN_SHIFT 30 28#define PWR_DOWN_MASK 0x3 29 30/* CPU Power control register definitions */ 31#define MEM_PWR_OK BIT(0) 32#define MEM_PWR_ON BIT(1) 33#define MEM_CLAMP_ON BIT(2) 34#define MEM_PWR_OK_STATUS BIT(4) 35#define MEM_PWR_ON_STATUS BIT(5) 36#define MEM_PDA_SHIFT 8 37#define MEM_PDA_MASK 0xf 38#define MEM_PDA_CPU_MASK 0x1 39#define MEM_PDA_NEON_MASK 0xf 40#define CLAMP_ON BIT(15) 41#define PWR_OK_SHIFT 16 42#define PWR_OK_MASK 0xf 43#define PWR_ON_SHIFT 20 44#define PWR_CPU_MASK 0x03 45#define PWR_NEON_MASK 0x01 46#define PWR_ON_MASK 0xf 47#define PWR_OK_STATUS_SHIFT 24 48#define PWR_OK_STATUS_MASK 0xf 49#define PWR_ON_STATUS_SHIFT 28 50#define PWR_ON_STATUS_MASK 0xf 51 52#define ARM_CONTROL 0x30 53#define ARM_PWR_CONTROL_BASE 0x34 54#define ARM_PWR_CONTROL(x) (ARM_PWR_CONTROL_BASE + (x) * 0x4) 55#define ARM_NEON_L2 0x3c 56 57/* Perform a value write, then spin until the value shifted by 58 * shift is seen, masked with mask and is different from cond. 59 */ 60static int bpcm_wr_rd_mask(void __iomem *master, 61 unsigned int addr, u32 off, u32 *val, 62 u32 shift, u32 mask, u32 cond) 63{ 64 int ret; 65 66 ret = bpcm_wr(master, addr, off, *val); 67 if (ret) 68 return ret; 69 70 do { 71 ret = bpcm_rd(master, addr, off, val); 72 if (ret) 73 return ret; 74 75 cpu_relax(); 76 } while (((*val >> shift) & mask) != cond); 77 78 return ret; 79} 80 81/* Global lock to serialize accesses to the PMB registers while we 82 * are bringing up the secondary CPU 83 */ 84static DEFINE_SPINLOCK(pmb_lock); 85 86static int bcm63xx_pmb_get_resources(struct device_node *dn, 87 void __iomem **base, 88 unsigned int *cpu, 89 unsigned int *addr) 90{ 91 struct of_phandle_args args; 92 int ret; 93 94 *cpu = of_get_cpu_hwid(dn, 0); 95 if (*cpu == ~0U) { 96 pr_err("CPU is missing a reg node\n"); 97 return -ENODEV; 98 } 99 100 ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells", 101 0, &args); 102 if (ret) { 103 pr_err("CPU is missing a resets phandle\n"); 104 return ret; 105 } 106 107 if (args.args_count != 2) { 108 pr_err("reset-controller does not conform to reset-cells\n"); 109 return -EINVAL; 110 } 111 112 *base = of_iomap(args.np, 0); 113 if (!*base) { 114 pr_err("failed remapping PMB register\n"); 115 return -ENOMEM; 116 } 117 118 /* We do not need the number of zones */ 119 *addr = args.args[0]; 120 121 return 0; 122} 123 124int bcm63xx_pmb_power_on_cpu(struct device_node *dn) 125{ 126 void __iomem *base; 127 unsigned int cpu, addr; 128 unsigned long flags; 129 u32 val, ctrl; 130 int ret; 131 132 ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr); 133 if (ret) 134 return ret; 135 136 /* We would not know how to enable a third and greater CPU */ 137 WARN_ON(cpu > 1); 138 139 spin_lock_irqsave(&pmb_lock, flags); 140 141 /* Check if the CPU is already on and save the ARM_CONTROL register 142 * value since we will use it later for CPU de-assert once done with 143 * the CPU-specific power sequence 144 */ 145 ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl); 146 if (ret) 147 goto out; 148 149 if (ctrl & CPU_RESET_N(cpu)) { 150 pr_info("PMB: CPU%d is already powered on\n", cpu); 151 ret = 0; 152 goto out; 153 } 154 155 /* Power on PLL */ 156 ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val); 157 if (ret) 158 goto out; 159 160 val |= (PWR_CPU_MASK << PWR_ON_SHIFT); 161 162 ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val, 163 PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK); 164 if (ret) 165 goto out; 166 167 val |= (PWR_CPU_MASK << PWR_OK_SHIFT); 168 169 ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val, 170 PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK); 171 if (ret) 172 goto out; 173 174 val &= ~CLAMP_ON; 175 176 ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val); 177 if (ret) 178 goto out; 179 180 /* Power on CPU<N> RAM */ 181 val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT); 182 183 ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val); 184 if (ret) 185 goto out; 186 187 val |= MEM_PWR_ON; 188 189 ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val, 190 0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS); 191 if (ret) 192 goto out; 193 194 val |= MEM_PWR_OK; 195 196 ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val, 197 0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS); 198 if (ret) 199 goto out; 200 201 val &= ~MEM_CLAMP_ON; 202 203 ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val); 204 if (ret) 205 goto out; 206 207 /* De-assert CPU reset */ 208 ctrl |= CPU_RESET_N(cpu); 209 210 ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl); 211out: 212 spin_unlock_irqrestore(&pmb_lock, flags); 213 iounmap(base); 214 return ret; 215}