~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-zynq/slcr.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Xilinx SLCR driver
  4  *
  5  * Copyright (c) 2011-2013 Xilinx Inc.
  6  */
  7 
  8 #include <linux/io.h>
  9 #include <linux/reboot.h>
 10 #include <linux/mfd/syscon.h>
 11 #include <linux/of_address.h>
 12 #include <linux/regmap.h>
 13 #include "common.h"
 14 
 15 /* register offsets */
 16 #define SLCR_UNLOCK_OFFSET              0x8   /* SCLR unlock register */
 17 #define SLCR_PS_RST_CTRL_OFFSET         0x200 /* PS Software Reset Control */
 18 #define SLCR_A9_CPU_RST_CTRL_OFFSET     0x244 /* CPU Software Reset Control */
 19 #define SLCR_REBOOT_STATUS_OFFSET       0x258 /* PS Reboot Status */
 20 #define SLCR_PSS_IDCODE                 0x530 /* PS IDCODE */
 21 #define SLCR_L2C_RAM                    0xA1C /* L2C_RAM in AR#54190 */
 22 
 23 #define SLCR_UNLOCK_MAGIC               0xDF0D
 24 #define SLCR_A9_CPU_CLKSTOP             0x10
 25 #define SLCR_A9_CPU_RST                 0x1
 26 #define SLCR_PSS_IDCODE_DEVICE_SHIFT    12
 27 #define SLCR_PSS_IDCODE_DEVICE_MASK     0x1F
 28 
 29 static void __iomem *zynq_slcr_base;
 30 static struct regmap *zynq_slcr_regmap;
 31 
 32 /**
 33  * zynq_slcr_write - Write to a register in SLCR block
 34  *
 35  * @val:        Value to write to the register
 36  * @offset:     Register offset in SLCR block
 37  *
 38  * Return:      a negative value on error, 0 on success
 39  */
 40 static int zynq_slcr_write(u32 val, u32 offset)
 41 {
 42         return regmap_write(zynq_slcr_regmap, offset, val);
 43 }
 44 
 45 /**
 46  * zynq_slcr_read - Read a register in SLCR block
 47  *
 48  * @val:        Pointer to value to be read from SLCR
 49  * @offset:     Register offset in SLCR block
 50  *
 51  * Return:      a negative value on error, 0 on success
 52  */
 53 static int zynq_slcr_read(u32 *val, u32 offset)
 54 {
 55         return regmap_read(zynq_slcr_regmap, offset, val);
 56 }
 57 
 58 /**
 59  * zynq_slcr_unlock - Unlock SLCR registers
 60  *
 61  * Return:      a negative value on error, 0 on success
 62  */
 63 static inline int zynq_slcr_unlock(void)
 64 {
 65         zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET);
 66 
 67         return 0;
 68 }
 69 
 70 /**
 71  * zynq_slcr_get_device_id - Read device code id
 72  *
 73  * Return:      Device code id
 74  */
 75 u32 zynq_slcr_get_device_id(void)
 76 {
 77         u32 val;
 78 
 79         zynq_slcr_read(&val, SLCR_PSS_IDCODE);
 80         val >>= SLCR_PSS_IDCODE_DEVICE_SHIFT;
 81         val &= SLCR_PSS_IDCODE_DEVICE_MASK;
 82 
 83         return val;
 84 }
 85 
 86 /**
 87  * zynq_slcr_system_restart - Restart the entire system.
 88  *
 89  * @nb:         Pointer to restart notifier block (unused)
 90  * @action:     Reboot mode (unused)
 91  * @data:       Restart handler private data (unused)
 92  *
 93  * Return:      0 always
 94  */
 95 static
 96 int zynq_slcr_system_restart(struct notifier_block *nb,
 97                              unsigned long action, void *data)
 98 {
 99         u32 reboot;
100 
101         /*
102          * Clear 0x0F000000 bits of reboot status register to workaround
103          * the FSBL not loading the bitstream after soft-reboot
104          * This is a temporary solution until we know more.
105          */
106         zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET);
107         zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET);
108         zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET);
109         return 0;
110 }
111 
112 static struct notifier_block zynq_slcr_restart_nb = {
113         .notifier_call  = zynq_slcr_system_restart,
114         .priority       = 192,
115 };
116 
117 /**
118  * zynq_slcr_cpu_start - Start cpu
119  * @cpu:        cpu number
120  */
121 void zynq_slcr_cpu_start(int cpu)
122 {
123         u32 reg;
124 
125         zynq_slcr_read(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
126         reg &= ~(SLCR_A9_CPU_RST << cpu);
127         zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
128         reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
129         zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
130 
131         zynq_slcr_cpu_state_write(cpu, false);
132 }
133 
134 /**
135  * zynq_slcr_cpu_stop - Stop cpu
136  * @cpu:        cpu number
137  */
138 void zynq_slcr_cpu_stop(int cpu)
139 {
140         u32 reg;
141 
142         zynq_slcr_read(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
143         reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu;
144         zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
145 }
146 
147 /**
148  * zynq_slcr_cpu_state_read - Read cpu state
149  * @cpu:        cpu number
150  *
151  * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
152  * 0 means cpu is running, 1 cpu is going to die.
153  *
154  * Return: true if cpu is running, false if cpu is going to die
155  */
156 bool zynq_slcr_cpu_state_read(int cpu)
157 {
158         u32 state;
159 
160         state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
161         state &= 1 << (31 - cpu);
162 
163         return !state;
164 }
165 
166 /**
167  * zynq_slcr_cpu_state_write - Write cpu state
168  * @cpu:        cpu number
169  * @die:        cpu state - true if cpu is going to die
170  *
171  * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
172  * 0 means cpu is running, 1 cpu is going to die.
173  */
174 void zynq_slcr_cpu_state_write(int cpu, bool die)
175 {
176         u32 state, mask;
177 
178         state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
179         mask = 1 << (31 - cpu);
180         if (die)
181                 state |= mask;
182         else
183                 state &= ~mask;
184         writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
185 }
186 
187 /**
188  * zynq_early_slcr_init - Early slcr init function
189  *
190  * Return:      0 on success, negative errno otherwise.
191  *
192  * Called very early during boot from platform code to unlock SLCR.
193  */
194 int __init zynq_early_slcr_init(void)
195 {
196         struct device_node *np;
197 
198         np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr");
199         if (!np) {
200                 pr_err("%s: no slcr node found\n", __func__);
201                 BUG();
202         }
203 
204         zynq_slcr_base = of_iomap(np, 0);
205         if (!zynq_slcr_base) {
206                 pr_err("%s: Unable to map I/O memory\n", __func__);
207                 BUG();
208         }
209 
210         np->data = (__force void *)zynq_slcr_base;
211 
212         zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
213         if (IS_ERR(zynq_slcr_regmap)) {
214                 pr_err("%s: failed to find zynq-slcr\n", __func__);
215                 of_node_put(np);
216                 return -ENODEV;
217         }
218 
219         /* unlock the SLCR so that registers can be changed */
220         zynq_slcr_unlock();
221 
222         /* See AR#54190 design advisory */
223         regmap_update_bits(zynq_slcr_regmap, SLCR_L2C_RAM, 0x70707, 0x20202);
224 
225         register_restart_handler(&zynq_slcr_restart_nb);
226 
227         pr_info("%pOFn mapped to %p\n", np, zynq_slcr_base);
228 
229         of_node_put(np);
230 
231         return 0;
232 }
233 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php