mcs814x: add 3.14 kernel support
[openwrt.git] / target / linux / mcs814x / files-3.14 / arch / arm / mach-mcs814x / common.c
diff --git a/target/linux/mcs814x/files-3.14/arch/arm/mach-mcs814x/common.c b/target/linux/mcs814x/files-3.14/arch/arm/mach-mcs814x/common.c
new file mode 100644 (file)
index 0000000..d44f171
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * arch/arm/mach-mcs814x/common.c
+ *
+ * Core functions for Moschip MCS814x SoCs
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/mcs814x.h>
+#include <mach/cpu.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+
+void __iomem *mcs814x_sysdbg_base;
+
+static struct map_desc mcs814x_io_desc[] __initdata = {
+       {
+               .virtual        = MCS814X_IO_BASE,
+               .pfn            = __phys_to_pfn(MCS814X_IO_START),
+               .length         = MCS814X_IO_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+
+struct cpu_mode {
+       const char *name;
+       int gpio_start;
+       int gpio_end;
+};
+
+static const struct cpu_mode cpu_modes[] = {
+       {
+               .name           = "I2S",
+               .gpio_start     = 4,
+               .gpio_end       = 8,
+       },
+       {
+               .name           = "UART",
+               .gpio_start     = 4,
+               .gpio_end       = 9,
+       },
+       {
+               .name           = "External MII",
+               .gpio_start     = 0,
+               .gpio_end       = 16,
+       },
+       {
+               .name           = "Normal",
+               .gpio_start     = -1,
+               .gpio_end       = -1,
+       },
+};
+
+static void mcs814x_eth_hardware_filter_set(u8 value)
+{
+       u32 reg;
+
+       reg = readl_relaxed(MCS814X_VIRT_BASE + MCS814X_DBGLED);
+       if (value)
+               reg |= 0x80;
+       else
+               reg &= ~0x80;
+       writel_relaxed(reg, MCS814X_VIRT_BASE + MCS814X_DBGLED);
+}
+
+static void mcs814x_eth_led_cfg_set(u8 cfg)
+{
+       u32 reg;
+
+       reg = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS2);
+       reg &= ~LED_CFG_MASK;
+       reg |= cfg;
+       writel_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_BS2);
+}
+
+static void mcs814x_eth_buffer_shifting_set(u8 value)
+{
+       u8 reg;
+
+       reg = readb_relaxed(mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
+       if (value)
+               reg |= BUF_SHIFT_BIT;
+       else
+               reg &= ~BUF_SHIFT_BIT;
+       writeb_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
+}
+
+static struct of_device_id mcs814x_eth_ids[] __initdata = {
+       { .compatible = "moschip,nuport-mac", },
+       { /* sentinel */ },
+};
+
+/* Configure platform specific knobs based on ethernet device node
+ * properties */
+static void mcs814x_eth_init(void)
+{
+       struct device_node *np;
+       const unsigned int *intspec;
+
+       np = of_find_matching_node(NULL, mcs814x_eth_ids);
+       if (!np)
+               return;
+
+       /* hardware filter must always be enabled */
+       mcs814x_eth_hardware_filter_set(1);
+
+       intspec = of_get_property(np, "nuport-mac,buffer-shifting", NULL);
+       if (!intspec)
+               mcs814x_eth_buffer_shifting_set(0);
+       else
+               mcs814x_eth_buffer_shifting_set(1);
+
+       intspec = of_get_property(np, "nuport-mac,link-activity", NULL);
+       if (intspec)
+               mcs814x_eth_led_cfg_set(be32_to_cpup(intspec));
+
+       of_node_put(np);
+}
+
+void __init mcs814x_init_machine(void)
+{
+       u32 bs2, cpu_mode;
+       int gpio;
+
+       bs2 = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS2);
+       cpu_mode = (bs2 >> CPU_MODE_SHIFT) & CPU_MODE_MASK;
+
+       pr_info("CPU mode: %s\n", cpu_modes[cpu_mode].name);
+
+       /* request the gpios since the pins are muxed for functionnality */
+       for (gpio = cpu_modes[cpu_mode].gpio_start;
+               gpio == cpu_modes[cpu_mode].gpio_end; gpio++) {
+               if (gpio != -1)
+                       gpio_request(gpio, cpu_modes[cpu_mode].name);
+       }
+
+       mcs814x_eth_init();
+}
+
+void __init mcs814x_map_io(void)
+{
+       iotable_init(mcs814x_io_desc, ARRAY_SIZE(mcs814x_io_desc));
+
+       mcs814x_sysdbg_base = ioremap(MCS814X_IO_START + MCS814X_SYSDBG,
+                                       MCS814X_SYSDBG_SIZE);
+       if (!mcs814x_sysdbg_base)
+               panic("unable to remap sysdbg base");
+}
+
+void mcs814x_restart(enum reboot_mode mode, const char *cmd)
+{
+       writel_relaxed(~(1 << 31), mcs814x_sysdbg_base);
+}