Merge branch 'for-arm-soc' of git://git.armlinux.org.uk/~rmk/linux-arm into arm/soc
[linux-2.6-microblaze.git] / arch / arm / mach-bcm / bcm63xx_pmb.c
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 }