summaryrefslogtreecommitdiffstats
path: root/arch/mips/lantiq/xway
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/lantiq/xway')
-rw-r--r--arch/mips/lantiq/xway/Makefile2
-rw-r--r--arch/mips/lantiq/xway/dma.c17
-rw-r--r--arch/mips/lantiq/xway/gptu.c2
-rw-r--r--arch/mips/lantiq/xway/reset.c58
-rw-r--r--arch/mips/lantiq/xway/sysctrl.c4
-rw-r--r--arch/mips/lantiq/xway/xrx200_phy_fw.c97
6 files changed, 167 insertions, 13 deletions
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 70a58c747bd0..7a13660d630d 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1 +1,3 @@
obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o
+
+obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
index 55d2c4fa4714..e44a1866653f 100644
--- a/arch/mips/lantiq/xway/dma.c
+++ b/arch/mips/lantiq/xway/dma.c
@@ -25,6 +25,7 @@
#include <lantiq_soc.h>
#include <xway_dma.h>
+#define LTQ_DMA_ID 0x08
#define LTQ_DMA_CTRL 0x10
#define LTQ_DMA_CPOLL 0x14
#define LTQ_DMA_CS 0x18
@@ -48,7 +49,7 @@
#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
#define DMA_2W_BURST BIT(1) /* 2 word burst length */
#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
-#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */
+#define DMA_ETOP_ENDIANNESS (0xf << 8) /* endianness swap etop channels */
#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x))
@@ -191,10 +192,10 @@ ltq_dma_init_port(int p)
switch (p) {
case DMA_PORT_ETOP:
/*
- * Tell the DMA engine to swap the endianess of data frames and
+ * Tell the DMA engine to swap the endianness of data frames and
* drop packets if the channel arbitration fails.
*/
- ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
+ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANNESS | DMA_PDEN,
LTQ_DMA_PCTRL);
break;
@@ -209,11 +210,12 @@ ltq_dma_init_port(int p)
}
EXPORT_SYMBOL_GPL(ltq_dma_init_port);
-static int __devinit
+static int
ltq_dma_init(struct platform_device *pdev)
{
struct clk *clk;
struct resource *res;
+ unsigned id;
int i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -243,7 +245,12 @@ ltq_dma_init(struct platform_device *pdev)
ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
}
- dev_info(&pdev->dev, "init done\n");
+
+ id = ltq_dma_r32(LTQ_DMA_ID);
+ dev_info(&pdev->dev,
+ "Init done - hw rev: %X, ports: %d, channels: %d\n",
+ id & 0x1f, (id >> 16) & 0xf, id >> 20);
+
return 0;
}
diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c
index cbb56fc022bc..e30b1ed1b936 100644
--- a/arch/mips/lantiq/xway/gptu.c
+++ b/arch/mips/lantiq/xway/gptu.c
@@ -133,7 +133,7 @@ static inline void clkdev_add_gptu(struct device *dev, const char *con,
clkdev_add(&clk->cl);
}
-static int __devinit gptu_probe(struct platform_device *pdev)
+static int gptu_probe(struct platform_device *pdev)
{
struct clk *clk;
struct resource *res;
diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
index 22c55f73aa9d..544dbb7fb421 100644
--- a/arch/mips/lantiq/xway/reset.c
+++ b/arch/mips/lantiq/xway/reset.c
@@ -28,17 +28,24 @@
#define RCU_RST_REQ 0x0010
/* reset status register */
#define RCU_RST_STAT 0x0014
+/* vr9 gphy registers */
+#define RCU_GFS_ADD0_XRX200 0x0020
+#define RCU_GFS_ADD1_XRX200 0x0068
/* reboot bit */
+#define RCU_RD_GPHY0_XRX200 BIT(31)
#define RCU_RD_SRST BIT(30)
+#define RCU_RD_GPHY1_XRX200 BIT(29)
+
/* reset cause */
#define RCU_STAT_SHIFT 26
/* boot selection */
-#define RCU_BOOT_SEL_SHIFT 26
-#define RCU_BOOT_SEL_MASK 0x7
+#define RCU_BOOT_SEL(x) ((x >> 18) & 0x7)
+#define RCU_BOOT_SEL_XRX200(x) (((x >> 17) & 0xf) | ((x >> 8) & 0x10))
/* remapped base addr of the reset control unit */
static void __iomem *ltq_rcu_membase;
+static struct device_node *ltq_rcu_np;
/* This function is used by the watchdog driver */
int ltq_reset_cause(void)
@@ -52,7 +59,41 @@ EXPORT_SYMBOL_GPL(ltq_reset_cause);
unsigned char ltq_boot_select(void)
{
u32 val = ltq_rcu_r32(RCU_RST_STAT);
- return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK;
+
+ if (of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200"))
+ return RCU_BOOT_SEL_XRX200(val);
+
+ return RCU_BOOT_SEL(val);
+}
+
+/* reset / boot a gphy */
+static struct ltq_xrx200_gphy_reset {
+ u32 rd;
+ u32 addr;
+} xrx200_gphy[] = {
+ {RCU_RD_GPHY0_XRX200, RCU_GFS_ADD0_XRX200},
+ {RCU_RD_GPHY1_XRX200, RCU_GFS_ADD1_XRX200},
+};
+
+/* reset and boot a gphy. these phys only exist on xrx200 SoC */
+int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
+{
+ if (!of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200")) {
+ dev_err(dev, "this SoC has no GPHY\n");
+ return -EINVAL;
+ }
+ if (id > 1) {
+ dev_err(dev, "%u is an invalid gphy id\n", id);
+ return -EINVAL;
+ }
+ dev_info(dev, "booting GPHY%u firmware at %X\n", id, dev_addr);
+
+ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | xrx200_gphy[id].rd,
+ RCU_RST_REQ);
+ ltq_rcu_w32(dev_addr, xrx200_gphy[id].addr);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~xrx200_gphy[id].rd,
+ RCU_RST_REQ);
+ return 0;
}
/* reset a io domain for u micro seconds */
@@ -85,14 +126,17 @@ static void ltq_machine_power_off(void)
static int __init mips_reboot_setup(void)
{
struct resource res;
- struct device_node *np =
- of_find_compatible_node(NULL, NULL, "lantiq,rcu-xway");
+
+ ltq_rcu_np = of_find_compatible_node(NULL, NULL, "lantiq,rcu-xway");
+ if (!ltq_rcu_np)
+ ltq_rcu_np = of_find_compatible_node(NULL, NULL,
+ "lantiq,rcu-xrx200");
/* check if all the reset register range is available */
- if (!np)
+ if (!ltq_rcu_np)
panic("Failed to load reset resources from devicetree");
- if (of_address_to_resource(np, 0, &res))
+ if (of_address_to_resource(ltq_rcu_np, 0, &res))
panic("Failed to get rcu memory range");
if (request_mem_region(res.start, resource_size(&res), res.name) < 0)
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
index 2917b56b6b25..3925e6609acc 100644
--- a/arch/mips/lantiq/xway/sysctrl.c
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -370,6 +370,10 @@ void __init ltq_soc_init(void)
clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI);
clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL);
clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
+ clkdev_add_pmu("1e108000.eth", NULL, 0,
+ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
+ PMU_PPE_QSB | PMU_PPE_TOP);
} else if (of_machine_is_compatible("lantiq,ar9")) {
clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
ltq_ar9_fpi_hz());
diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c
new file mode 100644
index 000000000000..d4d9d31f152e
--- /dev/null
+++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+#define XRX200_GPHY_FW_ALIGN (16 * 1024)
+
+static dma_addr_t xway_gphy_load(struct platform_device *pdev)
+{
+ const struct firmware *fw;
+ dma_addr_t dev_addr = 0;
+ const char *fw_name;
+ void *fw_addr;
+ size_t size;
+
+ if (of_property_read_string(pdev->dev.of_node, "firmware", &fw_name)) {
+ dev_err(&pdev->dev, "failed to load firmware filename\n");
+ return 0;
+ }
+
+ dev_info(&pdev->dev, "requesting %s\n", fw_name);
+ if (request_firmware(&fw, fw_name, &pdev->dev)) {
+ dev_err(&pdev->dev, "failed to load firmware: %s\n", fw_name);
+ return 0;
+ }
+
+ /*
+ * GPHY cores need the firmware code in a persistent and contiguous
+ * memory area with a 16 kB boundary aligned start address
+ */
+ size = fw->size + XRX200_GPHY_FW_ALIGN;
+
+ fw_addr = dma_alloc_coherent(&pdev->dev, size, &dev_addr, GFP_KERNEL);
+ if (fw_addr) {
+ fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN);
+ dev_addr = ALIGN(dev_addr, XRX200_GPHY_FW_ALIGN);
+ memcpy(fw_addr, fw->data, fw->size);
+ } else {
+ dev_err(&pdev->dev, "failed to alloc firmware memory\n");
+ }
+
+ release_firmware(fw);
+ return dev_addr;
+}
+
+static int xway_phy_fw_probe(struct platform_device *pdev)
+{
+ dma_addr_t fw_addr;
+ struct property *pp;
+ unsigned char *phyids;
+ int i, ret = 0;
+
+ fw_addr = xway_gphy_load(pdev);
+ if (!fw_addr)
+ return -EINVAL;
+ pp = of_find_property(pdev->dev.of_node, "phys", NULL);
+ if (!pp)
+ return -ENOENT;
+ phyids = pp->value;
+ for (i = 0; i < pp->length && !ret; i++)
+ ret = xrx200_gphy_boot(&pdev->dev, phyids[i], fw_addr);
+ if (!ret)
+ mdelay(100);
+ return ret;
+}
+
+static const struct of_device_id xway_phy_match[] = {
+ { .compatible = "lantiq,phy-xrx200" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xway_phy_match);
+
+static struct platform_driver xway_phy_driver = {
+ .probe = xway_phy_fw_probe,
+ .driver = {
+ .name = "phy-xrx200",
+ .owner = THIS_MODULE,
+ .of_match_table = xway_phy_match,
+ },
+};
+
+module_platform_driver(xway_phy_driver);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader");
+MODULE_LICENSE("GPL");