Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Broadcom BCM63138 PMB initialization for secondary CPU(s)
0004  *
0005  * Copyright (C) 2015 Broadcom Corporation
0006  * Author: Florian Fainelli <f.fainelli@gmail.com>
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/io.h>
0010 #include <linux/spinlock.h>
0011 #include <linux/reset/bcm63xx_pmb.h>
0012 #include <linux/of.h>
0013 #include <linux/of_address.h>
0014 
0015 #include "bcm63xx_smp.h"
0016 
0017 /* ARM Control register definitions */
0018 #define CORE_PWR_CTRL_SHIFT 0
0019 #define CORE_PWR_CTRL_MASK  0x3
0020 #define PLL_PWR_ON      BIT(8)
0021 #define PLL_LDO_PWR_ON      BIT(9)
0022 #define PLL_CLAMP_ON        BIT(10)
0023 #define CPU_RESET_N(x)      BIT(13 + (x))
0024 #define NEON_RESET_N        BIT(15)
0025 #define PWR_CTRL_STATUS_SHIFT   28
0026 #define PWR_CTRL_STATUS_MASK    0x3
0027 #define PWR_DOWN_SHIFT      30
0028 #define PWR_DOWN_MASK       0x3
0029 
0030 /* CPU Power control register definitions */
0031 #define MEM_PWR_OK      BIT(0)
0032 #define MEM_PWR_ON      BIT(1)
0033 #define MEM_CLAMP_ON        BIT(2)
0034 #define MEM_PWR_OK_STATUS   BIT(4)
0035 #define MEM_PWR_ON_STATUS   BIT(5)
0036 #define MEM_PDA_SHIFT       8
0037 #define MEM_PDA_MASK        0xf
0038 #define  MEM_PDA_CPU_MASK   0x1
0039 #define  MEM_PDA_NEON_MASK  0xf
0040 #define CLAMP_ON        BIT(15)
0041 #define PWR_OK_SHIFT        16
0042 #define PWR_OK_MASK     0xf
0043 #define PWR_ON_SHIFT        20
0044 #define  PWR_CPU_MASK       0x03
0045 #define  PWR_NEON_MASK      0x01
0046 #define PWR_ON_MASK     0xf
0047 #define PWR_OK_STATUS_SHIFT 24
0048 #define PWR_OK_STATUS_MASK  0xf
0049 #define PWR_ON_STATUS_SHIFT 28
0050 #define PWR_ON_STATUS_MASK  0xf
0051 
0052 #define ARM_CONTROL     0x30
0053 #define ARM_PWR_CONTROL_BASE    0x34
0054 #define ARM_PWR_CONTROL(x)  (ARM_PWR_CONTROL_BASE + (x) * 0x4)
0055 #define ARM_NEON_L2     0x3c
0056 
0057 /* Perform a value write, then spin until the value shifted by
0058  * shift is seen, masked with mask and is different from cond.
0059  */
0060 static int bpcm_wr_rd_mask(void __iomem *master,
0061                unsigned int addr, u32 off, u32 *val,
0062                u32 shift, u32 mask, u32 cond)
0063 {
0064     int ret;
0065 
0066     ret = bpcm_wr(master, addr, off, *val);
0067     if (ret)
0068         return ret;
0069 
0070     do {
0071         ret = bpcm_rd(master, addr, off, val);
0072         if (ret)
0073             return ret;
0074 
0075         cpu_relax();
0076     } while (((*val >> shift) & mask) != cond);
0077 
0078     return ret;
0079 }
0080 
0081 /* Global lock to serialize accesses to the PMB registers while we
0082  * are bringing up the secondary CPU
0083  */
0084 static DEFINE_SPINLOCK(pmb_lock);
0085 
0086 static int bcm63xx_pmb_get_resources(struct device_node *dn,
0087                      void __iomem **base,
0088                      unsigned int *cpu,
0089                      unsigned int *addr)
0090 {
0091     struct of_phandle_args args;
0092     int ret;
0093 
0094     *cpu = of_get_cpu_hwid(dn, 0);
0095     if (*cpu == ~0U) {
0096         pr_err("CPU is missing a reg node\n");
0097         return -ENODEV;
0098     }
0099 
0100     ret = of_parse_phandle_with_args(dn, "resets", "#reset-cells",
0101                      0, &args);
0102     if (ret) {
0103         pr_err("CPU is missing a resets phandle\n");
0104         return ret;
0105     }
0106 
0107     if (args.args_count != 2) {
0108         pr_err("reset-controller does not conform to reset-cells\n");
0109         return -EINVAL;
0110     }
0111 
0112     *base = of_iomap(args.np, 0);
0113     if (!*base) {
0114         pr_err("failed remapping PMB register\n");
0115         return -ENOMEM;
0116     }
0117 
0118     /* We do not need the number of zones */
0119     *addr = args.args[0];
0120 
0121     return 0;
0122 }
0123 
0124 int bcm63xx_pmb_power_on_cpu(struct device_node *dn)
0125 {
0126     void __iomem *base;
0127     unsigned int cpu, addr;
0128     unsigned long flags;
0129     u32 val, ctrl;
0130     int ret;
0131 
0132     ret = bcm63xx_pmb_get_resources(dn, &base, &cpu, &addr);
0133     if (ret)
0134         return ret;
0135 
0136     /* We would not know how to enable a third and greater CPU */
0137     WARN_ON(cpu > 1);
0138 
0139     spin_lock_irqsave(&pmb_lock, flags);
0140 
0141     /* Check if the CPU is already on and save the ARM_CONTROL register
0142      * value since we will use it later for CPU de-assert once done with
0143      * the CPU-specific power sequence
0144      */
0145     ret = bpcm_rd(base, addr, ARM_CONTROL, &ctrl);
0146     if (ret)
0147         goto out;
0148 
0149     if (ctrl & CPU_RESET_N(cpu)) {
0150         pr_info("PMB: CPU%d is already powered on\n", cpu);
0151         ret = 0;
0152         goto out;
0153     }
0154 
0155     /* Power on PLL */
0156     ret = bpcm_rd(base, addr, ARM_PWR_CONTROL(cpu), &val);
0157     if (ret)
0158         goto out;
0159 
0160     val |= (PWR_CPU_MASK << PWR_ON_SHIFT);
0161 
0162     ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0163             PWR_ON_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
0164     if (ret)
0165         goto out;
0166 
0167     val |= (PWR_CPU_MASK << PWR_OK_SHIFT);
0168 
0169     ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0170             PWR_OK_STATUS_SHIFT, PWR_CPU_MASK, PWR_CPU_MASK);
0171     if (ret)
0172         goto out;
0173 
0174     val &= ~CLAMP_ON;
0175 
0176     ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
0177     if (ret)
0178         goto out;
0179 
0180     /* Power on CPU<N> RAM */
0181     val &= ~(MEM_PDA_MASK << MEM_PDA_SHIFT);
0182 
0183     ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
0184     if (ret)
0185         goto out;
0186 
0187     val |= MEM_PWR_ON;
0188 
0189     ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0190             0, MEM_PWR_ON_STATUS, MEM_PWR_ON_STATUS);
0191     if (ret)
0192         goto out;
0193 
0194     val |= MEM_PWR_OK;
0195 
0196     ret = bpcm_wr_rd_mask(base, addr, ARM_PWR_CONTROL(cpu), &val,
0197             0, MEM_PWR_OK_STATUS, MEM_PWR_OK_STATUS);
0198     if (ret)
0199         goto out;
0200 
0201     val &= ~MEM_CLAMP_ON;
0202 
0203     ret = bpcm_wr(base, addr, ARM_PWR_CONTROL(cpu), val);
0204     if (ret)
0205         goto out;
0206 
0207     /* De-assert CPU reset */
0208     ctrl |= CPU_RESET_N(cpu);
0209 
0210     ret = bpcm_wr(base, addr, ARM_CONTROL, ctrl);
0211 out:
0212     spin_unlock_irqrestore(&pmb_lock, flags);
0213     iounmap(base);
0214     return ret;
0215 }