Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[deliverable/linux.git] / arch / arm / mach-zynq / slcr.c
index 59ad09ff3bc064b7e3e5a8d9c3d68e698634c6a8..a37d49a6e6578cddf922f45cb8a87c6b306dae25 100644 (file)
@@ -15,7 +15,9 @@
  */
 
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_address.h>
+#include <linux/regmap.h>
 #include <linux/clk/zynq.h>
 #include "common.h"
 
 #define SLCR_A9_CPU_CLKSTOP            0x10
 #define SLCR_A9_CPU_RST                        0x1
 
-void __iomem *zynq_slcr_base;
+static void __iomem *zynq_slcr_base;
+static struct regmap *zynq_slcr_regmap;
+
+/**
+ * zynq_slcr_write - Write to a register in SLCR block
+ *
+ * @val:       Value to write to the register
+ * @offset:    Register offset in SLCR block
+ *
+ * Return:     a negative value on error, 0 on success
+ */
+static int zynq_slcr_write(u32 val, u32 offset)
+{
+       if (!zynq_slcr_regmap) {
+               writel(val, zynq_slcr_base + offset);
+               return 0;
+       }
+
+       return regmap_write(zynq_slcr_regmap, offset, val);
+}
+
+/**
+ * zynq_slcr_read - Read a register in SLCR block
+ *
+ * @val:       Pointer to value to be read from SLCR
+ * @offset:    Register offset in SLCR block
+ *
+ * Return:     a negative value on error, 0 on success
+ */
+static int zynq_slcr_read(u32 *val, u32 offset)
+{
+       if (zynq_slcr_regmap)
+               return regmap_read(zynq_slcr_regmap, offset, val);
+
+       *val = readl(zynq_slcr_base + offset);
+
+       return 0;
+}
+
+/**
+ * zynq_slcr_unlock - Unlock SLCR registers
+ *
+ * Return:     a negative value on error, 0 on success
+ */
+static inline int zynq_slcr_unlock(void)
+{
+       zynq_slcr_write(SLCR_UNLOCK_MAGIC, SLCR_UNLOCK_OFFSET);
+
+       return 0;
+}
 
 /**
  * zynq_slcr_system_reset - Reset the entire system.
@@ -43,16 +94,16 @@ void zynq_slcr_system_reset(void)
         * Note that this seems to require raw i/o
         * functions or there's a lockup?
         */
-       writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET);
+       zynq_slcr_unlock();
 
        /*
         * Clear 0x0F000000 bits of reboot status register to workaround
         * the FSBL not loading the bitstream after soft-reboot
         * This is a temporary solution until we know more.
         */
-       reboot = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
-       writel(reboot & 0xF0FFFFFF, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
-       writel(1, zynq_slcr_base + SLCR_PS_RST_CTRL_OFFSET);
+       zynq_slcr_read(&reboot, SLCR_REBOOT_STATUS_OFFSET);
+       zynq_slcr_write(reboot & 0xF0FFFFFF, SLCR_REBOOT_STATUS_OFFSET);
+       zynq_slcr_write(1, SLCR_PS_RST_CTRL_OFFSET);
 }
 
 /**
@@ -61,11 +112,13 @@ void zynq_slcr_system_reset(void)
  */
 void zynq_slcr_cpu_start(int cpu)
 {
-       u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET);
+       u32 reg;
+
+       zynq_slcr_read(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
        reg &= ~(SLCR_A9_CPU_RST << cpu);
-       writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET);
+       zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
        reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
-       writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET);
+       zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
 }
 
 /**
@@ -74,18 +127,39 @@ void zynq_slcr_cpu_start(int cpu)
  */
 void zynq_slcr_cpu_stop(int cpu)
 {
-       u32 reg = readl(zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET);
+       u32 reg;
+
+       zynq_slcr_read(&reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
        reg |= (SLCR_A9_CPU_CLKSTOP | SLCR_A9_CPU_RST) << cpu;
-       writel(reg, zynq_slcr_base + SLCR_A9_CPU_RST_CTRL_OFFSET);
+       zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
 }
 
 /**
- * zynq_slcr_init
- * Returns 0 on success, negative errno otherwise.
+ * zynq_slcr_init - Regular slcr driver init
+ *
+ * Return:     0 on success, negative errno otherwise.
  *
  * Called early during boot from platform code to remap SLCR area.
  */
 int __init zynq_slcr_init(void)
+{
+       zynq_slcr_regmap = syscon_regmap_lookup_by_compatible("xlnx,zynq-slcr");
+       if (IS_ERR(zynq_slcr_regmap)) {
+               pr_err("%s: failed to find zynq-slcr\n", __func__);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * zynq_early_slcr_init - Early slcr init function
+ *
+ * Return:     0 on success, negative errno otherwise.
+ *
+ * Called very early during boot from platform code to unlock SLCR.
+ */
+int __init zynq_early_slcr_init(void)
 {
        struct device_node *np;
 
@@ -101,8 +175,10 @@ int __init zynq_slcr_init(void)
                BUG();
        }
 
+       np->data = (__force void *)zynq_slcr_base;
+
        /* unlock the SLCR so that registers can be changed */
-       writel(SLCR_UNLOCK_MAGIC, zynq_slcr_base + SLCR_UNLOCK_OFFSET);
+       zynq_slcr_unlock();
 
        pr_info("%s mapped to %p\n", np->name, zynq_slcr_base);
 
This page took 0.033711 seconds and 5 git commands to generate.