Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Xilinx SLCR driver
0004  *
0005  * Copyright (c) 2011-2013 Xilinx Inc.
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 /* register offsets */
0017 #define SLCR_UNLOCK_OFFSET      0x8   /* SCLR unlock register */
0018 #define SLCR_PS_RST_CTRL_OFFSET     0x200 /* PS Software Reset Control */
0019 #define SLCR_A9_CPU_RST_CTRL_OFFSET 0x244 /* CPU Software Reset Control */
0020 #define SLCR_REBOOT_STATUS_OFFSET   0x258 /* PS Reboot Status */
0021 #define SLCR_PSS_IDCODE         0x530 /* PS IDCODE */
0022 #define SLCR_L2C_RAM            0xA1C /* L2C_RAM in AR#54190 */
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  * zynq_slcr_write - Write to a register in SLCR block
0035  *
0036  * @val:    Value to write to the register
0037  * @offset: Register offset in SLCR block
0038  *
0039  * Return:  a negative value on error, 0 on success
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  * zynq_slcr_read - Read a register in SLCR block
0048  *
0049  * @val:    Pointer to value to be read from SLCR
0050  * @offset: Register offset in SLCR block
0051  *
0052  * Return:  a negative value on error, 0 on success
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  * zynq_slcr_unlock - Unlock SLCR registers
0061  *
0062  * Return:  a negative value on error, 0 on success
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  * zynq_slcr_get_device_id - Read device code id
0073  *
0074  * Return:  Device code id
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  * zynq_slcr_system_restart - Restart the entire system.
0089  *
0090  * @nb:     Pointer to restart notifier block (unused)
0091  * @action: Reboot mode (unused)
0092  * @data:   Restart handler private data (unused)
0093  *
0094  * Return:  0 always
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      * Clear 0x0F000000 bits of reboot status register to workaround
0104      * the FSBL not loading the bitstream after soft-reboot
0105      * This is a temporary solution until we know more.
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  * zynq_slcr_cpu_start - Start cpu
0120  * @cpu:    cpu number
0121  */
0122 void zynq_slcr_cpu_start(int cpu)
0123 {
0124     u32 reg;
0125 
0126     zynq_slcr_read(&reg, 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  * zynq_slcr_cpu_stop - Stop cpu
0137  * @cpu:    cpu number
0138  */
0139 void zynq_slcr_cpu_stop(int cpu)
0140 {
0141     u32 reg;
0142 
0143     zynq_slcr_read(&reg, 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  * zynq_slcr_cpu_state - Read/write cpu state
0150  * @cpu:    cpu number
0151  *
0152  * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
0153  * 0 means cpu is running, 1 cpu is going to die.
0154  *
0155  * Return: true if cpu is running, false if cpu is going to die
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  * zynq_slcr_cpu_state - Read/write cpu state
0169  * @cpu:    cpu number
0170  * @die:    cpu state - true if cpu is going to die
0171  *
0172  * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
0173  * 0 means cpu is running, 1 cpu is going to die.
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  * zynq_early_slcr_init - Early slcr init function
0190  *
0191  * Return:  0 on success, negative errno otherwise.
0192  *
0193  * Called very early during boot from platform code to unlock SLCR.
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     /* unlock the SLCR so that registers can be changed */
0220     zynq_slcr_unlock();
0221 
0222     /* See AR#54190 design advisory */
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 }