0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/io.h>
0009 #include <linux/reboot.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/of_address.h>
0012 #include <linux/regmap.h>
0013 #include <linux/clk/zynq.h>
0014 #include "common.h"
0015
0016
0017 #define SLCR_UNLOCK_OFFSET 0x8
0018 #define SLCR_PS_RST_CTRL_OFFSET 0x200
0019 #define SLCR_A9_CPU_RST_CTRL_OFFSET 0x244
0020 #define SLCR_REBOOT_STATUS_OFFSET 0x258
0021 #define SLCR_PSS_IDCODE 0x530
0022 #define SLCR_L2C_RAM 0xA1C
0023
0024 #define SLCR_UNLOCK_MAGIC 0xDF0D
0025 #define SLCR_A9_CPU_CLKSTOP 0x10
0026 #define SLCR_A9_CPU_RST 0x1
0027 #define SLCR_PSS_IDCODE_DEVICE_SHIFT 12
0028 #define SLCR_PSS_IDCODE_DEVICE_MASK 0x1F
0029
0030 static void __iomem *zynq_slcr_base;
0031 static struct regmap *zynq_slcr_regmap;
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 static int zynq_slcr_write(u32 val, u32 offset)
0042 {
0043 return regmap_write(zynq_slcr_regmap, offset, val);
0044 }
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 static int zynq_slcr_read(u32 *val, u32 offset)
0055 {
0056 return regmap_read(zynq_slcr_regmap, offset, val);
0057 }
0058
0059
0060
0061
0062
0063
0064 static inline int zynq_slcr_unlock(void)
0065 {
0066 zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET);
0067
0068 return 0;
0069 }
0070
0071
0072
0073
0074
0075
0076 u32 zynq_slcr_get_device_id(void)
0077 {
0078 u32 val;
0079
0080 zynq_slcr_read(&val, SLCR_PSS_IDCODE);
0081 val >>= SLCR_PSS_IDCODE_DEVICE_SHIFT;
0082 val &= SLCR_PSS_IDCODE_DEVICE_MASK;
0083
0084 return val;
0085 }
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 static
0097 int zynq_slcr_system_restart(struct notifier_block *nb,
0098 unsigned long action, void *data)
0099 {
0100 u32 reboot;
0101
0102
0103
0104
0105
0106
0107 zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET);
0108 zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET);
0109 zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET);
0110 return 0;
0111 }
0112
0113 static struct notifier_block zynq_slcr_restart_nb = {
0114 .notifier_call = zynq_slcr_system_restart,
0115 .priority = 192,
0116 };
0117
0118
0119
0120
0121
0122 void zynq_slcr_cpu_start(int cpu)
0123 {
0124 u32 reg;
0125
0126 zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET);
0127 reg &= ~(SLCR_A9_CPU_RST << cpu);
0128 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
0129 reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
0130 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
0131
0132 zynq_slcr_cpu_state_write(cpu, false);
0133 }
0134
0135
0136
0137
0138
0139 void zynq_slcr_cpu_stop(int cpu)
0140 {
0141 u32 reg;
0142
0143 zynq_slcr_read(®, SLCR_A9_CPU_RST_CTRL_OFFSET);
0144 reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu;
0145 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 bool zynq_slcr_cpu_state_read(int cpu)
0158 {
0159 u32 state;
0160
0161 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
0162 state &= 1 << (31 - cpu);
0163
0164 return !state;
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 void zynq_slcr_cpu_state_write(int cpu, bool die)
0176 {
0177 u32 state, mask;
0178
0179 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
0180 mask = 1 << (31 - cpu);
0181 if (die)
0182 state |= mask;
0183 else
0184 state &= ~mask;
0185 writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
0186 }
0187
0188
0189
0190
0191
0192
0193
0194
0195 int __init zynq_early_slcr_init(void)
0196 {
0197 struct device_node *np;
0198
0199 np = of_find_compatible_node(NULL, NULL, "xlnx,zynq-slcr");
0200 if (!np) {
0201 pr_err("%s: no slcr node found\n", __func__);
0202 BUG();
0203 }
0204
0205 zynq_slcr_base = of_iomap(np, 0);
0206 if (!zynq_slcr_base) {
0207 pr_err("%s: Unable to map I/O memory\n", __func__);
0208 BUG();
0209 }
0210
0211 np->data = (__force void *)zynq_slcr_base;
0212
0213 zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
0214 if (IS_ERR(zynq_slcr_regmap)) {
0215 pr_err("%s: failed to find zynq-slcr\n", __func__);
0216 return -ENODEV;
0217 }
0218
0219
0220 zynq_slcr_unlock();
0221
0222
0223 regmap_update_bits(zynq_slcr_regmap, SLCR_L2C_RAM, 0x70707, 0x20202);
0224
0225 register_restart_handler(&zynq_slcr_restart_nb);
0226
0227 pr_info("%pOFn mapped to %p\n", np, zynq_slcr_base);
0228
0229 of_node_put(np);
0230
0231 return 0;
0232 }