ramips: add ralink v3.10 support

Signed-off-by: John Crispin <blogic@openwrt.org>

SVN-Revision: 37331
lede-17.01
John Crispin 2013-07-15 10:06:55 +00:00
parent f75bba6f87
commit a0de18807b
36 changed files with 14130 additions and 1 deletions

View File

@ -212,7 +212,7 @@
};
otg@101c0000 {
compatible = "ralink,rt3050-otg";
compatible = "ralink,rt3050-otg", "snps,dwc2";
reg = <0x101c0000 40000>;
interrupt-parent = <&intc>;

View File

@ -0,0 +1,78 @@
From a1f29e15505226c6bc3a714daf91edccfc3a9e13 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:08:11 +0200
Subject: [PATCH 01/33] MIPS: use set_mode() to enable/disable the cevt-r4k
irq
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/kernel/cevt-r4k.c | 39 ++++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 02033ea..da4a003 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -38,12 +38,6 @@ static int mips_next_event(unsigned long delta,
#endif /* CONFIG_MIPS_MT_SMTC */
-void mips_set_clock_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- /* Nothing to do ... */
-}
-
DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device);
int cp0_timer_irq_installed;
@@ -90,6 +84,32 @@ struct irqaction c0_compare_irqaction = {
.name = "timer",
};
+void mips_set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ if (cp0_timer_irq_installed)
+ break;
+
+ cp0_timer_irq_installed = 1;
+
+ setup_irq(evt->irq, &c0_compare_irqaction);
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ if (!cp0_timer_irq_installed)
+ break;
+
+ cp0_timer_irq_installed = 0;
+ free_irq(evt->irq, &c0_compare_irqaction);
+ break;
+
+ default:
+ pr_err("Unhandeled mips clock_mode\n");
+ break;
+ }
+}
void mips_event_handler(struct clock_event_device *dev)
{
@@ -215,13 +235,6 @@ int __cpuinit r4k_clockevent_init(void)
#endif
clockevents_register_device(cd);
- if (cp0_timer_irq_installed)
- return 0;
-
- cp0_timer_irq_installed = 1;
-
- setup_irq(irq, &c0_compare_irqaction);
-
return 0;
}
--
1.7.10.4

View File

@ -0,0 +1,141 @@
From 9a3055dad80db43aeb22b247512e18e8f06bf54c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 22 Apr 2013 23:11:42 +0200
Subject: [PATCH 02/33] MIPS: ralink: add pinmux driver
Add code to setup the pinmux on ralonk SoC. The SoC has a single 32 bit register
for this functionality with simple on/off bits. Building a full featured pinctrl
driver would be overkill.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Makefile | 2 +-
arch/mips/ralink/common.h | 2 ++
arch/mips/ralink/of.c | 2 ++
arch/mips/ralink/pinmux.c | 77 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 82 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/ralink/pinmux.c
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile
index 38cf1a8..341b4de 100644
--- a/arch/mips/ralink/Makefile
+++ b/arch/mips/ralink/Makefile
@@ -6,7 +6,7 @@
# Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
# Copyright (C) 2013 John Crispin <blogic@openwrt.org>
-obj-y := prom.o of.o reset.o clk.o irq.o
+obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o
obj-$(CONFIG_SOC_RT288X) += rt288x.o
obj-$(CONFIG_SOC_RT305X) += rt305x.o
diff --git a/arch/mips/ralink/common.h b/arch/mips/ralink/common.h
index 83144c3..f113fd6 100644
--- a/arch/mips/ralink/common.h
+++ b/arch/mips/ralink/common.h
@@ -50,4 +50,6 @@ extern void prom_soc_init(struct ralink_soc_info *soc_info);
__iomem void *plat_of_remap_node(const char *node);
+void ralink_pinmux(void);
+
#endif /* _RALINK_COMMON_H__ */
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index 6b5f340..b25c1f2 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -110,6 +110,8 @@ static int __init plat_of_setup(void)
if (of_platform_populate(NULL, of_ids, NULL, NULL))
panic("failed to populate DT\n");
+ ralink_pinmux();
+
return 0;
}
diff --git a/arch/mips/ralink/pinmux.c b/arch/mips/ralink/pinmux.c
new file mode 100644
index 0000000..1720216
--- /dev/null
+++ b/arch/mips/ralink/pinmux.c
@@ -0,0 +1,77 @@
+/*
+ * 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) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#include "common.h"
+
+#define SYSC_REG_GPIO_MODE 0x60
+
+static int ralink_mux_mask(const char *name, struct ralink_pinmux_grp *grps, u32* mask)
+{
+ for (; grps && grps->name; grps++)
+ if (!strcmp(grps->name, name)) {
+ *mask = grps->mask;
+ return 0;
+ }
+
+ return -1;
+}
+
+void ralink_pinmux(void)
+{
+ const __be32 *wdt;
+ struct device_node *np;
+ struct property *prop;
+ const char *uart, *pin;
+ u32 mode = 0;
+ int m;
+
+ np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-sysc");
+ if (!np)
+ return;
+
+ of_property_for_each_string(np, "ralink,gpiomux", prop, pin) {
+ if (!ralink_mux_mask(pin, rt_gpio_pinmux.mode, &m)) {
+ mode |= m;
+ pr_debug("pinmux: registered gpiomux \"%s\"\n", pin);
+ } else {
+ pr_err("pinmux: failed to load \"%s\"\n", pin);
+ }
+ }
+
+ of_property_for_each_string(np, "ralink,pinmux", prop, pin) {
+ if (!ralink_mux_mask(pin, rt_gpio_pinmux.mode, &m)) {
+ mode &= ~m;
+ pr_debug("pinmux: registered pinmux \"%s\"\n", pin);
+ } else {
+ pr_err("pinmux: failed to load group \"%s\"\n", pin);
+ }
+ }
+
+ of_property_read_string(np, "ralink,uartmux", &uart);
+ if (uart) {
+ mode &= ~(rt_gpio_pinmux.uart_mask << rt_gpio_pinmux.uart_shift);
+ if (ralink_mux_mask(uart, rt_gpio_pinmux.uart, &m)) {
+ pr_err("pinmux: failed to load uartmux \"%s\"\n", uart);
+ mode |= rt_gpio_pinmux.uart_mask << rt_gpio_pinmux.uart_shift;
+ } else {
+ mode |= m << rt_gpio_pinmux.uart_shift;
+ pr_debug("pinmux: registered uartmux \"%s\"\n", uart);
+ }
+ }
+
+ wdt = of_get_property(np, "ralink,wdtmux", NULL);
+ if (wdt && *wdt && rt_gpio_pinmux.wdt_reset)
+ rt_gpio_pinmux.wdt_reset();
+
+ rt_sysc_w32(mode, SYSC_REG_GPIO_MODE);
+}
--
1.7.10.4

View File

@ -0,0 +1,228 @@
From 298e990777004a6a72b1c95af5a2cd984c56135d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sat, 23 Mar 2013 19:44:41 +0100
Subject: [PATCH 03/33] MIPS: ralink: add support for periodic timer irq
Adds a driver for the periodic timer found on Ralink SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Makefile | 2 +-
arch/mips/ralink/timer.c | 192 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 193 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/ralink/timer.c
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile
index 341b4de..cae7d88 100644
--- a/arch/mips/ralink/Makefile
+++ b/arch/mips/ralink/Makefile
@@ -6,7 +6,7 @@
# Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
# Copyright (C) 2013 John Crispin <blogic@openwrt.org>
-obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o
+obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o timer.o
obj-$(CONFIG_SOC_RT288X) += rt288x.o
obj-$(CONFIG_SOC_RT305X) += rt305x.o
diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c
new file mode 100644
index 0000000..0a6856c
--- /dev/null
+++ b/arch/mips/ralink/timer.c
@@ -0,0 +1,192 @@
+/*
+ * 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) 2013 John Crispin <blogic@openwrt.org>
+*/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define TIMER_REG_TMRSTAT 0x00
+#define TIMER_REG_TMR0LOAD 0x10
+#define TIMER_REG_TMR0CTL 0x18
+
+#define TMRSTAT_TMR0INT BIT(0)
+
+#define TMR0CTL_ENABLE BIT(7)
+#define TMR0CTL_MODE_PERIODIC BIT(4)
+#define TMR0CTL_PRESCALER 1
+#define TMR0CTL_PRESCALE_VAL (0xf - TMR0CTL_PRESCALER)
+#define TMR0CTL_PRESCALE_DIV (65536 / BIT(TMR0CTL_PRESCALER))
+
+struct rt_timer {
+ struct device *dev;
+ void __iomem *membase;
+ int irq;
+ unsigned long timer_freq;
+ unsigned long timer_div;
+};
+
+static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val)
+{
+ __raw_writel(val, rt->membase + reg);
+}
+
+static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg)
+{
+ return __raw_readl(rt->membase + reg);
+}
+
+static irqreturn_t rt_timer_irq(int irq, void *_rt)
+{
+ struct rt_timer *rt = (struct rt_timer *) _rt;
+
+ rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+ rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT);
+
+ return IRQ_HANDLED;
+}
+
+
+static int rt_timer_request(struct rt_timer *rt)
+{
+ int err = request_irq(rt->irq, rt_timer_irq, IRQF_DISABLED,
+ dev_name(rt->dev), rt);
+ if (err) {
+ dev_err(rt->dev, "failed to request irq\n");
+ } else {
+ u32 t = TMR0CTL_MODE_PERIODIC | TMR0CTL_PRESCALE_VAL;
+ rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+ }
+ return err;
+}
+
+static void rt_timer_free(struct rt_timer *rt)
+{
+ free_irq(rt->irq, rt);
+}
+
+static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
+{
+ if (rt->timer_freq < divisor)
+ rt->timer_div = rt->timer_freq;
+ else
+ rt->timer_div = divisor;
+
+ rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+
+ return 0;
+}
+
+static int rt_timer_enable(struct rt_timer *rt)
+{
+ u32 t;
+
+ rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+
+ t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
+ t |= TMR0CTL_ENABLE;
+ rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+
+ return 0;
+}
+
+static void rt_timer_disable(struct rt_timer *rt)
+{
+ u32 t;
+
+ t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
+ t &= ~TMR0CTL_ENABLE;
+ rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+}
+
+static int rt_timer_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct rt_timer *rt;
+ struct clk *clk;
+
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ return -EINVAL;
+ }
+
+ rt = devm_kzalloc(&pdev->dev, sizeof(*rt), GFP_KERNEL);
+ if (!rt) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ rt->irq = platform_get_irq(pdev, 0);
+ if (!rt->irq) {
+ dev_err(&pdev->dev, "failed to load irq\n");
+ return -ENOENT;
+ }
+
+ rt->membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!rt->membase) {
+ dev_err(&pdev->dev, "failed to ioremap\n");
+ return -ENOMEM;
+ }
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed get clock rate\n");
+ return PTR_ERR(clk);
+ }
+
+ rt->timer_freq = clk_get_rate(clk) / TMR0CTL_PRESCALE_DIV;
+ if (!rt->timer_freq)
+ return -EINVAL;
+
+ rt->dev = &pdev->dev;
+ platform_set_drvdata(pdev, rt);
+
+ rt_timer_request(rt);
+ rt_timer_config(rt, 2);
+ rt_timer_enable(rt);
+
+ dev_info(&pdev->dev, "maximum frequncy is %luHz\n", rt->timer_freq);
+
+ return 0;
+}
+
+static int rt_timer_remove(struct platform_device *pdev)
+{
+ struct rt_timer *rt = platform_get_drvdata(pdev);
+
+ rt_timer_disable(rt);
+ rt_timer_free(rt);
+
+ return 0;
+}
+
+static const struct of_device_id rt_timer_match[] = {
+ { .compatible = "ralink,rt2880-timer" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt_timer_match);
+
+static struct platform_driver rt_timer_driver = {
+ .probe = rt_timer_probe,
+ .remove = rt_timer_remove,
+ .driver = {
+ .name = "rt-timer",
+ .owner = THIS_MODULE,
+ .of_match_table = rt_timer_match
+ },
+};
+
+module_platform_driver(rt_timer_driver);
+
+MODULE_DESCRIPTION("Ralink RT2880 timer");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
+MODULE_LICENSE("GPL");
--
1.7.10.4

View File

@ -0,0 +1,31 @@
From 3af962f91035ae4500e63c758c49f1c067bdae09 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 19 May 2013 00:42:23 +0200
Subject: [PATCH 04/33] MIPS: ralink: add rt_sysc_m32 helper
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/include/asm/mach-ralink/ralink_regs.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h
index 5a508f9..bd93014 100644
--- a/arch/mips/include/asm/mach-ralink/ralink_regs.h
+++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h
@@ -26,6 +26,13 @@ static inline u32 rt_sysc_r32(unsigned reg)
return __raw_readl(rt_sysc_membase + reg);
}
+static inline void rt_sysc_m32(u32 clr, u32 set, unsigned reg)
+{
+ u32 val = rt_sysc_r32(reg) & ~clr;
+
+ __raw_writel(val | set, rt_sysc_membase + reg);
+}
+
static inline void rt_memc_w32(u32 val, unsigned reg)
{
__raw_writel(val, rt_memc_membase + reg);
--
1.7.10.4

View File

@ -0,0 +1,39 @@
From 3f6b346e1dd83c4f43d94aefa0520ffdfafd5f0b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 20 May 2013 20:30:11 +0200
Subject: [PATCH 05/33] MIPS: ralink: make mt7620 ram detect verbose
Make the code print which of SDRAM, DDR1 or DDR2 was detected.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/mt7620.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index 0018b1a..ccdec5a 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -214,16 +214,19 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
switch (dram_type) {
case SYSCFG0_DRAM_TYPE_SDRAM:
+ pr_info("Board has SDRAM\n");
soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN;
soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX;
break;
case SYSCFG0_DRAM_TYPE_DDR1:
+ pr_info("Board has DDR1\n");
soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN;
soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX;
break;
case SYSCFG0_DRAM_TYPE_DDR2:
+ pr_info("Board has DDR2\n");
soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN;
soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX;
break;
--
1.7.10.4

View File

@ -0,0 +1,64 @@
From 74339d6eab7a37f7c629b737bf686d30e5014ce2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 20 May 2013 20:57:09 +0200
Subject: [PATCH 06/33] MIPS: ralink: add verbose pmu info
Print the PMU and LDO settings on boot.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/mt7620.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index ccdec5a..62356a0 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -20,6 +20,22 @@
#include "common.h"
+/* analog */
+#define PMU0_CFG 0x88
+#define PMU_SW_SET BIT(28)
+#define A_DCDC_EN BIT(24)
+#define A_SSC_PERI BIT(19)
+#define A_SSC_GEN BIT(18)
+#define A_SSC_M 0x3
+#define A_SSC_S 16
+#define A_DLY_M 0x7
+#define A_DLY_S 8
+#define A_VTUNE_M 0xff
+
+/* digital */
+#define PMU1_CFG 0x8C
+#define DIG_SW_SEL BIT(25)
+
/* does the board have sdram or ddram */
static int dram_type;
@@ -187,6 +203,8 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
u32 n1;
u32 rev;
u32 cfg0;
+ u32 pmu0;
+ u32 pmu1;
n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0);
n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1);
@@ -234,4 +252,12 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
BUG();
}
soc_info->mem_base = MT7620_DRAM_BASE;
+
+ pmu0 = __raw_readl(sysc + PMU0_CFG);
+ pmu1 = __raw_readl(sysc + PMU1_CFG);
+
+ pr_info("Analog PMU set to %s control\n",
+ (pmu0 & PMU_SW_SET) ? ("sw") : ("hw"));
+ pr_info("Digital PMU set to %s control\n",
+ (pmu1 & DIG_SW_SEL) ? ("sw") : ("hw"));
}
--
1.7.10.4

View File

@ -0,0 +1,83 @@
From 71409a190a0c8e3597cae7d46321742e29d8994b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 21 May 2013 15:50:31 +0200
Subject: [PATCH 07/33] MIPS: ralink: adds a bootrom dumper module
This patch adds a trivial driver that allows userland to extract the bootrom of
a SoC via debugfs.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Makefile | 2 ++
arch/mips/ralink/bootrom.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 arch/mips/ralink/bootrom.c
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile
index cae7d88..5fa6129 100644
--- a/arch/mips/ralink/Makefile
+++ b/arch/mips/ralink/Makefile
@@ -15,4 +15,6 @@ obj-$(CONFIG_SOC_MT7620) += mt7620.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_DEBUG_FS) += bootrom.o
+
obj-y += dts/
diff --git a/arch/mips/ralink/bootrom.c b/arch/mips/ralink/bootrom.c
new file mode 100644
index 0000000..f926f6f
--- /dev/null
+++ b/arch/mips/ralink/bootrom.c
@@ -0,0 +1,48 @@
+/*
+ * 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) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define BOOTROM_OFFSET 0x10118000
+#define BOOTROM_SIZE 0x8000
+
+static void __iomem *membase = (void __iomem*) KSEG1ADDR(BOOTROM_OFFSET);
+
+static int bootrom_show(struct seq_file *s, void *unused)
+{
+ seq_write(s, membase, BOOTROM_SIZE);
+
+ return 0;
+}
+
+static int bootrom_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, bootrom_show, NULL);
+}
+
+static const struct file_operations bootrom_file_ops = {
+ .open = bootrom_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int bootrom_setup(void)
+{
+ if (!debugfs_create_file("bootrom", 0444,
+ NULL, NULL, &bootrom_file_ops)) {
+ pr_err("Failed to create bootrom debugfs file\n");
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+postcore_initcall(bootrom_setup);
--
1.7.10.4

View File

@ -0,0 +1,121 @@
From 46446fcfc6e823005ebe71357b5995524e75542c Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 16 May 2013 23:28:23 +0200
Subject: [PATCH 08/33] MIPS: ralink: add illegal access driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Makefile | 2 +
arch/mips/ralink/ill_acc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
create mode 100644 arch/mips/ralink/ill_acc.c
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile
index 5fa6129..03af636 100644
--- a/arch/mips/ralink/Makefile
+++ b/arch/mips/ralink/Makefile
@@ -8,6 +8,8 @@
obj-y := prom.o of.o reset.o clk.o irq.o pinmux.o timer.o
+obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o
+
obj-$(CONFIG_SOC_RT288X) += rt288x.o
obj-$(CONFIG_SOC_RT305X) += rt305x.o
obj-$(CONFIG_SOC_RT3883) += rt3883.o
diff --git a/arch/mips/ralink/ill_acc.c b/arch/mips/ralink/ill_acc.c
new file mode 100644
index 0000000..4a3f696
--- /dev/null
+++ b/arch/mips/ralink/ill_acc.c
@@ -0,0 +1,87 @@
+/*
+ * 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) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define REG_ILL_ACC_ADDR 0x10
+#define REG_ILL_ACC_TYPE 0x14
+
+#define ILL_INT_STATUS BIT(31)
+#define ILL_ACC_WRITE BIT(30)
+#define ILL_ACC_LEN_M 0xff
+#define ILL_ACC_OFF_M 0xf
+#define ILL_ACC_OFF_S 16
+#define ILL_ACC_ID_M 0x7
+#define ILL_ACC_ID_S 8
+
+#define DRV_NAME "ill_acc"
+
+static const char *ill_acc_ids[] = {
+ "cpu", "dma", "ppe", "pdma rx","pdma tx", "pci/e", "wmac", "usb",
+};
+
+static irqreturn_t ill_acc_irq_handler(int irq, void *_priv)
+{
+ struct device *dev = (struct device *) _priv;
+ u32 addr = rt_memc_r32(REG_ILL_ACC_ADDR);
+ u32 type = rt_memc_r32(REG_ILL_ACC_TYPE);
+
+ dev_err(dev, "illegal %s access from %s - addr:0x%08x offset:%d len:%d\n",
+ (type & ILL_ACC_WRITE) ? ("write") : ("read"),
+ ill_acc_ids[(type >> ILL_ACC_ID_S) & ILL_ACC_ID_M],
+ addr, (type >> ILL_ACC_OFF_S) & ILL_ACC_OFF_M,
+ type & ILL_ACC_LEN_M);
+
+ rt_memc_w32(REG_ILL_ACC_TYPE, REG_ILL_ACC_TYPE);
+
+ return IRQ_HANDLED;
+}
+
+static int __init ill_acc_of_setup(void)
+{
+ struct platform_device *pdev;
+ struct device_node *np;
+ int irq;
+
+ /* somehow this driver breaks on RT5350 */
+ if (of_machine_is_compatible("ralink,rt5350-soc"))
+ return -EINVAL;
+
+ np = of_find_compatible_node(NULL, NULL, "ralink,rt3050-memc");
+ if (!np)
+ return -EINVAL;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ pr_err("%s: failed to lookup pdev\n", np->name);
+ return -EINVAL;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -EINVAL;
+ }
+
+ if (request_irq(irq, ill_acc_irq_handler, 0, "ill_acc", &pdev->dev)) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return -EINVAL;
+ }
+
+ rt_memc_w32(ILL_INT_STATUS, REG_ILL_ACC_TYPE);
+
+ dev_info(&pdev->dev, "irq registered\n");
+
+ return 0;
+}
+
+arch_initcall(ill_acc_of_setup);
--
1.7.10.4

View File

@ -0,0 +1,29 @@
From 070a389ae536a75b9184784f625949c215c533b6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 23 May 2013 18:50:56 +0200
Subject: [PATCH 09/33] MIPS: ralink: workaround DTB memory issue
If the DTB is too big a bug happens on boot when init ram is freed.
This is a temporary fix until the real cause is found.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/of.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index b25c1f2..8efb02b 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -74,7 +74,7 @@ void __init device_tree_init(void)
unflatten_device_tree();
/* free the space reserved for the dt blob */
- free_bootmem(base, size);
+ //free_bootmem(base, size);
}
void __init plat_mem_setup(void)
--
1.7.10.4

View File

@ -0,0 +1,25 @@
From 5340673ba16e3c8c9c1406d5ab84aca82e83e2ce Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 23 May 2013 18:46:25 +0200
Subject: [PATCH 10/33] MIPS: ralink: add spi clock definition to mt7620a
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/mt7620.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index 62356a0..96422e5 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -183,6 +183,7 @@ void __init ralink_clk_init(void)
ralink_clk_add("cpu", cpu_rate);
ralink_clk_add("10000100.timer", 40000000);
ralink_clk_add("10000500.uart", 40000000);
+ ralink_clk_add("10000b00.spi", 40000000);
ralink_clk_add("10000c00.uartlite", 40000000);
}
--
1.7.10.4

View File

@ -0,0 +1,329 @@
From 5d57ace094803c95230643941a47d749ff81d022 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 21 Mar 2013 18:27:29 +0100
Subject: [PATCH 11/33] PCI: MIPS: adds rt2880 pci support
Add support for the pci found on the rt2880 SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/pci/Makefile | 1 +
arch/mips/pci/pci-rt2880.c | 281 ++++++++++++++++++++++++++++++++++++++++++++
arch/mips/ralink/Kconfig | 1 +
3 files changed, 283 insertions(+)
create mode 100644 arch/mips/pci/pci-rt2880.c
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 2cb1d31..77974ba 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
obj-$(CONFIG_LANTIQ) += fixup-lantiq.o
obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o
+obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c
new file mode 100644
index 0000000..e2c4730
--- /dev/null
+++ b/arch/mips/pci/pci-rt2880.c
@@ -0,0 +1,281 @@
+/*
+ * Ralink RT288x SoC PCI register definitions
+ *
+ * Copyright (C) 2009 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Parts of this file are based on Ralink's 2.6.21 BSP
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+
+#include <asm/mach-ralink/rt288x.h>
+
+#define RT2880_PCI_BASE 0x00440000
+#define RT288X_CPU_IRQ_PCI 4
+
+#define RT2880_PCI_MEM_BASE 0x20000000
+#define RT2880_PCI_MEM_SIZE 0x10000000
+#define RT2880_PCI_IO_BASE 0x00460000
+#define RT2880_PCI_IO_SIZE 0x00010000
+
+#define RT2880_PCI_REG_PCICFG_ADDR 0x00
+#define RT2880_PCI_REG_PCIMSK_ADDR 0x0c
+#define RT2880_PCI_REG_BAR0SETUP_ADDR 0x10
+#define RT2880_PCI_REG_IMBASEBAR0_ADDR 0x18
+#define RT2880_PCI_REG_CONFIG_ADDR 0x20
+#define RT2880_PCI_REG_CONFIG_DATA 0x24
+#define RT2880_PCI_REG_MEMBASE 0x28
+#define RT2880_PCI_REG_IOBASE 0x2c
+#define RT2880_PCI_REG_ID 0x30
+#define RT2880_PCI_REG_CLASS 0x34
+#define RT2880_PCI_REG_SUBID 0x38
+#define RT2880_PCI_REG_ARBCTL 0x80
+
+static void __iomem *rt2880_pci_base;
+static DEFINE_SPINLOCK(rt2880_pci_lock);
+
+static u32 rt2880_pci_reg_read(u32 reg)
+{
+ return readl(rt2880_pci_base + reg);
+}
+
+static void rt2880_pci_reg_write(u32 val, u32 reg)
+{
+ writel(val, rt2880_pci_base + reg);
+}
+
+static inline u32 rt2880_pci_get_cfgaddr(unsigned int bus, unsigned int slot,
+ unsigned int func, unsigned int where)
+{
+ return ((bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) |
+ 0x80000000);
+}
+
+static int rt2880_pci_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ unsigned long flags;
+ u32 address;
+ u32 data;
+
+ address = rt2880_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+
+ spin_lock_irqsave(&rt2880_pci_lock, flags);
+ rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR);
+ data = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA);
+ spin_unlock_irqrestore(&rt2880_pci_lock, flags);
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+ case 2:
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ break;
+ case 4:
+ *val = data;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rt2880_pci_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ unsigned long flags;
+ u32 address;
+ u32 data;
+
+ address = rt2880_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+
+ spin_lock_irqsave(&rt2880_pci_lock, flags);
+ rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR);
+ data = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA);
+
+ switch (size) {
+ case 1:
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 2:
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 4:
+ data = val;
+ break;
+ }
+
+ rt2880_pci_reg_write(data, RT2880_PCI_REG_CONFIG_DATA);
+ spin_unlock_irqrestore(&rt2880_pci_lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rt2880_pci_ops = {
+ .read = rt2880_pci_config_read,
+ .write = rt2880_pci_config_write,
+};
+
+static struct resource rt2880_pci_mem_resource = {
+ .name = "PCI MEM space",
+ .start = RT2880_PCI_MEM_BASE,
+ .end = RT2880_PCI_MEM_BASE + RT2880_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource rt2880_pci_io_resource = {
+ .name = "PCI IO space",
+ .start = RT2880_PCI_IO_BASE,
+ .end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller rt2880_pci_controller = {
+ .pci_ops = &rt2880_pci_ops,
+ .mem_resource = &rt2880_pci_mem_resource,
+ .io_resource = &rt2880_pci_io_resource,
+};
+
+static inline u32 rt2880_pci_read_u32(unsigned long reg)
+{
+ unsigned long flags;
+ u32 address;
+ u32 ret;
+
+ address = rt2880_pci_get_cfgaddr(0, 0, 0, reg);
+
+ spin_lock_irqsave(&rt2880_pci_lock, flags);
+ rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR);
+ ret = rt2880_pci_reg_read(RT2880_PCI_REG_CONFIG_DATA);
+ spin_unlock_irqrestore(&rt2880_pci_lock, flags);
+
+ return ret;
+}
+
+static inline void rt2880_pci_write_u32(unsigned long reg, u32 val)
+{
+ unsigned long flags;
+ u32 address;
+
+ address = rt2880_pci_get_cfgaddr(0, 0, 0, reg);
+
+ spin_lock_irqsave(&rt2880_pci_lock, flags);
+ rt2880_pci_reg_write(address, RT2880_PCI_REG_CONFIG_ADDR);
+ rt2880_pci_reg_write(val, RT2880_PCI_REG_CONFIG_DATA);
+ spin_unlock_irqrestore(&rt2880_pci_lock, flags);
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ u16 cmd;
+ int irq = -1;
+
+ if (dev->bus->number != 0)
+ return irq;
+
+ switch (PCI_SLOT(dev->devfn)) {
+ case 0x00:
+ rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000);
+ (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0);
+ break;
+ case 0x11:
+ irq = RT288X_CPU_IRQ_PCI;
+ break;
+ default:
+ printk("%s:%s[%d] trying to alloc unknown pci irq\n",
+ __FILE__, __func__, __LINE__);
+ BUG();
+ break;
+ }
+
+ pci_write_config_byte((struct pci_dev*)dev, PCI_CACHE_LINE_SIZE, 0x14);
+ pci_write_config_byte((struct pci_dev*)dev, PCI_LATENCY_TIMER, 0xFF);
+ pci_read_config_word((struct pci_dev*)dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+ PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK |
+ PCI_COMMAND_SERR | PCI_COMMAND_WAIT | PCI_COMMAND_PARITY;
+ pci_write_config_word((struct pci_dev*)dev, PCI_COMMAND, cmd);
+ pci_write_config_byte((struct pci_dev*)dev, PCI_INTERRUPT_LINE,
+ dev->irq);
+ return irq;
+}
+
+static int rt288x_pci_probe(struct platform_device *pdev)
+{
+ void __iomem *io_map_base;
+ int i;
+
+ rt2880_pci_base = ioremap_nocache(RT2880_PCI_BASE, PAGE_SIZE);
+
+ io_map_base = ioremap(RT2880_PCI_IO_BASE, RT2880_PCI_IO_SIZE);
+ rt2880_pci_controller.io_map_base = (unsigned long) io_map_base;
+ set_io_port_base((unsigned long) io_map_base);
+
+ ioport_resource.start = RT2880_PCI_IO_BASE;
+ ioport_resource.end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1;
+
+ rt2880_pci_reg_write(0, RT2880_PCI_REG_PCICFG_ADDR);
+ for(i = 0; i < 0xfffff; i++) {}
+
+ rt2880_pci_reg_write(0x79, RT2880_PCI_REG_ARBCTL);
+ rt2880_pci_reg_write(0x07FF0001, RT2880_PCI_REG_BAR0SETUP_ADDR);
+ rt2880_pci_reg_write(RT2880_PCI_MEM_BASE, RT2880_PCI_REG_MEMBASE);
+ rt2880_pci_reg_write(RT2880_PCI_IO_BASE, RT2880_PCI_REG_IOBASE);
+ rt2880_pci_reg_write(0x08000000, RT2880_PCI_REG_IMBASEBAR0_ADDR);
+ rt2880_pci_reg_write(0x08021814, RT2880_PCI_REG_ID);
+ rt2880_pci_reg_write(0x00800001, RT2880_PCI_REG_CLASS);
+ rt2880_pci_reg_write(0x28801814, RT2880_PCI_REG_SUBID);
+ rt2880_pci_reg_write(0x000c0000, RT2880_PCI_REG_PCIMSK_ADDR);
+
+ rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000);
+ (void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0);
+
+ register_pci_controller(&rt2880_pci_controller);
+ return 0;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id rt288x_pci_match[] = {
+ { .compatible = "ralink,rt288x-pci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt288x_pci_match);
+
+static struct platform_driver rt288x_pci_driver = {
+ .probe = rt288x_pci_probe,
+ .driver = {
+ .name = "rt288x-pci",
+ .owner = THIS_MODULE,
+ .of_match_table = rt288x_pci_match,
+ },
+};
+
+int __init pcibios_init(void)
+{
+ int ret = platform_driver_register(&rt288x_pci_driver);
+ if (ret)
+ pr_info("rt288x-pci: Error registering platform driver!");
+ return ret;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 026e823..cd13da8 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -8,6 +8,7 @@ choice
config SOC_RT288X
bool "RT288x"
+ select HW_HAS_PCI
config SOC_RT305X
bool "RT305x"
--
1.7.10.4

View File

@ -0,0 +1,688 @@
From b43e77699154356a39796d95ef316699dafe409d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 21 Mar 2013 17:34:08 +0100
Subject: [PATCH 12/33] PCI: MIPS: adds rt3883 pci support
Add support for the pcie found on the rt3883 SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/pci/Makefile | 1 +
arch/mips/pci/pci-rt3883.c | 640 ++++++++++++++++++++++++++++++++++++++++++++
arch/mips/ralink/Kconfig | 1 +
3 files changed, 642 insertions(+)
create mode 100644 arch/mips/pci/pci-rt3883.c
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 77974ba..3cbfd9b 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
obj-$(CONFIG_LANTIQ) += fixup-lantiq.o
obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o
+obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c
new file mode 100644
index 0000000..212c90b
--- /dev/null
+++ b/arch/mips/pci/pci-rt3883.c
@@ -0,0 +1,640 @@
+/*
+ * Ralink RT3662/RT3883 SoC PCI support
+ *
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Parts of this file are based on Ralink's 2.6.21 BSP
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/rt3883.h>
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define RT3883_MEMORY_BASE 0x00000000
+#define RT3883_MEMORY_SIZE 0x02000000
+
+#define RT3883_PCI_REG_PCICFG 0x00
+#define RT3883_PCICFG_P2P_BR_DEVNUM_M 0xf
+#define RT3883_PCICFG_P2P_BR_DEVNUM_S 16
+#define RT3883_PCICFG_PCIRST BIT(1)
+#define RT3883_PCI_REG_PCIRAW 0x04
+#define RT3883_PCI_REG_PCIINT 0x08
+#define RT3883_PCI_REG_PCIENA 0x0c
+
+#define RT3883_PCI_REG_CFGADDR 0x20
+#define RT3883_PCI_REG_CFGDATA 0x24
+#define RT3883_PCI_REG_MEMBASE 0x28
+#define RT3883_PCI_REG_IOBASE 0x2c
+#define RT3883_PCI_REG_ARBCTL 0x80
+
+#define RT3883_PCI_REG_BASE(_x) (0x1000 + (_x) * 0x1000)
+#define RT3883_PCI_REG_BAR0SETUP(_x) (RT3883_PCI_REG_BASE((_x)) + 0x10)
+#define RT3883_PCI_REG_IMBASEBAR0(_x) (RT3883_PCI_REG_BASE((_x)) + 0x18)
+#define RT3883_PCI_REG_ID(_x) (RT3883_PCI_REG_BASE((_x)) + 0x30)
+#define RT3883_PCI_REG_CLASS(_x) (RT3883_PCI_REG_BASE((_x)) + 0x34)
+#define RT3883_PCI_REG_SUBID(_x) (RT3883_PCI_REG_BASE((_x)) + 0x38)
+#define RT3883_PCI_REG_STATUS(_x) (RT3883_PCI_REG_BASE((_x)) + 0x50)
+
+#define RT3883_PCI_MODE_NONE 0
+#define RT3883_PCI_MODE_PCI BIT(0)
+#define RT3883_PCI_MODE_PCIE BIT(1)
+#define RT3883_PCI_MODE_BOTH (RT3883_PCI_MODE_PCI | RT3883_PCI_MODE_PCIE)
+
+#define RT3883_PCI_IRQ_COUNT 32
+
+#define RT3883_P2P_BR_DEVNUM 1
+
+struct rt3883_pci_controller {
+ void __iomem *base;
+ spinlock_t lock;
+
+ struct irq_domain *irq_domain;
+
+ struct pci_controller pci_controller;
+ struct resource io_res;
+ struct resource mem_res;
+
+ bool pcie_ready;
+ unsigned char p2p_devnum;
+};
+
+static inline struct rt3883_pci_controller *
+pci_bus_to_rt3883_controller(struct pci_bus *bus)
+{
+ struct pci_controller *hose;
+
+ hose = (struct pci_controller *) bus->sysdata;
+ return container_of(hose, struct rt3883_pci_controller, pci_controller);
+}
+
+static inline u32 rt3883_pci_r32(struct rt3883_pci_controller *rpc,
+ unsigned reg)
+{
+ return ioread32(rpc->base + reg);
+}
+
+static inline void rt3883_pci_w32(struct rt3883_pci_controller *rpc,
+ u32 val, unsigned reg)
+{
+ iowrite32(val, rpc->base + reg);
+}
+
+static inline u32 rt3883_pci_get_cfgaddr(unsigned int bus, unsigned int slot,
+ unsigned int func, unsigned int where)
+{
+ return ((bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) |
+ 0x80000000);
+}
+
+static u32 rt3883_pci_read_cfg32(struct rt3883_pci_controller *rpc,
+ unsigned bus, unsigned slot,
+ unsigned func, unsigned reg)
+{
+ unsigned long flags;
+ u32 address;
+ u32 ret;
+
+ address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
+
+ spin_lock_irqsave(&rpc->lock, flags);
+ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+ ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+ spin_unlock_irqrestore(&rpc->lock, flags);
+
+ return ret;
+}
+
+static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc,
+ unsigned bus, unsigned slot,
+ unsigned func, unsigned reg, u32 val)
+{
+ unsigned long flags;
+ u32 address;
+
+ address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
+
+ spin_lock_irqsave(&rpc->lock, flags);
+ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+ rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA);
+ spin_unlock_irqrestore(&rpc->lock, flags);
+}
+
+static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct rt3883_pci_controller *rpc;
+ u32 pending;
+
+ rpc = irq_get_handler_data(irq);
+
+ pending = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIINT) &
+ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+
+ if (!pending) {
+ spurious_interrupt();
+ return;
+ }
+
+ while (pending) {
+ unsigned bit = __ffs(pending);
+
+ irq = irq_find_mapping(rpc->irq_domain, bit);
+ generic_handle_irq(irq);
+
+ pending &= ~BIT(bit);
+ }
+}
+
+static void rt3883_pci_irq_unmask(struct irq_data *d)
+{
+ struct rt3883_pci_controller *rpc;
+ u32 t;
+
+ rpc = irq_data_get_irq_chip_data(d);
+
+ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+ rt3883_pci_w32(rpc, t | BIT(d->hwirq), RT3883_PCI_REG_PCIENA);
+ /* flush write */
+ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+}
+
+static void rt3883_pci_irq_mask(struct irq_data *d)
+{
+ struct rt3883_pci_controller *rpc;
+ u32 t;
+
+ rpc = irq_data_get_irq_chip_data(d);
+
+ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+ rt3883_pci_w32(rpc, t & ~BIT(d->hwirq), RT3883_PCI_REG_PCIENA);
+ /* flush write */
+ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+}
+
+static struct irq_chip rt3883_pci_irq_chip = {
+ .name = "RT3883 PCI",
+ .irq_mask = rt3883_pci_irq_mask,
+ .irq_unmask = rt3883_pci_irq_unmask,
+ .irq_mask_ack = rt3883_pci_irq_mask,
+};
+
+static int rt3883_pci_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &rt3883_pci_irq_chip, handle_level_irq);
+ irq_set_chip_data(irq, d->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops rt3883_pci_irq_domain_ops = {
+ .map = rt3883_pci_irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int rt3883_pci_irq_init(struct device *dev,
+ struct rt3883_pci_controller *rpc)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *intc_np;
+ int irq;
+ int err;
+
+ intc_np = of_get_child_by_name(np, "interrupt-controller");
+ if (!intc_np) {
+ dev_err(dev, "no %s child node found", "interrupt-controller");
+ return -ENODEV;
+ }
+
+ irq = irq_of_parse_and_map(intc_np, 0);
+ if (irq == 0) {
+ dev_err(dev, "%s has no IRQ", of_node_full_name(intc_np));
+ err = -EINVAL;
+ goto err_put_intc;
+ }
+
+ /* disable all interrupts */
+ rt3883_pci_w32(rpc, 0, RT3883_PCI_REG_PCIENA);
+
+ rpc->irq_domain =
+ irq_domain_add_linear(intc_np, RT3883_PCI_IRQ_COUNT,
+ &rt3883_pci_irq_domain_ops,
+ rpc);
+ if (!rpc->irq_domain) {
+ dev_err(dev, "unable to add IRQ domain\n");
+ err = -ENODEV;
+ goto err_put_intc;
+ }
+
+ irq_set_handler_data(irq, rpc);
+ irq_set_chained_handler(irq, rt3883_pci_irq_handler);
+
+ return 0;
+
+err_put_intc:
+ of_node_put(intc_np);
+ return err;
+}
+
+static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct rt3883_pci_controller *rpc;
+ unsigned long flags;
+ u32 address;
+ u32 data;
+
+ rpc = pci_bus_to_rt3883_controller(bus);
+
+ if (!rpc->pcie_ready && bus->number == 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+
+ spin_lock_irqsave(&rpc->lock, flags);
+ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+ data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+ spin_unlock_irqrestore(&rpc->lock, flags);
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+ case 2:
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ break;
+ case 4:
+ *val = data;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct rt3883_pci_controller *rpc;
+ unsigned long flags;
+ u32 address;
+ u32 data;
+
+ rpc = pci_bus_to_rt3883_controller(bus);
+
+ if (!rpc->pcie_ready && bus->number == 1)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), where);
+
+ spin_lock_irqsave(&rpc->lock, flags);
+ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+ data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+
+ switch (size) {
+ case 1:
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 2:
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 4:
+ data = val;
+ break;
+ }
+
+ rt3883_pci_w32(rpc, data, RT3883_PCI_REG_CFGDATA);
+ spin_unlock_irqrestore(&rpc->lock, flags);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rt3883_pci_ops = {
+ .read = rt3883_pci_config_read,
+ .write = rt3883_pci_config_write,
+};
+
+static void rt3883_pci_preinit(struct rt3883_pci_controller *rpc, unsigned mode)
+{
+ u32 syscfg1;
+ u32 rstctrl;
+ u32 clkcfg1;
+ u32 t;
+
+ rstctrl = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL);
+ syscfg1 = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1);
+ clkcfg1 = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1);
+
+ if (mode & RT3883_PCI_MODE_PCIE) {
+ rstctrl |= RT3883_RSTCTRL_PCIE;
+ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+
+ /* setup PCI PAD drive mode */
+ syscfg1 &= ~(0x30);
+ syscfg1 |= (2 << 4);
+ rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1);
+
+ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+ t &= ~BIT(31);
+ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+
+ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1);
+ t &= 0x80ffffff;
+ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1);
+
+ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1);
+ t |= 0xa << 24;
+ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1);
+
+ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+ t |= BIT(31);
+ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+
+ msleep(50);
+
+ rstctrl &= ~RT3883_RSTCTRL_PCIE;
+ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+ }
+
+ syscfg1 |= (RT3883_SYSCFG1_PCIE_RC_MODE | RT3883_SYSCFG1_PCI_HOST_MODE);
+
+ clkcfg1 &= ~(RT3883_CLKCFG1_PCI_CLK_EN | RT3883_CLKCFG1_PCIE_CLK_EN);
+
+ if (mode & RT3883_PCI_MODE_PCI) {
+ clkcfg1 |= RT3883_CLKCFG1_PCI_CLK_EN;
+ rstctrl &= ~RT3883_RSTCTRL_PCI;
+ }
+
+ if (mode & RT3883_PCI_MODE_PCIE) {
+ clkcfg1 |= RT3883_CLKCFG1_PCIE_CLK_EN;
+ rstctrl &= ~RT3883_RSTCTRL_PCIE;
+ }
+
+ rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1);
+ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+ rt_sysc_w32(clkcfg1, RT3883_SYSC_REG_CLKCFG1);
+
+ msleep(500);
+
+ /*
+ * setup the device number of the P2P bridge
+ * and de-assert the reset line
+ */
+ t = (RT3883_P2P_BR_DEVNUM << RT3883_PCICFG_P2P_BR_DEVNUM_S);
+ rt3883_pci_w32(rpc, t, RT3883_PCI_REG_PCICFG);
+
+ /* flush write */
+ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCICFG);
+ msleep(500);
+
+ if (mode & RT3883_PCI_MODE_PCIE) {
+ msleep(500);
+
+ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_STATUS(1));
+
+ rpc->pcie_ready = t & BIT(0);
+
+ if (!rpc->pcie_ready) {
+ /* reset the PCIe block */
+ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL);
+ t |= RT3883_RSTCTRL_PCIE;
+ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL);
+ t &= ~RT3883_RSTCTRL_PCIE;
+ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL);
+
+ /* turn off PCIe clock */
+ t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1);
+ t &= ~RT3883_CLKCFG1_PCIE_CLK_EN;
+ rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1);
+
+ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+ t &= ~0xf000c080;
+ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+ }
+ }
+
+ /* enable PCI arbiter */
+ rt3883_pci_w32(rpc, 0x79, RT3883_PCI_REG_ARBCTL);
+}
+
+static inline void
+rt3883_dump_pci_config(struct rt3883_pci_controller *rpc,
+ int bus, int slot)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ u32 val;
+
+ val = rt3883_pci_read_cfg32(rpc, bus, slot, 0, i << 2);
+ pr_info("pci %02x:%02x.0 0x%02x = %08x\n",
+ bus, slot, i << 2, val);
+ }
+}
+
+static int rt3883_pci_probe(struct platform_device *pdev)
+{
+ struct rt3883_pci_controller *rpc;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct resource *res;
+ struct device_node *child;
+ u32 val;
+ int err;
+ int mode;
+
+ rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL);
+ if (!rpc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ rpc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rpc->base))
+ return PTR_ERR(rpc->base);
+
+ rpc->pci_controller.of_node = of_get_child_by_name(np, "host-bridge");
+ if (!rpc->pci_controller.of_node) {
+ dev_err(dev, "no %s child node found", "host-bridge");
+ return -ENODEV;
+ }
+
+ mode = RT3883_PCI_MODE_NONE;
+ for_each_child_of_node(rpc->pci_controller.of_node, child) {
+ u32 slot;
+
+ if (!of_device_is_available(child))
+ continue;
+
+ if (of_property_read_u32(child, "ralink,pci-slot",
+ &slot)) {
+ dev_err(dev, "no '%s' property found for %s\n",
+ "ralink,pci-slot",
+ of_node_full_name(child));
+ continue;
+ }
+
+ switch (slot) {
+ case 1:
+ mode |= RT3883_PCI_MODE_PCIE;
+ break;
+
+ case 17:
+ case 18:
+ mode |= RT3883_PCI_MODE_PCI;
+ break;
+ }
+ }
+
+ if (mode == RT3883_PCI_MODE_NONE) {
+ dev_err(dev, "unable to determine PCI mode\n");
+ err = -EINVAL;
+ goto err_put_hb_node;
+ }
+
+ dev_info(dev, "mode:%s%s\n",
+ (mode & RT3883_PCI_MODE_PCI) ? " PCI" : "",
+ (mode & RT3883_PCI_MODE_PCIE) ? " PCIe" : "");
+
+ rt3883_pci_preinit(rpc, mode);
+
+ rpc->pci_controller.pci_ops = &rt3883_pci_ops;
+ rpc->pci_controller.io_resource = &rpc->io_res;
+ rpc->pci_controller.mem_resource = &rpc->mem_res;
+
+ /* Load PCI I/O and memory resources from DT */
+ pci_load_of_ranges(&rpc->pci_controller,
+ rpc->pci_controller.of_node);
+
+ rt3883_pci_w32(rpc, rpc->mem_res.start, RT3883_PCI_REG_MEMBASE);
+ rt3883_pci_w32(rpc, rpc->io_res.start, RT3883_PCI_REG_IOBASE);
+
+ ioport_resource.start = rpc->io_res.start;
+ ioport_resource.end = rpc->io_res.end;
+
+ /* PCI */
+ rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(0));
+ rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(0));
+ rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(0));
+ rt3883_pci_w32(rpc, 0x00800001, RT3883_PCI_REG_CLASS(0));
+ rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(0));
+
+ /* PCIe */
+ rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(1));
+ rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(1));
+ rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(1));
+ rt3883_pci_w32(rpc, 0x06040001, RT3883_PCI_REG_CLASS(1));
+ rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(1));
+
+ err = rt3883_pci_irq_init(dev, rpc);
+ if (err)
+ goto err_put_hb_node;
+
+ /* PCIe */
+ val = rt3883_pci_read_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND);
+ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ rt3883_pci_write_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND, val);
+
+ /* PCI */
+ val = rt3883_pci_read_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND);
+ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ rt3883_pci_write_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND, val);
+
+ if (mode == RT3883_PCI_MODE_PCIE) {
+ rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(0));
+ rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(1));
+
+ rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+ PCI_BASE_ADDRESS_0,
+ RT3883_MEMORY_BASE);
+ /* flush write */
+ rt3883_pci_read_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+ PCI_BASE_ADDRESS_0);
+ } else {
+ rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+ PCI_IO_BASE, 0x00000101);
+ }
+
+ register_pci_controller(&rpc->pci_controller);
+
+ return 0;
+
+err_put_hb_node:
+ of_node_put(rpc->pci_controller.of_node);
+ return err;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct rt3883_pci_controller *rpc;
+ struct of_irq dev_irq;
+ int err;
+ int irq;
+
+ rpc = pci_bus_to_rt3883_controller(dev->bus);
+ err = of_irq_map_pci(dev, &dev_irq);
+ if (err) {
+ pr_err("pci %s: unable to get irq map, err=%d\n",
+ pci_name((struct pci_dev *) dev), err);
+ return 0;
+ }
+
+ irq = irq_create_of_mapping(dev_irq.controller,
+ dev_irq.specifier,
+ dev_irq.size);
+
+ if (irq == 0)
+ pr_crit("pci %s: no irq found for pin %u\n",
+ pci_name((struct pci_dev *) dev), pin);
+ else
+ pr_info("pci %s: using irq %d for pin %u\n",
+ pci_name((struct pci_dev *) dev), irq, pin);
+
+ return irq;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id rt3883_pci_ids[] = {
+ { .compatible = "ralink,rt3883-pci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt3883_pci_ids);
+
+static struct platform_driver rt3883_pci_driver = {
+ .probe = rt3883_pci_probe,
+ .driver = {
+ .name = "rt3883-pci",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rt3883_pci_ids),
+ },
+};
+
+static int __init rt3883_pci_init(void)
+{
+ return platform_driver_register(&rt3883_pci_driver);
+}
+
+postcore_initcall(rt3883_pci_init);
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index cd13da8..592e5f9 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -20,6 +20,7 @@ choice
bool "RT3883"
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
+ select HW_HAS_PCI
config SOC_MT7620
bool "MT7620"
--
1.7.10.4

View File

@ -0,0 +1,409 @@
From ded577553b06a85c12a89b8fbcfa2b51f30bc037 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sat, 18 May 2013 22:06:15 +0200
Subject: [PATCH 13/33] PCI: MIPS: adds mt7620a pcie driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/pci/Makefile | 1 +
arch/mips/pci/pci-mt7620a.c | 363 +++++++++++++++++++++++++++++++++++++++++++
arch/mips/ralink/Kconfig | 1 +
3 files changed, 365 insertions(+)
create mode 100644 arch/mips/pci/pci-mt7620a.c
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 3cbfd9b..025d3a7 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_LANTIQ) += fixup-lantiq.o
obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o
obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o
+obj-$(CONFIG_SOC_MT7620) += pci-mt7620a.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
diff --git a/arch/mips/pci/pci-mt7620a.c b/arch/mips/pci/pci-mt7620a.c
new file mode 100644
index 0000000..271763c
--- /dev/null
+++ b/arch/mips/pci/pci-mt7620a.c
@@ -0,0 +1,363 @@
+/*
+ * Ralink MT7620A SoC PCI support
+ *
+ * Copyright (C) 2007-2013 Bruce Chang
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define RALINK_PCI_MM_MAP_BASE 0x20000000
+#define RALINK_PCI_IO_MAP_BASE 0x10160000
+
+#define RALINK_INT_PCIE0 4
+#define RALINK_SYSTEM_CONTROL_BASE 0xb0000000
+#define RALINK_SYSCFG1 0x14
+#define RALINK_CLKCFG1 0x30
+#define RALINK_GPIOMODE 0x60
+#define RALINK_PCIE_CLK_GEN 0x7c
+#define RALINK_PCIE_CLK_GEN1 0x80
+#define PCIEPHY0_CFG 0x90
+#define PPLL_CFG1 0x9c
+#define PPLL_DRV 0xa0
+#define RALINK_PCI_HOST_MODE_EN (1<<7)
+#define RALINK_PCIE_RC_MODE_EN (1<<8)
+#define RALINK_PCIE_RST (1<<23)
+#define RALINK_PCI_RST (1<<24)
+#define RALINK_PCI_CLK_EN (1<<19)
+#define RALINK_PCIE_CLK_EN (1<<21)
+#define PCI_SLOTx2 (1<<11)
+#define PCI_SLOTx1 (2<<11)
+#define PDRV_SW_SET (1<<31)
+#define LC_CKDRVPD_ (1<<19)
+
+#define RALINK_PCI_CONFIG_ADDR 0x20
+#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24
+#define MEMORY_BASE 0x0
+#define RALINK_PCIE0_RST (1<<26)
+#define RALINK_PCI_BASE 0xB0140000
+#define RALINK_PCI_MEMBASE 0x28
+#define RALINK_PCI_IOBASE 0x2C
+
+#define RT6855_PCIE0_OFFSET 0x2000
+
+#define RALINK_PCI_PCICFG_ADDR 0x00
+#define RALINK_PCI0_BAR0SETUP_ADDR 0x10
+#define RALINK_PCI0_IMBASEBAR0_ADDR 0x18
+#define RALINK_PCI0_ID 0x30
+#define RALINK_PCI0_CLASS 0x34
+#define RALINK_PCI0_SUBID 0x38
+#define RALINK_PCI0_STATUS 0x50
+#define RALINK_PCI_PCIMSK_ADDR 0x0C
+
+#define RALINK_PCIE0_CLK_EN (1 << 26)
+
+#define BUSY 0x80000000
+#define WAITRETRY_MAX 10
+#define WRITE_MODE (1UL << 23)
+#define DATA_SHIFT 0
+#define ADDR_SHIFT 8
+
+
+static void __iomem *bridge_base;
+static void __iomem *pcie_base;
+
+static struct reset_control *rstpcie0;
+
+static inline void bridge_w32(u32 val, unsigned reg)
+{
+ iowrite32(val, bridge_base + reg);
+}
+
+static inline u32 bridge_r32(unsigned reg)
+{
+ return ioread32(bridge_base + reg);
+}
+
+static inline void pcie_w32(u32 val, unsigned reg)
+{
+ iowrite32(val, pcie_base + reg);
+}
+
+static inline u32 pcie_r32(unsigned reg)
+{
+ return ioread32(pcie_base + reg);
+}
+
+static inline void pcie_m32(u32 clr, u32 set, unsigned reg)
+{
+ u32 val = pcie_r32(reg);
+ val &= ~clr;
+ val |= set;
+ pcie_w32(val, reg);
+}
+
+int wait_pciephy_busy(void)
+{
+ unsigned long reg_value = 0x0, retry = 0;
+
+ while (1) {
+ //reg_value = rareg(READMODE, PCIEPHY0_CFG, 0);
+ reg_value = pcie_r32(PCIEPHY0_CFG);
+
+ if (reg_value & BUSY)
+ mdelay(100);
+ else
+ break;
+ if (retry++ > WAITRETRY_MAX){
+ printk("PCIE-PHY retry failed.\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void pcie_phy(unsigned long addr, unsigned long val)
+{
+ wait_pciephy_busy();
+ pcie_w32(WRITE_MODE | (val << DATA_SHIFT) | (addr << ADDR_SHIFT), PCIEPHY0_CFG);
+ mdelay(1);
+ wait_pciephy_busy();
+}
+
+static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
+{
+ unsigned int slot = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+ u32 address;
+ u32 data;
+
+ address = (((where & 0xF00) >> 8) << 24) | (bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
+ bridge_w32(address, RALINK_PCI_CONFIG_ADDR);
+ data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRTUAL_REG);
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+ case 2:
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ break;
+ case 4:
+ *val = data;
+ break;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+ unsigned int slot = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+ u32 address;
+ u32 data;
+
+ address = (((where & 0xF00) >> 8) << 24) | (bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
+ bridge_w32(address, RALINK_PCI_CONFIG_ADDR);
+ data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRTUAL_REG);
+
+ switch (size) {
+ case 1:
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 2:
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ break;
+ case 4:
+ data = val;
+ break;
+ }
+
+ bridge_w32(data, RALINK_PCI_CONFIG_DATA_VIRTUAL_REG);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mt7620a_pci_ops= {
+ .read = pci_config_read,
+ .write = pci_config_write,
+};
+
+static struct resource mt7620a_res_pci_mem1 = {
+ .name = "pci memory",
+ .start = RALINK_PCI_MM_MAP_BASE,
+ .end = (u32) ((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)),
+ .flags = IORESOURCE_MEM,
+};
+static struct resource mt7620a_res_pci_io1 = {
+ .name = "pci io",
+ .start = RALINK_PCI_IO_MAP_BASE,
+ .end = (u32) ((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)),
+ .flags = IORESOURCE_IO,
+};
+
+struct pci_controller mt7620a_controller = {
+ .pci_ops = &mt7620a_pci_ops,
+ .mem_resource = &mt7620a_res_pci_mem1,
+ .io_resource = &mt7620a_res_pci_io1,
+ .mem_offset = 0x00000000UL,
+ .io_offset = 0x00000000UL,
+ .io_map_base = 0xa0000000,
+};
+
+static int mt7620a_pci_probe(struct platform_device *pdev)
+{
+ struct resource *bridge_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *pcie_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ rstpcie0 = devm_reset_control_get(&pdev->dev, "pcie0");
+ if (IS_ERR(rstpcie0))
+ return PTR_ERR(rstpcie0);
+
+ bridge_base = devm_request_and_ioremap(&pdev->dev, bridge_res);
+ if (!bridge_base)
+ return -ENOMEM;
+
+ pcie_base = devm_request_and_ioremap(&pdev->dev, pcie_res);
+ if (!pcie_base)
+ return -ENOMEM;
+
+ iomem_resource.start = 0;
+ iomem_resource.end= ~0;
+ ioport_resource.start= 0;
+ ioport_resource.end = ~0;
+
+ /* PCIE: bypass PCIe DLL */
+ pcie_phy(0x0, 0x80);
+ pcie_phy(0x1, 0x04);
+ /* PCIE: Elastic buffer control */
+ pcie_phy(0x68, 0xB4);
+
+ reset_control_assert(rstpcie0);
+ rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
+ rt_sysc_m32(1<<19, 1<<31, PPLL_DRV);
+ rt_sysc_m32(0x3 << 16, 0, RALINK_GPIOMODE);
+
+ reset_control_deassert(rstpcie0);
+ rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
+
+ mdelay(100);
+
+ if (!(rt_sysc_r32(PPLL_CFG1) & 1<<23)) {
+ printk("MT7620 PPLL unlock\n");
+ reset_control_assert(rstpcie0);
+ rt_sysc_m32(BIT(26), 0, RALINK_CLKCFG1);
+ return 0;
+ }
+ rt_sysc_m32((0x1<<18) | (0x1<<17), (0x1 << 19) | (0x1 << 31), PPLL_DRV);
+
+ mdelay(100);
+ reset_control_assert(rstpcie0);
+ rt_sysc_m32(0x30, 2 << 4, RALINK_SYSCFG1);
+
+ rt_sysc_m32(~0x7fffffff, 0x80000000, RALINK_PCIE_CLK_GEN);
+ rt_sysc_m32(~0x80ffffff, 0xa << 24, RALINK_PCIE_CLK_GEN1);
+
+ mdelay(50);
+ reset_control_deassert(rstpcie0);
+ pcie_m32(BIT(1), 0, RALINK_PCI_PCICFG_ADDR);
+ mdelay(100);
+
+ if (( pcie_r32(RALINK_PCI0_STATUS) & 0x1) == 0) {
+ reset_control_assert(rstpcie0);
+ rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
+ rt_sysc_m32(LC_CKDRVPD_, PDRV_SW_SET, PPLL_DRV);
+ printk("PCIE0 no card, disable it(RST&CLK)\n");
+ }
+
+ bridge_w32(0xffffffff, RALINK_PCI_MEMBASE);
+ bridge_w32(RALINK_PCI_IO_MAP_BASE, RALINK_PCI_IOBASE);
+
+ pcie_w32(0x7FFF0000, RALINK_PCI0_BAR0SETUP_ADDR);
+ pcie_w32(MEMORY_BASE, RALINK_PCI0_IMBASEBAR0_ADDR);
+ pcie_w32(0x08021814, RALINK_PCI0_ID);
+ pcie_w32(0x06040001, RALINK_PCI0_CLASS);
+ pcie_w32(0x28801814, RALINK_PCI0_SUBID);
+ pcie_m32(0, BIT(20), RALINK_PCI_PCIMSK_ADDR);
+
+ register_pci_controller(&mt7620a_controller);
+
+ return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ const struct resource *res;
+ u16 cmd;
+ u32 val;
+ int i, irq = 0;
+
+ if ((dev->bus->number == 0) && (slot == 0)) {
+ pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR); //open 7FFF:2G; ENABLE
+ pci_config_write(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, MEMORY_BASE);
+ pci_config_read(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, &val);
+ } else if ((dev->bus->number == 1) && (slot == 0x0)) {
+ irq = RALINK_INT_PCIE0;
+ } else {
+ printk("bus=0x%x, slot = 0x%x\n", dev->bus->number, slot);
+ return 0;
+ }
+
+ for (i = 0; i < 6; i++) {
+ res = &dev->resource[i];
+ }
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+ // FIXME
+ cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ //pci_write_config_byte(dev, PCI_INTERRUPT_PIN, dev->irq);
+
+ return irq;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static const struct of_device_id mt7620a_pci_ids[] = {
+ { .compatible = "ralink,mt7620a-pci" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt7620a_pci_ids);
+
+static struct platform_driver mt7620a_pci_driver = {
+ .probe = mt7620a_pci_probe,
+ .driver = {
+ .name = "mt7620a-pci",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mt7620a_pci_ids),
+ },
+};
+
+static int __init mt7620a_pci_init(void)
+{
+ return platform_driver_register(&mt7620a_pci_driver);
+}
+
+arch_initcall(mt7620a_pci_init);
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 592e5f9..992e365 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -24,6 +24,7 @@ choice
config SOC_MT7620
bool "MT7620"
+ select HW_HAS_PCI
endchoice
--
1.7.10.4

View File

@ -0,0 +1,61 @@
From 7407b7d178e783074861a73da858b099f870270d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sat, 11 May 2013 23:40:19 +0200
Subject: [PATCH 14/33] NET: multi phy support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/phy/phy.c | 9 ++++++---
include/linux/phy.h | 2 +-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 38f0b31..ad64a75 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -773,7 +773,8 @@ void phy_state_machine(struct work_struct *work)
* negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
break;
}
@@ -843,7 +844,8 @@ void phy_state_machine(struct work_struct *work)
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
}
phydev->adjust_link(phydev->attached_dev);
@@ -855,7 +857,8 @@ void phy_state_machine(struct work_struct *work)
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
}
break;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 9e11039..9a8ca78 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -298,7 +298,7 @@ struct phy_device {
struct phy_c45_device_ids c45_ids;
bool is_c45;
-
+ bool no_auto_carrier_off;
enum phy_state state;
u32 dev_flags;
--
1.7.10.4

View File

@ -0,0 +1,83 @@
From 2a41724b2d0af9b4444572c4302570a3af377715 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:26:15 +0200
Subject: [PATCH 15/33] NET: add of_get_mac_address_mtd()
Many embedded devices have information such as mac addresses stored inside mtd
devices. This patch allows us to add a property inside a node describing a
network interface. The new property points at a mtd partition with an offset
where the mac address can be found.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++
include/linux/of_net.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index ffab033..15f4a71 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -10,6 +10,7 @@
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/export.h>
+#include <linux/mtd/mtd.h>
/**
* It maps 'enum phy_interface_t' found in include/linux/phy.h
@@ -92,3 +93,39 @@ const void *of_get_mac_address(struct device_node *np)
return NULL;
}
EXPORT_SYMBOL(of_get_mac_address);
+
+int of_get_mac_address_mtd(struct device_node *np, void *mac)
+{
+ struct device_node *mtd_np = NULL;
+ size_t retlen;
+ int size, ret;
+ struct mtd_info *mtd;
+ const char *part;
+ const __be32 *list;
+ phandle phandle;
+
+ list = of_get_property(np, "mtd-mac-address", &size);
+ if (!list || (size != (2 * sizeof(*list))))
+ return -ENOENT;
+
+ phandle = be32_to_cpup(list++);
+ if (phandle)
+ mtd_np = of_find_node_by_phandle(phandle);
+
+ if (!mtd_np)
+ return -ENOENT;
+
+ part = of_get_property(mtd_np, "label", NULL);
+ if (!part)
+ part = mtd_np->name;
+
+ mtd = get_mtd_device_nm(part);
+ if (IS_ERR(mtd))
+ return PTR_ERR(mtd);
+
+ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, (u_char *) mac);
+ put_mtd_device(mtd);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_get_mac_address_mtd);
diff --git a/include/linux/of_net.h b/include/linux/of_net.h
index 61bf53b..6e6b4a9 100644
--- a/include/linux/of_net.h
+++ b/include/linux/of_net.h
@@ -11,6 +11,7 @@
#include <linux/of.h>
extern const int of_get_phy_mode(struct device_node *np);
extern const void *of_get_mac_address(struct device_node *np);
+extern int of_get_mac_address_mtd(struct device_node *np, void *mac);
#else
static inline const int of_get_phy_mode(struct device_node *np)
{
--
1.7.10.4

View File

@ -0,0 +1,48 @@
From 3f40514a51b44171d274ef6a7d66dce9ae7c349d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 24 May 2013 21:28:08 +0200
Subject: [PATCH 17/33] USB: MIPS: ralink: fix usb issue on mt7620
USB fails when frequency scaling is enabled. Increase the idle cpu speed when
scaled.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/include/asm/mach-ralink/mt7620.h | 1 +
arch/mips/ralink/mt7620.c | 8 ++++++++
2 files changed, 9 insertions(+)
diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h
index 9809972..d469c69 100644
--- a/arch/mips/include/asm/mach-ralink/mt7620.h
+++ b/arch/mips/include/asm/mach-ralink/mt7620.h
@@ -20,6 +20,7 @@
#define SYSC_REG_CHIP_REV 0x0c
#define SYSC_REG_SYSTEM_CONFIG0 0x10
#define SYSC_REG_SYSTEM_CONFIG1 0x14
+#define SYSC_REG_CPU_SYS_CLKCFG 0x3c
#define SYSC_REG_CPLL_CONFIG0 0x54
#define SYSC_REG_CPLL_CONFIG1 0x58
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index 96422e5..6f6b1c8 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -185,6 +185,14 @@ void __init ralink_clk_init(void)
ralink_clk_add("10000500.uart", 40000000);
ralink_clk_add("10000b00.spi", 40000000);
ralink_clk_add("10000c00.uartlite", 40000000);
+
+#ifdef CONFIG_USB
+ /*
+ * When the CPU goes into sleep mode, the BUS clock will be too low for
+ * USB to function properly
+ */
+ rt_sysc_m32(0x1f1f, 0x303, SYSC_REG_CPU_SYS_CLKCFG);
+#endif
}
void __init ralink_of_remap(void)
--
1.7.10.4

View File

@ -0,0 +1,239 @@
From c5f51197b13fd312324ac0486a46e530e163eade Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:31:19 +0200
Subject: [PATCH 18/33] USB: phy: add ralink SoC driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/usb/phy/Kconfig | 8 ++
drivers/usb/phy/Makefile | 1 +
drivers/usb/phy/ralink-phy.c | 191 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 200 insertions(+)
create mode 100644 drivers/usb/phy/ralink-phy.c
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 2311b1e..2944b8c 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -210,4 +210,12 @@ config USB_ULPI_VIEWPORT
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
+config RALINK_USBPHY
+ bool "Ralink USB PHY controller Driver"
+ depends on MIPS && RALINK
+ select USB_OTG_UTILS
+ help
+ Enable this to support ralink USB phy controller for ralink
+ SoCs.
+
endif # USB_PHY
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index a9169cb..f7da66b 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -31,3 +31,4 @@ obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
+obj-$(CONFIG_RALINK_USBPHY) += ralink-phy.o
diff --git a/drivers/usb/phy/ralink-phy.c b/drivers/usb/phy/ralink-phy.c
new file mode 100644
index 0000000..269cff4
--- /dev/null
+++ b/drivers/usb/phy/ralink-phy.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * based on: Renesas R-Car USB phy driver
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/usb/otg.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define RT_SYSC_REG_SYSCFG1 0x014
+#define RT_SYSC_REG_CLKCFG1 0x030
+#define RT_SYSC_REG_USB_PHY_CFG 0x05c
+
+#define RT_RSTCTRL_UDEV BIT(25)
+#define RT_RSTCTRL_UHST BIT(22)
+#define RT_SYSCFG1_USB0_HOST_MODE BIT(10)
+
+#define MT7620_CLKCFG1_UPHY0_CLK_EN BIT(25)
+#define RT_CLKCFG1_UPHY1_CLK_EN BIT(20)
+#define RT_CLKCFG1_UPHY0_CLK_EN BIT(18)
+
+#define USB_PHY_UTMI_8B60M BIT(1)
+#define UDEV_WAKEUP BIT(0)
+
+static atomic_t usb_pwr_ref = ATOMIC_INIT(0);
+static struct reset_control *rstdev;
+static struct reset_control *rsthost;
+static u32 phy_clk;
+
+static void usb_phy_enable(int state)
+{
+ if (state)
+ rt_sysc_m32(0, phy_clk, RT_SYSC_REG_CLKCFG1);
+ else
+ rt_sysc_m32(phy_clk, 0, RT_SYSC_REG_CLKCFG1);
+ mdelay(100);
+}
+
+static int usb_power_on(struct usb_phy *phy)
+{
+ if (atomic_inc_return(&usb_pwr_ref) == 1) {
+ u32 t;
+
+ usb_phy_enable(1);
+
+// reset_control_assert(rstdev);
+// reset_control_assert(rsthost);
+
+ if (OTG_STATE_B_HOST) {
+ rt_sysc_m32(0, RT_SYSCFG1_USB0_HOST_MODE, RT_SYSC_REG_SYSCFG1);
+ reset_control_deassert(rsthost);
+ } else {
+ rt_sysc_m32(RT_SYSCFG1_USB0_HOST_MODE, 0, RT_SYSC_REG_SYSCFG1);
+ reset_control_deassert(rstdev);
+ }
+ mdelay(100);
+
+ t = rt_sysc_r32(RT_SYSC_REG_USB_PHY_CFG);
+ dev_info(phy->dev, "remote usb device wakeup %s\n",
+ (t & UDEV_WAKEUP) ? ("enabbled") : ("disabled"));
+ if (t & USB_PHY_UTMI_8B60M)
+ dev_info(phy->dev, "UTMI 8bit 60MHz\n");
+ else
+ dev_info(phy->dev, "UTMI 16bit 30MHz\n");
+ }
+
+ return 0;
+}
+
+static void usb_power_off(struct usb_phy *phy)
+{
+ if (atomic_dec_return(&usb_pwr_ref) == 0) {
+ usb_phy_enable(0);
+ reset_control_assert(rstdev);
+ reset_control_assert(rsthost);
+ }
+}
+
+static int usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ otg->gadget = NULL;
+ otg->host = host;
+
+ return 0;
+}
+
+static int usb_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ otg->host = NULL;
+ otg->gadget = gadget;
+
+ return 0;
+}
+
+static const struct of_device_id ralink_usbphy_dt_match[] = {
+ { .compatible = "ralink,rt3xxx-usbphy", .data = (void *) (RT_CLKCFG1_UPHY1_CLK_EN | RT_CLKCFG1_UPHY0_CLK_EN) },
+ { .compatible = "ralink,mt7620a-usbphy", .data = (void *) MT7620_CLKCFG1_UPHY0_CLK_EN },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ralink_usbphy_dt_match);
+
+static int usb_phy_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct usb_otg *otg;
+ struct usb_phy *phy;
+ int ret;
+
+ match = of_match_device(ralink_usbphy_dt_match, &pdev->dev);
+ phy_clk = (int) match->data;
+
+ rsthost = devm_reset_control_get(&pdev->dev, "host");
+ if (IS_ERR(rsthost))
+ return PTR_ERR(rsthost);
+
+ rstdev = devm_reset_control_get(&pdev->dev, "device");
+ if (IS_ERR(rstdev))
+ return PTR_ERR(rstdev);
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(&pdev->dev, "unable to allocate memory for USB PHY\n");
+ return -ENOMEM;
+ }
+
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg) {
+ dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n");
+ return -ENOMEM;
+ }
+
+ phy->dev = dev;
+ phy->label = dev_name(dev);
+ phy->init = usb_power_on;
+ phy->shutdown = usb_power_off;
+ otg->set_host = usb_set_host;
+ otg->set_peripheral = usb_set_peripheral;
+ otg->phy = phy;
+ phy->otg = otg;
+ ret = usb_add_phy(phy, USB_PHY_TYPE_USB2);
+
+ if (ret < 0) {
+ dev_err(dev, "usb phy addition error\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, phy);
+
+ dev_info(&pdev->dev, "loaded\n");
+
+ return ret;
+}
+
+static int usb_phy_remove(struct platform_device *pdev)
+{
+ struct usb_phy *phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(phy);
+
+ return 0;
+}
+
+static struct platform_driver usb_phy_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rt3xxx-usbphy",
+ .of_match_table = of_match_ptr(ralink_usbphy_dt_match),
+ },
+ .probe = usb_phy_probe,
+ .remove = usb_phy_remove,
+};
+
+module_platform_driver(usb_phy_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Ralink USB phy");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
--
1.7.10.4

View File

@ -0,0 +1,188 @@
From 40b9d3026ed0b3bcd59f90391195df5b2adabad2 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:34:53 +0200
Subject: [PATCH 19/33] USB: add OHCI/EHCI OF binding
based on f3bc64d6d1f21c1b92d75f233a37b75d77af6963
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Kconfig | 2 ++
drivers/usb/Makefile | 3 ++-
drivers/usb/host/ehci-platform.c | 19 +++++++++++++++----
drivers/usb/host/ohci-platform.c | 37 ++++++++++++++++++++++++++++++++-----
4 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 992e365..8f49ed7 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -24,6 +24,8 @@ choice
config SOC_MT7620
bool "MT7620"
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
endchoice
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c41feba..d155174 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/
+obj-$(CONFIG_USB_OTG_UTILS) += phy/
+
obj-$(CONFIG_PCI) += host/
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_ISP116X_HCD) += host/
@@ -44,7 +46,6 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_PHY) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index f47f259..84d22ff 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -117,6 +117,15 @@ static int ehci_platform_probe(struct platform_device *dev)
hcd->rsrc_start = res_mem->start;
hcd->rsrc_len = resource_size(res_mem);
+#ifdef CONFIG_USB_OTG_UTILS
+ hcd->phy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
+ if (!IS_ERR_OR_NULL(hcd->phy)) {
+ otg_set_host(hcd->phy->otg,
+ &hcd->self);
+ usb_phy_init(hcd->phy);
+ }
+#endif
+
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
@@ -154,6 +163,9 @@ static int ehci_platform_remove(struct platform_device *dev)
if (pdata == &ehci_platform_defaults)
dev->dev.platform_data = NULL;
+ if (pdata == &ehci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
return 0;
}
@@ -198,9 +210,8 @@ static int ehci_platform_resume(struct device *dev)
#define ehci_platform_resume NULL
#endif /* CONFIG_PM */
-static const struct of_device_id vt8500_ehci_ids[] = {
- { .compatible = "via,vt8500-ehci", },
- { .compatible = "wm,prizm-ehci", },
+static const struct of_device_id ralink_ehci_ids[] = {
+ { .compatible = "ralink,rt3xxx-ehci", },
{}
};
@@ -224,7 +235,7 @@ static struct platform_driver ehci_platform_driver = {
.owner = THIS_MODULE,
.name = "ehci-platform",
.pm = &ehci_platform_pm_ops,
- .of_match_table = of_match_ptr(vt8500_ehci_ids),
+ .of_match_table = of_match_ptr(ralink_ehci_ids),
}
};
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index c3e7287..dd9bac6 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -16,6 +16,10 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/usb/ohci_pdriver.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+
+static struct usb_ohci_pdata ohci_platform_defaults;
static int ohci_platform_reset(struct usb_hcd *hcd)
{
@@ -88,14 +92,22 @@ static int ohci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
- struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ohci_pdata *pdata;
int irq;
int err = -ENOMEM;
- if (!pdata) {
- WARN_ON(1);
- return -ENODEV;
- }
+ /*
+ * use reasonable defaults so platforms don't have to provide these.
+ * with DT probing on ARM, none of these are set.
+ */
+ if (!dev->dev.platform_data)
+ dev->dev.platform_data = &ohci_platform_defaults;
+ if (!dev->dev.dma_mask)
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ if (!dev->dev.coherent_dma_mask)
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ pdata = dev->dev.platform_data;
if (usb_disabled())
return -ENODEV;
@@ -128,6 +140,12 @@ static int ohci_platform_probe(struct platform_device *dev)
hcd->rsrc_start = res_mem->start;
hcd->rsrc_len = resource_size(res_mem);
+#ifdef CONFIG_USB_OTG_UTILS
+ hcd->phy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
+ if (!IS_ERR_OR_NULL(hcd->phy))
+ usb_phy_init(hcd->phy);
+#endif
+
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
@@ -162,6 +180,9 @@ static int ohci_platform_remove(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
+ if (pdata == &ohci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
return 0;
}
@@ -201,6 +222,11 @@ static int ohci_platform_resume(struct device *dev)
#define ohci_platform_resume NULL
#endif /* CONFIG_PM */
+static const struct of_device_id ralink_ohci_ids[] = {
+ { .compatible = "ralink,rt3xxx-ohci", },
+ {}
+};
+
static const struct platform_device_id ohci_platform_table[] = {
{ "ohci-platform", 0 },
{ }
@@ -221,5 +247,6 @@ static struct platform_driver ohci_platform_driver = {
.owner = THIS_MODULE,
.name = "ohci-platform",
.pm = &ohci_platform_pm_ops,
+ .of_match_table = of_match_ptr(ralink_ohci_ids),
}
};
--
1.7.10.4

View File

@ -0,0 +1,28 @@
From 629a2ca61e0fbf331f88692038391d22f21b7c70 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 15 Mar 2013 18:16:01 +0100
Subject: [PATCH 20/33] serial: ralink: adds mt7620 serial
Add the config symbol for Mediatek7620 SoC to SERIAL_8250_RT288X
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/tty/serial/8250/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 80fe91e..f6d6820 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -296,7 +296,7 @@ config SERIAL_8250_EM
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
- depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883)
+ depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
help
If you have a Ralink RT288x/RT305x SoC based board and want to use the
serial port, say Y to this option. The driver can handle up to 2 serial
--
1.7.10.4

View File

@ -0,0 +1,32 @@
From 53b934f796611b9a27b698429f1aaec0fe678693 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:18:57 +0200
Subject: [PATCH 21/33] serial: of: allow au1x00 and rt288x to load from OF
In order to make serial_8250 loadable via OF on Au1x00 and Ralink WiSoC we need
to default the iotype to UPIO_AU.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/tty/serial/of_serial.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 39c7ea4..0f333f3 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -103,7 +103,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->fifosize = prop;
port->irq = irq_of_parse_and_map(np, 0);
- port->iotype = UPIO_MEM;
+ if (of_device_is_compatible(np, "ralink,rt2880-uart"))
+ port->iotype = UPIO_AU;
+ else
+ port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
switch (prop) {
case 1:
--
1.7.10.4

View File

@ -0,0 +1,246 @@
From 10cb446ac01be52c49b5143c8601524bc4f53051 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:11:05 +0200
Subject: [PATCH 22/33] clocksource: MIPS: ralink: add support for systick
timer found on newer ralink SoC
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/Kconfig | 2 +
arch/mips/ralink/clk.c | 1 +
drivers/clocksource/Kconfig | 6 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/cevt-rt3352.c | 162 +++++++++++++++++++++++++++++++++++++
5 files changed, 172 insertions(+)
create mode 100644 drivers/clocksource/cevt-rt3352.c
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 8f49ed7..f5d97b8 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -15,6 +15,7 @@ choice
select USB_ARCH_HAS_HCD
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
+ select CLKEVT_RT3352
config SOC_RT3883
bool "RT3883"
@@ -27,6 +28,7 @@ choice
select USB_ARCH_HAS_OHCI
select USB_ARCH_HAS_EHCI
select HW_HAS_PCI
+ select CLKEVT_RT3352
endchoice
diff --git a/arch/mips/ralink/clk.c b/arch/mips/ralink/clk.c
index 8dfa22f..bba0cdf 100644
--- a/arch/mips/ralink/clk.c
+++ b/arch/mips/ralink/clk.c
@@ -69,4 +69,5 @@ void __init plat_time_init(void)
pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
mips_hpt_frequency = clk_get_rate(clk) / 2;
clk_put(clk);
+ clocksource_of_init();
}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f151c6c..0e58a49 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -7,6 +7,12 @@ config CLKSRC_I8253
config CLKEVT_I8253
bool
+config CLKEVT_RT3352
+ bool
+ depends on MIPS && RALINK
+ select CLKSRC_OF
+ select CLKSRC_MMIO
+
config I8253_LOCK
bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c7..423a2ef 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
obj-$(CONFIG_EM_TIMER_STI) += em_sti.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
+obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
diff --git a/drivers/clocksource/cevt-rt3352.c b/drivers/clocksource/cevt-rt3352.c
new file mode 100644
index 0000000..bd50edd
--- /dev/null
+++ b/drivers/clocksource/cevt-rt3352.c
@@ -0,0 +1,162 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 by John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+#include <asm/time.h>
+
+#define SYSTICK_FREQ (50 * 1000)
+
+#define SYSTICK_CONFIG 0x00
+#define SYSTICK_COMPARE 0x04
+#define SYSTICK_COUNT 0x08
+
+/* route systick irq to mips irq 7 instead of the r4k-timer */
+#define CFG_EXT_STK_EN 0x2
+/* enable the counter */
+#define CFG_CNT_EN 0x1
+
+struct systick_device {
+ void __iomem *membase;
+ struct clock_event_device dev;
+ int irq_requested;
+ int freq_scale;
+};
+
+static void systick_set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+
+static int systick_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ struct systick_device *sdev = container_of(evt, struct systick_device, dev);
+ u32 count;
+
+ count = ioread32(sdev->membase + SYSTICK_COUNT);
+ count = (count + delta) % SYSTICK_FREQ;
+ iowrite32(count + delta, sdev->membase + SYSTICK_COMPARE);
+
+ return 0;
+}
+
+static void systick_event_handler(struct clock_event_device *dev)
+{
+ /* noting to do here */
+}
+
+static irqreturn_t systick_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+
+ dev->event_handler(dev);
+
+ return IRQ_HANDLED;
+}
+
+static struct systick_device systick = {
+ .dev = {
+ /* cevt-r4k uses 300, make sure systick gets used if available */
+ .rating = 310,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = systick_next_event,
+ .set_mode = systick_set_clock_mode,
+ .event_handler = systick_event_handler,
+ },
+};
+
+static struct irqaction systick_irqaction = {
+ .handler = systick_interrupt,
+ .flags = IRQF_PERCPU | IRQF_TIMER,
+ .dev_id = &systick.dev,
+};
+
+/* ugly hack */
+#ifdef CONFIG_SOC_MT7620
+
+#define CLK_LUT_CFG 0x40
+#define SLEEP_EN BIT(31)
+
+static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
+{
+ if (sdev->freq_scale == status)
+ return;
+
+ sdev->freq_scale = status;
+
+ pr_info("%s: %s autosleep mode\n", systick.dev.name, (status) ? ("enable") : ("disable"));
+ if (status)
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
+ else
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
+}
+#else
+static inline void mt7620_freq_scaling(struct systick_device *sdev, int status) {}
+#endif
+
+static void systick_set_clock_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct systick_device *sdev = container_of(evt, struct systick_device, dev);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ if (!sdev->irq_requested)
+ setup_irq(systick.dev.irq, &systick_irqaction);
+ mt7620_freq_scaling(sdev, 1);
+ sdev->irq_requested = 1;
+ iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
+ break;
+
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ if (sdev->irq_requested)
+ free_irq(systick.dev.irq, &systick_irqaction);
+ mt7620_freq_scaling(sdev, 0);
+ sdev->irq_requested = 0;
+ iowrite32(0, systick.membase + SYSTICK_CONFIG);
+ break;
+
+ default:
+ pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name);
+ break;
+ }
+}
+
+static void __init ralink_systick_init(struct device_node *np)
+{
+ systick.membase = of_iomap(np, 0);
+ if (!systick.membase) {
+ pr_err("%s: of_iomap failed", np->name);
+ return;
+ }
+
+ clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+ SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up);
+
+ systick_irqaction.name = np->name;
+ systick.dev.name = np->name;
+ clockevent_set_clock(&systick.dev, SYSTICK_FREQ);
+ systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+ systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+ systick.dev.irq = irq_of_parse_and_map(np, 0);
+ if (!systick.dev.irq)
+ panic("%s: request_irq failed", np->name);
+
+ clockevents_register_device(&systick.dev);
+
+ pr_info("%s: runing - mult: %d, shift: %d\n", np->name, systick.dev.mult, systick.dev.shift);
+}
+
+CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
--
1.7.10.4

View File

@ -0,0 +1,425 @@
From 3af8b2904d2d4758f88bc96c7c9ecff4a708347f Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 14 Jul 2013 23:17:27 +0200
Subject: [PATCH 23/33] GPIO: MIPS: ralink: adds ralink gpio support
Add gpio driver for Ralink SoC. This driver makes the gpio core on
RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/mach-ralink/gpio.h | 24 +++
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-ralink.c | 326 ++++++++++++++++++++++++++++++
5 files changed, 358 insertions(+)
create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
create mode 100644 drivers/gpio/gpio-ralink.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 7a58ab9..5737c4b 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -443,6 +443,7 @@ config RALINK
select SYS_HAS_EARLY_PRINTK
select HAVE_MACH_CLKDEV
select CLKDEV_LOOKUP
+ select ARCH_REQUIRE_GPIOLIB
config SGI_IP22
bool "SGI IP22 (Indy/Indigo2)"
diff --git a/arch/mips/include/asm/mach-ralink/gpio.h b/arch/mips/include/asm/mach-ralink/gpio.h
new file mode 100644
index 0000000..f68ee16
--- /dev/null
+++ b/arch/mips/include/asm/mach-ralink/gpio.h
@@ -0,0 +1,24 @@
+/*
+ * Ralink SoC GPIO API support
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_MACH_RALINK_GPIO_H
+#define __ASM_MACH_RALINK_GPIO_H
+
+#define ARCH_NR_GPIOS 128
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
+
+#endif /* __ASM_MACH_RALINK_GPIO_H */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 573c449..4f2f7c2 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -209,6 +209,12 @@ config GPIO_RCAR
help
Say yes here to support GPIO on Renesas R-Car SoCs.
+config GPIO_RALINK
+ bool "Ralink GPIO Support"
+ depends on RALINK
+ help
+ Say yes here to support the Ralink SoC GPIO device
+
config GPIO_SPEAR_SPICS
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
depends on PLAT_SPEAR
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0cb2d65..feb9647 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+obj-$(CONFIG_GPIO_RALINK) += gpio-ralink.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
diff --git a/drivers/gpio/gpio-ralink.c b/drivers/gpio/gpio-ralink.c
new file mode 100644
index 0000000..12984f1
--- /dev/null
+++ b/drivers/gpio/gpio-ralink.c
@@ -0,0 +1,326 @@
+/*
+ * 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) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+
+enum ralink_gpio_reg {
+ GPIO_REG_INT = 0,
+ GPIO_REG_EDGE,
+ GPIO_REG_RENA,
+ GPIO_REG_FENA,
+ GPIO_REG_DATA,
+ GPIO_REG_DIR,
+ GPIO_REG_POL,
+ GPIO_REG_SET,
+ GPIO_REG_RESET,
+ GPIO_REG_TOGGLE,
+ GPIO_REG_MAX
+};
+
+struct ralink_gpio_chip {
+ struct gpio_chip chip;
+ u8 regs[GPIO_REG_MAX];
+
+ spinlock_t lock;
+ void __iomem *membase;
+ struct irq_domain *domain;
+ int irq;
+
+ u32 rising;
+ u32 falling;
+};
+
+#define MAP_MAX 4
+static struct irq_domain *irq_map[MAP_MAX];
+static int irq_map_count;
+static atomic_t irq_refcount = ATOMIC_INIT(0);
+
+static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
+{
+ struct ralink_gpio_chip *rg;
+
+ rg = container_of(chip, struct ralink_gpio_chip, chip);
+
+ return rg;
+}
+
+static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
+{
+ iowrite32(val, rg->membase + rg->regs[reg]);
+}
+
+static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
+{
+ return ioread32(rg->membase + rg->regs[reg]);
+}
+
+static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
+}
+
+static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
+}
+
+static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
+ t &= ~BIT(offset);
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int ralink_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+ unsigned long flags;
+ u32 t;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ ralink_gpio_set(chip, offset, value);
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
+ t |= BIT(offset);
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
+ spin_unlock_irqrestore(&rg->lock, flags);
+
+ return 0;
+}
+
+static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
+
+ if (rg->irq < 1)
+ return -1;
+
+ ralink_gpio_direction_input(chip, pin);
+
+ return irq_create_mapping(rg->domain, pin);
+}
+
+static void ralink_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int i;
+
+ for (i = 0; i < irq_map_count; i++) {
+ struct irq_domain *domain = irq_map[i];
+ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) domain->host_data;
+ unsigned long pending = rt_gpio_r32(rg, GPIO_REG_INT);
+ int bit;
+
+ for_each_set_bit(bit, &pending, rg->chip.ngpio) {
+ u32 map = irq_find_mapping(domain, bit);
+ generic_handle_irq(map);
+ rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
+ }
+ }
+}
+
+static void ralink_gpio_irq_unmask(struct irq_data *d)
+{
+ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data;
+ u32 val = rt_gpio_r32(rg, GPIO_REG_RENA);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ rt_gpio_w32(rg, GPIO_REG_RENA, val | (BIT(d->hwirq) & rg->rising));
+ rt_gpio_w32(rg, GPIO_REG_FENA, val | (BIT(d->hwirq) & rg->falling));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static void ralink_gpio_irq_mask(struct irq_data *d)
+{
+ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data;
+ u32 val = rt_gpio_r32(rg, GPIO_REG_RENA);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rg->lock, flags);
+ rt_gpio_w32(rg, GPIO_REG_FENA, val & ~BIT(d->hwirq));
+ rt_gpio_w32(rg, GPIO_REG_RENA, val & ~BIT(d->hwirq));
+ spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+ struct ralink_gpio_chip *rg = (struct ralink_gpio_chip *) d->domain->host_data;
+ u32 mask = BIT(d->hwirq);
+
+ if (type == IRQ_TYPE_PROBE) {
+ if ((rg->rising | rg->falling) & mask)
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_RISING;
+ }
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ rg->rising |= mask;
+ else
+ rg->rising &= mask;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ rg->falling |= mask;
+ else
+ rg->falling &= mask;
+
+ return 0;
+}
+
+static struct irq_chip ralink_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_unmask = ralink_gpio_irq_unmask,
+ .irq_mask = ralink_gpio_irq_mask,
+ .irq_mask_ack = ralink_gpio_irq_mask,
+ .irq_set_type = ralink_gpio_irq_type,
+};
+
+static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq);
+ irq_set_handler_data(irq, d);
+
+ return 0;
+}
+
+static const struct irq_domain_ops irq_domain_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = gpio_map,
+};
+
+static void ralink_gpio_irq_init(struct device_node *np, struct ralink_gpio_chip *rg)
+{
+ if (irq_map_count >= MAP_MAX)
+ return;
+
+ rg->irq = irq_of_parse_and_map(np, 0);
+ if (!rg->irq)
+ return;
+
+ rg->domain = irq_domain_add_linear(np, rg->chip.ngpio, &irq_domain_ops, rg);
+ if (!rg->domain) {
+ dev_err(rg->chip.dev, "irq_domain_add_linear failed\n");
+ return;
+ }
+
+ irq_map[irq_map_count++] = rg->domain;
+
+ rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
+ rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
+
+ if (!atomic_read(&irq_refcount))
+ irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
+ atomic_inc(&irq_refcount);
+
+ dev_info(rg->chip.dev, "registering %d irq handlers\n", rg->chip.ngpio);
+}
+
+static int ralink_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct ralink_gpio_chip *rg;
+ const __be32 *ngpio, *gpiobase;
+
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find resource\n");
+ return -ENOMEM;
+ }
+
+ rg = devm_kzalloc(&pdev->dev,
+ sizeof(struct ralink_gpio_chip), GFP_KERNEL);
+ if (!rg)
+ return -ENOMEM;
+
+ rg->membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!rg->membase) {
+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
+ return -ENOMEM;
+ }
+
+ if (of_property_read_u8_array(np, "ralink,register-map",
+ rg->regs, GPIO_REG_MAX)) {
+ dev_err(&pdev->dev, "failed to read register definition\n");
+ return -EINVAL;
+ }
+
+ ngpio = of_get_property(np, "ralink,num-gpios", NULL);
+ if (!ngpio) {
+ dev_err(&pdev->dev, "failed to read number of pins\n");
+ return -EINVAL;
+ }
+
+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
+ if (gpiobase)
+ rg->chip.base = be32_to_cpu(*gpiobase);
+ else
+ rg->chip.base = -1;
+
+ spin_lock_init(&rg->lock);
+
+ rg->chip.dev = &pdev->dev;
+ rg->chip.label = dev_name(&pdev->dev);
+ rg->chip.of_node = np;
+ rg->chip.ngpio = be32_to_cpu(*ngpio);
+ rg->chip.direction_input = ralink_gpio_direction_input;
+ rg->chip.direction_output = ralink_gpio_direction_output;
+ rg->chip.get = ralink_gpio_get;
+ rg->chip.set = ralink_gpio_set;
+ rg->chip.to_irq = ralink_gpio_to_irq;
+
+ /* set polarity to low for all lines */
+ rt_gpio_w32(rg, GPIO_REG_POL, 0);
+
+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
+
+ ralink_gpio_irq_init(np, rg);
+
+ return gpiochip_add(&rg->chip);
+}
+
+static const struct of_device_id ralink_gpio_match[] = {
+ { .compatible = "ralink,rt2880-gpio" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ralink_gpio_match);
+
+static struct platform_driver ralink_gpio_driver = {
+ .probe = ralink_gpio_probe,
+ .driver = {
+ .name = "rt2880_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = ralink_gpio_match,
+ },
+};
+
+static int __init ralink_gpio_init(void)
+{
+ return platform_driver_register(&ralink_gpio_driver);
+}
+
+subsys_initcall(ralink_gpio_init);
--
1.7.10.4

View File

@ -0,0 +1,528 @@
From d345c53b941a3d791c26f900af6e85aa1bcaf8b6 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 22 Apr 2013 23:16:18 +0200
Subject: [PATCH 24/33] SPI: ralink: add Ralink SoC spi driver
Add the driver needed to make SPI work on Ralink SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-ralink.c | 475 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 482 insertions(+)
create mode 100644 drivers/spi/spi-ralink.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 92a9345..30e73ea 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -345,6 +345,12 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI blocks.
+config SPI_RALINK
+ tristate "Ralink RT288x/RT305x/RT3662 SPI Controller"
+ depends on (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
+ help
+ This selects a driver for the Ralink RT288x/RT305x SPI Controller.
+
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 33f9c09..724e8de1 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -55,6 +55,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+obj-$(CONFIG_SPI_RALINK) += spi-ralink.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
diff --git a/drivers/spi/spi-ralink.c b/drivers/spi/spi-ralink.c
new file mode 100644
index 0000000..b07cbaa
--- /dev/null
+++ b/drivers/spi/spi-ralink.c
@@ -0,0 +1,475 @@
+/*
+ * spi-ralink.c -- Ralink RT288x/RT305x SPI controller driver
+ *
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Some parts are based on spi-orion.c:
+ * Author: Shadi Ammouri <shadi@marvell.com>
+ * Copyright (C) 2007-2008 Marvell Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "spi-ralink"
+#define RALINK_NUM_CHIPSELECTS 1 /* only one slave is supported*/
+#define RALINK_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
+
+#define RAMIPS_SPI_STAT 0x00
+#define RAMIPS_SPI_CFG 0x10
+#define RAMIPS_SPI_CTL 0x14
+#define RAMIPS_SPI_DATA 0x20
+
+/* SPISTAT register bit field */
+#define SPISTAT_BUSY BIT(0)
+
+/* SPICFG register bit field */
+#define SPICFG_LSBFIRST 0
+#define SPICFG_MSBFIRST BIT(8)
+#define SPICFG_SPICLKPOL BIT(6)
+#define SPICFG_RXCLKEDGE_FALLING BIT(5)
+#define SPICFG_TXCLKEDGE_FALLING BIT(4)
+#define SPICFG_SPICLK_PRESCALE_MASK 0x7
+#define SPICFG_SPICLK_DIV2 0
+#define SPICFG_SPICLK_DIV4 1
+#define SPICFG_SPICLK_DIV8 2
+#define SPICFG_SPICLK_DIV16 3
+#define SPICFG_SPICLK_DIV32 4
+#define SPICFG_SPICLK_DIV64 5
+#define SPICFG_SPICLK_DIV128 6
+#define SPICFG_SPICLK_DISABLE 7
+
+/* SPICTL register bit field */
+#define SPICTL_HIZSDO BIT(3)
+#define SPICTL_STARTWR BIT(2)
+#define SPICTL_STARTRD BIT(1)
+#define SPICTL_SPIENA BIT(0)
+
+#ifdef DEBUG
+#define spi_debug(args...) printk(args)
+#else
+#define spi_debug(args...)
+#endif
+
+struct ralink_spi {
+ struct spi_master *master;
+ void __iomem *base;
+ unsigned int sys_freq;
+ unsigned int speed;
+ struct clk *clk;
+};
+
+static inline struct ralink_spi *spidev_to_ralink_spi(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static inline u32 ralink_spi_read(struct ralink_spi *rs, u32 reg)
+{
+ return ioread32(rs->base + reg);
+}
+
+static inline void ralink_spi_write(struct ralink_spi *rs, u32 reg, u32 val)
+{
+ iowrite32(val, rs->base + reg);
+}
+
+static inline void ralink_spi_setbits(struct ralink_spi *rs, u32 reg, u32 mask)
+{
+ void __iomem *addr = rs->base + reg;
+ u32 val;
+
+ val = ioread32(addr);
+ val |= mask;
+ iowrite32(val, addr);
+}
+
+static inline void ralink_spi_clrbits(struct ralink_spi *rs, u32 reg, u32 mask)
+{
+ void __iomem *addr = rs->base + reg;
+ u32 val;
+
+ val = ioread32(addr);
+ val &= ~mask;
+ iowrite32(val, addr);
+}
+
+static int ralink_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
+{
+ struct ralink_spi *rs = spidev_to_ralink_spi(spi);
+ u32 rate;
+ u32 prescale;
+ u32 reg;
+
+ spi_debug("%s: speed:%u\n", __func__, speed);
+
+ /*
+ * the supported rates are: 2, 4, 8, ... 128
+ * round up as we look for equal or less speed
+ */
+ rate = DIV_ROUND_UP(rs->sys_freq, speed);
+ spi_debug("%s: rate-1:%u\n", __func__, rate);
+ rate = roundup_pow_of_two(rate);
+ spi_debug("%s: rate-2:%u\n", __func__, rate);
+
+ /* check if requested speed is too small */
+ if (rate > 128)
+ return -EINVAL;
+
+ if (rate < 2)
+ rate = 2;
+
+ /* Convert the rate to SPI clock divisor value. */
+ prescale = ilog2(rate/2);
+ spi_debug("%s: prescale:%u\n", __func__, prescale);
+
+ reg = ralink_spi_read(rs, RAMIPS_SPI_CFG);
+ reg = ((reg & ~SPICFG_SPICLK_PRESCALE_MASK) | prescale);
+ ralink_spi_write(rs, RAMIPS_SPI_CFG, reg);
+ rs->speed = speed;
+ return 0;
+}
+
+/*
+ * called only when no transfer is active on the bus
+ */
+static int
+ralink_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct ralink_spi *rs = spidev_to_ralink_spi(spi);
+ unsigned int speed = spi->max_speed_hz;
+ int rc;
+ unsigned int bits_per_word = 8;
+
+ if ((t != NULL) && t->speed_hz)
+ speed = t->speed_hz;
+
+ if ((t != NULL) && t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+
+ if (rs->speed != speed) {
+ spi_debug("%s: speed_hz:%u\n", __func__, speed);
+ rc = ralink_spi_baudrate_set(spi, speed);
+ if (rc)
+ return rc;
+ }
+
+ if (bits_per_word != 8) {
+ spi_debug("%s: bad bits_per_word: %u\n", __func__,
+ bits_per_word);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void ralink_spi_set_cs(struct ralink_spi *rs, int enable)
+{
+ if (enable)
+ ralink_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+ else
+ ralink_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+}
+
+static inline int ralink_spi_wait_till_ready(struct ralink_spi *rs)
+{
+ int i;
+
+ for (i = 0; i < RALINK_SPI_WAIT_RDY_MAX_LOOP; i++) {
+ u32 status;
+
+ status = ralink_spi_read(rs, RAMIPS_SPI_STAT);
+ if ((status & SPISTAT_BUSY) == 0)
+ return 0;
+
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static unsigned int
+ralink_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct ralink_spi *rs = spidev_to_ralink_spi(spi);
+ unsigned count = 0;
+ u8 *rx = xfer->rx_buf;
+ const u8 *tx = xfer->tx_buf;
+ int err;
+
+ spi_debug("%s(%d): %s %s\n", __func__, xfer->len,
+ (tx != NULL) ? "tx" : " ",
+ (rx != NULL) ? "rx" : " ");
+
+ if (tx) {
+ for (count = 0; count < xfer->len; count++) {
+ ralink_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
+ ralink_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
+ err = ralink_spi_wait_till_ready(rs);
+ if (err) {
+ dev_err(&spi->dev, "TX failed, err=%d\n", err);
+ goto out;
+ }
+ }
+ }
+
+ if (rx) {
+ for (count = 0; count < xfer->len; count++) {
+ ralink_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
+ err = ralink_spi_wait_till_ready(rs);
+ if (err) {
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
+ goto out;
+ }
+ rx[count] = (u8) ralink_spi_read(rs, RAMIPS_SPI_DATA);
+ }
+ }
+
+out:
+ return count;
+}
+
+static int ralink_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct ralink_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+ int par_override = 0;
+ int status = 0;
+ int cs_active = 0;
+
+ /* Load defaults */
+ status = ralink_spi_setup_transfer(spi, NULL);
+ if (status < 0)
+ goto msg_done;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ unsigned int bits_per_word = spi->bits_per_word;
+
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ dev_err(&spi->dev,
+ "message rejected: invalid transfer data buffers\n");
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (t->bits_per_word)
+ bits_per_word = t->bits_per_word;
+
+ if (bits_per_word != 8) {
+ dev_err(&spi->dev,
+ "message rejected: invalid transfer bits_per_word (%d bits)\n",
+ bits_per_word);
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (t->speed_hz && t->speed_hz < (rs->sys_freq / 128)) {
+ dev_err(&spi->dev,
+ "message rejected: device min speed (%d Hz) exceeds required transfer speed (%d Hz)\n",
+ (rs->sys_freq / 128), t->speed_hz);
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = ralink_spi_setup_transfer(spi, t);
+ if (status < 0)
+ goto msg_done;
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
+ }
+
+ if (!cs_active) {
+ ralink_spi_set_cs(rs, 1);
+ cs_active = 1;
+ }
+
+ if (t->len)
+ m->actual_length += ralink_spi_write_read(spi, t);
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (t->cs_change) {
+ ralink_spi_set_cs(rs, 0);
+ cs_active = 0;
+ }
+ }
+
+msg_done:
+ if (cs_active)
+ ralink_spi_set_cs(rs, 0);
+
+ m->status = status;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int ralink_spi_setup(struct spi_device *spi)
+{
+ struct ralink_spi *rs = spidev_to_ralink_spi(spi);
+
+ if ((spi->max_speed_hz == 0) ||
+ (spi->max_speed_hz > (rs->sys_freq / 2)))
+ spi->max_speed_hz = (rs->sys_freq / 2);
+
+ if (spi->max_speed_hz < (rs->sys_freq / 128)) {
+ dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n",
+ spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+ if (spi->bits_per_word != 0 && spi->bits_per_word != 8) {
+ dev_err(&spi->dev,
+ "setup: requested bits per words - os wrong %d bpw\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (spi->bits_per_word == 0)
+ spi->bits_per_word = 8;
+
+ /*
+ * baudrate & width will be set ralink_spi_setup_transfer
+ */
+ return 0;
+}
+
+static void ralink_spi_reset(struct ralink_spi *rs)
+{
+ ralink_spi_write(rs, RAMIPS_SPI_CFG,
+ SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING |
+ SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL);
+ ralink_spi_write(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO | SPICTL_SPIENA);
+}
+
+static int ralink_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct ralink_spi *rs;
+ struct resource *r;
+ int status = 0;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs));
+ if (master == NULL) {
+ dev_dbg(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ //if (pdev->id != -1)
+ master->bus_num = 0;
+
+ /* we support only mode 0, and no options */
+ master->mode_bits = 0;
+
+ master->setup = ralink_spi_setup;
+ master->transfer_one_message = ralink_spi_transfer_one_message;
+ master->num_chipselect = RALINK_NUM_CHIPSELECTS;
+ master->dev.of_node = pdev->dev.of_node;
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ rs = spi_master_get_devdata(master);
+ rs->master = master;
+
+ rs->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rs->clk)) {
+ status = PTR_ERR(rs->clk);
+ dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
+ status);
+ goto out_put_master;
+ }
+
+ status = clk_enable(rs->clk);
+ if (status)
+ goto out_put_clk;
+
+ rs->sys_freq = clk_get_rate(rs->clk);
+ spi_debug("%s: sys_freq: %u\n", __func__, rs->sys_freq);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ status = -ENODEV;
+ goto out_disable_clk;
+ }
+
+ rs->base = devm_request_and_ioremap(&pdev->dev, r);
+ if (!rs->base) {
+ status = -EADDRNOTAVAIL;
+ goto out_disable_clk;
+ }
+
+ device_reset(&pdev->dev);
+
+ ralink_spi_reset(rs);
+
+ status = spi_register_master(master);
+ if (status)
+ goto out_disable_clk;
+
+ return 0;
+
+out_disable_clk:
+ clk_disable(rs->clk);
+out_put_clk:
+ clk_put(rs->clk);
+out_put_master:
+ spi_master_put(master);
+ return status;
+}
+
+static int ralink_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct ralink_spi *rs;
+
+ master = dev_get_drvdata(&pdev->dev);
+ rs = spi_master_get_devdata(master);
+
+ clk_disable(rs->clk);
+ clk_put(rs->clk);
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
+static const struct of_device_id ralink_spi_match[] = {
+ { .compatible = "ralink,rt2880-spi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ralink_spi_match);
+
+static struct platform_driver ralink_spi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = ralink_spi_match,
+ },
+ .probe = ralink_spi_probe,
+ .remove = ralink_spi_remove,
+};
+
+module_platform_driver(ralink_spi_driver);
+
+MODULE_DESCRIPTION("Ralink SPI driver");
+MODULE_AUTHOR("Sergiy <piratfm@gmail.com>");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL");
--
1.7.10.4

View File

@ -0,0 +1,274 @@
From f51b3b84af840ea52170ae6444ddee26ec74f7a9 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 22 Apr 2013 23:23:07 +0200
Subject: [PATCH 25/33] watchdog: adds ralink wdt
Adds the watchdog driver for ralink SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/mt7620.c | 1 +
drivers/watchdog/Kconfig | 7 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/rt2880_wdt.c | 207 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 216 insertions(+)
create mode 100644 drivers/watchdog/rt2880_wdt.c
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index 6f6b1c8..14c28b0 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -182,6 +182,7 @@ void __init ralink_clk_init(void)
ralink_clk_add("cpu", cpu_rate);
ralink_clk_add("10000100.timer", 40000000);
+ ralink_clk_add("10000120.watchdog", 40000000);
ralink_clk_add("10000500.uart", 40000000);
ralink_clk_add("10000b00.spi", 40000000);
ralink_clk_add("10000c00.uartlite", 40000000);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index e89fc31..5e34760 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1104,6 +1104,13 @@ config LANTIQ_WDT
help
Hardware driver for the Lantiq SoC Watchdog Timer.
+config RALINK_WDT
+ tristate "Ralink SoC watchdog"
+ select WATCHDOG_CORE
+ depends on RALINK
+ help
+ Hardware driver for the Ralink SoC Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index a300b94..2681e3d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -134,6 +134,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
+obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
# PARISC Architecture
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c
new file mode 100644
index 0000000..ebba535
--- /dev/null
+++ b/drivers/watchdog/rt2880_wdt.c
@@ -0,0 +1,207 @@
+/*
+ * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ *
+ * This driver was based on: drivers/watchdog/softdog.c
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define SYSC_RSTSTAT 0x38
+#define WDT_RST_CAUSE BIT(1)
+
+#define RALINK_WDT_TIMEOUT 30
+#define RALINK_WDT_PRESCALE 65536
+
+#define TIMER_REG_TMR1LOAD 0x00
+#define TIMER_REG_TMR1CTL 0x08
+
+#define TMRSTAT_TMR1RST BIT(5)
+
+#define TMR1CTL_ENABLE BIT(7)
+#define TMR1CTL_MODE_SHIFT 4
+#define TMR1CTL_MODE_MASK 0x3
+#define TMR1CTL_MODE_FREE_RUNNING 0x0
+#define TMR1CTL_MODE_PERIODIC 0x1
+#define TMR1CTL_MODE_TIMEOUT 0x2
+#define TMR1CTL_MODE_WDT 0x3
+#define TMR1CTL_PRESCALE_MASK 0xf
+#define TMR1CTL_PRESCALE_65536 0xf
+
+static struct clk *rt288x_wdt_clk;
+static unsigned long rt288x_wdt_freq;
+static void __iomem *rt288x_wdt_base;
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static inline void rt_wdt_w32(unsigned reg, u32 val)
+{
+ iowrite32(val, rt288x_wdt_base + reg);
+}
+
+static inline u32 rt_wdt_r32(unsigned reg)
+{
+ return ioread32(rt288x_wdt_base + reg);
+}
+
+static int rt288x_wdt_ping(struct watchdog_device *w)
+{
+ rt_wdt_w32(TIMER_REG_TMR1LOAD, w->timeout * rt288x_wdt_freq);
+
+ return 0;
+}
+
+static int rt288x_wdt_start(struct watchdog_device *w)
+{
+ u32 t;
+
+ t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT |
+ TMR1CTL_PRESCALE_MASK);
+ t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT |
+ TMR1CTL_PRESCALE_65536);
+ rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+ rt288x_wdt_ping(w);
+
+ t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t |= TMR1CTL_ENABLE;
+ rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+ return 0;
+}
+
+static int rt288x_wdt_stop(struct watchdog_device *w)
+{
+ u32 t;
+
+ rt288x_wdt_ping(w);
+
+ t = rt_wdt_r32(TIMER_REG_TMR1CTL);
+ t &= ~TMR1CTL_ENABLE;
+ rt_wdt_w32(TIMER_REG_TMR1CTL, t);
+
+ return 0;
+}
+
+static int rt288x_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
+{
+ w->timeout = t;
+ rt288x_wdt_ping(w);
+
+ return 0;
+}
+
+static int rt288x_wdt_bootcause(void)
+{
+ if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
+ return WDIOF_CARDRESET;
+
+ return 0;
+}
+
+static struct watchdog_info rt288x_wdt_info = {
+ .identity = "Ralink Watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+};
+
+static struct watchdog_ops rt288x_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = rt288x_wdt_start,
+ .stop = rt288x_wdt_stop,
+ .ping = rt288x_wdt_ping,
+ .set_timeout = rt288x_wdt_set_timeout,
+};
+
+static struct watchdog_device rt288x_wdt_dev = {
+ .info = &rt288x_wdt_info,
+ .ops = &rt288x_wdt_ops,
+ .min_timeout = 1,
+};
+
+static int rt288x_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rt288x_wdt_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (IS_ERR(rt288x_wdt_base))
+ return PTR_ERR(rt288x_wdt_base);
+
+ rt288x_wdt_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rt288x_wdt_clk))
+ return PTR_ERR(rt288x_wdt_clk);
+
+ device_reset(&pdev->dev);
+
+ rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE;
+
+ rt288x_wdt_dev.dev = &pdev->dev;
+ rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause();
+
+ rt288x_wdt_dev.timeout = rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq);
+
+ watchdog_set_nowayout(&rt288x_wdt_dev, nowayout);
+
+ ret = watchdog_register_device(&rt288x_wdt_dev);
+ if (!ret)
+ dev_info(&pdev->dev, "Initialized\n");
+
+ return 0;
+}
+
+static int rt288x_wdt_remove(struct platform_device *pdev)
+{
+ watchdog_unregister_device(&rt288x_wdt_dev);
+
+ return 0;
+}
+
+static void rt288x_wdt_shutdown(struct platform_device *pdev)
+{
+ rt288x_wdt_stop(&rt288x_wdt_dev);
+}
+
+static const struct of_device_id rt288x_wdt_match[] = {
+ { .compatible = "ralink,rt2880-wdt" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt288x_wdt_match);
+
+static struct platform_driver rt288x_wdt_driver = {
+ .probe = rt288x_wdt_probe,
+ .remove = rt288x_wdt_remove,
+ .shutdown = rt288x_wdt_shutdown,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = rt288x_wdt_match,
+ },
+};
+
+module_platform_driver(rt288x_wdt_driver);
+
+MODULE_DESCRIPTION("MediaTek/Ralink RT288x/RT3xxx hardware watchdog driver");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
--
1.7.10.4

View File

@ -0,0 +1,358 @@
From 4596818bca07e0928168970839e08875cf51b4cc Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 29 Apr 2013 14:40:43 +0200
Subject: [PATCH 26/33] i2c: MIPS: adds ralink I2C driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
.../devicetree/bindings/i2c/i2c-ralink.txt | 27 ++
drivers/i2c/busses/Kconfig | 4 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-ralink.c | 274 ++++++++++++++++++++
4 files changed, 306 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
create mode 100644 drivers/i2c/busses/i2c-ralink.c
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ralink.txt b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
new file mode 100644
index 0000000..8fa8ac3
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
@@ -0,0 +1,27 @@
+I2C for Ralink platforms
+
+Required properties :
+- compatible : Must be "link,rt3052-i2c"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
+
+Example :
+
+palmbus@10000000 {
+ i2c@900 {
+ compatible = "link,rt3052-i2c";
+ reg = <0x900 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hwmon@4b {
+ compatible = "national,lm92";
+ reg = <0x4b>;
+ };
+ };
+};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 631736e..e2c2381 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -628,6 +628,10 @@ config I2C_PXA_SLAVE
is necessary for systems where the PXA may be a target on the
I2C bus.
+config I2C_RALINK
+ tristate "Ralink I2C Controller"
+ select OF_I2C
+
config HAVE_S3C2410_I2C
bool
help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 8f4fc23..7e39a13 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
diff --git a/drivers/i2c/busses/i2c-ralink.c b/drivers/i2c/busses/i2c-ralink.c
new file mode 100644
index 0000000..f4dc13d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ralink.c
@@ -0,0 +1,274 @@
+/*
+ * drivers/i2c/busses/i2c-ralink.c
+ *
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/of_i2c.h>
+#include <linux/err.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define REG_CONFIG_REG 0x00
+#define REG_CLKDIV_REG 0x04
+#define REG_DEVADDR_REG 0x08
+#define REG_ADDR_REG 0x0C
+#define REG_DATAOUT_REG 0x10
+#define REG_DATAIN_REG 0x14
+#define REG_STATUS_REG 0x18
+#define REG_STARTXFR_REG 0x1C
+#define REG_BYTECNT_REG 0x20
+
+#define I2C_STARTERR BIT(4)
+#define I2C_ACKERR BIT(3)
+#define I2C_DATARDY BIT(2)
+#define I2C_SDOEMPTY BIT(1)
+#define I2C_BUSY BIT(0)
+
+#define I2C_DEVADLEN_7 (6 << 2)
+#define I2C_ADDRDIS BIT(1)
+
+#define I2C_RETRY 0x400
+
+#define CLKDIV_VALUE 200 // clock rate is 40M, 40M / (200*2) = 100k (standard i2c bus rate).
+//#define CLKDIV_VALUE 50 // clock rate is 40M, 40M / (50*2) = 400k (fast i2c bus rate).
+
+#define READ_CMD 0x01
+#define WRITE_CMD 0x00
+#define READ_BLOCK 64
+
+static void __iomem *membase;
+static struct i2c_adapter *adapter;
+
+static void rt_i2c_w32(u32 val, unsigned reg)
+{
+ iowrite32(val, membase + reg);
+}
+
+static u32 rt_i2c_r32(unsigned reg)
+{
+ return ioread32(membase + reg);
+}
+
+static inline int rt_i2c_wait_rx_done(void)
+{
+ int retries = I2C_RETRY;
+
+ do {
+ if (!retries--)
+ break;
+ } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_DATARDY));
+
+ return (retries < 0);
+}
+
+static inline int rt_i2c_wait_idle(void)
+{
+ int retries = I2C_RETRY;
+
+ do {
+ if (!retries--)
+ break;
+ } while(rt_i2c_r32(REG_STATUS_REG) & I2C_BUSY);
+
+ return (retries < 0);
+}
+
+static inline int rt_i2c_wait_tx_done(void)
+{
+ int retries = I2C_RETRY;
+
+ do {
+ if (!retries--)
+ break;
+ } while(!(rt_i2c_r32(REG_STATUS_REG) & I2C_SDOEMPTY));
+
+ return (retries < 0);
+}
+
+static int rt_i2c_handle_msg(struct i2c_adapter *a, struct i2c_msg* msg)
+{
+ int i = 0, j = 0, pos = 0;
+ int nblock = msg->len / READ_BLOCK;
+ int rem = msg->len % READ_BLOCK;
+
+ if (msg->flags & I2C_M_TEN) {
+ printk("10 bits addr not supported\n");
+ return -EINVAL;
+ }
+
+ if (msg->flags & I2C_M_RD) {
+ for (i = 0; i < nblock; i++) {
+ rt_i2c_wait_idle();
+ rt_i2c_w32(READ_BLOCK - 1, REG_BYTECNT_REG);
+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG);
+ for (j = 0; j < READ_BLOCK; j++) {
+ if (rt_i2c_wait_rx_done())
+ return -1;
+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG);
+ }
+ }
+
+ rt_i2c_wait_idle();
+ rt_i2c_w32(rem - 1, REG_BYTECNT_REG);
+ rt_i2c_w32(READ_CMD, REG_STARTXFR_REG);
+ for (i = 0; i < rem; i++) {
+ if (rt_i2c_wait_rx_done())
+ return -1;
+ msg->buf[pos++] = rt_i2c_r32(REG_DATAIN_REG);
+ }
+ } else {
+ rt_i2c_wait_idle();
+ rt_i2c_w32(msg->len - 1, REG_BYTECNT_REG);
+ for (i = 0; i < msg->len; i++) {
+ rt_i2c_w32(msg->buf[i], REG_DATAOUT_REG);
+ rt_i2c_w32(WRITE_CMD, REG_STARTXFR_REG);
+ if (rt_i2c_wait_tx_done())
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int rt_i2c_master_xfer(struct i2c_adapter *a, struct i2c_msg *m, int n)
+{
+ int i = 0;
+ int ret = 0;
+
+ if (rt_i2c_wait_idle()) {
+ printk("i2c transfer failed\n");
+ return 0;
+ }
+
+ device_reset(a->dev.parent);
+
+ rt_i2c_w32(m->addr, REG_DEVADDR_REG);
+ rt_i2c_w32(I2C_DEVADLEN_7 | I2C_ADDRDIS, REG_CONFIG_REG);
+ rt_i2c_w32(CLKDIV_VALUE, REG_CLKDIV_REG);
+
+ for (i = 0; i < n && !ret; i++)
+ ret = rt_i2c_handle_msg(a, &m[i]);
+
+ if (ret) {
+ printk("i2c transfer failed\n");
+ return 0;
+ }
+
+ return n;
+}
+
+static u32 rt_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm rt_i2c_algo = {
+ .master_xfer = rt_i2c_master_xfer,
+ .functionality = rt_i2c_func,
+};
+
+static int rt_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int ret;
+
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ return -ENODEV;
+ }
+
+ adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!adapter) {
+ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n");
+ return -ENOMEM;
+ }
+
+ membase = devm_request_and_ioremap(&pdev->dev, res);
+ if (IS_ERR(membase))
+ return PTR_ERR(membase);
+
+ strlcpy(adapter->name, dev_name(&pdev->dev), sizeof(adapter->name));
+ adapter->owner = THIS_MODULE;
+ adapter->nr = pdev->id;
+ adapter->timeout = HZ;
+ adapter->algo = &rt_i2c_algo;
+ adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ adapter->dev.parent = &pdev->dev;
+ adapter->dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_numbered_adapter(adapter);
+ if (ret)
+ return ret;
+
+ of_i2c_register_devices(adapter);
+
+ platform_set_drvdata(pdev, adapter);
+
+ dev_info(&pdev->dev, "loaded\n");
+
+ return 0;
+}
+
+static int rt_i2c_remove(struct platform_device *pdev)
+{
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id i2c_rt_dt_ids[] = {
+ { .compatible = "ralink,rt2880-i2c", },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
+
+static struct platform_driver rt_i2c_driver = {
+ .probe = rt_i2c_probe,
+ .remove = rt_i2c_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-ralink",
+ .of_match_table = i2c_rt_dt_ids,
+ },
+};
+
+static int __init i2c_rt_init (void)
+{
+ return platform_driver_register(&rt_i2c_driver);
+}
+subsys_initcall(i2c_rt_init);
+
+static void __exit i2c_rt_exit (void)
+{
+ platform_driver_unregister(&rt_i2c_driver);
+}
+
+module_exit (i2c_rt_exit);
+
+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
+MODULE_DESCRIPTION("Ralink I2c host driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:Ralink-I2C");
--
1.7.10.4

View File

@ -0,0 +1,135 @@
From 0cc20912b376305452cdc5c8e7b97e156ba90e93 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 8 May 2013 22:08:39 +0200
Subject: [PATCH 28/33] reset: MIPS: ralink: add core/device reset wrapper
Add a helper for reseting different devices ont he SoC.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/Kconfig | 1 +
arch/mips/ralink/of.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
arch/mips/ralink/reset.c | 1 +
3 files changed, 61 insertions(+)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 5737c4b..8258e8e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -444,6 +444,7 @@ config RALINK
select HAVE_MACH_CLKDEV
select CLKDEV_LOOKUP
select ARCH_REQUIRE_GPIOLIB
+ select ARCH_HAS_RESET_CONTROLLER
config SGI_IP22
bool "SGI IP22 (Indy/Indigo2)"
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index 8efb02b..2faf478 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -14,16 +14,22 @@
#include <linux/sizes.h>
#include <linux/of_fdt.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/bootmem.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
+#include <linux/reset-controller.h>
#include <asm/reboot.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
+#include <asm/mach-ralink/ralink_regs.h>
+
#include "common.h"
+#define SYSC_REG_RESET_CTRL 0x034
+
__iomem void *rt_sysc_membase;
__iomem void *rt_memc_membase;
@@ -96,6 +102,53 @@ void __init plat_mem_setup(void)
soc_info.mem_size_max * SZ_1M);
}
+static int ralink_assert_device(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 val;
+
+ if (id < 8)
+ return -1;
+
+ val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+ val |= BIT(id);
+ rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
+
+ return 0;
+}
+
+static int ralink_deassert_device(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 val;
+
+ if (id < 8)
+ return -1;
+
+ val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+ val &= ~BIT(id);
+ rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
+
+ return 0;
+}
+
+static int ralink_reset_device(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ ralink_assert_device(rcdev, id);
+ return ralink_deassert_device(rcdev, id);
+}
+
+static struct reset_control_ops reset_ops = {
+ .reset = ralink_reset_device,
+ .assert = ralink_assert_device,
+ .deassert = ralink_deassert_device,
+};
+
+static struct reset_controller_dev reset_dev = {
+ .ops = &reset_ops,
+ .owner = THIS_MODULE,
+ .nr_resets = 32,
+ .of_reset_n_cells = 1,
+};
+
static int __init plat_of_setup(void)
{
static struct of_device_id of_ids[3];
@@ -110,6 +163,12 @@ static int __init plat_of_setup(void)
if (of_platform_populate(NULL, of_ids, NULL, NULL))
panic("failed to populate DT\n");
+ reset_dev.of_node = of_find_compatible_node(NULL, NULL, "ralink,rt2880-reset");
+ if (!reset_dev.of_node)
+ panic("Failed to find reset controller node");
+
+ reset_controller_register(&reset_dev);
+
ralink_pinmux();
return 0;
diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c
index 22120e5..6c15f4f 100644
--- a/arch/mips/ralink/reset.c
+++ b/arch/mips/ralink/reset.c
@@ -10,6 +10,7 @@
#include <linux/pm.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/reboot.h>
--
1.7.10.4

View File

@ -0,0 +1,338 @@
From 8f3ed1fffa35d18c2b20ebb866c71a22cc0589ff Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 23 Jun 2013 00:16:22 +0200
Subject: [PATCH 29/33] owrt: GPIO: add gpio_export_with_name
http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/133856.html
Signed-off-by: John Crispin <blogic@openwrt.org>
---
Documentation/devicetree/bindings/gpio/gpio.txt | 60 ++++++++++++++++++++
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++
drivers/gpio/gpiolib.c | 24 +++++---
include/asm-generic/gpio.h | 6 +-
include/linux/gpio.h | 26 ++++++++-
5 files changed, 172 insertions(+), 12 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index d933af3..c264748 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -112,3 +112,63 @@ where,
The pinctrl node must have "#gpio-range-cells" property to show number of
arguments to pass with phandle from gpio controllers node.
+
+3) gpio-export
+--------------
+
+gpio-export will allow you to automatically export gpio
+
+required properties:
+- compatible: Should be "gpio-export"
+
+in each child node will reprensent a gpio or if no name is specified
+a list of gpio to export
+
+required properties:
+- gpios: gpio to export
+
+optional properties:
+ - gpio-export,name: export name
+ - gpio-export,output: to set the as output with default value
+ if no present gpio as input
+ - pio-export,direction_may_change: boolean to allow the direction to be controllable
+
+Example:
+
+
+gpio_export {
+ compatible = "gpio-export";
+ #size-cells = <0>;
+
+ in {
+ gpio-export,name = "in";
+ gpios = <&pioC 20 0>;
+ };
+
+ out {
+ gpio-export,name = "out";
+ gpio-export,output = <1>;
+ gpio-export,direction_may_change;
+ gpios = <&pioC 21 0>;
+ };
+
+ in_out {
+ gpio-export,name = "in_out";
+ gpio-export,direction_may_change;
+ gpios = <&pioC 21 0>;
+ };
+
+ gpios_in {
+ gpios = <&pioB 0 0
+ &pioB 3 0
+ &pioC 4 0>;
+ gpio-export,direction_may_change;
+ };
+
+ gpios_out {
+ gpios = <&pioB 1 0
+ &pioB 2 0
+ &pioC 3 0>;
+ gpio-export,output = <1>;
+ };
+};
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 665f953..15ec5e5 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -21,6 +21,8 @@
#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
/* Private data structure for of_gpiochip_find_and_xlate */
struct gg_data {
@@ -242,3 +244,69 @@ void of_gpiochip_remove(struct gpio_chip *chip)
if (chip->of_node)
of_node_put(chip->of_node);
}
+
+static struct of_device_id gpio_export_ids[] = {
+ { .compatible = "gpio-export" },
+ { /* sentinel */ }
+};
+
+static int __init of_gpio_export_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ u32 val;
+ int nb = 0;
+
+ for_each_child_of_node(np, cnp) {
+ const char *name = NULL;
+ int gpio;
+ bool dmc;
+ int max_gpio = 1;
+ int i;
+
+ of_property_read_string(cnp, "gpio-export,name", &name);
+
+ if (!name)
+ max_gpio = of_gpio_count(cnp);
+
+ for (i = 0; i < max_gpio; i++) {
+ unsigned flags = 0;
+ enum of_gpio_flags of_flags;
+
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
+
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ else
+ flags |= GPIOF_IN;
+
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
+ continue;
+
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
+ gpio_export_with_name(gpio, dmc, name);
+ nb++;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
+
+ return 0;
+}
+
+static struct platform_driver gpio_export_driver = {
+ .driver = {
+ .name = "gpio-export",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_export_ids),
+ },
+};
+
+static int __init of_gpio_export_init(void)
+{
+ return platform_driver_probe(&gpio_export_driver, of_gpio_export_probe);
+}
+device_initcall(of_gpio_export_init);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c2534d6..8697c82 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -96,7 +96,7 @@ static int gpiod_get_value(const struct gpio_desc *desc);
static void gpiod_set_value(struct gpio_desc *desc, int value);
static int gpiod_cansleep(const struct gpio_desc *desc);
static int gpiod_to_irq(const struct gpio_desc *desc);
-static int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+static int gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
static int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
@@ -674,7 +674,7 @@ static ssize_t export_store(struct class *class,
status = -ENODEV;
goto done;
}
- status = gpiod_export(desc, true);
+ status = gpiod_export(desc, true, NULL);
if (status < 0)
gpiod_free(desc);
else
@@ -736,9 +736,10 @@ static struct class gpio_class = {
/**
- * gpio_export - export a GPIO through sysfs
+ * gpio_export_with_name - export a GPIO through sysfs
* @gpio: gpio to make available, already requested
* @direction_may_change: true if userspace may change gpio direction
+ * @name: gpio name
* Context: arch_initcall or later
*
* When drivers want to make a GPIO accessible to userspace after they
@@ -750,7 +751,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+static int gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
{
unsigned long flags;
int status;
@@ -783,6 +784,8 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
goto fail_unlock;
}
+ if (name)
+ ioname = name;
if (!desc->chip->direction_input || !desc->chip->direction_output)
direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -829,11 +832,11 @@ fail_unlock:
return status;
}
-int gpio_export(unsigned gpio, bool direction_may_change)
+int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
{
- return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ return gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
}
-EXPORT_SYMBOL_GPL(gpio_export);
+EXPORT_SYMBOL_GPL(gpio_export_with_name);
static int match_export(struct device *dev, const void *data)
{
@@ -1092,7 +1095,7 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
}
static inline int gpiod_export(struct gpio_desc *desc,
- bool direction_may_change)
+ bool direction_may_change, const char *name)
{
return -ENOSYS;
}
@@ -1521,6 +1524,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
if (flags & GPIOF_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ if (flags & GPIOF_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &gpio_desc[gpio].flags);
+
if (flags & GPIOF_DIR_IN)
err = gpiod_direction_input(desc);
else
@@ -1531,7 +1537,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
goto free_gpio;
if (flags & GPIOF_EXPORT) {
- err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
+ err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE, NULL);
if (err)
goto free_gpio;
}
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index bde6469..3290572 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -202,7 +202,8 @@ extern void gpio_free_array(const struct gpio *array, size_t num);
* A sysfs interface can be exported by individual drivers if they want,
* but more typically is configured entirely from userspace.
*/
-extern int gpio_export(unsigned gpio, bool direction_may_change);
+extern int gpio_export_with_name(unsigned gpio, bool direction_may_change,
+ const char *name);
extern int gpio_export_link(struct device *dev, const char *name,
unsigned gpio);
extern int gpio_sysfs_set_active_low(unsigned gpio, int value);
@@ -284,7 +285,8 @@ struct device;
/* sysfs support is only available with gpiolib, where it's optional */
-static inline int gpio_export(unsigned gpio, bool direction_may_change)
+static inline int gpio_export_with_name(unsigned gpio,
+ bool direction_may_change, const char *name)
{
return -ENOSYS;
}
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 552e3f4..07bbbcc7 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -27,6 +27,9 @@
#define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
#define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
+#define GPIOF_ACTIVE_LOW (1 << 6)
+
+
/**
* struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number
@@ -169,7 +172,8 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
WARN_ON(1);
}
-static inline int gpio_export(unsigned gpio, bool direction_may_change)
+static inline int gpio_export_with_name(unsigned gpio,
+ bool direction_may_change, const char *name)
{
/* GPIO can never have been requested or set as {in,out}put */
WARN_ON(1);
@@ -236,4 +240,24 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio);
+/**
+ * gpio_export - export a GPIO through sysfs
+ * @gpio: gpio to make available, already requested
+ * @direction_may_change: true if userspace may change gpio direction
+ * Context: arch_initcall or later
+ *
+ * When drivers want to make a GPIO accessible to userspace after they
+ * have requested it -- perhaps while debugging, or as part of their
+ * public interface -- they may use this routine. If the GPIO can
+ * change direction (some can't) and the caller allows it, userspace
+ * will see "direction" sysfs attribute which may be used to change
+ * the gpio's direction. A "value" attribute will always be provided.
+ *
+ * Returns zero on success, else an error.
+ */
+static inline int gpio_export(unsigned gpio,bool direction_may_change)
+{
+ return gpio_export_with_name(gpio, direction_may_change, NULL);
+}
+
#endif /* __LINUX_GPIO_H */
--
1.7.10.4

View File

@ -0,0 +1,306 @@
From daf08289dc0ac69af0d8293dacd5ca6291400593 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 24 Mar 2013 17:17:17 +0100
Subject: [PATCH 30/33] owrt: MIPS: ralink: add pseudo pwm led trigger based
on timer0
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/ralink/timer.c | 213 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 197 insertions(+), 16 deletions(-)
diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c
index 0a6856c..b156419 100644
--- a/arch/mips/ralink/timer.c
+++ b/arch/mips/ralink/timer.c
@@ -12,6 +12,8 @@
#include <linux/timer.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
#include <asm/mach-ralink/ralink_regs.h>
@@ -23,16 +25,34 @@
#define TMR0CTL_ENABLE BIT(7)
#define TMR0CTL_MODE_PERIODIC BIT(4)
-#define TMR0CTL_PRESCALER 1
+#define TMR0CTL_PRESCALER 2
#define TMR0CTL_PRESCALE_VAL (0xf - TMR0CTL_PRESCALER)
#define TMR0CTL_PRESCALE_DIV (65536 / BIT(TMR0CTL_PRESCALER))
+struct rt_timer_gpio {
+ struct list_head list;
+ struct led_classdev *led;
+};
+
struct rt_timer {
- struct device *dev;
- void __iomem *membase;
- int irq;
- unsigned long timer_freq;
- unsigned long timer_div;
+ struct device *dev;
+ void __iomem *membase;
+ int irq;
+
+ unsigned long timer_freq;
+ unsigned long timer_div;
+
+ struct list_head gpios;
+ struct led_trigger led_trigger;
+ unsigned int duty_cycle;
+ unsigned int duty;
+
+ unsigned int fade;
+ unsigned int fade_min;
+ unsigned int fade_max;
+ unsigned int fade_speed;
+ unsigned int fade_dir;
+ unsigned int fade_count;
};
static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val)
@@ -48,18 +68,46 @@ static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg)
static irqreturn_t rt_timer_irq(int irq, void *_rt)
{
struct rt_timer *rt = (struct rt_timer *) _rt;
+ struct rt_timer_gpio *gpio;
+ unsigned int val;
- rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+ if (rt->fade && (rt->fade_count++ > rt->fade_speed)) {
+ rt->fade_count = 0;
+ if (rt->duty_cycle <= rt->fade_min)
+ rt->fade_dir = 1;
+ else if (rt->duty_cycle >= rt->fade_max)
+ rt->fade_dir = 0;
+
+ if (rt->fade_dir)
+ rt->duty_cycle += 1;
+ else
+ rt->duty_cycle -= 1;
+
+ }
+
+ val = rt->timer_freq / rt->timer_div;
+ if (rt->duty)
+ val *= rt->duty_cycle;
+ else
+ val *= (100 - rt->duty_cycle);
+ val /= 100;
+
+ if (!list_empty(&rt->gpios))
+ list_for_each_entry(gpio, &rt->gpios, list)
+ led_set_brightness(gpio->led, !!rt->duty);
+
+ rt->duty = !rt->duty;
+
+ rt_timer_w32(rt, TIMER_REG_TMR0LOAD, val + 1);
rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT);
return IRQ_HANDLED;
}
-
static int rt_timer_request(struct rt_timer *rt)
{
- int err = request_irq(rt->irq, rt_timer_irq, IRQF_DISABLED,
- dev_name(rt->dev), rt);
+ int err = devm_request_irq(rt->dev, rt->irq, rt_timer_irq,
+ IRQF_DISABLED, dev_name(rt->dev), rt);
if (err) {
dev_err(rt->dev, "failed to request irq\n");
} else {
@@ -81,8 +129,6 @@ static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
else
rt->timer_div = divisor;
- rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
-
return 0;
}
@@ -108,11 +154,128 @@ static void rt_timer_disable(struct rt_timer *rt)
rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
}
+static ssize_t led_fade_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+
+ return sprintf(buf, "speed: %d, min: %d, max: %d\n", rt->fade_speed, rt->fade_min, rt->fade_max);
+}
+
+static ssize_t led_fade_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+ unsigned int speed = 0, min = 0, max = 0;
+ ssize_t ret = -EINVAL;
+
+ ret = sscanf(buf, "%u %u %u", &speed, &min, &max);
+
+ if (ret == 3) {
+ rt->fade_speed = speed;
+ rt->fade_min = min;
+ rt->fade_max = max;
+ rt->fade = 1;
+ } else {
+ rt->fade = 0;
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(fade, 0644, led_fade_show, led_fade_store);
+
+static ssize_t led_duty_cycle_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+
+ return sprintf(buf, "%u\n", rt->duty_cycle);
+}
+
+static ssize_t led_duty_cycle_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+ unsigned long state;
+ ssize_t ret = -EINVAL;
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ return ret;
+
+ if (state <= 100)
+ rt->duty_cycle = state;
+ else
+ rt->duty_cycle = 100;
+
+ rt->fade = 0;
+
+ return size;
+}
+
+static DEVICE_ATTR(duty_cycle, 0644, led_duty_cycle_show, led_duty_cycle_store);
+
+static void rt_timer_trig_activate(struct led_classdev *led_cdev)
+{
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+ struct rt_timer_gpio *gpio_data;
+ int rc;
+
+ led_cdev->trigger_data = NULL;
+ gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
+ if (!gpio_data)
+ return;
+
+ rc = device_create_file(led_cdev->dev, &dev_attr_duty_cycle);
+ if (rc)
+ goto err_gpio;
+ rc = device_create_file(led_cdev->dev, &dev_attr_fade);
+ if (rc)
+ goto err_out_duty_cycle;
+
+ led_cdev->activated = true;
+ led_cdev->trigger_data = gpio_data;
+ gpio_data->led = led_cdev;
+ list_add(&gpio_data->list, &rt->gpios);
+ led_cdev->trigger_data = gpio_data;
+ rt_timer_enable(rt);
+ return;
+
+err_out_duty_cycle:
+ device_remove_file(led_cdev->dev, &dev_attr_duty_cycle);
+
+err_gpio:
+ kfree(gpio_data);
+}
+
+static void rt_timer_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct rt_timer *rt = container_of(led_cdev->trigger, struct rt_timer, led_trigger);
+ struct rt_timer_gpio *gpio_data = (struct rt_timer_gpio*) led_cdev->trigger_data;
+
+ if (led_cdev->activated) {
+ device_remove_file(led_cdev->dev, &dev_attr_duty_cycle);
+ device_remove_file(led_cdev->dev, &dev_attr_fade);
+ led_cdev->activated = false;
+ }
+
+ list_del(&gpio_data->list);
+ rt_timer_disable(rt);
+ led_set_brightness(led_cdev, LED_OFF);
+}
+
static int rt_timer_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ const __be32 *divisor;
struct rt_timer *rt;
struct clk *clk;
+ int ret;
if (!res) {
dev_err(&pdev->dev, "no memory resource found\n");
@@ -147,12 +310,29 @@ static int rt_timer_probe(struct platform_device *pdev)
if (!rt->timer_freq)
return -EINVAL;
+ rt->duty_cycle = 100;
rt->dev = &pdev->dev;
platform_set_drvdata(pdev, rt);
- rt_timer_request(rt);
- rt_timer_config(rt, 2);
- rt_timer_enable(rt);
+ ret = rt_timer_request(rt);
+ if (ret)
+ return ret;
+
+ divisor = of_get_property(pdev->dev.of_node, "ralink,divisor", NULL);
+ if (divisor)
+ rt_timer_config(rt, be32_to_cpu(*divisor));
+ else
+ rt_timer_config(rt, 200);
+
+ rt->led_trigger.name = "pwmtimer",
+ rt->led_trigger.activate = rt_timer_trig_activate,
+ rt->led_trigger.deactivate = rt_timer_trig_deactivate,
+
+ ret = led_trigger_register(&rt->led_trigger);
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&rt->gpios);
dev_info(&pdev->dev, "maximum frequncy is %luHz\n", rt->timer_freq);
@@ -163,6 +343,7 @@ static int rt_timer_remove(struct platform_device *pdev)
{
struct rt_timer *rt = platform_get_drvdata(pdev);
+ led_trigger_unregister(&rt->led_trigger);
rt_timer_disable(rt);
rt_timer_free(rt);
@@ -187,6 +368,6 @@ static struct platform_driver rt_timer_driver = {
module_platform_driver(rt_timer_driver);
-MODULE_DESCRIPTION("Ralink RT2880 timer");
+MODULE_DESCRIPTION("Ralink RT2880 timer / pseudo pwm");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
MODULE_LICENSE("GPL");
--
1.7.10.4

View File

@ -0,0 +1,61 @@
From c174d2250e402399ad7dbdd57d51883d8804bba0 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 15 Jul 2013 00:40:37 +0200
Subject: [PATCH 31/33] owrt: MIPS: add OWRTDTB secion
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/kernel/head.S | 3 +++
arch/mips/ralink/Makefile | 2 +-
arch/mips/ralink/of.c | 4 +++-
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index c61cdae..b4e55bb 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -140,6 +140,9 @@ FEXPORT(__kernel_entry)
j kernel_entry
#endif
+ .ascii "OWRTDTB:"
+ EXPORT(__image_dtb)
+ .fill 0x4000
__REF
NESTED(kernel_entry, 16, sp) # kernel entry point
diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile
index 03af636..9b32626 100644
--- a/arch/mips/ralink/Makefile
+++ b/arch/mips/ralink/Makefile
@@ -19,4 +19,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_DEBUG_FS) += bootrom.o
-obj-y += dts/
+#obj-y += dts/
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index 2faf478..d87222f 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -83,6 +83,8 @@ void __init device_tree_init(void)
//free_bootmem(base, size);
}
+extern struct boot_param_header __image_dtb;
+
void __init plat_mem_setup(void)
{
set_io_port_base(KSEG1);
@@ -91,7 +93,7 @@ void __init plat_mem_setup(void)
* Load the builtin devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
- __dt_setup_arch(&__dtb_start);
+ __dt_setup_arch(&__image_dtb);
if (soc_info.mem_size)
add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M,
--
1.7.10.4

View File

@ -0,0 +1,34 @@
From 413b2ed67d8e4dc1242edb9286ea3f634d10a6ba Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 15 Jul 2013 00:38:51 +0200
Subject: [PATCH 32/33] mtd: fix cfi cmdset 0002 erase status check
---
drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fff665d..ab8eb03 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1956,7 +1956,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr))
+ if (chip_good(map, adr, map_word_ff(map)))
break;
if (time_after(jiffies, timeo)) {
@@ -2045,7 +2045,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr)) {
+ if (chip_good(map, adr, map_word_ff(map))) {
xip_enable(map, chip, adr);
break;
}
--
1.7.10.4

View File

@ -0,0 +1,75 @@
From d5b094ea6d435817d295d554d652a97a5014c64f Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 15 Jul 2013 00:39:21 +0200
Subject: [PATCH 33/33] mtd: cfi cmdset 0002 force word write
---
drivers/mtd/chips/cfi_cmdset_0002.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index ab8eb03..d84668d 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -41,7 +41,7 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
-#define FORCE_WORD_WRITE 0
+#define FORCE_WORD_WRITE 1
#define MAX_WORD_RETRIES 3
@@ -52,7 +52,9 @@
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+#if !FORCE_WORD_WRITE
static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+#endif
static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_amdstd_sync (struct mtd_info *);
@@ -192,6 +194,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd)
}
#endif
+#if !FORCE_WORD_WRITE
static void fixup_use_write_buffers(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
@@ -201,6 +204,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd)
mtd->_write = cfi_amdstd_write_buffers;
}
}
+#endif /* !FORCE_WORD_WRITE */
/* Atmel chips don't use the same PRI format as AMD chips */
static void fixup_convert_atmel_pri(struct mtd_info *mtd)
@@ -1461,6 +1465,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
/*
* FIXME: interleaved mode not tested, and probably not supported!
*/
+#if !FORCE_WORD_WRITE
static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
unsigned long adr, const u_char *buf,
int len)
@@ -1584,7 +1589,6 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
return ret;
}
-
static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -1659,6 +1663,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
return 0;
}
+#endif /* !FORCE_WORD_WRITE */
/*
* Wait for the flash chip to become ready to write data
--
1.7.10.4

View File

@ -0,0 +1,15 @@
Index: linux-3.10.1/drivers/mtd/mtdpart.c
===================================================================
--- linux-3.10.1.orig/drivers/mtd/mtdpart.c 2013-07-15 11:39:25.376669514 +0200
+++ linux-3.10.1/drivers/mtd/mtdpart.c 2013-07-15 11:49:53.040684471 +0200
@@ -807,10 +807,6 @@
return;
len = be32_to_cpu(hdr.size) + 0x40;
- len = mtd_pad_erasesize(master, part->offset, len);
- if (len + master->erasesize > part->mtd.size)
- return;
-
__mtd_add_partition(master, "rootfs", part->offset + len,
part->mtd.size - len, false);
}

View File

@ -0,0 +1,152 @@
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CEVT_R4K=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKEVT_RT3352=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLKSRC_OF=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
CONFIG_CMDLINE_BOOL=y
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CSRC_R4K=y
CONFIG_DMA_NONCOHERENT=y
# CONFIG_DTB_RT305X_EVAL is not set
CONFIG_DTB_RT_NONE=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_RALINK=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_MACH_CLKDEV=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HW_RANDOM=m
CONFIG_HZ_PERIODIC=y
CONFIG_IMAGE_CMDLINE_HACK=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_CPU=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_M25PXX_USE_FAST_READ=y
CONFIG_MDIO_BOARDINFO=y
# CONFIG_MII is not set
CONFIG_MIPS=y
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT_DISABLED=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_OF=y
CONFIG_MTD_UIMAGE_SPLIT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
# CONFIG_NET_IP_TUNNEL is not set
CONFIG_NET_RALINK=y
CONFIG_NET_RALINK_ESW_RT3052=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_DEVICE=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_MTD=y
CONFIG_OF_NET=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
# CONFIG_PREEMPT_RCU is not set
CONFIG_RALINK=y
CONFIG_RALINK_WDT=y
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RESET_CONTROLLER=y
# CONFIG_SCSI_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=4
CONFIG_SERIAL_8250_RT288X=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_SLAB is not set
CONFIG_SLUB=y
# CONFIG_SOC_MT7620 is not set
# CONFIG_SOC_RT288X is not set
CONFIG_SOC_RT305X=y
# CONFIG_SOC_RT3883 is not set
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_RALINK=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_UIDGID_CONVERTED=y
# CONFIG_USB_ARCH_HAS_XHCI is not set
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_ZONE_DMA_FLAG=0