root/arch/arm/mach-bcm/bcm63xx_pmb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bpcm_wr_rd_mask
  2. bcm63xx_pmb_get_resources
  3. bcm63xx_pmb_power_on_cpu

   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  */
  60 static 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  */
  84 static DEFINE_SPINLOCK(pmb_lock);
  85 
  86 static 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         ret = of_property_read_u32(dn, "reg", cpu);
  95         if (ret) {
  96                 pr_err("CPU is missing a reg node\n");
  97                 return ret;
  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 
 124 int 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);
 211 out:
 212         spin_unlock_irqrestore(&pmb_lock, flags);
 213         iounmap(base);
 214         return ret;
 215 }

/* [<][>][^][v][top][bottom][index][help] */