* [PATCH 00/10] MIPS: add support for Lantiq SoCs
@ 2011-01-05 19:56 John Crispin
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
` (10 more replies)
0 siblings, 11 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
This series will add support for the Lantiq/XWAY family of SoCs.
Cc: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
John Crispin (10):
MIPS: lantiq: add initial support for Lantiq SoCs
MIPS: lantiq: add SoC specific code for XWAY family
MIPS: lantiq: add PCI controller support.
MIPS: lantiq: add serial port support
MIPS: lantiq: add watchdog support
MIPS: lantiq: add NOR flash support
MIPS: lantiq: add NOR flash CFI address swizzle
MIPS: lantiq: add platform device support
MIPS: lantiq: add mips_machine support
MIPS: lantiq: add machtypes for lantiq eval kits
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 18 +
arch/mips/include/asm/mach-lantiq/lantiq.h | 48 ++
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 25 +
arch/mips/include/asm/mach-lantiq/war.h | 24 +
arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 +
.../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 62 ++
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 119 +++
arch/mips/lantiq/Kconfig | 23 +
arch/mips/lantiq/Makefile | 11 +
arch/mips/lantiq/Platform | 8 +
arch/mips/lantiq/clk.c | 129 ++++
arch/mips/lantiq/clk.h | 18 +
arch/mips/lantiq/devices.c | 127 ++++
arch/mips/lantiq/devices.h | 20 +
arch/mips/lantiq/early_printk.c | 47 ++
arch/mips/lantiq/irq.c | 209 ++++++
arch/mips/lantiq/machtypes.h | 20 +
arch/mips/lantiq/prom.c | 84 +++
arch/mips/lantiq/prom.h | 26 +
arch/mips/lantiq/setup.c | 70 ++
arch/mips/lantiq/xway/Kconfig | 25 +
arch/mips/lantiq/xway/Makefile | 7 +
arch/mips/lantiq/xway/clk-ase.c | 53 ++
arch/mips/lantiq/xway/clk-xway.c | 221 ++++++
arch/mips/lantiq/xway/devices.c | 55 ++
arch/mips/lantiq/xway/devices.h | 16 +
arch/mips/lantiq/xway/gpio.c | 205 ++++++
arch/mips/lantiq/xway/mach-easy50601.c | 70 ++
arch/mips/lantiq/xway/mach-easy50712.c | 70 ++
arch/mips/lantiq/xway/pmu.c | 36 +
arch/mips/lantiq/xway/prom-ase.c | 41 +
arch/mips/lantiq/xway/prom-xway.c | 56 ++
arch/mips/lantiq/xway/reset.c | 53 ++
arch/mips/pci/Makefile | 1 +
arch/mips/pci/ops-lantiq.c | 118 +++
arch/mips/pci/pci-lantiq.c | 286 ++++++++
arch/mips/pci/pci-lantiq.h | 18 +
drivers/mtd/chips/Kconfig | 9 +
drivers/mtd/chips/cfi_cmdset_0002.c | 8 +
drivers/mtd/maps/Kconfig | 7 +
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/lantiq.c | 169 +++++
drivers/serial/Kconfig | 8 +
drivers/serial/Makefile | 1 +
drivers/serial/lantiq.c | 774 ++++++++++++++++++++
drivers/watchdog/Kconfig | 6 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/lantiq_wdt.c | 208 ++++++
49 files changed, 3630 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h
create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
create mode 100644 arch/mips/lantiq/Kconfig
create mode 100644 arch/mips/lantiq/Makefile
create mode 100644 arch/mips/lantiq/Platform
create mode 100644 arch/mips/lantiq/clk.c
create mode 100644 arch/mips/lantiq/clk.h
create mode 100644 arch/mips/lantiq/devices.c
create mode 100644 arch/mips/lantiq/devices.h
create mode 100644 arch/mips/lantiq/early_printk.c
create mode 100644 arch/mips/lantiq/irq.c
create mode 100644 arch/mips/lantiq/machtypes.h
create mode 100644 arch/mips/lantiq/prom.c
create mode 100644 arch/mips/lantiq/prom.h
create mode 100644 arch/mips/lantiq/setup.c
create mode 100644 arch/mips/lantiq/xway/Kconfig
create mode 100644 arch/mips/lantiq/xway/Makefile
create mode 100644 arch/mips/lantiq/xway/clk-ase.c
create mode 100644 arch/mips/lantiq/xway/clk-xway.c
create mode 100644 arch/mips/lantiq/xway/devices.c
create mode 100644 arch/mips/lantiq/xway/devices.h
create mode 100644 arch/mips/lantiq/xway/gpio.c
create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c
create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c
create mode 100644 arch/mips/lantiq/xway/pmu.c
create mode 100644 arch/mips/lantiq/xway/prom-ase.c
create mode 100644 arch/mips/lantiq/xway/prom-xway.c
create mode 100644 arch/mips/lantiq/xway/reset.c
create mode 100644 arch/mips/pci/ops-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.h
create mode 100644 drivers/mtd/maps/lantiq.c
create mode 100644 drivers/serial/lantiq.c
create mode 100644 drivers/watchdog/lantiq_wdt.c
--
1.7.2.3
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 20:25 ` Geert Uytterhoeven
2011-01-13 11:05 ` Daniel Schwierzeck
2011-01-05 19:56 ` [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family John Crispin
` (9 subsequent siblings)
10 siblings, 2 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
Add initial support for Mips based SoCs made by Lantiq. This series will add
support for the XWAY family.
The series allows booting a minimal system using a initramfs or NOR. Missing
drivers and support for Amazon and GPON family will be provided in a later
series.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
---
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 16 ++
arch/mips/include/asm/mach-lantiq/lantiq.h | 48 +++++++
arch/mips/include/asm/mach-lantiq/war.h | 24 +++
arch/mips/lantiq/Makefile | 9 ++
arch/mips/lantiq/Platform | 7 +
arch/mips/lantiq/clk.c | 129 +++++++++++++++++
arch/mips/lantiq/clk.h | 18 +++
arch/mips/lantiq/early_printk.c | 47 ++++++
arch/mips/lantiq/irq.c | 209 ++++++++++++++++++++++++++++
arch/mips/lantiq/prom.c | 84 +++++++++++
arch/mips/lantiq/prom.h | 26 ++++
arch/mips/lantiq/setup.c | 45 ++++++
13 files changed, 663 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
create mode 100644 arch/mips/lantiq/Makefile
create mode 100644 arch/mips/lantiq/Platform
create mode 100644 arch/mips/lantiq/clk.c
create mode 100644 arch/mips/lantiq/clk.h
create mode 100644 arch/mips/lantiq/early_printk.c
create mode 100644 arch/mips/lantiq/irq.c
create mode 100644 arch/mips/lantiq/prom.c
create mode 100644 arch/mips/lantiq/prom.h
create mode 100644 arch/mips/lantiq/setup.c
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index 78439b8..8b7c26f 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -10,6 +10,7 @@ platforms += dec
platforms += emma
platforms += jazz
platforms += jz4740
+platforms += lantiq
platforms += lasat
platforms += loongson
platforms += mipssim
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 913d50d..a2396f1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -192,6 +192,22 @@ config MACH_JZ4740
select SYS_HAS_EARLY_PRINTK
select HAVE_PWM
+config LANTIQ
+ bool "Lantiq based platforms"
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select CEVT_R4K
+ select CSRC_R4K
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MULTITHREADING
+ select SYS_HAS_EARLY_PRINTK
+ select ARCH_REQUIRE_GPIOLIB
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+
config LASAT
bool "LASAT Networks platforms"
select CEVT_R4K
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
new file mode 100644
index 0000000..54eb033
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_H__
+#define _LANTIQ_H__
+
+/* generic reg access functions */
+#define ltq_r32(reg) __raw_readl(reg)
+#define ltq_w32(val, reg) __raw_writel(val, reg)
+#define ltq_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(reg) & ~clear) | set, reg)
+
+extern unsigned int ltq_get_cpu_ver(void);
+extern unsigned int ltq_get_soc_type(void);
+
+/* clock speeds */
+#define CLOCK_60M 60000000
+#define CLOCK_83M 83333333
+#define CLOCK_111M 111111111
+#define CLOCK_133M 133333333
+#define CLOCK_167M 166666667
+#define CLOCK_200M 200000000
+#define CLOCK_266M 266666666
+#define CLOCK_333M 333333333
+#define CLOCK_400M 400000000
+
+/* spinlock all ebu i/o */
+extern spinlock_t ebu_lock;
+
+/* some irq helpers */
+extern void ltq_disable_irq(unsigned int irq_nr);
+extern void ltq_mask_and_ack_irq(unsigned int irq_nr);
+extern void ltq_enable_irq(unsigned int irq_nr);
+
+#define IOPORT_RESOURCE_START 0x10000000
+#define IOPORT_RESOURCE_END 0xffffffff
+#define IOMEM_RESOURCE_START 0x10000000
+#define IOMEM_RESOURCE_END 0xffffffff
+
+#define LTQ_FLASH_START 0x10000000
+#define LTQ_FLASH_MAX 0x04000000
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h
new file mode 100644
index 0000000..01b08ef
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/war.h
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H
+#define __ASM_MIPS_MACH_LANTIQ_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
new file mode 100644
index 0000000..6a30de6
--- /dev/null
+++ b/arch/mips/lantiq/Makefile
@@ -0,0 +1,9 @@
+# Copyright (C) 2010 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.
+
+obj-y := irq.o setup.o clk.o prom.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
new file mode 100644
index 0000000..eef587f
--- /dev/null
+++ b/arch/mips/lantiq/Platform
@@ -0,0 +1,7 @@
+#
+# Lantiq
+#
+
+platform-$(CONFIG_LANTIQ) += lantiq/
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+load-$(CONFIG_LANTIQ) = 0xffffffff80002000
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
new file mode 100644
index 0000000..4283d92
--- /dev/null
+++ b/arch/mips/lantiq/clk.c
@@ -0,0 +1,129 @@
+/*
+ * 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) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq.h>
+
+#include "clk.h"
+
+struct clk {
+ const char *name;
+ unsigned long rate;
+ unsigned long (*get_rate) (void);
+};
+
+static struct clk *cpu_clk;
+static int cpu_clk_cnt;
+
+static unsigned int r4k_offset;
+static unsigned int r4k_cur;
+
+static struct clk cpu_clk_generic[] = {
+ {
+ .name = "cpu",
+ .get_rate = ltq_get_cpu_hz,
+ }, {
+ .name = "fpi",
+ .get_rate = ltq_get_fpi_hz,
+ }, {
+ .name = "io",
+ .get_rate = ltq_get_io_region_clock,
+ },
+};
+
+void
+clk_init(void)
+{
+ int i;
+ cpu_clk = cpu_clk_generic;
+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
+ for (i = 0; i < cpu_clk_cnt; i++)
+ printk(KERN_INFO "%s: %ld\n",
+ cpu_clk[i].name, clk_get_rate(&cpu_clk[i]));
+}
+
+static inline int
+clk_good(struct clk *clk)
+{
+ return clk && !IS_ERR(clk);
+}
+
+unsigned long
+clk_get_rate(struct clk *clk)
+{
+ if (unlikely(!clk_good(clk)))
+ return 0;
+
+ if (clk->rate != 0)
+ return clk->rate;
+
+ if (clk->get_rate != NULL)
+ return clk->get_rate();
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk*
+clk_get(struct device *dev, const char *id)
+{
+ int i;
+ for (i = 0; i < cpu_clk_cnt; i++)
+ if (!strcmp(id, cpu_clk[i].name))
+ return &cpu_clk[i];
+ BUG();
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void
+clk_put(struct clk *clk)
+{
+ /* not used */
+}
+EXPORT_SYMBOL(clk_put);
+
+static inline u32
+ltq_get_counter_resolution(void)
+{
+ u32 res;
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set mips32r2\n"
+ ".set noreorder\n"
+ "rdhwr %0, $3\n"
+ "ehb\n"
+ ".set pop\n"
+ : "=&r" (res)
+ : /* no input */
+ : "memory");
+ instruction_hazard();
+ return res;
+}
+
+void __init
+plat_time_init(void)
+{
+ struct clk *clk = clk_get(0, "cpu");
+ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
+ r4k_cur = (read_c0_count() + r4k_offset);
+ write_c0_compare(r4k_cur);
+}
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
new file mode 100644
index 0000000..3328925
--- /dev/null
+++ b/arch/mips/lantiq/clk.h
@@ -0,0 +1,18 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_CLK_H__
+#define _LTQ_CLK_H__
+
+extern void clk_init(void);
+
+extern unsigned long ltq_get_cpu_hz(void);
+extern unsigned long ltq_get_fpi_hz(void);
+extern unsigned long ltq_get_io_region_clock(void);
+
+#endif
diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
new file mode 100644
index 0000000..0aaf4f7
--- /dev/null
+++ b/arch/mips/lantiq/early_printk.c
@@ -0,0 +1,47 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+
+#include <lantiq.h>
+#include <lantiq_soc.h>
+
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE)
+#define ASC_BUF 1024
+#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
+#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
+#define TXMASK 0x3F00
+#define TXOFFSET 8
+
+void
+prom_putchar(char c)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+ if (c == '\n')
+ ltq_w32('\r', LTQ_ASC_TBUF);
+ ltq_w32(c, LTQ_ASC_TBUF);
+ local_irq_restore(flags);
+}
+
+void
+early_printf(const char *fmt, ...)
+{
+ char buf[ASC_BUF];
+ va_list args;
+ int l;
+ char *p, *buf_end;
+ va_start(args, fmt);
+ l = vsnprintf(buf, ASC_BUF, fmt, args);
+ va_end(args);
+ buf_end = buf + l;
+ for (p = buf; p < buf_end; p++)
+ prom_putchar(*p);
+}
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
new file mode 100644
index 0000000..b1535ee
--- /dev/null
+++ b/arch/mips/lantiq/irq.c
@@ -0,0 +1,209 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+
+#include <lantiq.h>
+#include <irq.h>
+
+#define LTQ_ICU_BASE_ADDR (KSEG1 | 0x1F880200)
+
+#define LTQ_ICU_IM0_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0000))
+#define LTQ_ICU_IM0_IER ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0008))
+#define LTQ_ICU_IM0_IOSR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0010))
+#define LTQ_ICU_IM0_IRSR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0018))
+#define LTQ_ICU_IM0_IMR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0020))
+
+#define LTQ_ICU_IM1_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0028))
+#define LTQ_ICU_IM2_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0050))
+#define LTQ_ICU_IM3_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0078))
+#define LTQ_ICU_IM4_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x00A0))
+
+#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
+
+void
+ltq_disable_irq(unsigned int irq_nr)
+{
+ u32 *ier = LTQ_ICU_IM0_IER;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_w32(ltq_r32(ier) & ~(1 << irq_nr), ier);
+}
+EXPORT_SYMBOL(ltq_disable_irq);
+
+void
+ltq_mask_and_ack_irq(unsigned int irq_nr)
+{
+ u32 *ier = LTQ_ICU_IM0_IER;
+ u32 *isr = LTQ_ICU_IM0_ISR;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_w32(ltq_r32(ier) & ~(1 << irq_nr), ier);
+ ltq_w32((1 << irq_nr), isr);
+}
+EXPORT_SYMBOL(ltq_mask_and_ack_irq);
+
+static void
+ltq_ack_irq(unsigned int irq_nr)
+{
+ u32 *isr = LTQ_ICU_IM0_ISR;
+ irq_nr -= INT_NUM_IRQ0;
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_w32((1 << irq_nr), isr);
+}
+
+void
+ltq_enable_irq(unsigned int irq_nr)
+{
+ u32 *ier = LTQ_ICU_IM0_IER;
+ irq_nr -= INT_NUM_IRQ0;
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_w32(ltq_r32(ier) | (1 << irq_nr), ier);
+}
+EXPORT_SYMBOL(ltq_enable_irq);
+
+static unsigned int
+ltq_startup_irq(unsigned int irq)
+{
+ ltq_enable_irq(irq);
+ return 0;
+}
+
+static void
+ltq_end_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ ltq_enable_irq(irq);
+}
+
+static struct irq_chip
+ltq_irq_type = {
+ "ltq_irq",
+ .startup = ltq_startup_irq,
+ .enable = ltq_enable_irq,
+ .disable = ltq_disable_irq,
+ .unmask = ltq_enable_irq,
+ .ack = ltq_ack_irq,
+ .mask = ltq_disable_irq,
+ .mask_ack = ltq_mask_and_ack_irq,
+ .end = ltq_end_irq,
+};
+
+static void
+ltq_hw_irqdispatch(int module)
+{
+ u32 irq;
+
+ irq = ltq_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
+ if (irq == 0)
+ return;
+
+ /* silicon bug causes only the msb set to 1 to be valid. all
+ other bits might be bogus */
+ irq = __fls(irq);
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+}
+
+#define DEFINE_HWx_IRQDISPATCH(x) \
+static void ltq_hw ## x ## _irqdispatch(void)\
+{\
+ ltq_hw_irqdispatch(x); \
+}
+DEFINE_HWx_IRQDISPATCH(0)
+DEFINE_HWx_IRQDISPATCH(1)
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+
+static void ltq_hw5_irqdispatch(void)
+{
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+}
+
+asmlinkage void
+plat_irq_dispatch(void)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ unsigned int i;
+
+ if (pending & CAUSEF_IP7) {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+ for (i = 0; i < 5; i++) {
+ if (pending & (CAUSEF_IP2 << i)) {
+ ltq_hw_irqdispatch(i);
+ goto out;
+ }
+ }
+ }
+ printk(KERN_ALERT "Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+
+out:
+ return;
+}
+
+static struct irqaction
+cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+void __init
+arch_init_irq(void)
+{
+ int i;
+
+ for (i = 0; i < 5; i++)
+ ltq_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
+
+ mips_cpu_irq_init();
+
+ for (i = 2; i <= 6; i++)
+ setup_irq(i, &cascade);
+
+ if (cpu_has_vint) {
+ printk(KERN_INFO "Setting up vectored interrupts\n");
+ set_vi_handler(2, ltq_hw0_irqdispatch);
+ set_vi_handler(3, ltq_hw1_irqdispatch);
+ set_vi_handler(4, ltq_hw2_irqdispatch);
+ set_vi_handler(5, ltq_hw3_irqdispatch);
+ set_vi_handler(6, ltq_hw4_irqdispatch);
+ set_vi_handler(7, ltq_hw5_irqdispatch);
+ }
+
+ for (i = INT_NUM_IRQ0;
+ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+ set_irq_chip_and_handler(i, <q_irq_type,
+ handle_level_irq);
+
+ #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #else
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+ #endif
+}
+
+unsigned int __cpuinit
+get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
new file mode 100644
index 0000000..6561e4e
--- /dev/null
+++ b/arch/mips/lantiq/prom.c
@@ -0,0 +1,84 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq.h>
+
+#include "prom.h"
+#include "clk.h"
+
+static struct ltq_soc_info soc_info;
+
+/* for Multithreading (APRP) on MIPS34K */
+unsigned long physical_memsize;
+
+/* all access to the ebu must be locked */
+DEFINE_SPINLOCK(ebu_lock);
+EXPORT_SYMBOL_GPL(ebu_lock);
+
+unsigned int
+ltq_get_cpu_ver(void)
+{
+ return soc_info.rev;
+}
+EXPORT_SYMBOL(ltq_get_cpu_ver);
+
+unsigned int
+ltq_get_soc_type(void)
+{
+ return soc_info.type;
+}
+EXPORT_SYMBOL(ltq_get_soc_type);
+
+const char*
+get_system_type(void)
+{
+ return soc_info.sys_type;
+}
+
+void
+prom_free_prom_memory(void)
+{
+}
+
+static void __init
+prom_init_cmdline(void)
+{
+ int argc = fw_arg0;
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
+ int i;
+ arcs_cmdline[0] = '\0';
+ if (argc)
+ for (i = 1; i < argc; i++) {
+ strlcat(arcs_cmdline, (char *)KSEG1ADDR(argv[i]),
+ COMMAND_LINE_SIZE);
+ if (i + 1 != argc)
+ strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
+ }
+ if (!*arcs_cmdline)
+ strcpy(&(arcs_cmdline[0]),
+ "console=ttyS1,115200 rootfstype=squashfs,jffs2");
+}
+
+void __init
+prom_init(void)
+{
+ struct clk *clk;
+ ltq_soc_detect(&soc_info);
+ clk_init();
+ clk = clk_get(0, "cpu");
+ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d %ldMhz",
+ soc_info.name, soc_info.rev, clk_get_rate(clk) / 1000000);
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ printk(KERN_INFO "SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
+}
diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
new file mode 100644
index 0000000..3b92197
--- /dev/null
+++ b/arch/mips/lantiq/prom.h
@@ -0,0 +1,26 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PROM_H__
+#define _LTQ_PROM_H__
+
+#define LTQ_SYS_TYPE_LEN 0x100
+
+struct ltq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+};
+
+void ltq_soc_detect(struct ltq_soc_info *i);
+
+void early_printf(const char *fmt, ...);
+
+#endif
diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
new file mode 100644
index 0000000..f0f74d2
--- /dev/null
+++ b/arch/mips/lantiq/setup.c
@@ -0,0 +1,45 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+
+#include <lantiq.h>
+
+void __init
+plat_mem_setup(void)
+{
+ /* assume 16M as default */
+ unsigned long memsize = 16;
+ char **envp = (char **) KSEG1ADDR(fw_arg2);
+ u32 status;
+
+ /* make sure to have no "reverse endian" for user mode */
+ status = read_c0_status();
+ status &= (~(1<<25));
+ write_c0_status(status);
+
+ ioport_resource.start = IOPORT_RESOURCE_START;
+ ioport_resource.end = IOPORT_RESOURCE_END;
+ iomem_resource.start = IOMEM_RESOURCE_START;
+ iomem_resource.end = IOMEM_RESOURCE_END;
+
+ while (*envp) {
+ char *e = (char *)KSEG1ADDR(*envp);
+ if (!strncmp(e, "memsize=", 8)) {
+ e += 8;
+ strict_strtoul(e, 0, &memsize);
+ }
+ envp++;
+ }
+ memsize *= 1024 * 1024;
+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+}
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 03/10] MIPS: lantiq: add PCI controller support John Crispin
` (8 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
Add support for the Lantiq XWAY family of Mips24KEc SoCs.
* Danube (PSB50702)
* Twinpass (PSB4000)
* AR9 (PSB50802)
* Amazon SE (PSB5061)
The Amazon SE is a lightweight SoC and has no PCI as well as a different
clock. We split the code out into seperate files to handle this.
The GPIO pins on the SoCs are multi function and there are several bits
we can use to configure the pins. To be as compatible as possible to
GPIOLIB we add a function
int lq_gpio_request(unsigned int pin, unsigned int alt0,
unsigned int alt1, unsigned int dir, const char *name);
which lets you configure the 2 "alternate function" bits. This way drivers like
PCI can make use of GPIOLIB without a cubersome wrapper.
The pll code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was
taken from a 2.4.20 source tree and was never really changed by me since then.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++
.../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 62 ++++++
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 119 +++++++++++
arch/mips/lantiq/Kconfig | 21 ++
arch/mips/lantiq/Makefile | 2 +
arch/mips/lantiq/Platform | 1 +
arch/mips/lantiq/xway/Makefile | 4 +
arch/mips/lantiq/xway/clk-ase.c | 53 +++++
arch/mips/lantiq/xway/clk-xway.c | 221 ++++++++++++++++++++
arch/mips/lantiq/xway/gpio.c | 205 ++++++++++++++++++
arch/mips/lantiq/xway/pmu.c | 36 ++++
arch/mips/lantiq/xway/prom-ase.c | 41 ++++
arch/mips/lantiq/xway/prom-xway.c | 56 +++++
arch/mips/lantiq/xway/reset.c | 53 +++++
15 files changed, 893 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
create mode 100644 arch/mips/lantiq/Kconfig
create mode 100644 arch/mips/lantiq/xway/Makefile
create mode 100644 arch/mips/lantiq/xway/clk-ase.c
create mode 100644 arch/mips/lantiq/xway/clk-xway.c
create mode 100644 arch/mips/lantiq/xway/gpio.c
create mode 100644 arch/mips/lantiq/xway/pmu.c
create mode 100644 arch/mips/lantiq/xway/prom-ase.c
create mode 100644 arch/mips/lantiq/xway/prom-xway.c
create mode 100644 arch/mips/lantiq/xway/reset.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index a2396f1..9d3fd89 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -736,6 +736,7 @@ source "arch/mips/alchemy/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
+source "arch/mips/lantiq/Kconfig"
source "arch/mips/lasat/Kconfig"
source "arch/mips/pmc-sierra/Kconfig"
source "arch/mips/powertv/Kconfig"
diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h
new file mode 100644
index 0000000..a1471d2
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h
@@ -0,0 +1,18 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef __LANTIQ_IRQ_H
+#define __LANTIQ_IRQ_H
+
+#include <lantiq_irq.h>
+
+#define NR_IRQS 256
+
+#include_next <irq.h>
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
new file mode 100644
index 0000000..2d29e77
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
@@ -0,0 +1,62 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_XWAY_IRQ_H__
+#define _LANTIQ_XWAY_IRQ_H__
+
+#define INT_NUM_IRQ0 8
+#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
+#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32)
+#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64)
+#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96)
+#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128)
+#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
+
+#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
+#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
+#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
+
+#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
+#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
+#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
+
+#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
+#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23)
+
+#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23)
+#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22)
+#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23)
+
+#define MIPS_CPU_TIMER_IRQ 7
+
+#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0)
+#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1)
+#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2)
+#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3)
+#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4)
+#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5)
+#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6)
+#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7)
+#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8)
+#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9)
+#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10)
+#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11)
+#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25)
+#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26)
+#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27)
+#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28)
+#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29)
+#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30)
+#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16)
+#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21)
+
+#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24)
+
+#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14)
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
new file mode 100644
index 0000000..74beeb7
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -0,0 +1,119 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+
+#ifndef _LTQ_XWAY_H__
+#define _LTQ_XWAY_H__
+
+#include <lantiq.h>
+
+/* request a non-gpio and set the PIO config */
+extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name);
+extern int ltq_gpio_setconfig(unsigned int pin,
+ unsigned int reg, unsigned int val);
+
+extern void ltq_pmu_enable(unsigned int module);
+extern void ltq_pmu_disable(unsigned int module);
+
+/*------------ Chip IDs */
+#define SOC_ID_DANUBE1 0x129
+#define SOC_ID_DANUBE2 0x12B
+#define SOC_ID_TWINPASS 0x12D
+#define SOC_ID_AMAZON_SE 0x152
+#define SOC_ID_ARX188 0x16C
+#define SOC_ID_ARX168 0x16D
+#define SOC_ID_ARX182 0x16F
+
+/*------------ SoC Types */
+#define SOC_TYPE_DANUBE 0x01
+#define SOC_TYPE_TWINPASS 0x02
+#define SOC_TYPE_AR9 0x03
+#define SOC_TYPE_AMAZON_SE 0x04
+
+/*------------ ASC0/1 */
+#define LTQ_ASC0_BASE 0x1E100400
+#define LTQ_ASC1_BASE 0x1E100C00
+#define LTQ_ASC_SIZE 0x400
+
+/*------------ RCU */
+#define LTQ_RCU_BASE_ADDR 0xBF203000
+
+/*------------ GPTU */
+#define LTQ_GPTU_BASE_ADDR 0xB8000300
+
+/*------------ EBU */
+#define LTQ_EBU_GPIO_START 0x14000000
+#define LTQ_EBU_GPIO_SIZE 0x1000
+
+#define LTQ_EBU_BASE_ADDR 0xBE105300
+
+#define LTQ_EBU_BUSCON0 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0060))
+#define LTQ_EBU_PCC_CON ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0090))
+#define LTQ_EBU_PCC_IEN ((u32 *)(LTQ_EBU_BASE_ADDR + 0x00A4))
+#define LTQ_EBU_PCC_ISTAT ((u32 *)(LTQ_EBU_BASE_ADDR + 0x00A0))
+#define LTQ_EBU_BUSCON1 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0064))
+#define LTQ_EBU_ADDRSEL1 ((u32 *)(LTQ_EBU_BASE_ADDR + 0x0024))
+
+#define EBU_WRDIS 0x80000000
+
+/*------------ CGU */
+#define LTQ_CGU_BASE_ADDR (KSEG1 + 0x1F103000)
+
+/*------------ PMU */
+#define LTQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000)
+
+#define PMU_DMA 0x0020
+#define PMU_USB 0x8041
+#define PMU_LED 0x0800
+#define PMU_GPT 0x1000
+#define PMU_PPE 0x2000
+#define PMU_FPI 0x4000
+#define PMU_SWITCH 0x10000000
+
+/*------------ ETOP */
+#define LTQ_PPE32_BASE_ADDR 0xBE180000
+#define LTQ_PPE32_SIZE 0x40000
+
+/*------------ DMA */
+#define LTQ_DMA_BASE_ADDR 0xBE104100
+
+/*------------ PCI */
+#define PCI_CR_BASE_ADDR (KSEG1 + 0x1E105400)
+#define PCI_CS_BASE_ADDR (KSEG1 + 0x17000000)
+
+/*------------ WDT */
+#define LTQ_WDT_BASE 0x1F880000
+#define LTQ_WDT_SIZE 0x400
+
+/*------------ Serial To Parallel conversion */
+#define LTQ_STP_BASE 0x1E100BB0
+#define LTQ_STP_SIZE 0x40
+
+/*------------ GPIO */
+#define LTQ_GPIO0_BASE_ADDR 0x1E100B10
+#define LTQ_GPIO1_BASE_ADDR 0x1E100B40
+#define LTQ_GPIO_SIZE 0x30
+
+/*------------ SSC */
+#define LTQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800)
+
+/*------------ MEI */
+#define LTQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000)
+
+/*------------ DEU */
+#define LTQ_DEU_BASE (KSEG1 + 0x1E103100)
+
+/*------------ MPS */
+#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
+#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
+
+#endif
+
+#endif
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
new file mode 100644
index 0000000..2780461
--- /dev/null
+++ b/arch/mips/lantiq/Kconfig
@@ -0,0 +1,21 @@
+if LANTIQ
+
+config SOC_TYPE_XWAY
+ bool
+ default n
+
+choice
+ prompt "SoC Type"
+ default SOC_XWAY
+
+config SOC_AMAZON_SE
+ bool "Amazon SE"
+ select SOC_TYPE_XWAY
+
+config SOC_XWAY
+ bool "XWAY"
+ select SOC_TYPE_XWAY
+ select HW_HAS_PCI
+endchoice
+
+endif
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
index 6a30de6..a268391 100644
--- a/arch/mips/lantiq/Makefile
+++ b/arch/mips/lantiq/Makefile
@@ -7,3 +7,5 @@
obj-y := irq.o setup.o clk.o prom.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
index eef587f..f3dff05 100644
--- a/arch/mips/lantiq/Platform
+++ b/arch/mips/lantiq/Platform
@@ -5,3 +5,4 @@
platform-$(CONFIG_LANTIQ) += lantiq/
cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
new file mode 100644
index 0000000..64730d5
--- /dev/null
+++ b/arch/mips/lantiq/xway/Makefile
@@ -0,0 +1,4 @@
+obj-y := pmu.o reset.o gpio.o
+
+obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
+obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c
new file mode 100644
index 0000000..ecc3b7c
--- /dev/null
+++ b/arch/mips/lantiq/xway/clk-ase.c
@@ -0,0 +1,53 @@
+/*
+ * 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) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_CGU_SYS ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0010))
+
+unsigned int
+ltq_get_io_region_clock(void)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int
+ltq_get_fpi_bus_clock(int fpi)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int
+ltq_get_cpu_hz(void)
+{
+ if (ltq_r32(LTQ_CGU_SYS) & (1 << 5))
+ return CLOCK_266M;
+ else
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int
+ltq_get_fpi_hz(void)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
+
+
diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c
new file mode 100644
index 0000000..8e7e3d6
--- /dev/null
+++ b/arch/mips/lantiq/xway/clk-xway.c
@@ -0,0 +1,221 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+static unsigned int ltq_ram_clocks[] = {
+ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
+#define DDR_HZ ltq_ram_clocks[ltq_r32(LTQ_CGU_SYS) & 0x3]
+
+#define BASIC_FREQUENCY_1 35328000
+#define BASIC_FREQUENCY_2 36000000
+#define BASIS_REQUENCY_USB 12000000
+
+#define GET_BITS(x, msb, lsb) \
+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
+
+#define CGU_PLL0_PHASE_DIVIDER_ENABLE (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
+#define CGU_PLL0_BYPASS (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
+#define CGU_PLL0_CFG_DSMSEL (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
+#define CGU_PLL0_CFG_FRAC_EN (ltq_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
+#define CGU_PLL1_SRC (ltq_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
+#define CGU_PLL2_PHASE_DIVIDER_ENABLE (ltq_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
+#define CGU_SYS_FPI_SEL (1 << 6)
+#define CGU_SYS_DDR_SEL 0x3
+#define CGU_PLL0_SRC (1 << 29)
+
+#define CGU_PLL0_CFG_PLLK GET_BITS(*LTQ_CGU_PLL0_CFG, 26, 17)
+#define CGU_PLL0_CFG_PLLN GET_BITS(*LTQ_CGU_PLL0_CFG, 12, 6)
+#define CGU_PLL0_CFG_PLLM GET_BITS(*LTQ_CGU_PLL0_CFG, 5, 2)
+#define CGU_PLL2_SRC GET_BITS(*LTQ_CGU_PLL2_CFG, 18, 17)
+#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(*LTQ_CGU_PLL2_CFG, 16, 13)
+
+#define LTQ_GPTU_GPT_CLC ((u32 *)(LTQ_GPTU_BASE_ADDR + 0x0000))
+#define LTQ_CGU_PLL0_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0004))
+#define LTQ_CGU_PLL1_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0008))
+#define LTQ_CGU_PLL2_CFG ((u32 *)(LTQ_CGU_BASE_ADDR + 0x000C))
+#define LTQ_CGU_SYS ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0010))
+#define LTQ_CGU_UPDATE ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0014))
+#define LTQ_CGU_IF_CLK ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0018))
+#define LTQ_CGU_OSC_CON ((u32 *)(LTQ_CGU_BASE_ADDR + 0x001C))
+#define LTQ_CGU_SMD ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0020))
+#define LTQ_CGU_CT1SR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0028))
+#define LTQ_CGU_CT2SR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x002C))
+#define LTQ_CGU_PCMCR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0030))
+#define LTQ_CGU_PCI_CR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0034))
+#define LTQ_CGU_PD_PC ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0038))
+#define LTQ_CGU_FMR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x003C))
+
+static unsigned int ltq_get_pll0_fdiv(void);
+
+static inline unsigned int
+get_input_clock(int pll)
+{
+ switch (pll) {
+ case 0:
+ if (ltq_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
+ return BASIS_REQUENCY_USB;
+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ return BASIC_FREQUENCY_1;
+ else
+ return BASIC_FREQUENCY_2;
+ case 1:
+ if (CGU_PLL1_SRC)
+ return BASIS_REQUENCY_USB;
+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ return BASIC_FREQUENCY_1;
+ else
+ return BASIC_FREQUENCY_2;
+ case 2:
+ switch (CGU_PLL2_SRC) {
+ case 0:
+ return ltq_get_pll0_fdiv();
+ case 1:
+ return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
+ BASIC_FREQUENCY_1 :
+ BASIC_FREQUENCY_2;
+ case 2:
+ return BASIS_REQUENCY_USB;
+ }
+ default:
+ return 0;
+ }
+}
+
+static inline unsigned int
+cal_dsm(int pll, unsigned int num, unsigned int den)
+{
+ u64 res, clock = get_input_clock(pll);
+ res = num * clock;
+ do_div(res, den);
+ return res;
+}
+
+static inline unsigned int
+mash_dsm(int pll, unsigned int M, unsigned int N, unsigned int K)
+{
+ unsigned int num = ((N + 1) << 10) + K;
+ unsigned int den = (M + 1) << 10;
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int
+ssff_dsm_1(int pll, unsigned int M, unsigned int N, unsigned int K)
+{
+ unsigned int num = ((N + 1) << 11) + K + 512;
+ unsigned int den = (M + 1) << 11;
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int
+ssff_dsm_2(int pll, unsigned int M, unsigned int N, unsigned int K)
+{
+ unsigned int num = K >= 512 ?
+ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
+ unsigned int den = (M + 1) << 12;
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int
+dsm(int pll, unsigned int M, unsigned int N, unsigned int K,
+ unsigned int dsmsel, unsigned int phase_div_en)
+{
+ if (!dsmsel)
+ return mash_dsm(pll, M, N, K);
+ else if (!phase_div_en)
+ return mash_dsm(pll, M, N, K);
+ else
+ return ssff_dsm_2(pll, M, N, K);
+}
+
+static inline unsigned int
+ltq_get_pll0_fosc(void)
+{
+ if (CGU_PLL0_BYPASS)
+ return get_input_clock(0);
+ else
+ return !CGU_PLL0_CFG_FRAC_EN
+ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
+ CGU_PLL0_CFG_DSMSEL,
+ CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
+ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
+ CGU_PLL0_PHASE_DIVIDER_ENABLE);
+}
+
+static unsigned int
+ltq_get_pll0_fdiv(void)
+{
+ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
+ return (ltq_get_pll0_fosc() + (div >> 1)) / div;
+}
+
+unsigned int
+ltq_get_io_region_clock(void)
+{
+ unsigned int ret = ltq_get_pll0_fosc();
+ switch (ltq_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
+ default:
+ case 0:
+ return (ret + 1) / 2;
+ case 1:
+ return (ret * 2 + 2) / 5;
+ case 2:
+ return (ret + 1) / 3;
+ case 3:
+ return (ret + 2) / 4;
+ }
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int
+ltq_get_fpi_bus_clock(int fpi)
+{
+ unsigned int ret = ltq_get_io_region_clock();
+ if ((fpi == 2) && (ltq_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
+ ret >>= 1;
+ return ret;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int
+ltq_get_cpu_hz(void)
+{
+ switch (ltq_r32(LTQ_CGU_SYS) & 0xc) {
+ case 0:
+ return CLOCK_333M;
+ case 4:
+ return DDR_HZ;
+ case 8:
+ return DDR_HZ << 1;
+ default:
+ return DDR_HZ >> 1;
+ }
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int
+ltq_get_fpi_hz(void)
+{
+ unsigned int ddr_clock = DDR_HZ;
+ if (ltq_r32(LTQ_CGU_SYS) & 0x40)
+ return ddr_clock >> 1;
+ return ddr_clock;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
+
+
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
new file mode 100644
index 0000000..2faa23a
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio.c
@@ -0,0 +1,205 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <lantiq.h>
+
+#define LQ_GPIO0_BASE_ADDR 0x1E100B10
+#define LQ_GPIO1_BASE_ADDR 0x1E100B40
+#define LQ_GPIO_SIZE 0x30
+
+#define LQ_GPIO_OUT 0x00
+#define LQ_GPIO_IN 0x04
+#define LQ_GPIO_DIR 0x08
+#define LQ_GPIO_ALTSEL0 0x0C
+#define LQ_GPIO_ALTSEL1 0x10
+#define LQ_GPIO_OD 0x14
+
+#define PINS_PER_PORT 16
+
+#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
+#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
+#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r)
+
+struct ltq_gpio {
+ void __iomem *membase;
+ struct gpio_chip chip;
+};
+
+int
+gpio_to_irq(unsigned int gpio)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int
+irq_to_gpio(unsigned int gpio)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+
+int
+ltq_gpio_setconfig(unsigned int pin, unsigned int reg, unsigned int val)
+{
+ void __iomem *membase = (void *)KSEG1ADDR(LQ_GPIO0_BASE_ADDR);
+ if (pin >= (2 * PINS_PER_PORT))
+ return -EINVAL;
+ if (pin >= PINS_PER_PORT) {
+ pin -= PINS_PER_PORT;
+ membase += LQ_GPIO_SIZE;
+ }
+ if (val)
+ ltq_w32_mask(0, (1 << pin), membase + reg);
+ else
+ ltq_w32_mask((1 << pin), 0, membase + reg);
+ return 0;
+}
+EXPORT_SYMBOL(ltq_gpio_setconfig);
+
+int
+ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name)
+{
+ void __iomem *membase = (void *)KSEG1ADDR(LQ_GPIO0_BASE_ADDR);
+ if (pin >= (2 * PINS_PER_PORT))
+ return -EINVAL;
+ if (gpio_request(pin, name)) {
+ printk(KERN_ERR "failed to register %s gpio\n", name);
+ return -EBUSY;
+ }
+ gpio_direction_output(pin, dir);
+ if (pin >= PINS_PER_PORT) {
+ pin -= PINS_PER_PORT;
+ membase += LQ_GPIO_SIZE;
+ }
+ if (alt0)
+ ltq_gpio_setbit(membase, LQ_GPIO_ALTSEL0, pin);
+ else
+ ltq_gpio_clearbit(membase, LQ_GPIO_ALTSEL0, pin);
+ if (alt1)
+ ltq_gpio_setbit(membase, LQ_GPIO_ALTSEL1, pin);
+ else
+ ltq_gpio_clearbit(membase, LQ_GPIO_ALTSEL1, pin);
+ return 0;
+}
+EXPORT_SYMBOL(ltq_gpio_request);
+
+static void
+ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+ if (value)
+ ltq_gpio_setbit(ltq_gpio->membase, LQ_GPIO_OUT, offset);
+ else
+ ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_OUT, offset);
+}
+
+static int
+ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+ return ltq_gpio_getbit(ltq_gpio->membase, LQ_GPIO_IN, offset);
+}
+
+static int
+ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+ ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_OD, offset);
+ ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_DIR, offset);
+ return 0;
+}
+
+static int
+ltq_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+ ltq_gpio_setbit(ltq_gpio->membase, LQ_GPIO_OD, offset);
+ ltq_gpio_setbit(ltq_gpio->membase, LQ_GPIO_DIR, offset);
+ ltq_gpio_set(chip, offset, value);
+ return 0;
+}
+
+static int
+ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+ ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_ALTSEL0, offset);
+ ltq_gpio_clearbit(ltq_gpio->membase, LQ_GPIO_ALTSEL1, offset);
+ return 0;
+}
+
+static int
+ltq_gpio_probe(struct platform_device *pdev)
+{
+ struct ltq_gpio *ltq_gpio =
+ kzalloc(sizeof(struct ltq_gpio), GFP_KERNEL);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int ret = 0;
+ if (!res) {
+ ret = -ENOENT;
+ goto err_free;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ ret = -EBUSY;
+ goto err_free;
+ }
+ ltq_gpio->membase = ioremap_nocache(res->start, resource_size(res));
+ if (!ltq_gpio->membase) {
+ ret = -ENOMEM;
+ goto err_release_mem_region;
+ }
+ ltq_gpio->chip.label = "ltq_gpio";
+ ltq_gpio->chip.direction_input = ltq_gpio_direction_input;
+ ltq_gpio->chip.direction_output = ltq_gpio_direction_output;
+ ltq_gpio->chip.get = ltq_gpio_get;
+ ltq_gpio->chip.set = ltq_gpio_set;
+ ltq_gpio->chip.request = ltq_gpio_req;
+ ltq_gpio->chip.base = PINS_PER_PORT * pdev->id;
+ ltq_gpio->chip.ngpio = PINS_PER_PORT;
+ platform_set_drvdata(pdev, ltq_gpio);
+ ret = gpiochip_add(<q_gpio->chip);
+ if (!ret)
+ return 0;
+
+ iounmap(ltq_gpio->membase);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free:
+ kfree(ltq_gpio);
+ return ret;
+}
+
+static struct platform_driver
+ltq_gpio_driver = {
+ .probe = ltq_gpio_probe,
+ .driver = {
+ .name = "ltq_gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+ltq_gpio_init(void)
+{
+ int ret = platform_driver_register(<q_gpio_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_gpio : Error registering platfom driver!");
+ return ret;
+}
+
+arch_initcall(ltq_gpio_init);
diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
new file mode 100644
index 0000000..78f4a4c
--- /dev/null
+++ b/arch/mips/lantiq/xway/pmu.c
@@ -0,0 +1,36 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_PMU_PWDCR ((u32 *)(LTQ_PMU_BASE_ADDR + 0x001C))
+#define LTQ_PMU_PWDSR ((u32 *)(LTQ_PMU_BASE_ADDR + 0x0020))
+
+void
+ltq_pmu_enable(unsigned int module)
+{
+ int err = 1000000;
+
+ ltq_w32(ltq_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
+ do {} while (--err && (ltq_r32(LTQ_PMU_PWDSR) & module));
+
+ if (!err)
+ panic("activating PMU module failed!");
+}
+EXPORT_SYMBOL(ltq_pmu_enable);
+
+void
+ltq_pmu_disable(unsigned int module)
+{
+ ltq_w32(ltq_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
+}
+EXPORT_SYMBOL(ltq_pmu_disable);
diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c
new file mode 100644
index 0000000..55f5041
--- /dev/null
+++ b/arch/mips/lantiq/xway/prom-ase.c
@@ -0,0 +1,41 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_AMAZON_SE "Amazon_SE"
+
+#define PART_SHIFT 12
+#define PART_MASK 0x0FFFFFFF
+#define REV_SHIFT 28
+#define REV_MASK 0xF0000000
+
+void __init
+ltq_soc_detect(struct ltq_soc_info *i)
+{
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+ switch (i->partnum) {
+ case SOC_ID_AMAZON_SE:
+ i->name = SOC_AMAZON_SE;
+ i->type = SOC_TYPE_AMAZON_SE;
+ break;
+
+ default:
+ early_printf(KERN_ERR "unknown chiprev : 0x%08X\n", i->partnum);
+ unreachable();
+ break;
+ }
+}
diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c
new file mode 100644
index 0000000..5c4e1a7
--- /dev/null
+++ b/arch/mips/lantiq/xway/prom-xway.c
@@ -0,0 +1,56 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_DANUBE "Danube"
+#define SOC_TWINPASS "Twinpass"
+#define SOC_AR9 "AR9"
+
+#define PART_SHIFT 12
+#define PART_MASK 0x0FFFFFFF
+#define REV_SHIFT 28
+#define REV_MASK 0xF0000000
+
+void __init
+ltq_soc_detect(struct ltq_soc_info *i)
+{
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+ switch (i->partnum) {
+ case SOC_ID_DANUBE1:
+ case SOC_ID_DANUBE2:
+ i->name = SOC_DANUBE;
+ i->type = SOC_TYPE_DANUBE;
+ break;
+
+ case SOC_ID_TWINPASS:
+ i->name = SOC_TWINPASS;
+ i->type = SOC_TYPE_DANUBE;
+ break;
+
+ case SOC_ID_ARX188:
+ case SOC_ID_ARX168:
+ case SOC_ID_ARX182:
+ i->name = SOC_AR9;
+ i->type = SOC_TYPE_AR9;
+ break;
+
+ default:
+ early_printf("unknown chiprev : 0x%08X\n", i->partnum);
+ unreachable();
+ break;
+ }
+}
diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
new file mode 100644
index 0000000..64ecd77
--- /dev/null
+++ b/arch/mips/lantiq/xway/reset.c
@@ -0,0 +1,53 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <asm/reboot.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_RCU_RST ((u32 *)(LTQ_RCU_BASE_ADDR + 0x0010))
+#define LTQ_RCU_RST_ALL 0x40000000
+
+static void
+ltq_machine_restart(char *command)
+{
+ printk(KERN_NOTICE "System restart\n");
+ local_irq_disable();
+ ltq_w32(ltq_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST);
+ unreachable();
+}
+
+static void
+ltq_machine_halt(void)
+{
+ printk(KERN_NOTICE "System halted.\n");
+ local_irq_disable();
+ unreachable();
+}
+
+static void
+ltq_machine_power_off(void)
+{
+ printk(KERN_NOTICE "Please turn off the power now.\n");
+ local_irq_disable();
+ unreachable();
+}
+
+static int __init
+mips_reboot_setup(void)
+{
+ _machine_restart = ltq_machine_restart;
+ _machine_halt = ltq_machine_halt;
+ pm_power_off = ltq_machine_power_off;
+ return 0;
+}
+
+arch_initcall(mips_reboot_setup);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 03/10] MIPS: lantiq: add PCI controller support.
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
2011-01-05 19:56 ` [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 04/10] MIPS: lantiq: add serial port support John Crispin
` (7 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds
the driver that allows us to use the EBU as a PCI controller. In order for
PCI to work the EBU is set to endianess swap all the data. In addition we
need to make use of SWAP_IO_SPACE for device->host DMA to work.
The clock of the PCI works in several modes (internal/external). If this
is not configured correctly the SoC will hang.
Currently only 1 pci irq pin is supported.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
---
.../mips/include/asm/mach-lantiq/lantiq_platform.h | 25 ++
arch/mips/pci/Makefile | 1 +
arch/mips/pci/ops-lantiq.c | 118 ++++++++
arch/mips/pci/pci-lantiq.c | 286 ++++++++++++++++++++
arch/mips/pci/pci-lantiq.h | 18 ++
5 files changed, 448 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h
create mode 100644 arch/mips/pci/ops-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.c
create mode 100644 arch/mips/pci/pci-lantiq.h
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
new file mode 100644
index 0000000..c0d4c6c
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -0,0 +1,25 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_PLATFORM_H__
+#define _LANTIQ_PLATFORM_H__
+
+#include <linux/mtd/partitions.h>
+
+/* struct used to pass info to the pci core */
+enum {
+ PCI_CLOCK_INT = 0,
+ PCI_CLOCK_EXT
+};
+
+struct ltq_pci_data {
+ int clock;
+ int req_mask;
+};
+
+#endif
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index c9209ca..4a5d1ae 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o
obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o
+obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o
ifdef CONFIG_PCI_MSI
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c
new file mode 100644
index 0000000..457c9f1
--- /dev/null
+++ b/arch/mips/pci/ops-lantiq.c
@@ -0,0 +1,118 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/addrspace.h>
+#include <linux/vmalloc.h>
+
+#include <lantiq_soc.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BUSNUM_SHF 16
+#define LTQ_PCI_CFG_DEVNUM_SHF 11
+#define LTQ_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int
+ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, unsigned int where, u32 *data)
+{
+ unsigned long cfg_base;
+ unsigned long flags;
+
+ u32 temp;
+
+ /* we support slot from 0 to 15 */
+ /* dev_fn 0&0x68 (AD29) is ifxmips itself */
+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
+ return 1;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+
+ cfg_base = ltq_pci_mapped_cfg;
+ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
+ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE) {
+ ltq_w32(swab32(*data), ((u32 *)cfg_base));
+ } else {
+ *data = ltq_r32(((u32 *)(cfg_base)));
+ *data = swab32(*data);
+ }
+ wmb();
+
+ /* clean possible Master abort */
+ cfg_base = (ltq_pci_mapped_cfg | (0x0 << LTQ_PCI_CFG_FUNNUM_SHF)) + 4;
+ temp = ltq_r32(((u32 *)(cfg_base)));
+ temp = swab32(temp);
+ cfg_base = (ltq_pci_mapped_cfg | (0x68 << LTQ_PCI_CFG_FUNNUM_SHF)) + 4;
+ ltq_w32(temp, ((u32 *)cfg_base));
+
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
+ return 1;
+
+ return 0;
+}
+
+int
+ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4) {
+ data = val;
+ } else {
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus,
+ devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
new file mode 100644
index 0000000..70f7c0f
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.c
@@ -0,0 +1,286 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <asm/pci.h>
+#include <asm/gpio.h>
+#include <asm/addrspace.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BASE 0x17000000
+#define LTQ_PCI_CFG_SIZE 0x00008000
+#define LTQ_PCI_MEM_BASE 0x18000000
+#define LTQ_PCI_MEM_SIZE 0x02000000
+#define LTQ_PCI_IO_BASE 0x1AE00000
+#define LTQ_PCI_IO_SIZE 0x00200000
+
+#define PCI_CR_FCI_ADDR_MAP0 ((u32 *)(PCI_CR_BASE_ADDR + 0x00C0))
+#define PCI_CR_FCI_ADDR_MAP1 ((u32 *)(PCI_CR_BASE_ADDR + 0x00C4))
+#define PCI_CR_FCI_ADDR_MAP2 ((u32 *)(PCI_CR_BASE_ADDR + 0x00C8))
+#define PCI_CR_FCI_ADDR_MAP3 ((u32 *)(PCI_CR_BASE_ADDR + 0x00CC))
+#define PCI_CR_FCI_ADDR_MAP4 ((u32 *)(PCI_CR_BASE_ADDR + 0x00D0))
+#define PCI_CR_FCI_ADDR_MAP5 ((u32 *)(PCI_CR_BASE_ADDR + 0x00D4))
+#define PCI_CR_FCI_ADDR_MAP6 ((u32 *)(PCI_CR_BASE_ADDR + 0x00D8))
+#define PCI_CR_FCI_ADDR_MAP7 ((u32 *)(PCI_CR_BASE_ADDR + 0x00DC))
+#define PCI_CR_CLK_CTRL ((u32 *)(PCI_CR_BASE_ADDR + 0x0000))
+#define PCI_CR_PCI_MOD ((u32 *)(PCI_CR_BASE_ADDR + 0x0030))
+#define PCI_CR_PC_ARB ((u32 *)(PCI_CR_BASE_ADDR + 0x0080))
+#define PCI_CR_FCI_ADDR_MAP11hg ((u32 *)(PCI_CR_BASE_ADDR + 0x00E4))
+#define PCI_CR_BAR11MASK ((u32 *)(PCI_CR_BASE_ADDR + 0x0044))
+#define PCI_CR_BAR12MASK ((u32 *)(PCI_CR_BASE_ADDR + 0x0048))
+#define PCI_CR_BAR13MASK ((u32 *)(PCI_CR_BASE_ADDR + 0x004C))
+#define PCI_CS_BASE_ADDR1 ((u32 *)(PCI_CS_BASE_ADDR + 0x0010))
+#define PCI_CR_PCI_ADDR_MAP11 ((u32 *)(PCI_CR_BASE_ADDR + 0x0064))
+#define PCI_CR_FCI_BURST_LENGTH ((u32 *)(PCI_CR_BASE_ADDR + 0x00E8))
+#define PCI_CR_PCI_EOI ((u32 *)(PCI_CR_BASE_ADDR + 0x002C))
+#define PCI_CS_STS_CMD ((u32 *)(PCI_CS_BASE_ADDR + 0x0004))
+
+#define PCI_MASTER0_REQ_MASK_2BITS 8
+#define PCI_MASTER1_REQ_MASK_2BITS 10
+#define PCI_MASTER2_REQ_MASK_2BITS 12
+#define INTERNAL_ARB_ENABLE_BIT 0
+
+#define LTQ_CGU_IFCCR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0018))
+#define LTQ_CGU_PCICR ((u32 *)(LTQ_CGU_BASE_ADDR + 0x0034))
+
+u32 ltq_pci_mapped_cfg;
+
+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
+/* Since the PCI REQ pins can be reused for other functionality, make it
+ possible to exclude those from interpretation by the PCI controller */
+static int ltq_pci_req_mask = 0xf;
+
+struct pci_ops ltq_pci_ops = {
+ .read = ltq_pci_read_config_dword,
+ .write = ltq_pci_write_config_dword
+};
+
+static struct resource pci_io_resource = {
+ .name = "pci io space",
+ .start = LTQ_PCI_IO_BASE,
+ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .name = "pci memory space",
+ .start = LTQ_PCI_MEM_BASE,
+ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller ltq_pci_controller = {
+ .pci_ops = <q_pci_ops,
+ .mem_resource = &pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &pci_io_resource,
+ .io_offset = 0x00000000UL,
+};
+
+int
+pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ u8 pin;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ switch (pin) {
+ case 0:
+ break;
+ case 1:
+ /* falling edge level triggered:0x4
+ low level:0xc, rising edge:0x2 */
+ ltq_w32(ltq_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON);
+ ltq_w32(ltq_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ printk(KERN_WARNING "interrupt pin %d not supported yet!\n",
+ pin);
+ default:
+ printk(KERN_WARNING "invalid interrupt pin %d\n", pin);
+ return 1;
+ }
+
+ if (ltqpci_plat_dev_init)
+ return ltqpci_plat_dev_init(dev);
+
+ return 0;
+}
+
+static u32
+ltq_calc_bar11mask(void)
+{
+ u32 mem, bar11mask;
+
+ /* BAR11MASK value depends on available memory on system. */
+ mem = num_physpages * PAGE_SIZE;
+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
+
+ return bar11mask;
+}
+
+static void
+ltq_pci_setup_clk(int external_clock)
+{
+ /* set clock to 33Mhz */
+ ltq_w32(ltq_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+ ltq_w32(ltq_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+ if (external_clock) {
+ ltq_w32(ltq_r32(LTQ_CGU_IFCCR) & ~(1 << 16), LTQ_CGU_IFCCR);
+ ltq_w32((1 << 30), LTQ_CGU_PCICR);
+ } else {
+ ltq_w32(ltq_r32(LTQ_CGU_IFCCR) | (1 << 16), LTQ_CGU_IFCCR);
+ ltq_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
+ }
+}
+
+static void
+ltq_pci_setup_gpio(void)
+{
+ /* PCI reset line is gpio driven */
+ ltq_gpio_request(21, 0, 0, 1, "pci-reset");
+
+ /* PCI_REQ line */
+ ltq_gpio_request(29, 1, 0, 0, "pci-req");
+
+ /* PCI_GNT line */
+ ltq_gpio_request(30, 1, 0, 1, "pci-gnt");
+}
+
+static int __devinit
+ltq_pci_startup(void)
+{
+ u32 temp_buffer;
+
+ /* setup pci clock and gpis used by pci */
+ ltq_pci_setup_gpio();
+
+ /* enable auto-switching between PCI and EBU */
+ ltq_w32(0xa, PCI_CR_CLK_CTRL);
+
+ /* busy, i.e. configuration is not done, PCI access has to be retried */
+ ltq_w32(ltq_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+ /* BUS Master/IO/MEM access */
+ ltq_w32(ltq_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
+
+ /* enable external 2 PCI masters */
+ temp_buffer = ltq_r32(PCI_CR_PC_ARB);
+ temp_buffer &= (~(ltq_pci_req_mask << 16));
+ /* enable internal arbiter */
+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
+ /* enable internal PCI master reqest */
+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
+
+ /* enable EBU request */
+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
+
+ /* enable all external masters request */
+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
+ ltq_w32(temp_buffer, PCI_CR_PC_ARB);
+ wmb();
+
+ /* setup BAR memory regions */
+ ltq_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
+ ltq_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
+ ltq_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
+ ltq_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
+ ltq_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
+ ltq_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
+ ltq_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
+ ltq_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
+ ltq_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
+ ltq_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK);
+ ltq_w32(0, PCI_CR_PCI_ADDR_MAP11);
+ ltq_w32(0, PCI_CS_BASE_ADDR1);
+ /* both TX and RX endian swap are enabled */
+ ltq_w32(ltq_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
+ wmb();
+ ltq_w32(ltq_r32(PCI_CR_BAR12MASK) | 0x80000000, PCI_CR_BAR12MASK);
+ ltq_w32(ltq_r32(PCI_CR_BAR13MASK) | 0x80000000, PCI_CR_BAR13MASK);
+ /*use 8 dw burst length */
+ ltq_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
+ ltq_w32(ltq_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+
+ /* toggle reset pin */
+ __gpio_set_value(21, 0);
+ wmb();
+ mdelay(1);
+ __gpio_set_value(21, 1);
+ return 0;
+}
+
+int __init
+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 13:
+ /* IDSEL = AD29 --> USB Host Controller */
+ return INT_NUM_IM1_IRL0 + 17;
+ case 14:
+ /* IDSEL = AD30 --> mini PCI connector */
+ return INT_NUM_IM0_IRL0 + 22;
+ default:
+ printk(KERN_INFO "ltq_pci: no IRQ found for slot %d, pin %d\n",
+ slot, pin);
+ return 0;
+ }
+}
+
+static int __devinit
+ltq_pci_probe(struct platform_device *pdev)
+{
+ struct ltq_pci_data *ltq_pci_data =
+ (struct ltq_pci_data *) pdev->dev.platform_data;
+ pci_probe_only = 0;
+ ltq_pci_req_mask = ltq_pci_data->req_mask;
+ ltq_pci_setup_clk(ltq_pci_data->clock);
+ ltq_pci_startup();
+ ltq_pci_mapped_cfg =
+ (u32)ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
+ ltq_pci_controller.io_map_base =
+ (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
+ register_pci_controller(<q_pci_controller);
+ return 0;
+}
+
+static struct platform_driver
+ltq_pci_driver = {
+ .probe = ltq_pci_probe,
+ .driver = {
+ .name = "ltq_pci",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+pcibios_init(void)
+{
+ int ret = platform_driver_register(<q_pci_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
+ return ret;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h
new file mode 100644
index 0000000..de75dd7
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.h
@@ -0,0 +1,18 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PCI_H__
+#define _LTQ_PCI_H__
+
+extern u32 ltq_pci_mapped_cfg;
+extern int ltq_pci_read_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+extern int ltq_pci_write_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
+
+#endif
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 04/10] MIPS: lantiq: add serial port support
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (2 preceding siblings ...)
2011-01-05 19:56 ` [PATCH 03/10] MIPS: lantiq: add PCI controller support John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 05/10] MIPS: lantiq: add watchdog support John Crispin
` (6 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, Felix Fietkau, linux-mips
This patch adds the driver for the 2 serial ports found inside the Lantiq SoC family
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Cc: linux-mips@linux-mips.org
---
drivers/serial/Kconfig | 8 +
drivers/serial/Makefile | 1 +
drivers/serial/lantiq.c | 774 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 783 insertions(+), 0 deletions(-)
create mode 100644 drivers/serial/lantiq.c
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index aff9dcd..e3a45ff 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1454,6 +1454,14 @@ config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
help
Support for Console on the NWP serial ports.
+config SERIAL_LANTIQ
+ bool "Lantiq serial driver"
+ depends on LANTIQ
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for console and UART on Lantiq SoCs.
+
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
depends on QUICC_ENGINE
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index c570576..434e0e0 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -89,3 +89,4 @@ obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
diff --git a/drivers/serial/lantiq.c b/drivers/serial/lantiq.c
new file mode 100644
index 0000000..c08e0a6
--- /dev/null
+++ b/drivers/serial/lantiq.c
@@ -0,0 +1,774 @@
+/*
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2004 Infineon IFAP DC COM CPE
+ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#define ltq_r32(reg) __raw_readl(reg)
+#define ltq_r8(reg) __raw_readb(reg)
+#define ltq_w32(val, reg) __raw_writel(val, reg)
+#define ltq_w8(val, reg) __raw_writeb(val, reg)
+#define ltq_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg)
+
+#define PORT_LTQ_ASC 111
+#define MAXPORTS 2
+
+#define UART_DUMMY_UER_RX 1
+
+#define DRVNAME "ltq_asc"
+
+#ifdef __BIG_ENDIAN
+#define LTQ_ASC_TBUF (0x0020 + 3)
+#define LTQ_ASC_RBUF (0x0024 + 3)
+#else
+#define LTQ_ASC_TBUF 0x0020
+#define LTQ_ASC_RBUF 0x0024
+#endif
+
+#define LTQ_ASC_FSTAT 0x0048
+#define LTQ_ASC_WHBSTATE 0x0018
+#define LTQ_ASC_STATE 0x0014
+#define LTQ_ASC_IRNCR 0x00F8
+#define LTQ_ASC_CLC 0x0000
+#define LTQ_ASC_ID 0x0008
+#define LTQ_ASC_PISEL 0x0004
+#define LTQ_ASC_TXFCON 0x0044
+#define LTQ_ASC_RXFCON 0x0040
+#define LTQ_ASC_CON 0x0010
+#define LTQ_ASC_BG 0x0050
+#define LTQ_ASC_IRNREN 0x00F4
+
+#define ASC_IRNREN_TX 0x1
+#define ASC_IRNREN_RX 0x2
+#define ASC_IRNREN_ERR 0x4
+#define ASC_IRNREN_TX_BUF 0x8
+#define ASC_IRNCR_TIR 0x1
+#define ASC_IRNCR_RIR 0x2
+#define ASC_IRNCR_EIR 0x4
+
+#define ASCOPT_CSIZE 0x3
+#define ASCOPT_CS7 0x1
+#define ASCOPT_CS8 0x2
+#define ASCOPT_PARENB 0x4
+#define ASCOPT_STOPB 0x8
+#define ASCOPT_PARODD 0x0
+#define ASCOPT_CREAD 0x20
+#define TXFIFO_FL 1
+#define RXFIFO_FL 1
+#define ASCCLC_DISS 0x2
+#define ASCCLC_RMCMASK 0x0000FF00
+#define ASCCLC_RMCOFFSET 8
+#define ASCCON_M_8ASYNC 0x0
+#define ASCCON_M_7ASYNC 0x2
+#define ASCCON_ODD 0x00000020
+#define ASCCON_STP 0x00000080
+#define ASCCON_BRS 0x00000100
+#define ASCCON_FDE 0x00000200
+#define ASCCON_R 0x00008000
+#define ASCCON_FEN 0x00020000
+#define ASCCON_ROEN 0x00080000
+#define ASCCON_TOEN 0x00100000
+#define ASCSTATE_PE 0x00010000
+#define ASCSTATE_FE 0x00020000
+#define ASCSTATE_ROE 0x00080000
+#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
+#define ASCWHBSTATE_CLRREN 0x00000001
+#define ASCWHBSTATE_SETREN 0x00000002
+#define ASCWHBSTATE_CLRPE 0x00000004
+#define ASCWHBSTATE_CLRFE 0x00000008
+#define ASCWHBSTATE_CLRROE 0x00000020
+#define ASCTXFCON_TXFEN 0x0001
+#define ASCTXFCON_TXFFLU 0x0002
+#define ASCTXFCON_TXFITLMASK 0x3F00
+#define ASCTXFCON_TXFITLOFF 8
+#define ASCRXFCON_RXFEN 0x0001
+#define ASCRXFCON_RXFFLU 0x0002
+#define ASCRXFCON_RXFITLMASK 0x3F00
+#define ASCRXFCON_RXFITLOFF 8
+#define ASCFSTAT_RXFFLMASK 0x003F
+#define ASCFSTAT_TXFFLMASK 0x3F00
+#define ASCFSTAT_TXFFLOFF 8
+#define ASCFSTAT_RXFREEMASK 0x003F0000
+#define ASCFSTAT_RXFREEOFF 16
+#define ASCFSTAT_TXFREEMASK 0x3F000000
+#define ASCFSTAT_TXFREEOFF 24
+
+static void lqasc_tx_chars(struct uart_port *port);
+static struct ltq_uart_port *lqasc_port[2];
+static struct uart_driver lqasc_reg;
+
+struct ltq_uart_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int tx_irq;
+ unsigned int rx_irq;
+ unsigned int err_irq;
+};
+
+static inline struct
+ltq_uart_port *to_ltq_uart_port(struct uart_port *port)
+{
+ return container_of(port, struct ltq_uart_port, port);
+}
+
+static void
+lqasc_stop_tx(struct uart_port *port)
+{
+ return;
+}
+
+static void
+lqasc_start_tx(struct uart_port *port)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ lqasc_tx_chars(port);
+ local_irq_restore(flags);
+ return;
+}
+
+static void
+lqasc_stop_rx(struct uart_port *port)
+{
+ ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
+}
+
+static void
+lqasc_enable_ms(struct uart_port *port)
+{
+}
+
+static void
+lqasc_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->state->port.tty;
+ unsigned int ch = 0, rsr = 0, fifocnt;
+
+ fifocnt =
+ ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
+ while (fifocnt--) {
+ u8 flag = TTY_NORMAL;
+ ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
+ rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
+ & ASCSTATE_ANY) | UART_DUMMY_UER_RX;
+ tty_flip_buffer_push(tty);
+ port->icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ if (rsr & ASCSTATE_ANY) {
+ if (rsr & ASCSTATE_PE) {
+ port->icount.parity++;
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ } else if (rsr & ASCSTATE_FE) {
+ port->icount.frame++;
+ ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ }
+ if (rsr & ASCSTATE_ROE) {
+ port->icount.overrun++;
+ ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
+ port->membase + LTQ_ASC_WHBSTATE);
+ }
+
+ rsr &= port->read_status_mask;
+
+ if (rsr & ASCSTATE_PE)
+ flag = TTY_PARITY;
+ else if (rsr & ASCSTATE_FE)
+ flag = TTY_FRAME;
+ }
+
+ if ((rsr & port->ignore_status_mask) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ if (rsr & ASCSTATE_ROE)
+ /*
+ * Overrun is special, since it's reported
+ * immediately, and doesn't affect the current
+ * character
+ */
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ if (ch != 0)
+ tty_flip_buffer_push(tty);
+ return;
+}
+
+static void
+lqasc_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ if (uart_tx_stopped(port)) {
+ lqasc_stop_tx(port);
+ return;
+ }
+
+ while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
+ ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
+ if (port->x_char) {
+ ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
+ port->icount.tx++;
+ port->x_char = 0;
+ continue;
+ }
+
+ if (uart_circ_empty(xmit))
+ break;
+
+ ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
+ port->membase + LTQ_ASC_TBUF);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static irqreturn_t
+lqasc_tx_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
+ lqasc_start_tx(port);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_err_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ /* clear any pending interrupts */
+ ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
+ ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+lqasc_rx_int(int irq, void *_port)
+{
+ struct uart_port *port = (struct uart_port *)_port;
+ ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
+ lqasc_rx_chars(port);
+ return IRQ_HANDLED;
+}
+
+static unsigned int
+lqasc_tx_empty(struct uart_port *port)
+{
+ int status;
+ status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
+ return status ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int
+lqasc_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
+}
+
+static void
+lqasc_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+}
+
+static void
+lqasc_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int
+lqasc_startup(struct uart_port *port)
+{
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+ int retval;
+
+ port->uartclk = clk_get_rate(ltq_port->clk);
+
+ ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
+ port->membase + LTQ_ASC_CLC);
+
+ ltq_w32(0, port->membase + LTQ_ASC_PISEL);
+ ltq_w32(
+ ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
+ ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
+ port->membase + LTQ_ASC_TXFCON);
+ ltq_w32(
+ ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
+ | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
+ port->membase + LTQ_ASC_RXFCON);
+ /* make sure other settings are written to hardware before
+ setting enable bits */
+ wmb();
+ ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
+ ASCCON_ROEN, port->membase + LTQ_ASC_CON);
+
+ retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
+ IRQF_DISABLED, "asc_tx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_tx_int\n");
+ return retval;
+ }
+
+ retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
+ IRQF_DISABLED, "asc_rx", port);
+ if (retval) {
+ pr_err("failed to request lqasc_rx_int\n");
+ goto err1;
+ }
+
+ retval = request_irq(ltq_port->err_irq, lqasc_err_int,
+ IRQF_DISABLED, "asc_err", port);
+ if (retval) {
+ pr_err("failed to request lqasc_err_int\n");
+ goto err2;
+ }
+
+ ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
+ port->membase + LTQ_ASC_IRNREN);
+ return 0;
+
+err2:
+ free_irq(ltq_port->rx_irq, port);
+err1:
+ free_irq(ltq_port->tx_irq, port);
+ return retval;
+}
+
+static void
+lqasc_shutdown(struct uart_port *port)
+{
+ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
+ free_irq(ltq_port->tx_irq, port);
+ free_irq(ltq_port->rx_irq, port);
+ free_irq(ltq_port->err_irq, port);
+
+ ltq_w32(0, port->membase + LTQ_ASC_CON);
+ ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
+ port->membase + LTQ_ASC_RXFCON);
+ ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
+ port->membase + LTQ_ASC_TXFCON);
+}
+
+static void
+lqasc_set_termios(struct uart_port *port,
+ struct ktermios *new, struct ktermios *old)
+{
+ unsigned int cflag;
+ unsigned int iflag;
+ unsigned int quot;
+ unsigned int baud;
+ unsigned int con = 0;
+ unsigned long flags;
+
+ cflag = new->c_cflag;
+ iflag = new->c_iflag;
+
+ switch (cflag & CSIZE) {
+ case CS7:
+ con = ASCCON_M_7ASYNC;
+ break;
+
+ case CS5:
+ case CS6:
+ default:
+ con = ASCCON_M_8ASYNC;
+ break;
+ }
+
+ if (cflag & CSTOPB)
+ con |= ASCCON_STP;
+
+ if (cflag & PARENB) {
+ if (!(cflag & PARODD))
+ con &= ~ASCCON_ODD;
+ else
+ con |= ASCCON_ODD;
+ }
+
+ port->read_status_mask = ASCSTATE_ROE;
+ if (iflag & INPCK)
+ port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+ port->ignore_status_mask = 0;
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
+
+ if (iflag & IGNBRK) {
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (iflag & IGNPAR)
+ port->ignore_status_mask |= ASCSTATE_ROE;
+ }
+
+ if ((cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_DUMMY_UER_RX;
+
+ /* set error signals - framing, parity and overrun, enable receiver */
+ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
+
+ local_irq_save(flags);
+
+ /* set up CON */
+ ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
+
+ /* Set baud rate - take a divider of 2 into account */
+ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+ quot = quot / 2 - 1;
+
+ /* disable the baudrate generator */
+ ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
+
+ /* make sure the fractional divider is off */
+ ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
+
+ /* set up to use divisor of 2 */
+ ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
+
+ /* now we can write the new baudrate into the register */
+ ltq_w32(quot, port->membase + LTQ_ASC_BG);
+
+ /* turn the baudrate generator back on */
+ ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
+
+ /* enable rx */
+ ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
+
+ local_irq_restore(flags);
+}
+
+static const char*
+lqasc_type(struct uart_port *port)
+{
+ if (port->type == PORT_LTQ_ASC)
+ return DRVNAME;
+ else
+ return NULL;
+}
+
+static void
+lqasc_release_port(struct uart_port *port)
+{
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+}
+
+static int
+lqasc_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *mmres;
+ int size;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mmres)
+ return -ENODEV;
+ size = resource_size(mmres);
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap_nocache(port->mapbase, size);
+ if (port->membase == NULL)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void
+lqasc_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_LTQ_ASC;
+ lqasc_request_port(port);
+ }
+}
+
+static int
+lqasc_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops lqasc_pops = {
+ .tx_empty = lqasc_tx_empty,
+ .set_mctrl = lqasc_set_mctrl,
+ .get_mctrl = lqasc_get_mctrl,
+ .stop_tx = lqasc_stop_tx,
+ .start_tx = lqasc_start_tx,
+ .stop_rx = lqasc_stop_rx,
+ .enable_ms = lqasc_enable_ms,
+ .break_ctl = lqasc_break_ctl,
+ .startup = lqasc_startup,
+ .shutdown = lqasc_shutdown,
+ .set_termios = lqasc_set_termios,
+ .type = lqasc_type,
+ .release_port = lqasc_release_port,
+ .request_port = lqasc_request_port,
+ .config_port = lqasc_config_port,
+ .verify_port = lqasc_verify_port,
+};
+
+static void
+lqasc_console_putchar(struct uart_port *port, int ch)
+{
+ int fifofree;
+
+ if (!port->membase)
+ return;
+
+ do {
+ fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
+ & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
+ } while (fifofree == 0);
+ ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
+}
+
+
+static void
+lqasc_console_write(struct console *co, const char *s, u_int count)
+{
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ unsigned long flags;
+
+ if (co->index >= MAXPORTS)
+ return;
+
+ ltq_port = lqasc_port[co->index];
+ if (!ltq_port)
+ return;
+
+ port = <q_port->port;
+
+ local_irq_save(flags);
+ uart_console_write(port, s, count, lqasc_console_putchar);
+ local_irq_restore(flags);
+}
+
+static int __init
+lqasc_console_setup(struct console *co, char *options)
+{
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= MAXPORTS)
+ return -ENODEV;
+
+ ltq_port = lqasc_port[co->index];
+ if (!ltq_port)
+ return -ENODEV;
+
+ port = <q_port->port;
+
+ port->uartclk = clk_get_rate(ltq_port->clk);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console lqasc_console = {
+ .name = "ttyS",
+ .write = lqasc_console_write,
+ .device = uart_console_device,
+ .setup = lqasc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &lqasc_reg,
+};
+
+static int __init
+lqasc_console_init(void)
+{
+ register_console(&lqasc_console);
+ return 0;
+}
+console_initcall(lqasc_console_init);
+
+static struct uart_driver lqasc_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = DRVNAME,
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = MAXPORTS,
+ .cons = &lqasc_console,
+};
+
+static int __devinit
+lqasc_probe(struct platform_device *pdev)
+{
+ struct ltq_uart_port *ltq_port;
+ struct uart_port *port;
+ struct resource *mmres, *irqres;
+ int tx_irq, rx_irq, err_irq;
+ struct clk *clk;
+ int ret;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mmres || !irqres)
+ return -ENODEV;
+
+ if (pdev->id >= MAXPORTS)
+ return -EBUSY;
+
+ if (lqasc_port[pdev->id] != NULL)
+ return -EBUSY;
+
+ clk = clk_get(&pdev->dev, "fpi");
+ if (IS_ERR(clk)) {
+ pr_err("failed to get fpi clk\n");
+ return -ENOENT;
+ }
+
+ tx_irq = platform_get_irq_byname(pdev, "tx");
+ if (tx_irq < 0) {
+ /* without named resources: assume standard irq scheme */
+ tx_irq = irqres->start;
+ rx_irq = irqres->start+2;
+ err_irq = irqres->start+3;
+ } else {
+ /* other irqs must be named also! */
+ rx_irq = platform_get_irq_byname(pdev, "rx");
+ err_irq = platform_get_irq_byname(pdev, "err");
+ if ((rx_irq < 0) | (err_irq < 0))
+ return -ENODEV;
+ }
+
+ ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL);
+ if (!ltq_port)
+ return -ENOMEM;
+
+ port = <q_port->port;
+
+ port->iotype = SERIAL_IO_MEM;
+ port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->ops = &lqasc_pops;
+ port->fifosize = 16;
+ port->type = PORT_LTQ_ASC,
+ port->line = pdev->id;
+ port->dev = &pdev->dev;
+
+ port->irq = tx_irq; /* unused, just to be backward-compatibe */
+ port->mapbase = mmres->start;
+
+ ltq_port->clk = clk;
+
+ ltq_port->tx_irq = tx_irq;
+ ltq_port->rx_irq = rx_irq;
+ ltq_port->err_irq = err_irq;
+
+ lqasc_port[pdev->id] = ltq_port;
+ platform_set_drvdata(pdev, ltq_port);
+
+ ret = uart_add_one_port(&lqasc_reg, port);
+
+ return ret;
+}
+
+static int __devexit
+lqasc_remove(struct platform_device *pdev)
+{
+ struct ltq_uart_port *ltq_port = platform_get_drvdata(pdev);
+ int ret;
+
+ clk_put(ltq_port->clk);
+ platform_set_drvdata(pdev, NULL);
+ lqasc_port[pdev->id] = NULL;
+ ret = uart_remove_one_port(&lqasc_reg, <q_port->port);
+ kfree(ltq_port);
+
+ return 0;
+}
+
+static struct platform_driver lqasc_driver = {
+ .probe = lqasc_probe,
+ .remove = __devexit_p(lqasc_remove),
+
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_lqasc(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&lqasc_reg);
+ if (ret != 0)
+ return ret;
+
+ ret = platform_driver_register(&lqasc_driver);
+ if (ret != 0)
+ uart_unregister_driver(&lqasc_reg);
+
+ return ret;
+}
+
+void __exit
+exit_lqasc(void)
+{
+ platform_driver_unregister(&lqasc_driver);
+ uart_unregister_driver(&lqasc_reg);
+}
+
+module_init(init_lqasc);
+module_exit(exit_lqasc);
+
+MODULE_DESCRIPTION("Lantiq serial port driver");
+MODULE_LICENSE("GPL");
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 05/10] MIPS: lantiq: add watchdog support
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (3 preceding siblings ...)
2011-01-05 19:56 ` [PATCH 04/10] MIPS: lantiq: add serial port support John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 23:49 ` Jamie Iles
2011-01-05 19:56 ` John Crispin
` (5 subsequent siblings)
10 siblings, 1 reply; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle
Cc: John Crispin, Ralph Hempel, Wim Van Sebroeck, linux-mips,
linux-watchdog
This patch adds the driver for the watchdog found inside the Lantiq SoC family.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: linux-mips@linux-mips.org
Cc: linux-watchdog@vger.kernel.org
---
drivers/watchdog/Kconfig | 6 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/lantiq_wdt.c | 208 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 215 insertions(+), 0 deletions(-)
create mode 100644 drivers/watchdog/lantiq_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index a5ad77e..3e0733e 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -930,6 +930,12 @@ config BCM63XX_WDT
To compile this driver as a loadable module, choose M here.
The module will be called bcm63xx_wdt.
+config LANTIQ_WDT
+ tristate "Lantiq SoC watchdog"
+ depends on LANTIQ
+ help
+ Hardware driver for the Lantiq SoC Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 4b0ef38..d845e47 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -119,6 +119,7 @@ obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
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
# PARISC Architecture
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
new file mode 100644
index 0000000..543bcf1
--- /dev/null
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -0,0 +1,208 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ * Based on EP93xx wdt driver
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#include <lantiq.h>
+
+#define LTQ_WDT_PW1 0x00BE0000
+#define LTQ_WDT_PW2 0x00DC0000
+
+#define LTQ_BIU_WDT_CR 0x3F0
+#define LTQ_BIU_WDT_SR 0x3F8
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+static int wdt_ok_to_close;
+#endif
+
+static int wdt_timeout = 30;
+static __iomem void *wdt_membase;
+static unsigned long io_region_clk;
+
+static int
+ltq_wdt_enable(unsigned int timeout)
+{
+ ltq_w32(LTQ_WDT_PW1, wdt_membase + LTQ_BIU_WDT_CR);
+ ltq_w32(LTQ_WDT_PW2 |
+ (0x3 << 26) | /* PWL */
+ (0x3 << 24) | /* CLKDIV */
+ (0x1 << 31) | /* enable */
+ ((timeout * (io_region_clk / 0x40000)) + 0x1000), /* reload */
+ wdt_membase + LTQ_BIU_WDT_CR);
+ return 0;
+}
+
+static void
+ltq_wdt_disable(void)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ wdt_ok_to_close = 0;
+#endif
+ ltq_w32(LTQ_WDT_PW1, wdt_membase + LTQ_BIU_WDT_CR);
+ ltq_w32(LTQ_WDT_PW2, wdt_membase + LTQ_BIU_WDT_CR);
+}
+
+static ssize_t
+ltq_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ size_t i;
+ if (!len)
+ return 0;
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ wdt_ok_to_close = 1;
+ }
+#endif
+ ltq_wdt_enable(wdt_timeout);
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_MAGICCLOSE,
+ .identity = "ltq_wdt",
+};
+
+static long
+ltq_wdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(wdt_timeout, (int __user *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(wdt_timeout, (int __user *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ ltq_wdt_enable(wdt_timeout);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int
+ltq_wdt_open(struct inode *inode, struct file *file)
+{
+ ltq_wdt_enable(wdt_timeout);
+ return nonseekable_open(inode, file);
+}
+
+static int
+ltq_wdt_release(struct inode *inode, struct file *file)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ if (wdt_ok_to_close)
+ ltq_wdt_disable();
+ else
+#endif
+ printk(KERN_ERR "ltq_wdt: watchdog closed without warning,"
+ " rebooting system\n");
+ return 0;
+}
+
+static const struct file_operations ltq_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = ltq_wdt_write,
+ .unlocked_ioctl = ltq_wdt_ioctl,
+ .open = ltq_wdt_open,
+ .release = ltq_wdt_release,
+};
+
+static struct miscdevice ltq_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = <q_wdt_fops,
+};
+
+static int
+ltq_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct clk *clk;
+ int ret = 0;
+ if (!res)
+ return -ENOENT;
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res)
+ return -EBUSY;
+ wdt_membase = ioremap_nocache(res->start, resource_size(res));
+ if (!wdt_membase) {
+ ret = -ENOMEM;
+ goto err_release_mem_region;
+ }
+ clk = clk_get(&pdev->dev, "io");
+ io_region_clk = clk_get_rate(clk);;
+ ret = misc_register(<q_wdt_miscdev);
+ if (!ret)
+ return 0;
+
+ iounmap(wdt_membase);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+ return ret;
+}
+
+static int
+ltq_wdt_remove(struct platform_device *dev)
+{
+ ltq_wdt_disable();
+ misc_deregister(<q_wdt_miscdev);
+ return 0;
+}
+
+static struct platform_driver ltq_wdt_driver = {
+ .probe = ltq_wdt_probe,
+ .remove = ltq_wdt_remove,
+ .driver = {
+ .name = "ltq_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+init_ltq_wdt(void)
+{
+ return platform_driver_register(<q_wdt_driver);
+}
+
+static void __exit
+exit_ltq_wdt(void)
+{
+ platform_driver_unregister(<q_wdt_driver);
+}
+
+module_init(init_ltq_wdt);
+module_exit(exit_ltq_wdt);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq Watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 06/10] MIPS: lantiq: add NOR flash support
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family John Crispin
` (9 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle
Cc: John Crispin, Ralph Hempel, David Woodhouse, linux-mips,
linux-mtd
NOR flash is attached to the same EBU (External Bus Unit) as PCI. As described
in the PCI patch, the EBU is a little obscure, resulting in the upper and lower
16 bit of the data on a 32 bit read are swapped. (essentially we have a addr^=2)
This only happens on the read of data. In order to not have to high an impact
on the read performance from the EBU we store all data on the flash with
addr^=2. This allows us to do generic reads without having to do any swapping.
For the write to now work we need to swizzle the the 0x2 bit of the addr.
However this write swizzle needs to only happen when doing a CMD and not a DATA
write.
As the MTD layer currently makes no difference between a CMD and DATA read when
using complex maps, the map driver does not know when the swizzle and when not
to swizzle. The next patch in the series adds a hack to the MTD to workaround
this problem. I am sending these 2 patches to the mtd list aswell. There are
several ways to solve this generically in the mtd layer in a much better way.
This will have minor impact on the actual map code provided in this patch.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linux-mips@linux-mips.org
Cc: linux-mtd@lists.infradead.org
---
drivers/mtd/maps/Kconfig | 7 ++
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/lantiq.c | 169 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/maps/lantiq.c
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index a0dd7bb..ca69a7f 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -260,6 +260,13 @@ config MTD_BCM963XX
Support for parsing CFE image tag and creating MTD partitions on
Broadcom BCM63xx boards.
+config MTD_LANTIQ
+ bool "Lantiq SoC NOR support"
+ depends on LANTIQ && MTD_PARTITIONS
+ help
+ Support for NOR flash chips on Lantiq SoC. The Chips are connected
+ to the SoCs EBU (External Bus Unit)
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index c7869c7..bb2ce2f 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+obj-$(CONFIG_MTD_LANTIQ) += lantiq.o
diff --git a/drivers/mtd/maps/lantiq.c b/drivers/mtd/maps/lantiq.c
new file mode 100644
index 0000000..e5a361e
--- /dev/null
+++ b/drivers/mtd/maps/lantiq.c
@@ -0,0 +1,169 @@
+/*
+ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/magic.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+static map_word
+ltq_read16(struct map_info *map, unsigned long adr)
+{
+ unsigned long flags;
+ map_word temp;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ temp.x[0] = *((__u16 *)(map->virt + adr));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ return temp;
+}
+
+static void
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ *((__u16 *)(map->virt + adr)) = d.x[0];
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+ltq_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ unsigned char *p;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ from = (unsigned long)(from + map->virt);
+ p = (unsigned char *) from;
+ to_8 = (unsigned char *) to;
+ while (len--)
+ *to_8++ = *p++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+ltq_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ unsigned char *p = (unsigned char *)from;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ to += (unsigned long) map->virt;
+ to_8 = (unsigned char *)to;
+ while (len--)
+ *p++ = *to_8++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char * const part_probe_types[] = {
+ "cmdlinepart", NULL };
+
+static struct map_info ltq_map = {
+ .name = "ltq_nor",
+ .bankwidth = 2,
+ .read = ltq_read16,
+ .write = ltq_write16,
+ .copy_from = ltq_copy_from,
+ .copy_to = ltq_copy_to,
+};
+
+static int
+ltq_mtd_probe(struct platform_device *pdev)
+{
+ struct physmap_flash_data *ltq_mtd_data =
+ (struct physmap_flash_data *) dev_get_platdata(&pdev->dev);
+ struct mtd_info *ltq_mtd = NULL;
+ struct mtd_partition *parts = NULL;
+ struct resource *res = 0;
+ int nr_parts = 0;
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+ ltq_w32(ltq_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
+#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource");
+ return -ENOENT;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request mem resource");
+ return -EBUSY;
+ }
+
+ ltq_map.phys = res->start;
+ ltq_map.size = resource_size(res);
+ ltq_map.virt = ioremap_nocache(ltq_map.phys, ltq_map.size);
+
+ if (!ltq_map.virt) {
+ dev_err(&pdev->dev, "failed to ioremap!\n");
+ return -EIO;
+ }
+
+ ltq_mtd = (struct mtd_info *) do_map_probe("cfi_probe", <q_map);
+ if (!ltq_mtd) {
+ iounmap(ltq_map.virt);
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
+ }
+
+ ltq_mtd->owner = THIS_MODULE;
+
+ nr_parts = parse_mtd_partitions(ltq_mtd, part_probe_types, &parts, 0);
+ if (nr_parts > 0) {
+ dev_info(&pdev->dev,
+ "using %d partitions from cmdline", nr_parts);
+ } else {
+ nr_parts = ltq_mtd_data->nr_parts;
+ parts = ltq_mtd_data->parts;
+ }
+
+ add_mtd_partitions(ltq_mtd, parts, nr_parts);
+ return 0;
+}
+
+static struct platform_driver ltq_mtd_driver = {
+ .probe = ltq_mtd_probe,
+ .driver = {
+ .name = "ltq_nor",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_ltq_mtd(void)
+{
+ int ret = platform_driver_register(<q_mtd_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_nor: error registering platfom driver");
+ return ret;
+}
+
+module_init(init_ltq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 06/10] MIPS: lantiq: add NOR flash support
@ 2011-01-05 19:56 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, Ralph Hempel, David Woodhouse, linux-mtd,
John Crispin
NOR flash is attached to the same EBU (External Bus Unit) as PCI. As described
in the PCI patch, the EBU is a little obscure, resulting in the upper and lower
16 bit of the data on a 32 bit read are swapped. (essentially we have a addr^=2)
This only happens on the read of data. In order to not have to high an impact
on the read performance from the EBU we store all data on the flash with
addr^=2. This allows us to do generic reads without having to do any swapping.
For the write to now work we need to swizzle the the 0x2 bit of the addr.
However this write swizzle needs to only happen when doing a CMD and not a DATA
write.
As the MTD layer currently makes no difference between a CMD and DATA read when
using complex maps, the map driver does not know when the swizzle and when not
to swizzle. The next patch in the series adds a hack to the MTD to workaround
this problem. I am sending these 2 patches to the mtd list aswell. There are
several ways to solve this generically in the mtd layer in a much better way.
This will have minor impact on the actual map code provided in this patch.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linux-mips@linux-mips.org
Cc: linux-mtd@lists.infradead.org
---
drivers/mtd/maps/Kconfig | 7 ++
drivers/mtd/maps/Makefile | 1 +
drivers/mtd/maps/lantiq.c | 169 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/maps/lantiq.c
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index a0dd7bb..ca69a7f 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -260,6 +260,13 @@ config MTD_BCM963XX
Support for parsing CFE image tag and creating MTD partitions on
Broadcom BCM63xx boards.
+config MTD_LANTIQ
+ bool "Lantiq SoC NOR support"
+ depends on LANTIQ && MTD_PARTITIONS
+ help
+ Support for NOR flash chips on Lantiq SoC. The Chips are connected
+ to the SoCs EBU (External Bus Unit)
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index c7869c7..bb2ce2f 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+obj-$(CONFIG_MTD_LANTIQ) += lantiq.o
diff --git a/drivers/mtd/maps/lantiq.c b/drivers/mtd/maps/lantiq.c
new file mode 100644
index 0000000..e5a361e
--- /dev/null
+++ b/drivers/mtd/maps/lantiq.c
@@ -0,0 +1,169 @@
+/*
+ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/magic.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+static map_word
+ltq_read16(struct map_info *map, unsigned long adr)
+{
+ unsigned long flags;
+ map_word temp;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ temp.x[0] = *((__u16 *)(map->virt + adr));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ return temp;
+}
+
+static void
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ adr ^= 2;
+ *((__u16 *)(map->virt + adr)) = d.x[0];
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+ltq_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ unsigned char *p;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ from = (unsigned long)(from + map->virt);
+ p = (unsigned char *) from;
+ to_8 = (unsigned char *) to;
+ while (len--)
+ *to_8++ = *p++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+void
+ltq_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ unsigned char *p = (unsigned char *)from;
+ unsigned char *to_8;
+ unsigned long flags;
+ spin_lock_irqsave(&ebu_lock, flags);
+ to += (unsigned long) map->virt;
+ to_8 = (unsigned char *)to;
+ while (len--)
+ *p++ = *to_8++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char * const part_probe_types[] = {
+ "cmdlinepart", NULL };
+
+static struct map_info ltq_map = {
+ .name = "ltq_nor",
+ .bankwidth = 2,
+ .read = ltq_read16,
+ .write = ltq_write16,
+ .copy_from = ltq_copy_from,
+ .copy_to = ltq_copy_to,
+};
+
+static int
+ltq_mtd_probe(struct platform_device *pdev)
+{
+ struct physmap_flash_data *ltq_mtd_data =
+ (struct physmap_flash_data *) dev_get_platdata(&pdev->dev);
+ struct mtd_info *ltq_mtd = NULL;
+ struct mtd_partition *parts = NULL;
+ struct resource *res = 0;
+ int nr_parts = 0;
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+ ltq_w32(ltq_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
+#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource");
+ return -ENOENT;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request mem resource");
+ return -EBUSY;
+ }
+
+ ltq_map.phys = res->start;
+ ltq_map.size = resource_size(res);
+ ltq_map.virt = ioremap_nocache(ltq_map.phys, ltq_map.size);
+
+ if (!ltq_map.virt) {
+ dev_err(&pdev->dev, "failed to ioremap!\n");
+ return -EIO;
+ }
+
+ ltq_mtd = (struct mtd_info *) do_map_probe("cfi_probe", <q_map);
+ if (!ltq_mtd) {
+ iounmap(ltq_map.virt);
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
+ }
+
+ ltq_mtd->owner = THIS_MODULE;
+
+ nr_parts = parse_mtd_partitions(ltq_mtd, part_probe_types, &parts, 0);
+ if (nr_parts > 0) {
+ dev_info(&pdev->dev,
+ "using %d partitions from cmdline", nr_parts);
+ } else {
+ nr_parts = ltq_mtd_data->nr_parts;
+ parts = ltq_mtd_data->parts;
+ }
+
+ add_mtd_partitions(ltq_mtd, parts, nr_parts);
+ return 0;
+}
+
+static struct platform_driver ltq_mtd_driver = {
+ .probe = ltq_mtd_probe,
+ .driver = {
+ .name = "ltq_nor",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_ltq_mtd(void)
+{
+ int ret = platform_driver_register(<q_mtd_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_nor: error registering platfom driver");
+ return ret;
+}
+
+module_init(init_ltq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 07/10] MIPS: lantiq: add NOR flash CFI address swizzle
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family John Crispin
` (9 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle
Cc: John Crispin, Ralph Hempel, David Woodhouse, linux-mips,
linux-mtd
This patch adds the hack mentioned in the previous patch.
It is only a hack to make the map driver work until a better solution
is discussed.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linux-mips@linux-mips.org
Cc: linux-mtd@lists.infradead.org
---
drivers/mtd/chips/Kconfig | 9 +++++++++
drivers/mtd/chips/cfi_cmdset_0002.c | 8 ++++++++
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 35c6a23..9ecb5eb 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -39,6 +39,15 @@ config MTD_CFI_ADV_OPTIONS
If unsure, say 'N'.
+config MTD_CFI_CMD_SWIZZLE
+ bool "Swizzle last bit of command address"
+ default y
+ depends on LANTIQ
+ help
+ lantiq SoCs share the external bus unit with the pci interface
+ for MTD to work at the the same time with PCI, we need to add
+ this quirk
+
choice
prompt "Flash cmd/query data swapping"
depends on MTD_CFI_ADV_OPTIONS
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 3b8e32d..e047af1 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -39,7 +39,12 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
+
+#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
+#define FORCE_WORD_WRITE 1
+#else
#define FORCE_WORD_WRITE 0
+#endif
#define MAX_WORD_RETRIES 3
@@ -1140,6 +1145,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
int retry_cnt = 0;
adr += chip->start;
+#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
+ adr ^= 2;
+#endif
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 07/10] MIPS: lantiq: add NOR flash CFI address swizzle
@ 2011-01-05 19:56 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle
Cc: linux-mips, Ralph Hempel, David Woodhouse, linux-mtd,
John Crispin
This patch adds the hack mentioned in the previous patch.
It is only a hack to make the map driver work until a better solution
is discussed.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: linux-mips@linux-mips.org
Cc: linux-mtd@lists.infradead.org
---
drivers/mtd/chips/Kconfig | 9 +++++++++
drivers/mtd/chips/cfi_cmdset_0002.c | 8 ++++++++
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 35c6a23..9ecb5eb 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -39,6 +39,15 @@ config MTD_CFI_ADV_OPTIONS
If unsure, say 'N'.
+config MTD_CFI_CMD_SWIZZLE
+ bool "Swizzle last bit of command address"
+ default y
+ depends on LANTIQ
+ help
+ lantiq SoCs share the external bus unit with the pci interface
+ for MTD to work at the the same time with PCI, we need to add
+ this quirk
+
choice
prompt "Flash cmd/query data swapping"
depends on MTD_CFI_ADV_OPTIONS
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 3b8e32d..e047af1 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -39,7 +39,12 @@
#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
+
+#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
+#define FORCE_WORD_WRITE 1
+#else
#define FORCE_WORD_WRITE 0
+#endif
#define MAX_WORD_RETRIES 3
@@ -1140,6 +1145,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
int retry_cnt = 0;
adr += chip->start;
+#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
+ adr ^= 2;
+#endif
mutex_lock(&chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 08/10] MIPS: lantiq: add platform device support
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (6 preceding siblings ...)
2011-01-05 19:56 ` John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 09/10] MIPS: lantiq: add mips_machine support John Crispin
` (2 subsequent siblings)
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
This patch adds the wrappers for registering our platform devices.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
---
arch/mips/lantiq/Makefile | 2 +-
arch/mips/lantiq/devices.c | 127 +++++++++++++++++++++++++++++++++++++++
arch/mips/lantiq/devices.h | 20 ++++++
arch/mips/lantiq/xway/Makefile | 2 +-
arch/mips/lantiq/xway/devices.c | 55 +++++++++++++++++
arch/mips/lantiq/xway/devices.h | 16 +++++
6 files changed, 220 insertions(+), 2 deletions(-)
create mode 100644 arch/mips/lantiq/devices.c
create mode 100644 arch/mips/lantiq/devices.h
create mode 100644 arch/mips/lantiq/xway/devices.c
create mode 100644 arch/mips/lantiq/xway/devices.h
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
index a268391..e5dae0e 100644
--- a/arch/mips/lantiq/Makefile
+++ b/arch/mips/lantiq/Makefile
@@ -4,7 +4,7 @@
# under the terms of the GNU General Public License version 2 as published
# by the Free Software Foundation.
-obj-y := irq.o setup.o clk.o prom.o
+obj-y := irq.o setup.o clk.o prom.o devices.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
new file mode 100644
index 0000000..2c68d8e
--- /dev/null
+++ b/arch/mips/lantiq/devices.c
@@ -0,0 +1,127 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+
+#include "devices.h"
+
+#define IRQ_RES(resname, irq) \
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
+
+/* nor flash */
+static struct resource ltq_nor_resource = {
+ .name = "nor",
+ .start = LTQ_FLASH_START,
+ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+ .resource = <q_nor_resource,
+ .num_resources = 1,
+};
+
+void __init
+ltq_register_nor(struct physmap_flash_data *data)
+{
+ ltq_nor.dev.platform_data = data;
+ platform_device_register(<q_nor);
+}
+
+/* watchdog */
+static struct resource ltq_wdt_resource = {
+ .name = "watchdog",
+ .start = LTQ_WDT_BASE,
+ .end = LTQ_WDT_BASE + LTQ_WDT_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+void __init
+ltq_register_wdt(void)
+{
+ platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1);
+}
+
+/* asc ports */
+static struct resource ltq_asc0_resources[] = {
+ {
+ .start = LTQ_ASC0_BASE,
+ .end = LTQ_ASC0_BASE + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
+};
+
+static struct resource ltq_asc1_resources[] = {
+ {
+ .start = LTQ_ASC1_BASE,
+ .end = LTQ_ASC1_BASE + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
+};
+
+void __init
+ltq_register_asc(int port)
+{
+ switch (port) {
+ case 0:
+ platform_device_register_simple("ltq_asc", 0,
+ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources));
+ break;
+ case 1:
+ platform_device_register_simple("ltq_asc", 1,
+ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources));
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef CONFIG_PCI
+/* pci */
+static struct platform_device ltq_pci = {
+ .name = "ltq_pci",
+ .num_resources = 0,
+};
+
+void __init
+ltq_register_pci(struct ltq_pci_data *data)
+{
+ ltq_pci.dev.platform_data = data;
+ platform_device_register(<q_pci);
+}
+#else
+void __init
+ltq_register_pci(struct ltq_pci_data *data)
+{
+}
+#endif
diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
new file mode 100644
index 0000000..069006c
--- /dev/null
+++ b/arch/mips/lantiq/devices.h
@@ -0,0 +1,20 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_H__
+#define _LTQ_DEVICES_H__
+
+#include <lantiq_platform.h>
+#include <linux/mtd/physmap.h>
+
+extern void ltq_register_nor(struct physmap_flash_data *data);
+extern void ltq_register_wdt(void);
+extern void ltq_register_asc(int port);
+extern void ltq_register_pci(struct ltq_pci_data *data);
+
+#endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 64730d5..7b36708 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1,4 @@
-obj-y := pmu.o reset.o gpio.o
+obj-y := pmu.o reset.o gpio.o devices.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
new file mode 100644
index 0000000..c2be742
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.c
@@ -0,0 +1,55 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mtd/physmap.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+
+/* gpio */
+static struct resource ltq_gpio_resource[] = {
+ {
+ .name = "gpio0",
+ .start = LTQ_GPIO0_BASE_ADDR,
+ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "gpio1",
+ .start = LTQ_GPIO1_BASE_ADDR,
+ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+void __init
+ltq_register_gpio(void)
+{
+ platform_device_register_simple("ltq_gpio", 0,
+ <q_gpio_resource[0], 1);
+ platform_device_register_simple("ltq_gpio", 1,
+ <q_gpio_resource[1], 1);
+}
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
new file mode 100644
index 0000000..d248bf3
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.h
@@ -0,0 +1,16 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_XWAY_H__
+#define _LTQ_DEVICES_XWAY_H__
+
+#include "../devices.h"
+
+extern void ltq_register_gpio(void);
+
+#endif
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 09/10] MIPS: lantiq: add mips_machine support
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (7 preceding siblings ...)
2011-01-05 19:56 ` [PATCH 08/10] MIPS: lantiq: add platform device support John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-05 19:56 ` [PATCH 10/10] MIPS: lantiq: add machtypes for lantiq eval kits John Crispin
2011-01-11 2:44 ` [PATCH 00/10] MIPS: add support for Lantiq SoCs Daniel Schwierzeck
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, Gabor Juhos, linux-mips
This patch adds support for Gabor's mips_machine patch.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: Gabor Juhos <juhosg@openwrt.org>
Cc: linux-mips@linux-mips.org
---
arch/mips/Kconfig | 1 +
arch/mips/lantiq/machtypes.h | 18 ++++++++++++++++++
arch/mips/lantiq/setup.c | 25 +++++++++++++++++++++++++
3 files changed, 44 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/lantiq/machtypes.h
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 9d3fd89..ee5dccf 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -207,6 +207,7 @@ config LANTIQ
select ARCH_REQUIRE_GPIOLIB
select SWAP_IO_SPACE
select BOOT_RAW
+ select MIPS_MACHINE
config LASAT
bool "LASAT Networks platforms"
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
new file mode 100644
index 0000000..ffcacfc
--- /dev/null
+++ b/arch/mips/lantiq/machtypes.h
@@ -0,0 +1,18 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_MACH_H__
+#define _LANTIQ_MACH_H__
+
+#include <asm/mips_machine.h>
+
+enum lantiq_mach_type {
+ LTQ_MACH_GENERIC = 0,
+};
+
+#endif
diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
index f0f74d2..b30567e 100644
--- a/arch/mips/lantiq/setup.c
+++ b/arch/mips/lantiq/setup.c
@@ -14,6 +14,9 @@
#include <lantiq.h>
+#include "machtypes.h"
+#include "devices.h"
+
void __init
plat_mem_setup(void)
{
@@ -43,3 +46,25 @@ plat_mem_setup(void)
memsize *= 1024 * 1024;
add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
}
+
+static int __init
+lantiq_setup(void)
+{
+ ltq_register_asc(0);
+ ltq_register_asc(1);
+ mips_machine_setup();
+ return 0;
+}
+
+arch_initcall(lantiq_setup);
+
+static void __init
+lantiq_generic_init(void)
+{
+ /* Nothing to do */
+}
+
+MIPS_MACHINE(LTQ_MACH_GENERIC,
+ "Generic",
+ "Generic Lantiq based board",
+ lantiq_generic_init);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH 10/10] MIPS: lantiq: add machtypes for lantiq eval kits
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (8 preceding siblings ...)
2011-01-05 19:56 ` [PATCH 09/10] MIPS: lantiq: add mips_machine support John Crispin
@ 2011-01-05 19:56 ` John Crispin
2011-01-11 2:44 ` [PATCH 00/10] MIPS: add support for Lantiq SoCs Daniel Schwierzeck
10 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-05 19:56 UTC (permalink / raw)
To: Ralf Baechle; +Cc: John Crispin, Ralph Hempel, linux-mips
This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation
boards
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
Cc: linux-mips@linux-mips.org
---
arch/mips/lantiq/Kconfig | 2 +
arch/mips/lantiq/machtypes.h | 2 +
arch/mips/lantiq/xway/Kconfig | 25 +++++++++++
arch/mips/lantiq/xway/Makefile | 3 +
arch/mips/lantiq/xway/mach-easy50601.c | 70 ++++++++++++++++++++++++++++++++
arch/mips/lantiq/xway/mach-easy50712.c | 70 ++++++++++++++++++++++++++++++++
6 files changed, 172 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/lantiq/xway/Kconfig
create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c
create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
index 2780461..3fccf21 100644
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -18,4 +18,6 @@ config SOC_XWAY
select HW_HAS_PCI
endchoice
+source "arch/mips/lantiq/xway/Kconfig"
+
endif
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
index ffcacfc..7e01b8c 100644
--- a/arch/mips/lantiq/machtypes.h
+++ b/arch/mips/lantiq/machtypes.h
@@ -13,6 +13,8 @@
enum lantiq_mach_type {
LTQ_MACH_GENERIC = 0,
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
};
#endif
diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig
new file mode 100644
index 0000000..f6d0bec
--- /dev/null
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -0,0 +1,25 @@
+if SOC_XWAY
+
+menu "Mips Machine"
+
+config LANTIQ_MACH_EASY50712
+ bool "Easy50712 - Danube"
+ default y
+
+endmenu
+
+endif
+
+if SOC_AMAZON_SE
+
+menu "Mips Machine"
+
+config LANTIQ_MACH_EASY50601
+ bool "Easy50601 - Amazon SE"
+ default y
+
+endmenu
+
+endif
+
+
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 7b36708..570507c 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -2,3 +2,6 @@ obj-y := pmu.o reset.o gpio.o devices.o
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
+
+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
+obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c
new file mode 100644
index 0000000..fb591fc
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50601.c
@@ -0,0 +1,70 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition easy50601_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0xE0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+#endif
+
+static struct physmap_flash_data easy50601_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(easy50601_partitions),
+ .parts = easy50601_partitions,
+#endif
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .req_mask = 0xf,
+};
+
+static void __init
+easy50601_init(void)
+{
+ ltq_register_gpio();
+ ltq_register_nor(&easy50601_flash_data);
+ ltq_register_wdt();
+ ltq_register_pci(<q_pci_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50601,
+ "EASY50601",
+ "EASY50601 Eval Board",
+ easy50601_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
new file mode 100644
index 0000000..816d1ce
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -0,0 +1,70 @@
+/*
+ * 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) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition easy50712_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0xE0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+#endif
+
+static struct physmap_flash_data easy50712_flash_data = {
+#ifdef CONFIG_MTD_PARTITIONS
+ .nr_parts = ARRAY_SIZE(easy50712_partitions),
+ .parts = easy50712_partitions,
+#endif
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .req_mask = 0xf,
+};
+
+static void __init
+easy50712_init(void)
+{
+ ltq_register_gpio();
+ ltq_register_nor(&easy50712_flash_data);
+ ltq_register_wdt();
+ ltq_register_pci(<q_pci_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50712,
+ "EASY50712",
+ "EASY50712 Eval Board",
+ easy50712_init);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
@ 2011-01-05 20:25 ` Geert Uytterhoeven
2011-01-13 11:05 ` Daniel Schwierzeck
1 sibling, 0 replies; 32+ messages in thread
From: Geert Uytterhoeven @ 2011-01-05 20:25 UTC (permalink / raw)
To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
On Wed, Jan 5, 2011 at 20:56, John Crispin <blogic@openwrt.org> wrote:
> --- /dev/null
> +++ b/arch/mips/lantiq/prom.c
> @@ -0,0 +1,84 @@
> +static void __init
> +prom_init_cmdline(void)
> +{
> + int argc = fw_arg0;
> + char **argv = (char **) KSEG1ADDR(fw_arg1);
> + int i;
> + arcs_cmdline[0] = '\0';
> + if (argc)
> + for (i = 1; i < argc; i++) {
> + strlcat(arcs_cmdline, (char *)KSEG1ADDR(argv[i]),
> + COMMAND_LINE_SIZE);
> + if (i + 1 != argc)
> + strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
> + }
> + if (!*arcs_cmdline)
> + strcpy(&(arcs_cmdline[0]),
> + "console=ttyS1,115200 rootfstype=squashfs,jffs2");
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
CONFIG_CMDLINE???
> +}
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 05/10] MIPS: lantiq: add watchdog support
2011-01-05 19:56 ` [PATCH 05/10] MIPS: lantiq: add watchdog support John Crispin
@ 2011-01-05 23:49 ` Jamie Iles
2011-01-06 9:51 ` John Crispin
0 siblings, 1 reply; 32+ messages in thread
From: Jamie Iles @ 2011-01-05 23:49 UTC (permalink / raw)
To: John Crispin
Cc: Ralf Baechle, Ralph Hempel, Wim Van Sebroeck, linux-mips,
linux-watchdog
Hi John,
A few nitpicks inline, but otherwise looks good to me.
Jamie
On Wed, Jan 05, 2011 at 08:56:14PM +0100, John Crispin wrote:
> This patch adds the driver for the watchdog found inside the Lantiq SoC family.
>
> Signed-off-by: John Crispin <blogic@openwrt.org>
> Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
> Cc: Wim Van Sebroeck <wim@iguana.be>
> Cc: linux-mips@linux-mips.org
> Cc: linux-watchdog@vger.kernel.org
> ---
> drivers/watchdog/Kconfig | 6 +
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/lantiq_wdt.c | 208 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 215 insertions(+), 0 deletions(-)
> create mode 100644 drivers/watchdog/lantiq_wdt.c
[...]
> diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
> new file mode 100644
> index 0000000..543bcf1
> --- /dev/null
> +++ b/drivers/watchdog/lantiq_wdt.c
> @@ -0,0 +1,208 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + * Based on EP93xx wdt driver
> + */
> +
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/miscdevice.h>
> +#include <linux/miscdevice.h>
Duplicated include of linux/miscdevice.h
> +#include <linux/watchdog.h>
> +#include <linux/platform_device.h>
> +#include <linux/uaccess.h>
> +#include <linux/clk.h>
> +
> +#include <lantiq.h>
> +
> +#define LTQ_WDT_PW1 0x00BE0000
> +#define LTQ_WDT_PW2 0x00DC0000
> +
> +#define LTQ_BIU_WDT_CR 0x3F0
> +#define LTQ_BIU_WDT_SR 0x3F8
It's not obvious to me what these defines actually mean. A couple of
short comments to describe what they are?
> +
> +#ifndef CONFIG_WATCHDOG_NOWAYOUT
> +static int wdt_ok_to_close;
> +#endif
> +
> +static int wdt_timeout = 30;
> +static __iomem void *wdt_membase;
I think this would normally be "static void __iomem" rather than "static
__iomem void". Also these could do with the ltq_ prefix for namespacing.
> +static unsigned long io_region_clk;
Better to name this io_region_clk_rate?
> +
> +static int
> +ltq_wdt_enable(unsigned int timeout)
> +{
> + ltq_w32(LTQ_WDT_PW1, wdt_membase + LTQ_BIU_WDT_CR);
> + ltq_w32(LTQ_WDT_PW2 |
> + (0x3 << 26) | /* PWL */
> + (0x3 << 24) | /* CLKDIV */
> + (0x1 << 31) | /* enable */
> + ((timeout * (io_region_clk / 0x40000)) + 0x1000), /* reload */
> + wdt_membase + LTQ_BIU_WDT_CR);
Perhaps a comment describing the how this value is calculated? What does
PWL mean and what are the significance of 0x40000 and 0x1000? Also, do
you need to check that the timeout won't overflow the bits for the
reload value?
> + return 0;
> +}
> +
> +static void
> +ltq_wdt_disable(void)
> +{
> +#ifndef CONFIG_WATCHDOG_NOWAYOUT
> + wdt_ok_to_close = 0;
> +#endif
> + ltq_w32(LTQ_WDT_PW1, wdt_membase + LTQ_BIU_WDT_CR);
> + ltq_w32(LTQ_WDT_PW2, wdt_membase + LTQ_BIU_WDT_CR);
> +}
> +
> +static ssize_t
> +ltq_wdt_write(struct file *file, const char __user *data,
> + size_t len, loff_t *ppos)
> +{
> + size_t i;
> + if (!len)
> + return 0;
> +#ifndef CONFIG_WATCHDOG_NOWAYOUT
> + for (i = 0; i != len; i++) {
> + char c;
> + if (get_user(c, data + i))
> + return -EFAULT;
> + if (c == 'V')
> + wdt_ok_to_close = 1;
> + }
> +#endif
> + ltq_wdt_enable(wdt_timeout);
> + return len;
> +}
> +
> +static struct watchdog_info ident = {
> + .options = WDIOF_MAGICCLOSE,
I think you can also add WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING.
> + .identity = "ltq_wdt",
> +};
> +
> +static long
> +ltq_wdt_ioctl(struct file *file,
> + unsigned int cmd, unsigned long arg)
> +{
> + int ret = -ENOTTY;
> + switch (cmd) {
> + case WDIOC_GETSUPPORT:
> + ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
> + sizeof(ident)) ? -EFAULT : 0;
> + break;
> +
> + case WDIOC_GETTIMEOUT:
> + ret = put_user(wdt_timeout, (int __user *)arg);
> + break;
> +
> + case WDIOC_SETTIMEOUT:
> + ret = get_user(wdt_timeout, (int __user *)arg);
Should you reset the WDT with the new timeout here rather than waiting
for the next keepalive?
> + break;
> +
> + case WDIOC_KEEPALIVE:
> + ltq_wdt_enable(wdt_timeout);
> + ret = 0;
> + break;
> + }
> + return ret;
> +}
> +
> +static int
> +ltq_wdt_open(struct inode *inode, struct file *file)
> +{
> + ltq_wdt_enable(wdt_timeout);
> + return nonseekable_open(inode, file);
> +}
> +
> +static int
> +ltq_wdt_release(struct inode *inode, struct file *file)
> +{
> +#ifndef CONFIG_WATCHDOG_NOWAYOUT
> + if (wdt_ok_to_close)
> + ltq_wdt_disable();
> + else
> +#endif
> + printk(KERN_ERR "ltq_wdt: watchdog closed without warning,"
> + " rebooting system\n");
> + return 0;
> +}
> +
> +static const struct file_operations ltq_wdt_fops = {
> + .owner = THIS_MODULE,
> + .write = ltq_wdt_write,
> + .unlocked_ioctl = ltq_wdt_ioctl,
Align the .unlocked_ioctl assignment with the others?
> + .open = ltq_wdt_open,
> + .release = ltq_wdt_release,
Add ".llseek = no_llseek"?
> +};
> +
> +static struct miscdevice ltq_wdt_miscdev = {
> + .minor = WATCHDOG_MINOR,
> + .name = "watchdog",
> + .fops = <q_wdt_fops,
> +};
> +
> +static int
> +ltq_wdt_probe(struct platform_device *pdev)
> +{
> + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + struct clk *clk;
> + int ret = 0;
> + if (!res)
> + return -ENOENT;
> + res = request_mem_region(res->start, resource_size(res),
> + dev_name(&pdev->dev));
> + if (!res)
> + return -EBUSY;
> + wdt_membase = ioremap_nocache(res->start, resource_size(res));
> + if (!wdt_membase) {
> + ret = -ENOMEM;
> + goto err_release_mem_region;
> + }
You can use devm_request_mem_region() and devm_ioremap_nocache() to
simplify the error handling and removal.
> + clk = clk_get(&pdev->dev, "io");
Do you need a clk_enable() here too? Or a comment explaining it's always
enabled (if it is)?
> + io_region_clk = clk_get_rate(clk);;
> + ret = misc_register(<q_wdt_miscdev);
> + if (!ret)
> + return 0;
> +
> + iounmap(wdt_membase);
> +err_release_mem_region:
> + release_mem_region(res->start, resource_size(res));
> + return ret;
> +}
> +
> +static int
> +ltq_wdt_remove(struct platform_device *dev)
> +{
> + ltq_wdt_disable();
> + misc_deregister(<q_wdt_miscdev);
I think you need a clk_put() here too to balance the clk_get() in the
probe method so you'll need to keep a reference to the clk.
> + return 0;
> +}
> +
> +static struct platform_driver ltq_wdt_driver = {
> + .probe = ltq_wdt_probe,
> + .remove = ltq_wdt_remove,
> + .driver = {
> + .name = "ltq_wdt",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init
> +init_ltq_wdt(void)
> +{
> + return platform_driver_register(<q_wdt_driver);
> +}
> +
> +static void __exit
> +exit_ltq_wdt(void)
> +{
> + platform_driver_unregister(<q_wdt_driver);
> +}
> +
> +module_init(init_ltq_wdt);
> +module_exit(exit_ltq_wdt);
> +
> +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
> +MODULE_DESCRIPTION("Lantiq Watchdog");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
> --
> 1.7.2.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 05/10] MIPS: lantiq: add watchdog support
2011-01-05 23:49 ` Jamie Iles
@ 2011-01-06 9:51 ` John Crispin
2011-01-06 11:15 ` Jamie Iles
0 siblings, 1 reply; 32+ messages in thread
From: John Crispin @ 2011-01-06 9:51 UTC (permalink / raw)
To: Jamie Iles
Cc: Ralf Baechle, Ralph Hempel, Wim Van Sebroeck, linux-mips,
linux-watchdog
On 06/01/11 00:49, Jamie Iles wrote:
> I think you need a clk_put() here too to balance the clk_get() in the
> probe method so you'll need to keep a reference to the clk.
>
>
Hi Jamie,
i will fold your suggestions into the series.
the clk.c/h implementation on the lantiq target is very simple. it only
allows to read the static rates of the 3 clocks. clk_put is implemented
as follows
void
clk_put(struct clk *clk)
{
/* not used */
}
EXPORT_SYMBOL(clk_put);
so in theory you are right and we should call that function, however as
it is only a stub and the driver is only used by the lantiq target i
think it is save to leave out the clk_put(); call. we could however put
a commet in the code to make this clear (same as with the clk_enable()
not being needed as the clocks are always running)
Thanks,
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 07/10] MIPS: lantiq: add NOR flash CFI address swizzle
2011-01-05 19:56 ` John Crispin
@ 2011-01-06 10:06 ` John Crispin
-1 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-06 10:06 UTC (permalink / raw)
To: David Woodhouse; +Cc: Ralf Baechle, Ralph Hempel, linux-mips, linux-mtd
On 05/01/11 20:56, John Crispin wrote:
>
> adr += chip->start;
> +#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
> + adr ^= 2;
> +#endif
>
> mutex_lock(&chip->mutex);
> ret = get_chip(map, chip, adr, FL_WRITING);
>
Hi,
What this patch essentially does is to make sure to pass a addr with the
^=2 hack already applied, so that the complex map ends up with an un
swizzled addr as it applies the hack internally again.
I think it would be cleanest to extend the read/write callbacks of
struct map_info; with a flag indicating whether we are doing a CMD or
DATA action. as the 2 following macros are used anyway, it should not be
too hard to implement this.
#define map_read(map, ofs) (map)->read(map, ofs)
#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
I am not sure however if this is the correct fix.
Thanks,
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 07/10] MIPS: lantiq: add NOR flash CFI address swizzle
@ 2011-01-06 10:06 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-06 10:06 UTC (permalink / raw)
To: David Woodhouse; +Cc: linux-mips, Ralph Hempel, linux-mtd, Ralf Baechle
On 05/01/11 20:56, John Crispin wrote:
>
> adr += chip->start;
> +#ifdef CONFIG_MTD_CFI_CMD_SWIZZLE
> + adr ^= 2;
> +#endif
>
> mutex_lock(&chip->mutex);
> ret = get_chip(map, chip, adr, FL_WRITING);
>
Hi,
What this patch essentially does is to make sure to pass a addr with the
^=2 hack already applied, so that the complex map ends up with an un
swizzled addr as it applies the hack internally again.
I think it would be cleanest to extend the read/write callbacks of
struct map_info; with a flag indicating whether we are doing a CMD or
DATA action. as the 2 following macros are used anyway, it should not be
too hard to implement this.
#define map_read(map, ofs) (map)->read(map, ofs)
#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
I am not sure however if this is the correct fix.
Thanks,
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 05/10] MIPS: lantiq: add watchdog support
2011-01-06 9:51 ` John Crispin
@ 2011-01-06 11:15 ` Jamie Iles
2011-01-06 11:38 ` John Crispin
0 siblings, 1 reply; 32+ messages in thread
From: Jamie Iles @ 2011-01-06 11:15 UTC (permalink / raw)
To: John Crispin
Cc: Jamie Iles, Ralf Baechle, Ralph Hempel, Wim Van Sebroeck,
linux-mips, linux-watchdog
On Thu, Jan 06, 2011 at 10:51:10AM +0100, John Crispin wrote:
> On 06/01/11 00:49, Jamie Iles wrote:
> > I think you need a clk_put() here too to balance the clk_get() in the
> > probe method so you'll need to keep a reference to the clk.
> >
> >
>
> Hi Jamie,
>
> i will fold your suggestions into the series.
>
> the clk.c/h implementation on the lantiq target is very simple. it only
> allows to read the static rates of the 3 clocks. clk_put is implemented
> as follows
>
> void
> clk_put(struct clk *clk)
> {
> /* not used */
> }
> EXPORT_SYMBOL(clk_put);
>
> so in theory you are right and we should call that function, however as
> it is only a stub and the driver is only used by the lantiq target i
> think it is save to leave out the clk_put(); call. we could however put
> a commet in the code to make this clear (same as with the clk_enable()
> not being needed as the clocks are always running)
Could that ever change for future devices that share the same watchdog
block? If so, then adding in that clk_put() and clk_enable() might be
worth it as it doesn't cost much.
Jamie
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 05/10] MIPS: lantiq: add watchdog support
2011-01-06 11:15 ` Jamie Iles
@ 2011-01-06 11:38 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-06 11:38 UTC (permalink / raw)
To: Jamie Iles
Cc: Ralf Baechle, Ralph Hempel, Wim Van Sebroeck, linux-mips,
linux-watchdog
On 06/01/11 12:15, Jamie Iles wrote:
> On Thu, Jan 06, 2011 at 10:51:10AM +0100, John Crispin wrote:
>
>> On 06/01/11 00:49, Jamie Iles wrote:
>>
>>> I think you need a clk_put() here too to balance the clk_get() in the
>>> probe method so you'll need to keep a reference to the clk.
>>>
>>>
>>>
>> Hi Jamie,
>>
>> i will fold your suggestions into the series.
>>
>> the clk.c/h implementation on the lantiq target is very simple. it only
>> allows to read the static rates of the 3 clocks. clk_put is implemented
>> as follows
>>
>> void
>> clk_put(struct clk *clk)
>> {
>> /* not used */
>> }
>> EXPORT_SYMBOL(clk_put);
>>
>> so in theory you are right and we should call that function, however as
>> it is only a stub and the driver is only used by the lantiq target i
>> think it is save to leave out the clk_put(); call. we could however put
>> a commet in the code to make this clear (same as with the clk_enable()
>> not being needed as the clocks are always running)
>>
> Could that ever change for future devices that share the same watchdog
> block? If so, then adding in that clk_put() and clk_enable() might be
> worth it as it doesn't cost much.
>
> Jamie
>
>
agreed, i will add both calls.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 00/10] MIPS: add support for Lantiq SoCs
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
` (9 preceding siblings ...)
2011-01-05 19:56 ` [PATCH 10/10] MIPS: lantiq: add machtypes for lantiq eval kits John Crispin
@ 2011-01-11 2:44 ` Daniel Schwierzeck
2011-01-11 12:07 ` John Crispin
10 siblings, 1 reply; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-11 2:44 UTC (permalink / raw)
To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
Hi John,
after the 2.6.36 release i've started the same upstream project. I'm
hacking software for CPE's with Danube and VRX SoC's thus I have full
access to hardware manuals and latest BSP's. Maybe we should merge our
code somehow ;)
Daniel
On 01/05/2011 08:56 PM, John Crispin wrote:
> This series will add support for the Lantiq/XWAY family of SoCs.
>
> Cc: Ralph Hempel<ralph.hempel@lantiq.com>
> Cc: linux-mips@linux-mips.org
>
> John Crispin (10):
> MIPS: lantiq: add initial support for Lantiq SoCs
> MIPS: lantiq: add SoC specific code for XWAY family
> MIPS: lantiq: add PCI controller support.
> MIPS: lantiq: add serial port support
> MIPS: lantiq: add watchdog support
> MIPS: lantiq: add NOR flash support
> MIPS: lantiq: add NOR flash CFI address swizzle
> MIPS: lantiq: add platform device support
> MIPS: lantiq: add mips_machine support
> MIPS: lantiq: add machtypes for lantiq eval kits
>
> arch/mips/Kbuild.platforms | 1 +
> arch/mips/Kconfig | 18 +
> arch/mips/include/asm/mach-lantiq/lantiq.h | 48 ++
> .../mips/include/asm/mach-lantiq/lantiq_platform.h | 25 +
> arch/mips/include/asm/mach-lantiq/war.h | 24 +
> arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 +
> .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 62 ++
> .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 119 +++
> arch/mips/lantiq/Kconfig | 23 +
> arch/mips/lantiq/Makefile | 11 +
> arch/mips/lantiq/Platform | 8 +
> arch/mips/lantiq/clk.c | 129 ++++
> arch/mips/lantiq/clk.h | 18 +
> arch/mips/lantiq/devices.c | 127 ++++
> arch/mips/lantiq/devices.h | 20 +
> arch/mips/lantiq/early_printk.c | 47 ++
> arch/mips/lantiq/irq.c | 209 ++++++
> arch/mips/lantiq/machtypes.h | 20 +
> arch/mips/lantiq/prom.c | 84 +++
> arch/mips/lantiq/prom.h | 26 +
> arch/mips/lantiq/setup.c | 70 ++
> arch/mips/lantiq/xway/Kconfig | 25 +
> arch/mips/lantiq/xway/Makefile | 7 +
> arch/mips/lantiq/xway/clk-ase.c | 53 ++
> arch/mips/lantiq/xway/clk-xway.c | 221 ++++++
> arch/mips/lantiq/xway/devices.c | 55 ++
> arch/mips/lantiq/xway/devices.h | 16 +
> arch/mips/lantiq/xway/gpio.c | 205 ++++++
> arch/mips/lantiq/xway/mach-easy50601.c | 70 ++
> arch/mips/lantiq/xway/mach-easy50712.c | 70 ++
> arch/mips/lantiq/xway/pmu.c | 36 +
> arch/mips/lantiq/xway/prom-ase.c | 41 +
> arch/mips/lantiq/xway/prom-xway.c | 56 ++
> arch/mips/lantiq/xway/reset.c | 53 ++
> arch/mips/pci/Makefile | 1 +
> arch/mips/pci/ops-lantiq.c | 118 +++
> arch/mips/pci/pci-lantiq.c | 286 ++++++++
> arch/mips/pci/pci-lantiq.h | 18 +
> drivers/mtd/chips/Kconfig | 9 +
> drivers/mtd/chips/cfi_cmdset_0002.c | 8 +
> drivers/mtd/maps/Kconfig | 7 +
> drivers/mtd/maps/Makefile | 1 +
> drivers/mtd/maps/lantiq.c | 169 +++++
> drivers/serial/Kconfig | 8 +
> drivers/serial/Makefile | 1 +
> drivers/serial/lantiq.c | 774 ++++++++++++++++++++
> drivers/watchdog/Kconfig | 6 +
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/lantiq_wdt.c | 208 ++++++
> 49 files changed, 3630 insertions(+), 0 deletions(-)
> create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
> create mode 100644 arch/mips/lantiq/Kconfig
> create mode 100644 arch/mips/lantiq/Makefile
> create mode 100644 arch/mips/lantiq/Platform
> create mode 100644 arch/mips/lantiq/clk.c
> create mode 100644 arch/mips/lantiq/clk.h
> create mode 100644 arch/mips/lantiq/devices.c
> create mode 100644 arch/mips/lantiq/devices.h
> create mode 100644 arch/mips/lantiq/early_printk.c
> create mode 100644 arch/mips/lantiq/irq.c
> create mode 100644 arch/mips/lantiq/machtypes.h
> create mode 100644 arch/mips/lantiq/prom.c
> create mode 100644 arch/mips/lantiq/prom.h
> create mode 100644 arch/mips/lantiq/setup.c
> create mode 100644 arch/mips/lantiq/xway/Kconfig
> create mode 100644 arch/mips/lantiq/xway/Makefile
> create mode 100644 arch/mips/lantiq/xway/clk-ase.c
> create mode 100644 arch/mips/lantiq/xway/clk-xway.c
> create mode 100644 arch/mips/lantiq/xway/devices.c
> create mode 100644 arch/mips/lantiq/xway/devices.h
> create mode 100644 arch/mips/lantiq/xway/gpio.c
> create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c
> create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c
> create mode 100644 arch/mips/lantiq/xway/pmu.c
> create mode 100644 arch/mips/lantiq/xway/prom-ase.c
> create mode 100644 arch/mips/lantiq/xway/prom-xway.c
> create mode 100644 arch/mips/lantiq/xway/reset.c
> create mode 100644 arch/mips/pci/ops-lantiq.c
> create mode 100644 arch/mips/pci/pci-lantiq.c
> create mode 100644 arch/mips/pci/pci-lantiq.h
> create mode 100644 drivers/mtd/maps/lantiq.c
> create mode 100644 drivers/serial/lantiq.c
> create mode 100644 drivers/watchdog/lantiq_wdt.c
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 06/10] MIPS: lantiq: add NOR flash support
2011-01-05 19:56 ` John Crispin
@ 2011-01-11 2:59 ` Daniel Schwierzeck
-1 siblings, 0 replies; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-11 2:59 UTC (permalink / raw)
To: John Crispin
Cc: Ralf Baechle, Ralph Hempel, David Woodhouse, linux-mips,
linux-mtd
Hi John,
the EBU doesn't allow unaligned read or write access thus Lantiq added
this alignment hack directly in hardware. The addr^=2 is only needed
during CFI probe because odd addresses are accessed. A simple solution
is inside your patch.
The spin_lock_irqsave(&ebu_lock, flags); is actually not needed because
the EBU does access arbitration and protection already in hardware.
Daniel
On 01/05/2011 08:56 PM, John Crispin wrote:
> NOR flash is attached to the same EBU (External Bus Unit) as PCI. As described
> in the PCI patch, the EBU is a little obscure, resulting in the upper and lower
> 16 bit of the data on a 32 bit read are swapped. (essentially we have a addr^=2)
> This only happens on the read of data. In order to not have to high an impact
> on the read performance from the EBU we store all data on the flash with
> addr^=2. This allows us to do generic reads without having to do any swapping.
> For the write to now work we need to swizzle the the 0x2 bit of the addr.
> However this write swizzle needs to only happen when doing a CMD and not a DATA
> write.
>
> As the MTD layer currently makes no difference between a CMD and DATA read when
> using complex maps, the map driver does not know when the swizzle and when not
> to swizzle. The next patch in the series adds a hack to the MTD to workaround
> this problem. I am sending these 2 patches to the mtd list aswell. There are
> several ways to solve this generically in the mtd layer in a much better way.
> This will have minor impact on the actual map code provided in this patch.
>
> Signed-off-by: John Crispin<blogic@openwrt.org>
> Signed-off-by: Ralph Hempel<ralph.hempel@lantiq.com>
> Cc: David Woodhouse<dwmw2@infradead.org>
> Cc: linux-mips@linux-mips.org
> Cc: linux-mtd@lists.infradead.org
> ---
> drivers/mtd/maps/Kconfig | 7 ++
> drivers/mtd/maps/Makefile | 1 +
> drivers/mtd/maps/lantiq.c | 169 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 177 insertions(+), 0 deletions(-)
> create mode 100644 drivers/mtd/maps/lantiq.c
>
> diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
> index a0dd7bb..ca69a7f 100644
> --- a/drivers/mtd/maps/Kconfig
> +++ b/drivers/mtd/maps/Kconfig
> @@ -260,6 +260,13 @@ config MTD_BCM963XX
> Support for parsing CFE image tag and creating MTD partitions on
> Broadcom BCM63xx boards.
>
> +config MTD_LANTIQ
> + bool "Lantiq SoC NOR support"
> + depends on LANTIQ&& MTD_PARTITIONS
> + help
> + Support for NOR flash chips on Lantiq SoC. The Chips are connected
> + to the SoCs EBU (External Bus Unit)
> +
> config MTD_DILNETPC
> tristate "CFI Flash device mapped on DIL/Net PC"
> depends on X86&& MTD_CONCAT&& MTD_PARTITIONS&& MTD_CFI_INTELEXT&& BROKEN
> diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
> index c7869c7..bb2ce2f 100644
> --- a/drivers/mtd/maps/Makefile
> +++ b/drivers/mtd/maps/Makefile
> @@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
> obj-$(CONFIG_MTD_VMU) += vmu-flash.o
> obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
> obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
> +obj-$(CONFIG_MTD_LANTIQ) += lantiq.o
> diff --git a/drivers/mtd/maps/lantiq.c b/drivers/mtd/maps/lantiq.c
> new file mode 100644
> index 0000000..e5a361e
> --- /dev/null
> +++ b/drivers/mtd/maps/lantiq.c
> @@ -0,0 +1,169 @@
> +/*
> + * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
> + * Copyright (C) 2010 John Crispin<blogic@openwrt.org>
> + */
> +
> +#include<linux/module.h>
> +#include<linux/types.h>
> +#include<linux/kernel.h>
> +#include<linux/io.h>
> +#include<linux/init.h>
> +#include<linux/mtd/mtd.h>
> +#include<linux/mtd/map.h>
> +#include<linux/mtd/partitions.h>
> +#include<linux/mtd/cfi.h>
> +#include<linux/magic.h>
> +#include<linux/platform_device.h>
> +#include<linux/mtd/physmap.h>
> +
> +#include<lantiq_soc.h>
> +#include<lantiq_platform.h>
> +
static int ltq_probing = 0;
> +static map_word
> +ltq_read16(struct map_info *map, unsigned long adr)
> +{
> + unsigned long flags;
> + map_word temp;
> + spin_lock_irqsave(&ebu_lock, flags);
if (ltq_probing)
adr ^= 2;
> + temp.x[0] = *((__u16 *)(map->virt + adr));
> + spin_unlock_irqrestore(&ebu_lock, flags);
> + return temp;
> +}
> +
> +static void
> +ltq_write16(struct map_info *map, map_word d, unsigned long adr)
> +{
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
if (ltq_probing)
adr ^= 2;
> + *((__u16 *)(map->virt + adr)) = d.x[0];
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_from(struct map_info *map, void *to,
> + unsigned long from, ssize_t len)
> +{
> + unsigned char *p;
> + unsigned char *to_8;
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
> + from = (unsigned long)(from + map->virt);
> + p = (unsigned char *) from;
> + to_8 = (unsigned char *) to;
> + while (len--)
> + *to_8++ = *p++;
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_to(struct map_info *map, unsigned long to,
> + const void *from, ssize_t len)
> +{
> + unsigned char *p = (unsigned char *)from;
> + unsigned char *to_8;
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
> + to += (unsigned long) map->virt;
> + to_8 = (unsigned char *)to;
> + while (len--)
> + *p++ = *to_8++;
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +static const char * const part_probe_types[] = {
> + "cmdlinepart", NULL };
> +
> +static struct map_info ltq_map = {
> + .name = "ltq_nor",
> + .bankwidth = 2,
> + .read = ltq_read16,
> + .write = ltq_write16,
> + .copy_from = ltq_copy_from,
> + .copy_to = ltq_copy_to,
> +};
> +
> +static int
> +ltq_mtd_probe(struct platform_device *pdev)
> +{
> + struct physmap_flash_data *ltq_mtd_data =
> + (struct physmap_flash_data *) dev_get_platdata(&pdev->dev);
> + struct mtd_info *ltq_mtd = NULL;
> + struct mtd_partition *parts = NULL;
> + struct resource *res = 0;
> + int nr_parts = 0;
> +
> +#ifdef CONFIG_SOC_TYPE_XWAY
> + ltq_w32(ltq_r32(LTQ_EBU_BUSCON0)& ~EBU_WRDIS, LTQ_EBU_BUSCON0);
> +#endif
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get memory resource");
> + return -ENOENT;
> + }
> + res = request_mem_region(res->start, resource_size(res),
> + dev_name(&pdev->dev));
> + if (!res) {
> + dev_err(&pdev->dev, "failed to request mem resource");
> + return -EBUSY;
> + }
> +
> + ltq_map.phys = res->start;
> + ltq_map.size = resource_size(res);
> + ltq_map.virt = ioremap_nocache(ltq_map.phys, ltq_map.size);
> +
> + if (!ltq_map.virt) {
> + dev_err(&pdev->dev, "failed to ioremap!\n");
> + return -EIO;
> + }
> +
ltq_probing = 1;
> + ltq_mtd = (struct mtd_info *) do_map_probe("cfi_probe",<q_map);
ltq_probing = 0;
> + if (!ltq_mtd) {
> + iounmap(ltq_map.virt);
> + dev_err(&pdev->dev, "probing failed\n");
> + return -ENXIO;
> + }
> +
> + ltq_mtd->owner = THIS_MODULE;
> +
> + nr_parts = parse_mtd_partitions(ltq_mtd, part_probe_types,&parts, 0);
> + if (nr_parts> 0) {
> + dev_info(&pdev->dev,
> + "using %d partitions from cmdline", nr_parts);
> + } else {
> + nr_parts = ltq_mtd_data->nr_parts;
> + parts = ltq_mtd_data->parts;
> + }
> +
> + add_mtd_partitions(ltq_mtd, parts, nr_parts);
> + return 0;
> +}
> +
> +static struct platform_driver ltq_mtd_driver = {
> + .probe = ltq_mtd_probe,
> + .driver = {
> + .name = "ltq_nor",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +int __init
> +init_ltq_mtd(void)
> +{
> + int ret = platform_driver_register(<q_mtd_driver);
> + if (ret)
> + printk(KERN_INFO "ltq_nor: error registering platfom driver");
> + return ret;
> +}
> +
> +module_init(init_ltq_mtd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Crispin<blogic@openwrt.org>");
> +MODULE_DESCRIPTION("Lantiq SoC NOR");
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 06/10] MIPS: lantiq: add NOR flash support
@ 2011-01-11 2:59 ` Daniel Schwierzeck
0 siblings, 0 replies; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-11 2:59 UTC (permalink / raw)
To: John Crispin
Cc: linux-mips, linux-mtd, Ralph Hempel, David Woodhouse,
Ralf Baechle
Hi John,
the EBU doesn't allow unaligned read or write access thus Lantiq added
this alignment hack directly in hardware. The addr^=2 is only needed
during CFI probe because odd addresses are accessed. A simple solution
is inside your patch.
The spin_lock_irqsave(&ebu_lock, flags); is actually not needed because
the EBU does access arbitration and protection already in hardware.
Daniel
On 01/05/2011 08:56 PM, John Crispin wrote:
> NOR flash is attached to the same EBU (External Bus Unit) as PCI. As described
> in the PCI patch, the EBU is a little obscure, resulting in the upper and lower
> 16 bit of the data on a 32 bit read are swapped. (essentially we have a addr^=2)
> This only happens on the read of data. In order to not have to high an impact
> on the read performance from the EBU we store all data on the flash with
> addr^=2. This allows us to do generic reads without having to do any swapping.
> For the write to now work we need to swizzle the the 0x2 bit of the addr.
> However this write swizzle needs to only happen when doing a CMD and not a DATA
> write.
>
> As the MTD layer currently makes no difference between a CMD and DATA read when
> using complex maps, the map driver does not know when the swizzle and when not
> to swizzle. The next patch in the series adds a hack to the MTD to workaround
> this problem. I am sending these 2 patches to the mtd list aswell. There are
> several ways to solve this generically in the mtd layer in a much better way.
> This will have minor impact on the actual map code provided in this patch.
>
> Signed-off-by: John Crispin<blogic@openwrt.org>
> Signed-off-by: Ralph Hempel<ralph.hempel@lantiq.com>
> Cc: David Woodhouse<dwmw2@infradead.org>
> Cc: linux-mips@linux-mips.org
> Cc: linux-mtd@lists.infradead.org
> ---
> drivers/mtd/maps/Kconfig | 7 ++
> drivers/mtd/maps/Makefile | 1 +
> drivers/mtd/maps/lantiq.c | 169 +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 177 insertions(+), 0 deletions(-)
> create mode 100644 drivers/mtd/maps/lantiq.c
>
> diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
> index a0dd7bb..ca69a7f 100644
> --- a/drivers/mtd/maps/Kconfig
> +++ b/drivers/mtd/maps/Kconfig
> @@ -260,6 +260,13 @@ config MTD_BCM963XX
> Support for parsing CFE image tag and creating MTD partitions on
> Broadcom BCM63xx boards.
>
> +config MTD_LANTIQ
> + bool "Lantiq SoC NOR support"
> + depends on LANTIQ&& MTD_PARTITIONS
> + help
> + Support for NOR flash chips on Lantiq SoC. The Chips are connected
> + to the SoCs EBU (External Bus Unit)
> +
> config MTD_DILNETPC
> tristate "CFI Flash device mapped on DIL/Net PC"
> depends on X86&& MTD_CONCAT&& MTD_PARTITIONS&& MTD_CFI_INTELEXT&& BROKEN
> diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
> index c7869c7..bb2ce2f 100644
> --- a/drivers/mtd/maps/Makefile
> +++ b/drivers/mtd/maps/Makefile
> @@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
> obj-$(CONFIG_MTD_VMU) += vmu-flash.o
> obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
> obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
> +obj-$(CONFIG_MTD_LANTIQ) += lantiq.o
> diff --git a/drivers/mtd/maps/lantiq.c b/drivers/mtd/maps/lantiq.c
> new file mode 100644
> index 0000000..e5a361e
> --- /dev/null
> +++ b/drivers/mtd/maps/lantiq.c
> @@ -0,0 +1,169 @@
> +/*
> + * 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) 2004 Liu Peng Infineon IFAP DC COM CPE
> + * Copyright (C) 2010 John Crispin<blogic@openwrt.org>
> + */
> +
> +#include<linux/module.h>
> +#include<linux/types.h>
> +#include<linux/kernel.h>
> +#include<linux/io.h>
> +#include<linux/init.h>
> +#include<linux/mtd/mtd.h>
> +#include<linux/mtd/map.h>
> +#include<linux/mtd/partitions.h>
> +#include<linux/mtd/cfi.h>
> +#include<linux/magic.h>
> +#include<linux/platform_device.h>
> +#include<linux/mtd/physmap.h>
> +
> +#include<lantiq_soc.h>
> +#include<lantiq_platform.h>
> +
static int ltq_probing = 0;
> +static map_word
> +ltq_read16(struct map_info *map, unsigned long adr)
> +{
> + unsigned long flags;
> + map_word temp;
> + spin_lock_irqsave(&ebu_lock, flags);
if (ltq_probing)
adr ^= 2;
> + temp.x[0] = *((__u16 *)(map->virt + adr));
> + spin_unlock_irqrestore(&ebu_lock, flags);
> + return temp;
> +}
> +
> +static void
> +ltq_write16(struct map_info *map, map_word d, unsigned long adr)
> +{
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
if (ltq_probing)
adr ^= 2;
> + *((__u16 *)(map->virt + adr)) = d.x[0];
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_from(struct map_info *map, void *to,
> + unsigned long from, ssize_t len)
> +{
> + unsigned char *p;
> + unsigned char *to_8;
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
> + from = (unsigned long)(from + map->virt);
> + p = (unsigned char *) from;
> + to_8 = (unsigned char *) to;
> + while (len--)
> + *to_8++ = *p++;
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +void
> +ltq_copy_to(struct map_info *map, unsigned long to,
> + const void *from, ssize_t len)
> +{
> + unsigned char *p = (unsigned char *)from;
> + unsigned char *to_8;
> + unsigned long flags;
> + spin_lock_irqsave(&ebu_lock, flags);
> + to += (unsigned long) map->virt;
> + to_8 = (unsigned char *)to;
> + while (len--)
> + *p++ = *to_8++;
> + spin_unlock_irqrestore(&ebu_lock, flags);
> +}
> +
> +static const char * const part_probe_types[] = {
> + "cmdlinepart", NULL };
> +
> +static struct map_info ltq_map = {
> + .name = "ltq_nor",
> + .bankwidth = 2,
> + .read = ltq_read16,
> + .write = ltq_write16,
> + .copy_from = ltq_copy_from,
> + .copy_to = ltq_copy_to,
> +};
> +
> +static int
> +ltq_mtd_probe(struct platform_device *pdev)
> +{
> + struct physmap_flash_data *ltq_mtd_data =
> + (struct physmap_flash_data *) dev_get_platdata(&pdev->dev);
> + struct mtd_info *ltq_mtd = NULL;
> + struct mtd_partition *parts = NULL;
> + struct resource *res = 0;
> + int nr_parts = 0;
> +
> +#ifdef CONFIG_SOC_TYPE_XWAY
> + ltq_w32(ltq_r32(LTQ_EBU_BUSCON0)& ~EBU_WRDIS, LTQ_EBU_BUSCON0);
> +#endif
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get memory resource");
> + return -ENOENT;
> + }
> + res = request_mem_region(res->start, resource_size(res),
> + dev_name(&pdev->dev));
> + if (!res) {
> + dev_err(&pdev->dev, "failed to request mem resource");
> + return -EBUSY;
> + }
> +
> + ltq_map.phys = res->start;
> + ltq_map.size = resource_size(res);
> + ltq_map.virt = ioremap_nocache(ltq_map.phys, ltq_map.size);
> +
> + if (!ltq_map.virt) {
> + dev_err(&pdev->dev, "failed to ioremap!\n");
> + return -EIO;
> + }
> +
ltq_probing = 1;
> + ltq_mtd = (struct mtd_info *) do_map_probe("cfi_probe",<q_map);
ltq_probing = 0;
> + if (!ltq_mtd) {
> + iounmap(ltq_map.virt);
> + dev_err(&pdev->dev, "probing failed\n");
> + return -ENXIO;
> + }
> +
> + ltq_mtd->owner = THIS_MODULE;
> +
> + nr_parts = parse_mtd_partitions(ltq_mtd, part_probe_types,&parts, 0);
> + if (nr_parts> 0) {
> + dev_info(&pdev->dev,
> + "using %d partitions from cmdline", nr_parts);
> + } else {
> + nr_parts = ltq_mtd_data->nr_parts;
> + parts = ltq_mtd_data->parts;
> + }
> +
> + add_mtd_partitions(ltq_mtd, parts, nr_parts);
> + return 0;
> +}
> +
> +static struct platform_driver ltq_mtd_driver = {
> + .probe = ltq_mtd_probe,
> + .driver = {
> + .name = "ltq_nor",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +int __init
> +init_ltq_mtd(void)
> +{
> + int ret = platform_driver_register(<q_mtd_driver);
> + if (ret)
> + printk(KERN_INFO "ltq_nor: error registering platfom driver");
> + return ret;
> +}
> +
> +module_init(init_ltq_mtd);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Crispin<blogic@openwrt.org>");
> +MODULE_DESCRIPTION("Lantiq SoC NOR");
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 06/10] MIPS: lantiq: add NOR flash support
2011-01-11 2:59 ` Daniel Schwierzeck
@ 2011-01-11 10:29 ` John Crispin
-1 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-11 10:29 UTC (permalink / raw)
To: Daniel Schwierzeck
Cc: Ralf Baechle, Ralph Hempel, David Woodhouse, linux-mips,
linux-mtd
On 11/01/11 03:59, Daniel Schwierzeck wrote:
> Hi John,
>
> the EBU doesn't allow unaligned read or write access thus Lantiq added
> this alignment hack directly in hardware. The addr^=2 is only needed
> during CFI probe because odd addresses are accessed. A simple solution
> is inside your patch.
>
> The spin_lock_irqsave(&ebu_lock, flags); is actually not needed
> because the EBU does access arbitration and protection already in
> hardware.
>
> Daniel
>
Hi Daniel,
thx, i will try it out later on and then merge it into v2 of the series.
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 06/10] MIPS: lantiq: add NOR flash support
@ 2011-01-11 10:29 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-11 10:29 UTC (permalink / raw)
To: Daniel Schwierzeck
Cc: linux-mips, linux-mtd, Ralph Hempel, David Woodhouse,
Ralf Baechle
On 11/01/11 03:59, Daniel Schwierzeck wrote:
> Hi John,
>
> the EBU doesn't allow unaligned read or write access thus Lantiq added
> this alignment hack directly in hardware. The addr^=2 is only needed
> during CFI probe because odd addresses are accessed. A simple solution
> is inside your patch.
>
> The spin_lock_irqsave(&ebu_lock, flags); is actually not needed
> because the EBU does access arbitration and protection already in
> hardware.
>
> Daniel
>
Hi Daniel,
thx, i will try it out later on and then merge it into v2 of the series.
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 00/10] MIPS: add support for Lantiq SoCs
2011-01-11 2:44 ` [PATCH 00/10] MIPS: add support for Lantiq SoCs Daniel Schwierzeck
@ 2011-01-11 12:07 ` John Crispin
2011-01-11 12:40 ` Daniel Schwierzeck
0 siblings, 1 reply; 32+ messages in thread
From: John Crispin @ 2011-01-11 12:07 UTC (permalink / raw)
To: Daniel Schwierzeck; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
On 11/01/11 03:44, Daniel Schwierzeck wrote:
> Hi John,
>
> after the 2.6.36 release i've started the same upstream project. I'm
> hacking software for CPE's with Danube and VRX SoC's thus I have full
> access to hardware manuals and latest BSP's. Maybe we should merge our
> code somehow ;)
>
> Daniel
Hi Daniel,
i am in the middle of finishing my dma/etop rewrite. once this is done i
think the core is ready.
in general all contributions are welcome. question is if it is a good
idea to merge the 2 trees now or if we merge one and then fix/add
fetures that your tree has that mine is missing.
i was unable to find any public place where you keep your code. could
you upload it somewhere so i can see what the exact differences are ?
also could you tell me what the code base is based on ? (spinacer,
ifxcpe, ifxmips...)
i have so far not added vrx support due to lack of hardware to test on.
a quick read of the docs does tell me however that only the gbit
phy/switch and the clk needs to be adapted for vrx to also work. the
gbit phy/switch part will already be included in my etop patches as it
is needed by the arx series
thanks,
John
thanks,
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 00/10] MIPS: add support for Lantiq SoCs
2011-01-11 12:07 ` John Crispin
@ 2011-01-11 12:40 ` Daniel Schwierzeck
2011-01-11 12:49 ` John Crispin
0 siblings, 1 reply; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-11 12:40 UTC (permalink / raw)
To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
Hi John,
2011/1/11 John Crispin <blogic@openwrt.org>:
> On 11/01/11 03:44, Daniel Schwierzeck wrote:
>> Hi John,
>>
>> after the 2.6.36 release i've started the same upstream project. I'm
>> hacking software for CPE's with Danube and VRX SoC's thus I have full
>> access to hardware manuals and latest BSP's. Maybe we should merge our
>> code somehow ;)
>>
>> Daniel
>
> Hi Daniel,
>
> i am in the middle of finishing my dma/etop rewrite. once this is done i
> think the core is ready.
>
> in general all contributions are welcome. question is if it is a good
> idea to merge the 2 trees now or if we merge one and then fix/add
> fetures that your tree has that mine is missing.
Actually my tree is very experimental yet so I'm going to contribute
to your tree.
>
> i was unable to find any public place where you keep your code. could
> you upload it somewhere so i can see what the exact differences are ?
>
> also could you tell me what the code base is based on ? (spinacer,
> ifxcpe, ifxmips...)
>
> i have so far not added vrx support due to lack of hardware to test on.
> a quick read of the docs does tell me however that only the gbit
> phy/switch and the clk needs to be adapted for vrx to also work. the
> gbit phy/switch part will already be included in my etop patches as it
> is needed by the arx series
I have an eval board with VRX288 so I could help with adding and
testing board support for that board.
Daniel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 00/10] MIPS: add support for Lantiq SoCs
2011-01-11 12:40 ` Daniel Schwierzeck
@ 2011-01-11 12:49 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-11 12:49 UTC (permalink / raw)
To: Daniel Schwierzeck; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
> I have an eval board with VRX288 so I could help with adding and
> testing board support for that board.
>
> Daniel
>
>
Hi Daniel,
awesome ! i will hack up a patch for vrx support that integrates with my
structure and will provide it to you for testing an potentiually fixing
in the next few days
thanks,
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
2011-01-05 20:25 ` Geert Uytterhoeven
@ 2011-01-13 11:05 ` Daniel Schwierzeck
2011-01-13 11:14 ` John Crispin
1 sibling, 1 reply; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-13 11:05 UTC (permalink / raw)
To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
Hi John,
I have some additional suggestions.
2011/1/5 John Crispin <blogic@openwrt.org>:
> Add initial support for Mips based SoCs made by Lantiq. This series will add
> support for the XWAY family.
>
> The series allows booting a minimal system using a initramfs or NOR. Missing
> drivers and support for Amazon and GPON family will be provided in a later
> series.
>
> Signed-off-by: John Crispin <blogic@openwrt.org>
> Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
> Cc: linux-mips@linux-mips.org
> ---
> arch/mips/Kbuild.platforms | 1 +
> arch/mips/Kconfig | 16 ++
> arch/mips/include/asm/mach-lantiq/lantiq.h | 48 +++++++
> arch/mips/include/asm/mach-lantiq/war.h | 24 +++
> arch/mips/lantiq/Makefile | 9 ++
> arch/mips/lantiq/Platform | 7 +
> arch/mips/lantiq/clk.c | 129 +++++++++++++++++
> arch/mips/lantiq/clk.h | 18 +++
> arch/mips/lantiq/early_printk.c | 47 ++++++
> arch/mips/lantiq/irq.c | 209 ++++++++++++++++++++++++++++
> arch/mips/lantiq/prom.c | 84 +++++++++++
> arch/mips/lantiq/prom.h | 26 ++++
> arch/mips/lantiq/setup.c | 45 ++++++
> 13 files changed, 663 insertions(+), 0 deletions(-)
> create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h
> create mode 100644 arch/mips/include/asm/mach-lantiq/war.h
> create mode 100644 arch/mips/lantiq/Makefile
> create mode 100644 arch/mips/lantiq/Platform
> create mode 100644 arch/mips/lantiq/clk.c
> create mode 100644 arch/mips/lantiq/clk.h
> create mode 100644 arch/mips/lantiq/early_printk.c
> create mode 100644 arch/mips/lantiq/irq.c
> create mode 100644 arch/mips/lantiq/prom.c
> create mode 100644 arch/mips/lantiq/prom.h
> create mode 100644 arch/mips/lantiq/setup.c
>
> diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
> index 78439b8..8b7c26f 100644
> --- a/arch/mips/Kbuild.platforms
> +++ b/arch/mips/Kbuild.platforms
> @@ -10,6 +10,7 @@ platforms += dec
> platforms += emma
> platforms += jazz
> platforms += jz4740
> +platforms += lantiq
> platforms += lasat
> platforms += loongson
> platforms += mipssim
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 913d50d..a2396f1 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -192,6 +192,22 @@ config MACH_JZ4740
> select SYS_HAS_EARLY_PRINTK
> select HAVE_PWM
>
> +config LANTIQ
> + bool "Lantiq based platforms"
> + select DMA_NONCOHERENT
> + select IRQ_CPU
> + select CEVT_R4K
> + select CSRC_R4K
> + select SYS_HAS_CPU_MIPS32_R1
> + select SYS_HAS_CPU_MIPS32_R2
> + select SYS_SUPPORTS_BIG_ENDIAN
> + select SYS_SUPPORTS_32BIT_KERNEL
> + select SYS_SUPPORTS_MULTITHREADING
> + select SYS_HAS_EARLY_PRINTK
> + select ARCH_REQUIRE_GPIOLIB
> + select SWAP_IO_SPACE
> + select BOOT_RAW
> +
> config LASAT
> bool "LASAT Networks platforms"
> select CEVT_R4K
> diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
> new file mode 100644
> index 0000000..54eb033
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
> @@ -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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#ifndef _LANTIQ_H__
> +#define _LANTIQ_H__
> +
> +/* generic reg access functions */
> +#define ltq_r32(reg) __raw_readl(reg)
> +#define ltq_w32(val, reg) __raw_writel(val, reg)
> +#define ltq_w32_mask(clear, set, reg) \
> + ltq_w32((ltq_r32(reg) & ~clear) | set, reg)
> +
> +extern unsigned int ltq_get_cpu_ver(void);
> +extern unsigned int ltq_get_soc_type(void);
> +
> +/* clock speeds */
> +#define CLOCK_60M 60000000
> +#define CLOCK_83M 83333333
> +#define CLOCK_111M 111111111
> +#define CLOCK_133M 133333333
> +#define CLOCK_167M 166666667
> +#define CLOCK_200M 200000000
> +#define CLOCK_266M 266666666
> +#define CLOCK_333M 333333333
> +#define CLOCK_400M 400000000
> +
> +/* spinlock all ebu i/o */
> +extern spinlock_t ebu_lock;
> +
> +/* some irq helpers */
> +extern void ltq_disable_irq(unsigned int irq_nr);
> +extern void ltq_mask_and_ack_irq(unsigned int irq_nr);
> +extern void ltq_enable_irq(unsigned int irq_nr);
> +
> +#define IOPORT_RESOURCE_START 0x10000000
> +#define IOPORT_RESOURCE_END 0xffffffff
> +#define IOMEM_RESOURCE_START 0x10000000
> +#define IOMEM_RESOURCE_END 0xffffffff
> +
> +#define LTQ_FLASH_START 0x10000000
> +#define LTQ_FLASH_MAX 0x04000000
> +
> +#endif
> diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h
> new file mode 100644
> index 0000000..01b08ef
> --- /dev/null
> +++ b/arch/mips/include/asm/mach-lantiq/war.h
> @@ -0,0 +1,24 @@
> +/*
> + * 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.
> + *
> + */
> +#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H
> +#define __ASM_MIPS_MACH_LANTIQ_WAR_H
> +
> +#define R4600_V1_INDEX_ICACHEOP_WAR 0
> +#define R4600_V1_HIT_CACHEOP_WAR 0
> +#define R4600_V2_HIT_CACHEOP_WAR 0
> +#define R5432_CP0_INTERRUPT_WAR 0
> +#define BCM1250_M3_WAR 0
> +#define SIBYTE_1956_WAR 0
> +#define MIPS4K_ICACHE_REFILL_WAR 0
> +#define MIPS_CACHE_SYNC_WAR 0
> +#define TX49XX_ICACHE_INDEX_INV_WAR 0
> +#define RM9000_CDEX_SMP_WAR 0
> +#define ICACHE_REFILLS_WORKAROUND_WAR 0
> +#define R10000_LLSC_WAR 0
> +#define MIPS34K_MISSED_ITLB_WAR 0
> +
> +#endif
> diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
> new file mode 100644
> index 0000000..6a30de6
> --- /dev/null
> +++ b/arch/mips/lantiq/Makefile
> @@ -0,0 +1,9 @@
> +# Copyright (C) 2010 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.
> +
> +obj-y := irq.o setup.o clk.o prom.o
> +
> +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
> diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
> new file mode 100644
> index 0000000..eef587f
> --- /dev/null
> +++ b/arch/mips/lantiq/Platform
> @@ -0,0 +1,7 @@
> +#
> +# Lantiq
> +#
> +
> +platform-$(CONFIG_LANTIQ) += lantiq/
> +cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
> +load-$(CONFIG_LANTIQ) = 0xffffffff80002000
> diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
> new file mode 100644
> index 0000000..4283d92
> --- /dev/null
> +++ b/arch/mips/lantiq/clk.c
> @@ -0,0 +1,129 @@
> +/*
> + * 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) 2010 Thomas Langer <thomas.langer@lantiq.com>
> + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/list.h>
> +
> +#include <asm/time.h>
> +#include <asm/irq.h>
> +#include <asm/div64.h>
> +
> +#include <lantiq.h>
> +
> +#include "clk.h"
> +
> +struct clk {
> + const char *name;
> + unsigned long rate;
> + unsigned long (*get_rate) (void);
> +};
> +
> +static struct clk *cpu_clk;
> +static int cpu_clk_cnt;
> +
> +static unsigned int r4k_offset;
> +static unsigned int r4k_cur;
What is the sense of these variables? They are never really used.
> +
> +static struct clk cpu_clk_generic[] = {
> + {
> + .name = "cpu",
> + .get_rate = ltq_get_cpu_hz,
> + }, {
> + .name = "fpi",
> + .get_rate = ltq_get_fpi_hz,
> + }, {
> + .name = "io",
> + .get_rate = ltq_get_io_region_clock,
> + },
> +};
> +
> +void
> +clk_init(void)
> +{
> + int i;
> + cpu_clk = cpu_clk_generic;
> + cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
> + for (i = 0; i < cpu_clk_cnt; i++)
> + printk(KERN_INFO "%s: %ld\n",
> + cpu_clk[i].name, clk_get_rate(&cpu_clk[i]));
> +}
> +
> +static inline int
> +clk_good(struct clk *clk)
> +{
> + return clk && !IS_ERR(clk);
> +}
> +
> +unsigned long
> +clk_get_rate(struct clk *clk)
> +{
> + if (unlikely(!clk_good(clk)))
> + return 0;
> +
> + if (clk->rate != 0)
> + return clk->rate;
> +
> + if (clk->get_rate != NULL)
> + return clk->get_rate();
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(clk_get_rate);
> +
> +struct clk*
> +clk_get(struct device *dev, const char *id)
> +{
> + int i;
> + for (i = 0; i < cpu_clk_cnt; i++)
> + if (!strcmp(id, cpu_clk[i].name))
> + return &cpu_clk[i];
> + BUG();
> + return ERR_PTR(-ENOENT);
> +}
> +EXPORT_SYMBOL(clk_get);
> +
> +void
> +clk_put(struct clk *clk)
> +{
> + /* not used */
> +}
> +EXPORT_SYMBOL(clk_put);
> +
> +static inline u32
> +ltq_get_counter_resolution(void)
> +{
> + u32 res;
> + __asm__ __volatile__(
> + ".set push\n"
> + ".set mips32r2\n"
> + ".set noreorder\n"
> + "rdhwr %0, $3\n"
> + "ehb\n"
> + ".set pop\n"
> + : "=&r" (res)
> + : /* no input */
> + : "memory");
> + instruction_hazard();
> + return res;
> +}
> +
> +void __init
> +plat_time_init(void)
> +{
> + struct clk *clk = clk_get(0, "cpu");
> + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
> + r4k_cur = (read_c0_count() + r4k_offset);
> + write_c0_compare(r4k_cur);
Like stated above the r4k_cur and r4k_offset are only initailied with
0. So the last two lines
could be written as write_c0_compare(read_c0_count()) and are actually
ineffective.
> +}
> diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
> new file mode 100644
> index 0000000..3328925
> --- /dev/null
> +++ b/arch/mips/lantiq/clk.h
> @@ -0,0 +1,18 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#ifndef _LTQ_CLK_H__
> +#define _LTQ_CLK_H__
> +
> +extern void clk_init(void);
> +
> +extern unsigned long ltq_get_cpu_hz(void);
> +extern unsigned long ltq_get_fpi_hz(void);
> +extern unsigned long ltq_get_io_region_clock(void);
> +
> +#endif
> diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
> new file mode 100644
> index 0000000..0aaf4f7
> --- /dev/null
> +++ b/arch/mips/lantiq/early_printk.c
> @@ -0,0 +1,47 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#include <linux/init.h>
> +#include <linux/cpu.h>
> +
> +#include <lantiq.h>
> +#include <lantiq_soc.h>
> +
> +#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE)
> +#define ASC_BUF 1024
> +#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
> +#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
> +#define TXMASK 0x3F00
> +#define TXOFFSET 8
> +
> +void
> +prom_putchar(char c)
> +{
> + unsigned long flags;
> + local_irq_save(flags);
> + do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
> + if (c == '\n')
> + ltq_w32('\r', LTQ_ASC_TBUF);
> + ltq_w32(c, LTQ_ASC_TBUF);
> + local_irq_restore(flags);
> +}
> +
> +void
> +early_printf(const char *fmt, ...)
> +{
> + char buf[ASC_BUF];
> + va_list args;
> + int l;
> + char *p, *buf_end;
> + va_start(args, fmt);
> + l = vsnprintf(buf, ASC_BUF, fmt, args);
> + va_end(args);
> + buf_end = buf + l;
> + for (p = buf; p < buf_end; p++)
> + prom_putchar(*p);
> +}
With CONFIG_EARLY_PRINTK enabled and prom_putchar() implemented you
can use printk() everywhere.
So an own early_printf() is not needed.
> diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
> new file mode 100644
> index 0000000..b1535ee
> --- /dev/null
> +++ b/arch/mips/lantiq/irq.c
> @@ -0,0 +1,209 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +
> +#include <asm/bootinfo.h>
> +#include <asm/irq_cpu.h>
> +
> +#include <lantiq.h>
> +#include <irq.h>
> +
> +#define LTQ_ICU_BASE_ADDR (KSEG1 | 0x1F880200)
> +
> +#define LTQ_ICU_IM0_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0000))
> +#define LTQ_ICU_IM0_IER ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0008))
> +#define LTQ_ICU_IM0_IOSR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0010))
> +#define LTQ_ICU_IM0_IRSR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0018))
> +#define LTQ_ICU_IM0_IMR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0020))
> +
> +#define LTQ_ICU_IM1_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0028))
> +#define LTQ_ICU_IM2_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0050))
> +#define LTQ_ICU_IM3_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x0078))
> +#define LTQ_ICU_IM4_ISR ((u32 *)(LTQ_ICU_BASE_ADDR + 0x00A0))
> +
> +#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
> +
> +void
> +ltq_disable_irq(unsigned int irq_nr)
> +{
> + u32 *ier = LTQ_ICU_IM0_IER;
> + irq_nr -= INT_NUM_IRQ0;
> + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
> + irq_nr %= INT_NUM_IM_OFFSET;
> + ltq_w32(ltq_r32(ier) & ~(1 << irq_nr), ier);
> +}
> +EXPORT_SYMBOL(ltq_disable_irq);
> +
> +void
> +ltq_mask_and_ack_irq(unsigned int irq_nr)
> +{
> + u32 *ier = LTQ_ICU_IM0_IER;
> + u32 *isr = LTQ_ICU_IM0_ISR;
> + irq_nr -= INT_NUM_IRQ0;
> + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
> + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
> + irq_nr %= INT_NUM_IM_OFFSET;
> + ltq_w32(ltq_r32(ier) & ~(1 << irq_nr), ier);
> + ltq_w32((1 << irq_nr), isr);
> +}
> +EXPORT_SYMBOL(ltq_mask_and_ack_irq);
> +
> +static void
> +ltq_ack_irq(unsigned int irq_nr)
> +{
> + u32 *isr = LTQ_ICU_IM0_ISR;
> + irq_nr -= INT_NUM_IRQ0;
> + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
> + irq_nr %= INT_NUM_IM_OFFSET;
> + ltq_w32((1 << irq_nr), isr);
> +}
> +
> +void
> +ltq_enable_irq(unsigned int irq_nr)
> +{
> + u32 *ier = LTQ_ICU_IM0_IER;
> + irq_nr -= INT_NUM_IRQ0;
> + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
> + irq_nr %= INT_NUM_IM_OFFSET;
> + ltq_w32(ltq_r32(ier) | (1 << irq_nr), ier);
> +}
> +EXPORT_SYMBOL(ltq_enable_irq);
> +
> +static unsigned int
> +ltq_startup_irq(unsigned int irq)
> +{
> + ltq_enable_irq(irq);
> + return 0;
> +}
> +
> +static void
> +ltq_end_irq(unsigned int irq)
> +{
> + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
> + ltq_enable_irq(irq);
> +}
> +
> +static struct irq_chip
> +ltq_irq_type = {
> + "ltq_irq",
> + .startup = ltq_startup_irq,
> + .enable = ltq_enable_irq,
> + .disable = ltq_disable_irq,
> + .unmask = ltq_enable_irq,
> + .ack = ltq_ack_irq,
> + .mask = ltq_disable_irq,
> + .mask_ack = ltq_mask_and_ack_irq,
> + .end = ltq_end_irq,
> +};
> +
> +static void
> +ltq_hw_irqdispatch(int module)
> +{
> + u32 irq;
> +
> + irq = ltq_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
> + if (irq == 0)
> + return;
> +
> + /* silicon bug causes only the msb set to 1 to be valid. all
> + other bits might be bogus */
> + irq = __fls(irq);
> + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
> +}
> +
> +#define DEFINE_HWx_IRQDISPATCH(x) \
> +static void ltq_hw ## x ## _irqdispatch(void)\
> +{\
> + ltq_hw_irqdispatch(x); \
> +}
> +DEFINE_HWx_IRQDISPATCH(0)
> +DEFINE_HWx_IRQDISPATCH(1)
> +DEFINE_HWx_IRQDISPATCH(2)
> +DEFINE_HWx_IRQDISPATCH(3)
> +DEFINE_HWx_IRQDISPATCH(4)
The interrupt line IM0-IRL22 is shared by PCI (INT A) and EBU. Thus
ltq_hw0_irqdispatch()
should clear the PCI bit (5th bit) in EBU_PCC_ISTAT register (EBU_BASE
+ 0xA0) if you enable
this interrupt in pcibios_plat_dev_init().
This is undocumented in the hardware manuals but can be found in all
Lantiq BSP's.
> +
> +static void ltq_hw5_irqdispatch(void)
> +{
> + do_IRQ(MIPS_CPU_TIMER_IRQ);
> +}
> +
> +asmlinkage void
> +plat_irq_dispatch(void)
> +{
> + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
> + unsigned int i;
> +
> + if (pending & CAUSEF_IP7) {
> + do_IRQ(MIPS_CPU_TIMER_IRQ);
> + goto out;
> + } else {
> + for (i = 0; i < 5; i++) {
> + if (pending & (CAUSEF_IP2 << i)) {
> + ltq_hw_irqdispatch(i);
> + goto out;
> + }
> + }
> + }
> + printk(KERN_ALERT "Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
> +
> +out:
> + return;
> +}
> +
> +static struct irqaction
> +cascade = {
> + .handler = no_action,
> + .flags = IRQF_DISABLED,
> + .name = "cascade",
> +};
> +
> +void __init
> +arch_init_irq(void)
> +{
> + int i;
> +
> + for (i = 0; i < 5; i++)
> + ltq_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
Perhaps pending interrupts should be cleared too with
ltq_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
> +
> + mips_cpu_irq_init();
> +
> + for (i = 2; i <= 6; i++)
> + setup_irq(i, &cascade);
> +
> + if (cpu_has_vint) {
> + printk(KERN_INFO "Setting up vectored interrupts\n");
> + set_vi_handler(2, ltq_hw0_irqdispatch);
> + set_vi_handler(3, ltq_hw1_irqdispatch);
> + set_vi_handler(4, ltq_hw2_irqdispatch);
> + set_vi_handler(5, ltq_hw3_irqdispatch);
> + set_vi_handler(6, ltq_hw4_irqdispatch);
> + set_vi_handler(7, ltq_hw5_irqdispatch);
> + }
> +
> + for (i = INT_NUM_IRQ0;
> + i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
> + set_irq_chip_and_handler(i, <q_irq_type,
> + handle_level_irq);
> +
> + #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
> + set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
> + IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
> + #else
> + set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
> + IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
> + #endif
> +}
> +
> +unsigned int __cpuinit
> +get_c0_compare_int(void)
> +{
> + return CP0_LEGACY_COMPARE_IRQ;
> +}
> diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
> new file mode 100644
> index 0000000..6561e4e
> --- /dev/null
> +++ b/arch/mips/lantiq/prom.c
> @@ -0,0 +1,84 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <asm/bootinfo.h>
> +#include <asm/time.h>
> +
> +#include <lantiq.h>
> +
> +#include "prom.h"
> +#include "clk.h"
> +
> +static struct ltq_soc_info soc_info;
> +
> +/* for Multithreading (APRP) on MIPS34K */
> +unsigned long physical_memsize;
> +
> +/* all access to the ebu must be locked */
> +DEFINE_SPINLOCK(ebu_lock);
> +EXPORT_SYMBOL_GPL(ebu_lock);
This lock is only needed if you want to use software arbitration.
Normally the EBU does hardware arbitration and can be accessed safely
without lock.
> +
> +unsigned int
> +ltq_get_cpu_ver(void)
> +{
> + return soc_info.rev;
> +}
> +EXPORT_SYMBOL(ltq_get_cpu_ver);
> +
> +unsigned int
> +ltq_get_soc_type(void)
> +{
> + return soc_info.type;
> +}
> +EXPORT_SYMBOL(ltq_get_soc_type);
> +
> +const char*
> +get_system_type(void)
> +{
> + return soc_info.sys_type;
> +}
> +
> +void
> +prom_free_prom_memory(void)
> +{
> +}
> +
> +static void __init
> +prom_init_cmdline(void)
> +{
> + int argc = fw_arg0;
> + char **argv = (char **) KSEG1ADDR(fw_arg1);
> + int i;
> + arcs_cmdline[0] = '\0';
> + if (argc)
> + for (i = 1; i < argc; i++) {
> + strlcat(arcs_cmdline, (char *)KSEG1ADDR(argv[i]),
> + COMMAND_LINE_SIZE);
> + if (i + 1 != argc)
> + strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
> + }
> + if (!*arcs_cmdline)
> + strcpy(&(arcs_cmdline[0]),
> + "console=ttyS1,115200 rootfstype=squashfs,jffs2");
> +}
> +
> +void __init
> +prom_init(void)
> +{
> + struct clk *clk;
> + ltq_soc_detect(&soc_info);
> + clk_init();
> + clk = clk_get(0, "cpu");
> + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d %ldMhz",
> + soc_info.name, soc_info.rev, clk_get_rate(clk) / 1000000);
> + soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
> + printk(KERN_INFO "SoC: %s\n", soc_info.sys_type);
> + prom_init_cmdline();
> +}
> diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
> new file mode 100644
> index 0000000..3b92197
> --- /dev/null
> +++ b/arch/mips/lantiq/prom.h
> @@ -0,0 +1,26 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#ifndef _LTQ_PROM_H__
> +#define _LTQ_PROM_H__
> +
> +#define LTQ_SYS_TYPE_LEN 0x100
> +
> +struct ltq_soc_info {
> + unsigned char *name;
> + unsigned int rev;
> + unsigned int partnum;
> + unsigned int type;
> + unsigned char sys_type[LTQ_SYS_TYPE_LEN];
> +};
> +
> +void ltq_soc_detect(struct ltq_soc_info *i);
> +
> +void early_printf(const char *fmt, ...);
> +
> +#endif
> diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
> new file mode 100644
> index 0000000..f0f74d2
> --- /dev/null
> +++ b/arch/mips/lantiq/setup.c
> @@ -0,0 +1,45 @@
> +/*
> + * 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) 2010 John Crispin <blogic@openwrt.org>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <asm/bootinfo.h>
> +
> +#include <lantiq.h>
> +
> +void __init
> +plat_mem_setup(void)
> +{
> + /* assume 16M as default */
> + unsigned long memsize = 16;
> + char **envp = (char **) KSEG1ADDR(fw_arg2);
> + u32 status;
> +
> + /* make sure to have no "reverse endian" for user mode */
> + status = read_c0_status();
> + status &= (~(1<<25));
> + write_c0_status(status);
> +
> + ioport_resource.start = IOPORT_RESOURCE_START;
> + ioport_resource.end = IOPORT_RESOURCE_END;
> + iomem_resource.start = IOMEM_RESOURCE_START;
> + iomem_resource.end = IOMEM_RESOURCE_END;
> +
> + while (*envp) {
> + char *e = (char *)KSEG1ADDR(*envp);
> + if (!strncmp(e, "memsize=", 8)) {
> + e += 8;
> + strict_strtoul(e, 0, &memsize);
> + }
> + envp++;
> + }
> + memsize *= 1024 * 1024;
> + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
> +}
> --
> 1.7.2.3
>
>
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-13 11:05 ` Daniel Schwierzeck
@ 2011-01-13 11:14 ` John Crispin
2011-01-13 12:47 ` Daniel Schwierzeck
0 siblings, 1 reply; 32+ messages in thread
From: John Crispin @ 2011-01-13 11:14 UTC (permalink / raw)
To: Daniel Schwierzeck; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
Hi Daniel,
>> +static struct clk *cpu_clk;
>> +static int cpu_clk_cnt;
>> +
>> +static unsigned int r4k_offset;
>> +static unsigned int r4k_cur;
>>
> What is the sense of these variables? They are never really used.
>
left overs from old kernel patches, i'll remove them
>> +void __init
>> +plat_time_init(void)
>> +{
>> + struct clk *clk = clk_get(0, "cpu");
>> + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
>> + r4k_cur = (read_c0_count() + r4k_offset);
>> + write_c0_compare(r4k_cur);
>>
> Like stated above the r4k_cur and r4k_offset are only initailied with
> 0. So the last two lines
> could be written as write_c0_compare(read_c0_count()) and are actually
> ineffective.
>
>
ok
>> +void
>> +early_printf(const char *fmt, ...)
>> +{
>> + char buf[ASC_BUF];
>> + va_list args;
>> + int l;
>> + char *p, *buf_end;
>> + va_start(args, fmt);
>> + l = vsnprintf(buf, ASC_BUF, fmt, args);
>> + va_end(args);
>> + buf_end = buf + l;
>> + for (p = buf; p < buf_end; p++)
>> + prom_putchar(*p);
>> +}
>>
> With CONFIG_EARLY_PRINTK enabled and prom_putchar() implemented you
> can use printk() everywhere.
> So an own early_printf() is not needed.
>
>
not quite, this is used by the prom code where printk is followed by an
unreachable() rendering the printk to not work. i asked in #mipslinux
about this already and was tolf that this is the only work around as the
early_printk api does not expose its internal simple_printf() function.
>> +
>> +static void
>> +ltq_hw_irqdispatch(int module)
>> +{
>> + u32 irq;
>> +
>> + irq = ltq_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
>> + if (irq == 0)
>> + return;
>> +
>> + /* silicon bug causes only the msb set to 1 to be valid. all
>> + other bits might be bogus */
>> + irq = __fls(irq);
>> + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
>> +}
>> +
>> +#define DEFINE_HWx_IRQDISPATCH(x) \
>> +static void ltq_hw ## x ## _irqdispatch(void)\
>> +{\
>> + ltq_hw_irqdispatch(x); \
>> +}
>> +DEFINE_HWx_IRQDISPATCH(0)
>> +DEFINE_HWx_IRQDISPATCH(1)
>> +DEFINE_HWx_IRQDISPATCH(2)
>> +DEFINE_HWx_IRQDISPATCH(3)
>> +DEFINE_HWx_IRQDISPATCH(4)
>>
> The interrupt line IM0-IRL22 is shared by PCI (INT A) and EBU. Thus
> ltq_hw0_irqdispatch()
> should clear the PCI bit (5th bit) in EBU_PCC_ISTAT register (EBU_BASE
> + 0xA0) if you enable
> this interrupt in pcibios_plat_dev_init().
> This is undocumented in the hardware manuals but can be found in all
> Lantiq BSP's.
>
>
i'll look into it
> +void __init
>> +arch_init_irq(void)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < 5; i++)
>> + ltq_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
>>
> Perhaps pending interrupts should be cleared too with
> ltq_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
>
>
will look into this too
>> +
>> +/* all access to the ebu must be locked */
>> +DEFINE_SPINLOCK(ebu_lock);
>> +EXPORT_SYMBOL_GPL(ebu_lock);
>>
> This lock is only needed if you want to use software arbitration.
> Normally the EBU does hardware arbitration and can be accessed safely
> without lock.
>
>
openwrt borks up on mini_fo init when this lock is not in-place. we saw
a lot of issues in the past which lead to this lock being added. i will
retry it with out the lock to verify
thx i will fold all suggestions into the next version of the series.
John
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-13 11:14 ` John Crispin
@ 2011-01-13 12:47 ` Daniel Schwierzeck
2011-01-13 15:03 ` John Crispin
0 siblings, 1 reply; 32+ messages in thread
From: Daniel Schwierzeck @ 2011-01-13 12:47 UTC (permalink / raw)
To: John Crispin; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
Hi John,
2011/1/13 John Crispin <blogic@openwrt.org>:
>
>>> +
>>> +/* all access to the ebu must be locked */
>>> +DEFINE_SPINLOCK(ebu_lock);
>>> +EXPORT_SYMBOL_GPL(ebu_lock);
>>>
>> This lock is only needed if you want to use software arbitration.
>> Normally the EBU does hardware arbitration and can be accessed safely
>> without lock.
>>
>>
> openwrt borks up on mini_fo init when this lock is not in-place. we saw
> a lot of issues in the past which lead to this lock being added. i will
> retry it with out the lock to verify
>
Ok I never tried mini_fo bit it's working fine with squashfs. Maybe
it's a problem with your EBU setup. We always reset
the EBU_ADDR_SEL0 and EBU_CON_0 registers in U-Boot's lowlevel_init.S.
The values are EBU_ADDR_SEL0 = 0x10000021
and EBU_CON_0 = 0x8001F7FF.
My suggestion is to wrap the locking mechanism into separate inline
functions and define them only if really needed and enabled in kernel
config.
Daniel
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH 01/10] MIPS: lantiq: add initial support for Lantiq SoCs
2011-01-13 12:47 ` Daniel Schwierzeck
@ 2011-01-13 15:03 ` John Crispin
0 siblings, 0 replies; 32+ messages in thread
From: John Crispin @ 2011-01-13 15:03 UTC (permalink / raw)
To: Daniel Schwierzeck; +Cc: Ralf Baechle, Ralph Hempel, linux-mips
On 13/01/11 13:47, Daniel Schwierzeck wrote:
> Hi John,
>
> 2011/1/13 John Crispin <blogic@openwrt.org>:
>
>>
>>>> +
>>>> +/* all access to the ebu must be locked */
>>>> +DEFINE_SPINLOCK(ebu_lock);
>>>> +EXPORT_SYMBOL_GPL(ebu_lock);
>>>>
>>>>
>>> This lock is only needed if you want to use software arbitration.
>>> Normally the EBU does hardware arbitration and can be accessed safely
>>> without lock.
>>>
>>>
>>>
>> openwrt borks up on mini_fo init when this lock is not in-place. we saw
>> a lot of issues in the past which lead to this lock being added. i will
>> retry it with out the lock to verify
>>
>>
> Ok I never tried mini_fo bit it's working fine with squashfs. Maybe
> it's a problem with your EBU setup. We always reset
> the EBU_ADDR_SEL0 and EBU_CON_0 registers in U-Boot's lowlevel_init.S.
> The values are EBU_ADDR_SEL0 = 0x10000021
> and EBU_CON_0 = 0x8001F7FF.
> My suggestion is to wrap the locking mechanism into separate inline
> functions and define them only if really needed and enabled in kernel
> config.
>
> Daniel
>
>
>
Ok, i will try with those values to see if the EBU is setup incorrectly,
thx for the pointers !
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2011-01-13 15:02 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-05 19:56 [PATCH 00/10] MIPS: add support for Lantiq SoCs John Crispin
2011-01-05 19:56 ` [PATCH 01/10] MIPS: lantiq: add initial " John Crispin
2011-01-05 20:25 ` Geert Uytterhoeven
2011-01-13 11:05 ` Daniel Schwierzeck
2011-01-13 11:14 ` John Crispin
2011-01-13 12:47 ` Daniel Schwierzeck
2011-01-13 15:03 ` John Crispin
2011-01-05 19:56 ` [PATCH 02/10] MIPS: lantiq: add SoC specific code for XWAY family John Crispin
2011-01-05 19:56 ` [PATCH 03/10] MIPS: lantiq: add PCI controller support John Crispin
2011-01-05 19:56 ` [PATCH 04/10] MIPS: lantiq: add serial port support John Crispin
2011-01-05 19:56 ` [PATCH 05/10] MIPS: lantiq: add watchdog support John Crispin
2011-01-05 23:49 ` Jamie Iles
2011-01-06 9:51 ` John Crispin
2011-01-06 11:15 ` Jamie Iles
2011-01-06 11:38 ` John Crispin
2011-01-05 19:56 ` [PATCH 06/10] MIPS: lantiq: add NOR flash support John Crispin
2011-01-05 19:56 ` John Crispin
2011-01-11 2:59 ` Daniel Schwierzeck
2011-01-11 2:59 ` Daniel Schwierzeck
2011-01-11 10:29 ` John Crispin
2011-01-11 10:29 ` John Crispin
2011-01-05 19:56 ` [PATCH 07/10] MIPS: lantiq: add NOR flash CFI address swizzle John Crispin
2011-01-05 19:56 ` John Crispin
2011-01-06 10:06 ` John Crispin
2011-01-06 10:06 ` John Crispin
2011-01-05 19:56 ` [PATCH 08/10] MIPS: lantiq: add platform device support John Crispin
2011-01-05 19:56 ` [PATCH 09/10] MIPS: lantiq: add mips_machine support John Crispin
2011-01-05 19:56 ` [PATCH 10/10] MIPS: lantiq: add machtypes for lantiq eval kits John Crispin
2011-01-11 2:44 ` [PATCH 00/10] MIPS: add support for Lantiq SoCs Daniel Schwierzeck
2011-01-11 12:07 ` John Crispin
2011-01-11 12:40 ` Daniel Schwierzeck
2011-01-11 12:49 ` John Crispin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.