linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH arm: initial TI-Nspire support]
@ 2013-04-04  9:01 Daniel Tang
  2013-04-04 11:12 ` Arnd Bergmann
  2013-04-09 11:14 ` Linus Walleij
  0 siblings, 2 replies; 23+ messages in thread
From: Daniel Tang @ 2013-04-04  9:01 UTC (permalink / raw)
  To: linux-arm-kernel, linux; +Cc: linux-kernel, fabian, Lionel Debroux

We're sending out for comments an early patch adding TI-Nspire support
to Linux.

Some words on the Nspire platform: it's a series of graphing
calculators, made of four models: "Clickpad" (2007-2010), "Touchpad"
(2010-2012?), "CX" (2011-), "CM-C" (2011-).

The main hardware characteristics are significantly outdated - and
yet, Nspires are the most powerful graphing calculators on the
market:
    * ARM926EJ-S based ASICs by LSI Logic, up to 200+ MHz;
    * 32 MB of SDRAM for Clickpad/Touchpad/CM-C, 64 MB of SDRAM for CX;
    * 512 KB of external NOR Flash for first-stage bootloader ("boot1")
      on the oldest models, internal since then;
    * NAND Flash for manufacturer data + boot2 (second-stage
      platform-specific bootloader) + "diags" (diagnostics software)
      + filesystem (containing OS): 32 MB for Clickpad / Touchpad,
      128 MB for CX. Multiple chip models are used.
    * 320x240 grayscale non-backlit DSTN screen for Clickpad / Touchpad
      (usually used in 4 bpp mode), 320x240 16 bpp backlit color screen
      for CX / CM-C;
    * USB OTG capable controller, for calc-to-calc transfers;
    * RS232 TTL and GPIO on proprietary-pitch "dock" connector.


>From a software point of view, the Nspire is usually running a
proprietary Nucleus-based OS, which uses the proprietary Datalight
Reliance filesystem, layered on top of proprietary FlashFX.
TI uses RSA signature validation for boot2, diags and OS upgrades;
boot2 and diags are compressed, OS upgrades are encrypted (Blowfish).
On the CX, some chunks of the boot2 are encrypted with 3-DES.
The officially sanctioned programming abilities are pretty limited:
    * a BASIC which cannot draw pixels to the screen or read arbitrary
      keys from the keyboard (yes, we're talking about a calculator
      used for teaching purposes !!);
    * a proprietary Lua with significant two-way incompatibilities with
      standard Lua: no io.*, so no file I/O, and no os.*; but a
      proprietary framework for event-driven programming.

Native code is accessible on select OS versions (Ndless) or boot2
versions (nLaunch & nLaunch CX) through arbitrary native code execution
exploits.
TI actively fights attempts to use native code on the Nspire series.


Patch contents
--------------
This patch (against mainline, but it also applies to linux-next)
contains the essential support code required to boot Linux to a shell 
on all models, but contains nothing else at the moment.
Code containing drivers for other peripherals exists, and will
eventually be posted for review as well: we need to do a bit of
cleanup. If you prefer them to be posted here now, we'll do.
They're at https://github.com/tangrs/linux .

A possibly noteworthy fact is that despite the gradual shift to
using Device Tree definitions for ARM machine types, we've decided not
to use it, for the following reasons:

    * the (perceived) extra complexity and code size;
    * the fact that we're using our own, simple, bootloader, due to
      the impossibility to bootstrap on most models (because boot1
      is usually not modifiable) and the fact that the image is stored
      in a proprietary FS not supported by mainline Linux and
      common bootloaders...


TODO
----
    * Address review comments, of course ;-)
    * Expand and clean up the drivers that have been written so far
      (for instance, GPIO) and submit them for review.
    * Continue to reverse engineer and write drivers to support the
      remaining hardware. We still need to work on power management and
      the NAND Flash. The platform also has a SPI somewhere, probably
      another USB port, and more anecdotal, 3-DES and SHA-256 hardware
      acceleration.


Thanks in advance for reviews ;)

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
Signed-off-by: Fabian Vogt <fabian@ritter-vogt.de>
Signed-off-by: Lionel Debroux <lionel_debroux@yahoo.fr>
---
 arch/arm/Kconfig                                 |   17 +
 arch/arm/Makefile                                |    1 +
 arch/arm/mach-nspire/Kconfig                     |   36 +++
 arch/arm/mach-nspire/Makefile                    |   16 +
 arch/arm/mach-nspire/Makefile.boot               |    1 +
 arch/arm/mach-nspire/classic.c                   |  363 ++++++++++++++++++++++
 arch/arm/mach-nspire/classic.h                   |   23 ++
 arch/arm/mach-nspire/clock.c                     |   39 +++
 arch/arm/mach-nspire/clock.h                     |   10 +
 arch/arm/mach-nspire/common.c                    |  311 ++++++++++++++++++
 arch/arm/mach-nspire/common.h                    |   52 ++++
 arch/arm/mach-nspire/include/mach/clkdev.h       |   24 ++
 arch/arm/mach-nspire/include/mach/debug-macro.S  |   28 ++
 arch/arm/mach-nspire/include/mach/hardware.h     |   15 +
 arch/arm/mach-nspire/include/mach/irqs.h         |   34 ++
 arch/arm/mach-nspire/include/mach/keypad.h       |   31 ++
 arch/arm/mach-nspire/include/mach/memory.h       |   17 +
 arch/arm/mach-nspire/include/mach/nspire_clock.h |   52 ++++
 arch/arm/mach-nspire/include/mach/nspire_mmio.h  |   67 ++++
 arch/arm/mach-nspire/include/mach/sram.h         |   26 ++
 arch/arm/mach-nspire/include/mach/timex.h        |   15 +
 arch/arm/mach-nspire/include/mach/uncompress.h   |   42 +++
 arch/arm/mach-nspire/keypad.c                    |  100 ++++++
 arch/arm/mach-nspire/nspire_clp.c                |   57 ++++
 arch/arm/mach-nspire/nspire_cx.c                 |  316 +++++++++++++++++++
 arch/arm/mach-nspire/nspire_tp.c                 |   80 +++++
 arch/arm/mach-nspire/sram.c                      |   66 ++++
 arch/arm/mach-nspire/touchpad.c                  |   30 ++
 arch/arm/mach-nspire/touchpad.h                  |   17 +
 arch/arm/tools/mach-types                        |    3 +
 30 files changed, 1889 insertions(+)
 create mode 100644 arch/arm/mach-nspire/Kconfig
 create mode 100644 arch/arm/mach-nspire/Makefile
 create mode 100644 arch/arm/mach-nspire/Makefile.boot
 create mode 100644 arch/arm/mach-nspire/classic.c
 create mode 100644 arch/arm/mach-nspire/classic.h
 create mode 100644 arch/arm/mach-nspire/clock.c
 create mode 100644 arch/arm/mach-nspire/clock.h
 create mode 100644 arch/arm/mach-nspire/common.c
 create mode 100644 arch/arm/mach-nspire/common.h
 create mode 100644 arch/arm/mach-nspire/include/mach/clkdev.h
 create mode 100644 arch/arm/mach-nspire/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-nspire/include/mach/hardware.h
 create mode 100644 arch/arm/mach-nspire/include/mach/irqs.h
 create mode 100644 arch/arm/mach-nspire/include/mach/keypad.h
 create mode 100644 arch/arm/mach-nspire/include/mach/memory.h
 create mode 100644 arch/arm/mach-nspire/include/mach/nspire_clock.h
 create mode 100644 arch/arm/mach-nspire/include/mach/nspire_mmio.h
 create mode 100644 arch/arm/mach-nspire/include/mach/sram.h
 create mode 100644 arch/arm/mach-nspire/include/mach/timex.h
 create mode 100644 arch/arm/mach-nspire/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-nspire/keypad.c
 create mode 100644 arch/arm/mach-nspire/nspire_clp.c
 create mode 100644 arch/arm/mach-nspire/nspire_cx.c
 create mode 100644 arch/arm/mach-nspire/nspire_tp.c
 create mode 100644 arch/arm/mach-nspire/sram.c
 create mode 100644 arch/arm/mach-nspire/touchpad.c
 create mode 100644 arch/arm/mach-nspire/touchpad.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 13b7394..4aa5029 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -492,6 +492,21 @@ config ARCH_NETX
 	help
 	  This enables support for systems based on the Hilscher NetX Soc

+config ARCH_NSPIRE
+	bool "TI-NSPIRE based"
+	depends on MMU
+	select CPU_ARM926T
+	select HAVE_MACH_CLKDEV
+	select CLKDEV_LOOKUP
+	select ARM_AMBA
+	select USB_ARCH_HAS_EHCI
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select GENERIC_ALLOCATOR
+	select ARCH_HAS_CPUFREQ
+	select CPU_FREQ_TABLE
+	help
+	  This enables support for systems using the TI-NSPIRE CPU
+
 config ARCH_H720X
 	bool "Hynix HMS720x-based"
 	select ARCH_USES_GETTIMEOFFSET
@@ -1081,6 +1096,8 @@ source "arch/arm/mach-netx/Kconfig"

 source "arch/arm/mach-nomadik/Kconfig"

+source "arch/arm/mach-nspire/Kconfig"
+
 source "arch/arm/plat-omap/Kconfig"

 source "arch/arm/mach-omap1/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..2580d2b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -165,6 +165,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
+machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig
new file mode 100644
index 0000000..da032b7
--- /dev/null
+++ b/arch/arm/mach-nspire/Kconfig
@@ -0,0 +1,36 @@
+if ARCH_NSPIRE
+
+choice
+	prompt "Early printk and boot message serial interface"
+	help
+	  Early printk output interface
+	depends on EARLY_PRINTK
+	default NSPIRE_EARLYPRINTK_CX
+
+config NSPIRE_EARLYPRINTK_CLASSIC
+	bool "Classic"
+
+config NSPIRE_EARLYPRINTK_CX
+	bool "CX model"
+endchoice
+
+
+menu "Supported models"
+
+config MACH_NSPIRECX
+	select GENERIC_CLOCKEVENTS
+	select ARM_VIC
+	select ARM_TIMER_SP804
+	bool "CX/CX CAS"
+
+config MACH_NSPIRETP
+	select GENERIC_IRQ_CHIP
+	bool "Touchpad/Touchpad CAS"
+
+config MACH_NSPIRECLP
+	select GENERIC_IRQ_CHIP
+	bool "Clickpad/Clickpad CAS"
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile
new file mode 100644
index 0000000..f7108fe
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile
@@ -0,0 +1,16 @@
+obj-y				:=
+
+obj-y				+= common.o
+obj-y				+= clock.o
+obj-y				+= sram.o
+obj-y				+= keypad.o
+
+obj-$(CONFIG_MACH_NSPIRECX)	+= nspire_cx.o
+obj-$(CONFIG_MACH_NSPIRECX)	+= touchpad.o
+
+obj-$(CONFIG_MACH_NSPIRECLP)	+= nspire_clp.o
+obj-$(CONFIG_MACH_NSPIRECLP)	+= classic.o
+
+obj-$(CONFIG_MACH_NSPIRETP)	+= nspire_tp.o
+obj-$(CONFIG_MACH_NSPIRETP)	+= classic.o
+obj-$(CONFIG_MACH_NSPIRETP)	+= touchpad.o
diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
new file mode 100644
index 0000000..7db966b
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y	:= 0x10008000
diff --git a/arch/arm/mach-nspire/classic.c b/arch/arm/mach-nspire/classic.c
new file mode 100644
index 0000000..b1eddf3
--- /dev/null
+++ b/arch/arm/mach-nspire/classic.c
@@ -0,0 +1,363 @@
+/*
+ *	linux/arch/arm/mach-nspire/classic.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/serial_8250.h>
+#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach/time.h>
+#include <asm/exception.h>
+
+#include <mach/nspire_mmio.h>
+#include <mach/nspire_clock.h>
+#include <mach/clkdev.h>
+#include <mach/keypad.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+/* Clock */
+
+union reg_clk_speed {
+	unsigned long raw;
+	struct {
+		unsigned long __padding0:1;
+		unsigned long base_cpu_ratio:7;
+		unsigned long is_base_27mhz:1;
+		unsigned long __padding1:3;
+		unsigned long cpu_ahb_ratio:3;
+		unsigned long __padding2:1;
+		unsigned long base_val:5;
+	} val;
+};
+
+static struct nspire_clk_speeds classic_io_to_clocks(unsigned long val)
+{
+	struct nspire_clk_speeds clks;
+	union reg_clk_speed reg;
+
+	reg.raw = val;
+	reg.val.base_cpu_ratio *= 2;
+	reg.val.cpu_ahb_ratio++;
+
+	BUG_ON(reg.val.base_cpu_ratio == 0);
+
+	clks.base = reg.val.is_base_27mhz ? 27 : (300 - (6*reg.val.base_val));
+	clks.base *= 1000000; /* Convert to Hz */
+
+	clks.div.base_cpu = reg.val.base_cpu_ratio;
+	clks.div.cpu_ahb = reg.val.cpu_ahb_ratio;
+
+	return clks;
+}
+
+static unsigned long classic_clocks_to_io(struct nspire_clk_speeds *clks)
+{
+	union reg_clk_speed reg;
+
+	BUG_ON(clks->div.base_cpu < 2);
+	BUG_ON(clks->div.cpu_ahb < 1);
+
+	reg.raw = 0;
+	reg.val.base_cpu_ratio = clks->div.base_cpu / 2;
+	reg.val.cpu_ahb_ratio = clks->div.cpu_ahb - 1;
+	reg.val.is_base_27mhz = (clks->base <= 27000000);
+	reg.val.base_val = (300 - (clks->base / 1000000)) / 6;
+
+	return reg.raw;
+}
+
+/* Interrupt handling */
+
+static inline int check_interrupt(void __iomem *base, struct pt_regs *regs)
+{
+	if (readl(base + 0x0)) {
+		int irqnr = readl(base + 0x24);
+		unsigned prev_priority;
+		handle_IRQ(irqnr, regs);
+
+		/* Reset priorities */
+		prev_priority = readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
+		writel(prev_priority, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
+		return 1;
+	}
+	return 0;
+}
+
+asmlinkage void __exception_irq_entry
+	nspire_classic_handle_irq(struct pt_regs *regs)
+{
+	int serviced;
+
+	do {
+		void __iomem *reg_base = IOMEM(NSPIRE_INTERRUPT_VIRT_BASE);
+		serviced = 0;
+
+		/* IRQ */
+		serviced += check_interrupt(reg_base, regs);
+		/* FIQ */
+		serviced += check_interrupt(reg_base + 0x100, regs);
+	} while (serviced > 0);
+}
+
+static void classic_irq_ack(struct irq_data *d)
+{
+	readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
+}
+
+static void __init classic_allocate_gc(void)
+{
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+
+	gc = irq_alloc_generic_chip("NINT", 1, 0,
+		IOMEM(NSPIRE_INTERRUPT_VIRT_BASE), handle_level_irq);
+
+	ct = gc->chip_types;
+	ct->chip.irq_ack = classic_irq_ack;
+	ct->chip.irq_mask = irq_gc_mask_disable_reg;
+	ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+
+	ct->regs.mask = 0x8;
+	ct->regs.enable = 0x8;
+	ct->regs.disable = 0xc;
+
+	irq_setup_generic_chip(gc, IRQ_MSK(NR_IRQS), IRQ_GC_INIT_MASK_CACHE,
+		IRQ_NOREQUEST, 0);
+}
+
+void __init nspire_classic_init_irq(void)
+{
+	/* No stickies */
+	writel(0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x204));
+
+	/* Disable all interrupts */
+	writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0xc));
+	writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x10c));
+
+	/* Set all priorities to 0 */
+	memset_io(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x300), 0, 0x7f);
+
+	/* Accept interrupts of all priorities */
+	writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
+	writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x12c));
+
+	/* Clear existing interrupts */
+	readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
+	readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x128));
+
+	/* Add chip */
+	classic_allocate_gc();
+}
+
+
+/* Timer */
+
+static int classic_timer_set_event(unsigned long delta,
+				struct clock_event_device *dev)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	writel(delta, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2));
+	writel(1, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x8));
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x18));
+	local_irq_restore(flags);
+
+	return 0;
+}
+static void classic_timer_set_mode(enum clock_event_mode mode,
+				 struct clock_event_device *evt)
+{
+	evt->mode = mode;
+}
+
+static struct clock_event_device nspire_clkevt = {
+	.name		= "clockevent",
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.rating		= 400,
+	.set_next_event = classic_timer_set_event,
+	.set_mode	= classic_timer_set_mode,
+	.cpumask		= cpu_all_mask,
+};
+
+static irqreturn_t classic_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *c = dev_id;
+
+	/* Acknowledge */
+	writel((1<<0), NSPIRE_APB_VIRTIO(NSPIRE_APB_MISC + 0x20));
+
+	if (c->mode != CLOCK_EVT_FEAT_PERIODIC)
+		writel((1<<4) | 1, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x08));
+
+	if (c->event_handler)
+		c->event_handler(c);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction classic_timer_irq = {
+	.name			= "timer2",
+	.flags			= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler		= classic_timer_interrupt,
+	.dev_id			= &nspire_clkevt,
+};
+
+
+void __init nspire_classic_timer_init(void)
+{
+	struct clk *timer_clk;
+
+	/* Count down from 1 */
+	writel(1, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2));
+
+	/* Divider is zero */
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x4));
+
+	/* Decreasing timer and interrupt */
+	writel(1, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x8));
+
+	/* Interrupt on timer value reaching 0 */
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x18));
+
+	/* Acknowledge existing interrupts */
+	writel(~0, NSPIRE_APB_VIRTIO(NSPIRE_APB_MISC + 0x20));
+
+	/* Set interrupt masks */
+	writel((1<<0), NSPIRE_APB_VIRTIO(NSPIRE_APB_MISC + 0x24));
+
+	setup_irq(NSPIRE_IRQ_TIMER2, &classic_timer_irq);
+
+	timer_clk = clk_get(NULL, "timer2");
+	clk_enable(timer_clk);
+
+	/* Set clocksource to zero */
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0xc));
+
+	/* Divider is zero */
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x10));
+
+	/* Ever increasing timer */
+	writel((1<<3) | 7, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x14));
+
+	clocksource_mmio_init(NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0xc),
+		"clocksource", clk_get_rate(timer_clk), 200, 16,
+		clocksource_mmio_readw_up);
+
+	clockevents_config_and_register(&nspire_clkevt,
+		clk_get_rate(timer_clk), 0x0001, 0xfffe);
+}
+
+
+/* Serial */
+static struct plat_serial8250_port classic_serial_platform_data[] = {
+	{
+		.mapbase	= NSPIRE_APB_PHYS(NSPIRE_APB_UART),
+		.irq		= NSPIRE_IRQ_UART,
+		.uartclk	= 29491200,
+		.iotype		= UPIO_MEM,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+				UPF_IOREMAP,
+		.regshift	= 2
+	},
+	{ }
+};
+
+struct platform_device nspire_classic_serial_device = {
+	.name		= "serial8250",
+	.id			= PLAT8250_DEV_PLATFORM,
+	.dev = {
+		.platform_data = &classic_serial_platform_data
+	}
+};
+
+/* Framebuffer */
+static struct clcd_panel classic_lcd_panel = {
+	.mode		= {
+		.name		= "grayscale lcd",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 6,
+		.left_margin	= 6,
+	},
+	.width		= 71, /* 7.11cm */
+	.height		= 53, /* 5.33cm */
+	.tim2		= 0x80007d0,
+	.cntl		= CNTL_LCDBPP8 | CNTL_LCDMONO8,
+	.bpp		= 8,
+	.grayscale	= 1
+};
+#define PANEL_SIZE (19 * SZ_4K)
+
+static int classic_clcd_setup(struct clcd_fb *fb)
+{
+	return nspire_clcd_setup(fb, PANEL_SIZE, &classic_lcd_panel);
+}
+
+static struct clcd_board classic_clcd_data = {
+	.name		= "lcd controller",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.setup		= classic_clcd_setup,
+	.mmap		= nspire_clcd_mmap,
+	.remove		= nspire_clcd_remove,
+};
+
+AMBA_AHB_DEVICE(fb, "fb", 0, NSPIRE_LCD_PHYS_BASE,
+	{ NSPIRE_IRQ_LCD }, &classic_clcd_data);
+
+/* Init */
+void __init nspire_classic_init_early(void)
+{
+	nspire_io_to_clocks = classic_io_to_clocks;
+	nspire_clocks_to_io = classic_clocks_to_io;
+
+	nspire_init_early();
+}
+
+void __init nspire_classic_init(void)
+{
+	/*
+	 * Temporarily disable NAND writes on classics to prevent
+	 * accidental bricking.
+	 */
+	writel((1<<7), NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x18));
+
+	nspire_keypad_data.active_low = 1;
+
+	amba_device_register(&fb_device, &iomem_resource);
+	platform_device_register(&nspire_keypad_device);
+	platform_device_register(&nspire_classic_serial_device);
+
+	nspire_init();
+}
+
+void __init nspire_classic_init_late(void)
+{
+	nspire_init_late();
+}
diff --git a/arch/arm/mach-nspire/classic.h b/arch/arm/mach-nspire/classic.h
new file mode 100644
index 0000000..c440ebc
--- /dev/null
+++ b/arch/arm/mach-nspire/classic.h
@@ -0,0 +1,23 @@
+/*
+ *	linux/arch/arm/mach-nspire/classic.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <asm/exception.h>
+
+void __init nspire_classic_init_irq(void);
+void __init nspire_classic_init_early(void);
+void __init nspire_classic_init(void);
+void __init nspire_classic_init_late(void);
+asmlinkage void __exception_irq_entry
+	nspire_classic_handle_irq(struct pt_regs *regs);
+
+void __init nspire_classic_timer_init(void);
+
+extern struct irq_chip nspire_classic_irq_chip;
diff --git a/arch/arm/mach-nspire/clock.c b/arch/arm/mach-nspire/clock.c
new file mode 100644
index 0000000..c679449
--- /dev/null
+++ b/arch/arm/mach-nspire/clock.c
@@ -0,0 +1,39 @@
+/*
+ *  linux/arch/arm/mach-nspire/clock.c
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <asm-generic/errno.h>
+
+#include <mach/clkdev.h>
+
+void clk_disable(struct clk *clk)
+{
+}
+
+int clk_enable(struct clk *clk)
+{
+	return 0;
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->get_rate)
+		clk->get_rate(clk);
+
+	return clk->rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->set_rate)
+		return clk->set_rate(clk, rate);
+
+	return -ENOSYS;
+}
diff --git a/arch/arm/mach-nspire/clock.h b/arch/arm/mach-nspire/clock.h
new file mode 100644
index 0000000..43e99bd
--- /dev/null
+++ b/arch/arm/mach-nspire/clock.h
@@ -0,0 +1,10 @@
+/*
+ *  linux/arch/arm/mach-nspire/clock.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
diff --git a/arch/arm/mach-nspire/common.c b/arch/arm/mach-nspire/common.c
new file mode 100644
index 0000000..a7abc68
--- /dev/null
+++ b/arch/arm/mach-nspire/common.c
@@ -0,0 +1,311 @@
+/*
+ *	linux/arch/arm/mach-nspire/common.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/clkdev.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/chipidea.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/nspire_mmio.h>
+#include <mach/nspire_clock.h>
+#include <mach/irqs.h>
+#include <mach/clkdev.h>
+#include <mach/keypad.h>
+#include <mach/sram.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include "common.h"
+#include "clock.h"
+
+/* Clocks */
+
+struct nspire_clk_speeds (*nspire_io_to_clocks)(unsigned long);
+unsigned long (*nspire_clocks_to_io)(struct nspire_clk_speeds *);
+
+/* AHB clock */
+static void ahb_get_rate(struct clk *clk)
+{
+	struct nspire_clk_speeds speeds = nspire_get_clocks();
+	clk->rate = CLK_GET_AHB(&speeds);
+}
+
+static struct clk ahb_clk = {
+	.get_rate = ahb_get_rate,
+};
+
+/* APB clock */
+
+static void apb_get_rate(struct clk *clk)
+{
+	clk->rate = clk_get_rate(&ahb_clk) / 2;
+}
+
+static struct clk apb_clk = {
+	.get_rate = apb_get_rate
+};
+
+/* Misc */
+
+static struct clk systimer_clk = {
+	.rate	= 32768,
+};
+
+static struct clk uart_clk = {
+	.rate	= 12000000,
+};
+
+#ifdef CONFIG_MACH_NSPIRECX
+static struct clk i2c_clk = {
+	/* Doesn't matter, we set it manually */
+	.rate	= 250000,
+};
+#endif
+
+static struct clk_lookup nspire_clk_lookup[] = {
+	{
+		.dev_id = "uart",
+		.clk = &uart_clk
+	},
+	{
+		.dev_id = "fb",
+		.clk = &ahb_clk
+	},
+	{
+		.con_id = "ahb",
+		.clk = &ahb_clk
+	},
+	{
+		.dev_id = "watchdog",
+		.clk = &apb_clk
+	},
+	{
+		.dev_id = "nspire-keypad.0",
+		.clk = &apb_clk
+	},
+#ifdef CONFIG_MACH_NSPIRECX
+	{
+		.dev_id = "sp804",
+		.con_id = "timer2",
+		.clk = &systimer_clk
+	},
+	{
+		.dev_id = "i2c_designware.0",
+		.clk = &i2c_clk
+	},
+#endif
+#if defined(CONFIG_MACH_NSPIRECLP) || defined(CONFIG_MACH_NSPIRETP)
+	{
+		.dev_id = NULL,
+		.con_id = "timer2",
+		.clk = &systimer_clk
+	},
+#endif
+};
+
+/* Keypad */
+static struct resource nspire_keypad_resources[] = {
+	{
+		.start	= NSPIRE_APB_PHYS(NSPIRE_APB_KEYPAD),
+		.end	= NSPIRE_APB_PHYS(NSPIRE_APB_KEYPAD + SZ_4K - 1),
+		.flags	= IORESOURCE_MEM,
+	},
+	RESOURCE_ENTRY_IRQ(KEYPAD)
+};
+
+struct nspire_keypad_data nspire_keypad_data = {
+	.scan_interval	= 1000,
+	.row_delay	= 200
+};
+
+struct platform_device nspire_keypad_device = {
+	.name		= "nspire-keypad",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(nspire_keypad_resources),
+	.resource	= nspire_keypad_resources,
+	.dev = {
+		.platform_data = &nspire_keypad_data
+	}
+};
+
+
+/* GPIO */
+static struct resource nspire_gpio_resources[] = {
+	{
+		.start	= NSPIRE_APB_PHYS(NSPIRE_APB_GPIO),
+		.end	= NSPIRE_APB_PHYS(NSPIRE_APB_GPIO + SZ_4K - 1),
+		.flags	= IORESOURCE_MEM,
+	},
+	RESOURCE_ENTRY_IRQ(GPIO)
+};
+
+static struct platform_device nspire_gpio_device = {
+	.name		= "gpio-nspire",
+	.resource	= nspire_gpio_resources,
+	.num_resources	= ARRAY_SIZE(nspire_gpio_resources),
+};
+
+/* ADC */
+static struct resource nspire_adc_resources[] = {
+	RESOURCE_ENTRY_MEM(ADC),
+	RESOURCE_ENTRY_IRQ(ADC)
+};
+
+static struct platform_device nspire_adc_device = {
+	.name		= "nspire-adc",
+	.resource	= nspire_adc_resources,
+	.num_resources	= ARRAY_SIZE(nspire_adc_resources)
+};
+
+/* Framebuffer */
+int nspire_clcd_setup(struct clcd_fb *fb, unsigned panel_size,
+	struct clcd_panel *panel)
+{
+	dma_addr_t dma;
+
+	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+		panel_size, &dma, GFP_KERNEL);
+	if (!fb->fb.screen_base) {
+		pr_err("CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+	fb->fb.fix.smem_start = dma;
+	fb->fb.fix.smem_len = panel_size;
+	fb->panel = panel;
+
+	return 0;
+}
+
+int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+		fb->fb.screen_base, fb->fb.fix.smem_start,
+		fb->fb.fix.smem_len);
+}
+
+void nspire_clcd_remove(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+		fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+/* Watchdog */
+
+AMBA_APB_DEVICE(watchdog, "watchdog", 0, NSPIRE_APB_PHYS(NSPIRE_APB_WATCHDOG),
+	{ NSPIRE_IRQ_WATCHDOG }, NULL);
+
+/* Generic OTG */
+
+u64 nspire_usb_dma_mask = ~(u32)0;
+
+static struct resource otg_resources[] = {
+	RESOURCE_ENTRY_MEM(OTG),
+	RESOURCE_ENTRY_IRQ(OTG)
+};
+
+static struct ci13xxx_platform_data otg_pdata = {
+	.name = "nspire_usb",
+	.capoffset = 0x100,
+	.flags = CI13XXX_REGS_SHARED,
+};
+
+
+struct platform_device nspire_otg_device = {
+	.name		= "ci_hdrc",
+	.id		= 0,
+	.dev = {
+		.platform_data = &otg_pdata,
+		.coherent_dma_mask = ~0,
+		.dma_mask = &nspire_usb_dma_mask
+	},
+	.resource = otg_resources,
+	.num_resources = ARRAY_SIZE(otg_resources)
+};
+
+struct platform_device nspire_usb_nop_xceiver = {
+	.name		= "nop_usb_xceiv",
+};
+
+/* RTC */
+static struct resource nspire_rtc_resources[] = {
+	{
+		.start	= NSPIRE_APB_PHYS(NSPIRE_APB_RTC),
+		.end	= NSPIRE_APB_PHYS(NSPIRE_APB_RTC + SZ_4K - 1),
+		.flags	= IORESOURCE_MEM,
+	},
+	RESOURCE_ENTRY_IRQ(RTC)
+};
+
+static struct platform_device nspire_rtc_device = {
+	.name		= "nspire-rtc",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(nspire_rtc_resources),
+	.resource	= nspire_rtc_resources,
+};
+
+/* Memory mapped IO */
+struct map_desc nspire_io_regs[] __initdata = {
+	IOTABLE_ENTRY(ADC),
+	IOTABLE_ENTRY(APB),
+	IOTABLE_ENTRY(INTERRUPT),
+};
+
+void __init nspire_map_io(void)
+{
+	iotable_init(nspire_io_regs, ARRAY_SIZE(nspire_io_regs));
+}
+
+/* Clocks */
+void __init nspire_init_early(void)
+{
+	clkdev_add_table(nspire_clk_lookup, ARRAY_SIZE(nspire_clk_lookup));
+
+	/* Renable bus access to everything in case the OS disabled them */
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x18));
+	writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x20));
+
+	/*
+	 * Ack some non-maskable clock speed change interrupts before cpufreq
+	 * driver is brought up to avoid a race condition between an interrupt
+	 * happening and driver init.
+	 */
+
+	writel(3, NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x14));
+}
+
+/* Common init */
+void __init nspire_init(void)
+{
+	sram_init(NSPIRE_SRAM_PHYS_BASE, NSPIRE_SRAM_SIZE);
+	amba_device_register(&watchdog_device, &iomem_resource);
+
+	platform_device_register(&nspire_gpio_device);
+	platform_device_register(&nspire_rtc_device);
+	platform_device_register(&nspire_adc_device);
+
+}
+
+void __init nspire_init_late(void)
+{
+}
+
+/* Restart */
+void nspire_restart(char mode, const char *cmd)
+{
+	writel(2, NSPIRE_APB_VIRTIO(NSPIRE_APB_MISC + 0x8));
+}
diff --git a/arch/arm/mach-nspire/common.h b/arch/arm/mach-nspire/common.h
new file mode 100644
index 0000000..27e81b6
--- /dev/null
+++ b/arch/arm/mach-nspire/common.h
@@ -0,0 +1,52 @@
+/*
+ *	linux/arch/arm/mach-nspire/common.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+
+#define IOTABLE_ENTRY(t) \
+	{ \
+		.virtual	= NSPIRE_##t##_VIRT_BASE, \
+		.pfn		= __phys_to_pfn(NSPIRE_##t##_PHYS_BASE), \
+		.length		= NSPIRE_##t##_SIZE, \
+		.type		= MT_DEVICE \
+	}
+
+#define RESOURCE_ENTRY_IRQ(t) \
+	{ \
+		.start	= NSPIRE_IRQ_##t, \
+		.end	= NSPIRE_IRQ_##t, \
+		.flags	= IORESOURCE_IRQ \
+	}
+
+#define RESOURCE_ENTRY_MEM(t) \
+	{ \
+		.start	= NSPIRE_##t##_PHYS_BASE, \
+		.end	= NSPIRE_##t##_PHYS_BASE + NSPIRE_##t##_SIZE - 1, \
+		.flags	= IORESOURCE_MEM \
+	}
+
+extern struct platform_device nspire_keypad_device;
+extern struct platform_device nspire_otg_device;
+extern struct platform_device nspire_usb_nop_xceiver;
+extern struct nspire_keypad_data nspire_keypad_data;
+
+extern u64 nspire_usb_dma_mask;
+
+void __init nspire_map_io(void);
+void __init nspire_init_early(void);
+void __init nspire_init(void);
+void __init nspire_init_late(void);
+
+void nspire_restart(char mode, const char *cmd);
+
+int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma);
+void nspire_clcd_remove(struct clcd_fb *fb);
+int nspire_clcd_setup(struct clcd_fb *fb, unsigned panel_size,
+	struct clcd_panel *panel);
diff --git a/arch/arm/mach-nspire/include/mach/clkdev.h b/arch/arm/mach-nspire/include/mach/clkdev.h
new file mode 100644
index 0000000..b4afe65
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/clkdev.h
@@ -0,0 +1,24 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/clkdev.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_CLKDEV_H
+#define NSPIRE_CLKDEV_H
+
+struct clk {
+	void (*get_rate)(struct clk *clk);
+	int (*set_rate)(struct clk *clk, unsigned long rate);
+	unsigned long rate;
+};
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/debug-macro.S b/arch/arm/mach-nspire/include/mach/debug-macro.S
new file mode 100644
index 0000000..b71daa4
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/debug-macro.S
@@ -0,0 +1,28 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/debug-macro.S
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
+
+.macro	addruart, rp, rv, tmp
+	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
+	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
+.endm
+
+
+#ifdef CONFIG_NSPIRE_EARLYPRINTK_CX
+#include <asm/hardware/debug-pl01x.S>
+#endif
+
+#ifdef CONFIG_NSPIRE_EARLYPRINTK_CLASSIC
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/hardware.h b/arch/arm/mach-nspire/include/mach/hardware.h
new file mode 100644
index 0000000..7c9c3b6
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/hardware.h
@@ -0,0 +1,15 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/hardware.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_HARDWARE_H
+#define NSPIRE_HARDWARE_H
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/irqs.h b/arch/arm/mach-nspire/include/mach/irqs.h
new file mode 100644
index 0000000..70be120
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/irqs.h
@@ -0,0 +1,34 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/irqs.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_IRQS_H
+#define NSPIRE_IRQS_H
+
+#define NSPIRE_IRQ_MASK         0x007FEB9A
+
+enum {
+	NSPIRE_IRQ_UART = 1,
+	NSPIRE_IRQ_WATCHDOG = 3,
+	NSPIRE_IRQ_RTC = 4,
+	NSPIRE_IRQ_GPIO = 7,
+	NSPIRE_IRQ_OTG = 8,
+	NSPIRE_IRQ_HOSTUSB = 9,
+	NSPIRE_IRQ_ADC = 11,
+	NSPIRE_IRQ_PWR = 15,
+	NSPIRE_IRQ_KEYPAD = 16,
+	NSPIRE_IRQ_TIMER2 = 19,
+	NSPIRE_IRQ_I2C = 20,
+	NSPIRE_IRQ_LCD = 21
+};
+
+#define NR_IRQS 32
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/keypad.h b/arch/arm/mach-nspire/include/mach/keypad.h
new file mode 100644
index 0000000..18cf3fd
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/keypad.h
@@ -0,0 +1,31 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/keypad.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_KEYPAD_H
+#define NSPIRE_KEYPAD_H
+
+#define KEYPAD_BITMASK_COLS	11
+#define KEYPAD_BITMASK_ROWS	8
+
+struct nspire_keypad_data {
+	unsigned int (*evtcodes)[KEYPAD_BITMASK_COLS];
+
+	/* Maximum delay estimated assuming 33MHz APB */
+	unsigned short scan_interval;	/* In microseconds (~2000us max) */
+	unsigned short row_delay;	/* In microseconds (~500us max) */
+
+	bool active_low;
+};
+
+extern unsigned int nspire_touchpad_evtcode_map[][KEYPAD_BITMASK_COLS];
+extern unsigned int nspire_clickpad_evtcode_map[][KEYPAD_BITMASK_COLS];
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/memory.h b/arch/arm/mach-nspire/include/mach/memory.h
new file mode 100644
index 0000000..eec3f36
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/memory.h
@@ -0,0 +1,17 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/memory.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_MEMORY_H
+#define NSPIRE_MEMORY_H
+
+#define PLAT_PHYS_OFFSET 0x10000000
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/nspire_clock.h b/arch/arm/mach-nspire/include/mach/nspire_clock.h
new file mode 100644
index 0000000..a96b089
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/nspire_clock.h
@@ -0,0 +1,52 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/nspire_clock.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_CLOCK_H
+#define NSPIRE_CLOCK_H
+
+#include <linux/io.h>
+
+#include <mach/nspire_mmio.h>
+
+struct nspire_clk_divider {
+	unsigned char base_cpu, cpu_ahb;
+};
+
+struct nspire_clk_speeds {
+	unsigned long base;
+	struct nspire_clk_divider div;
+};
+
+#define CLK_GET_CPU(cs) ((cs)->base / (cs)->div.base_cpu)
+#define CLK_GET_AHB(cs) (CLK_GET_CPU(cs) / (cs)->div.cpu_ahb)
+
+extern struct nspire_clk_speeds (*nspire_io_to_clocks)(unsigned long);
+extern unsigned long (*nspire_clocks_to_io)(struct nspire_clk_speeds *);
+
+static inline struct nspire_clk_speeds nspire_get_clocks(void)
+{
+	unsigned long val = readl(NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x00));
+	BUG_ON(!nspire_io_to_clocks);
+	return nspire_io_to_clocks(val);
+}
+
+static inline void nspire_set_clocks(struct nspire_clk_speeds *clks)
+{
+	unsigned long val;
+	BUG_ON(!nspire_io_to_clocks);
+
+	val = nspire_clocks_to_io(clks);
+
+	writel(val, NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x00));
+	writel(4,   NSPIRE_APB_VIRTIO(NSPIRE_APB_POWER + 0x0c));
+}
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/nspire_mmio.h b/arch/arm/mach-nspire/include/mach/nspire_mmio.h
new file mode 100644
index 0000000..eaeb100
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/nspire_mmio.h
@@ -0,0 +1,67 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/nspire_mmio.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_MMIO_H
+#define NSPIRE_MMIO_H
+
+#include <asm-generic/sizes.h>
+
+/*
+	Memory map:
+	0xFEE00000 - 0xFF000000		0x90000000 - 0x90200000		(APB)
+	0xFEDFF000 - 0xFEE00000		0xDC000000 - 0xDC001000		(Interrupt Controller)
+	0xFED7F000 - 0xFEDFF000		0x00000000 - 0x00080000		(Boot1 ROM)
+	0xFED7E000 - 0xFED7F000		0xC4000000 - 0xC4001000		(ADC)
+*/
+#define NSPIRE_APB_PHYS_BASE		0x90000000
+#define NSPIRE_APB_SIZE			SZ_2M
+#define NSPIRE_APB_VIRT_BASE		0xFEE00000
+
+#define NSPIRE_APB_PHYS(x)		((NSPIRE_APB_PHYS_BASE) + (x))
+#define NSPIRE_APB_VIRT(x)		((NSPIRE_APB_VIRT_BASE) + (x))
+#define NSPIRE_APB_VIRTIO(x)		IOMEM(NSPIRE_APB_VIRT(x))
+
+
+#define NSPIRE_INTERRUPT_PHYS_BASE	0xDC000000
+#define NSPIRE_INTERRUPT_SIZE		SZ_4K
+#define NSPIRE_INTERRUPT_VIRT_BASE	0xFEDFF000
+
+#define NSPIRE_LCD_PHYS_BASE		0xC0000000
+
+#define NSPIRE_OTG_PHYS_BASE		0xB0000000
+#define NSPIRE_OTG_SIZE			SZ_8K
+
+#define NSPIRE_NAND_PHYS_BASE		0x81000000
+#define NSPIRE_NAND_SIZE		SZ_16M
+
+#define NSPIRE_BOOT1_PHYS_BASE		0x00000000
+#define NSPIRE_BOOT1_SIZE		0x00080000
+#define NSPIRE_BOOT1_VIRT_BASE		0xFED7F000
+
+#define NSPIRE_APB_GPIO			0x00000
+#define NSPIRE_APB_UART			0x20000
+#define NSPIRE_APB_I2C			0x50000
+#define NSPIRE_APB_WATCHDOG		0x60000
+#define NSPIRE_APB_RTC			0x90000
+#define NSPIRE_APB_MISC			0xA0000
+#define NSPIRE_APB_POWER		0xB0000
+#define NSPIRE_APB_TIMER2		0xD0000
+#define NSPIRE_APB_KEYPAD		0xE0000
+#define NSPIRE_APB_CONTRAST		0xF0000
+
+#define NSPIRE_SRAM_PHYS_BASE		0xA4000000
+#define NSPIRE_SRAM_SIZE		0x00020000
+
+#define NSPIRE_ADC_PHYS_BASE		0xC4000000
+#define NSPIRE_ADC_SIZE			SZ_4K
+#define NSPIRE_ADC_VIRT_BASE		0xFED7E000
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/sram.h b/arch/arm/mach-nspire/include/mach/sram.h
new file mode 100644
index 0000000..2f652f3
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/sram.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#ifndef NSPIRE_SRAM_H
+#define NSPIRE_SRAM_H
+
+void *sram_alloc(unsigned int size, dma_addr_t *dma_addr);
+void sram_free(dma_addr_t addr, unsigned int size);
+int __init sram_init(unsigned long base, unsigned long size);
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/timex.h b/arch/arm/mach-nspire/include/mach/timex.h
new file mode 100644
index 0000000..2d4449e
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/timex.h
@@ -0,0 +1,15 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/timex.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_TIMEX_H
+#define NSPIRE_TIMEX_H
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/uncompress.h b/arch/arm/mach-nspire/include/mach/uncompress.h
new file mode 100644
index 0000000..7be9d06
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/uncompress.h
@@ -0,0 +1,42 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/uncompress.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *	Copyright (C) 2013 Lionel Debroux <lionel_debroux@yahoo.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_UNCOMPRESS_H
+#define NSPIRE_UNCOMPRESS_H
+
+#include <mach/nspire_mmio.h>
+
+#define OFFSET_VAL(var, offset) ((var)[(offset)>>2])
+static inline void putc(int c)
+{
+	volatile unsigned __attribute__((unused)) *serial_base =
+		(volatile unsigned *) NSPIRE_APB_PHYS(NSPIRE_APB_UART);
+
+#ifdef CONFIG_NSPIRE_EARLYPRINTK_CLASSIC
+	OFFSET_VAL(serial_base, 0x00) = (unsigned char)c;
+	while (!(OFFSET_VAL(serial_base, 0x14) & (1<<5)))
+		barrier();
+#endif
+
+#ifdef CONFIG_NSPIRE_EARLYPRINTK_CX
+	OFFSET_VAL(serial_base, 0x00) = (unsigned char)c;
+	while (OFFSET_VAL(serial_base, 0x18) & (1<<5))
+		barrier();
+#endif
+
+}
+#undef OFFSET_VAL
+
+#define arch_decomp_setup()
+#define flush()
+
+#endif
diff --git a/arch/arm/mach-nspire/keypad.c b/arch/arm/mach-nspire/keypad.c
new file mode 100644
index 0000000..5cd9344
--- /dev/null
+++ b/arch/arm/mach-nspire/keypad.c
@@ -0,0 +1,100 @@
+/*
+ *	linux/arch/arm/mach-nspire/keypad.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/input.h>
+
+#include <mach/keypad.h>
+
+unsigned int nspire_touchpad_evtcode_map[][KEYPAD_BITMASK_COLS] = {
+	{
+		KEY_ENTER,	KEY_ENTER,	0,		0,
+		KEY_SPACE,	KEY_Z,		KEY_Y,		KEY_0,
+		KEY_TAB,	0,		0,
+	},
+	{
+		KEY_X,		KEY_W,		KEY_V,		KEY_3,
+		KEY_U,		KEY_T,		KEY_S,		KEY_1,
+		0,		0,		KEY_RIGHT
+	},
+	{
+		KEY_R,		KEY_Q,		KEY_P,		KEY_6,
+		KEY_O,		KEY_N,		KEY_M,		KEY_4,
+		KEY_APOSTROPHE, KEY_DOWN,	0
+	},
+	{
+		KEY_L,		KEY_K,		KEY_J,		KEY_9,
+		KEY_I,		KEY_H,		KEY_G,		KEY_7,
+		KEY_SLASH,	KEY_LEFT,	0
+	},
+	{
+		KEY_F,		KEY_E,		KEY_D,		0,
+		KEY_C,		KEY_B,		KEY_A,		KEY_EQUAL,
+		KEY_KPASTERISK, KEY_UP,		0
+	},
+	{
+		0,		KEY_LEFTALT,	KEY_MINUS,	KEY_RIGHTBRACE,
+		KEY_DOT,	KEY_LEFTBRACE,	KEY_5,		0,
+		KEY_SEMICOLON,	KEY_BACKSPACE,	KEY_DELETE
+	},
+	{
+		KEY_BACKSLASH,	0,		KEY_KPPLUS,	KEY_PAGEUP,
+		KEY_2,		KEY_PAGEDOWN,	KEY_8,		KEY_ESC,
+		0,		KEY_TAB,	0
+	},
+	{
+		0,		0,		0,		0,
+		0,		0,		0,		0,
+		KEY_LEFTSHIFT,	KEY_LEFTCTRL,	KEY_COMMA
+	},
+};
+
+unsigned int nspire_clickpad_evtcode_map[][KEYPAD_BITMASK_COLS] = {
+	{
+		KEY_ENTER,	KEY_ENTER,	KEY_SPACE,	0,
+		KEY_Z,		KEY_DOT,	KEY_Y,		KEY_0,
+		KEY_X,		0,		0,
+	},
+	{
+		KEY_COMMA,	KEY_KPPLUS,	KEY_W,		KEY_3,
+		KEY_V,		KEY_2,		KEY_U,		KEY_1,
+		KEY_T,		0,		0
+	},
+	{
+		KEY_KPSLASH,	KEY_MINUS,	KEY_S,		KEY_6,
+		KEY_R,		KEY_5,		KEY_Q,		KEY_4,
+		KEY_P,		0,		0
+	},
+	{
+		KEY_SEMICOLON,	KEY_KPASTERISK, KEY_O,		KEY_9,
+		KEY_N,		KEY_8,		KEY_M,		KEY_7,
+		KEY_L,		0,		0
+	},
+	{
+		KEY_APOSTROPHE, KEY_SLASH,	KEY_K,		0,
+		KEY_J,		0,		KEY_I,		0,
+		KEY_H,		0,		0
+	},
+	{
+		KEY_APOSTROPHE, 0,		KEY_G,		KEY_RIGHTBRACE,
+		KEY_F,		KEY_LEFTBRACE,	KEY_E,		KEY_DELETE,
+		KEY_D,		KEY_LEFTSHIFT,	0
+	},
+	{
+		0,		KEY_ENTER,	KEY_C,		KEY_PAGEUP,
+		KEY_B,		KEY_PAGEDOWN,	KEY_A,		KEY_ESC,
+		KEY_BACKSLASH,	KEY_TAB,	0
+	},
+	{
+		KEY_UP,		0,		KEY_RIGHT,	0,
+		KEY_DOWN,	0,		KEY_LEFT,	KEY_BACKSPACE,
+		KEY_LEFTCTRL,	0,		KEY_EQUAL
+	},
+};
diff --git a/arch/arm/mach-nspire/nspire_clp.c b/arch/arm/mach-nspire/nspire_clp.c
new file mode 100644
index 0000000..945ab5d
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire_clp.c
@@ -0,0 +1,57 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire_clp.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/input.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/mtd/nand.h>
+
+#include <mach/nspire_mmio.h>
+#include <mach/irqs.h>
+#include <mach/clkdev.h>
+#include <mach/sram.h>
+#include <mach/keypad.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "common.h"
+#include "classic.h"
+
+static void __init clp_init(void)
+{
+	nspire_keypad_data.evtcodes = nspire_clickpad_evtcode_map;
+	platform_device_register(&nspire_otg_device);
+	platform_device_register(&nspire_usb_nop_xceiver);
+
+	nspire_classic_init();
+}
+
+MACHINE_START(NSPIRECLP, "TI-NSPIRE Clickpad Calculator")
+	.map_io		= nspire_map_io,
+	.init_irq	= nspire_classic_init_irq,
+	.handle_irq	= nspire_classic_handle_irq,
+	.init_time	= nspire_classic_timer_init,
+	.init_early	= nspire_classic_init_early,
+	.init_machine	= clp_init,
+	.init_late	= nspire_classic_init_late,
+	.restart	= nspire_restart,
+MACHINE_END
diff --git a/arch/arm/mach-nspire/nspire_cx.c b/arch/arm/mach-nspire/nspire_cx.c
new file mode 100644
index 0000000..81bbbf8
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire_cx.c
@@ -0,0 +1,316 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire_cx.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/input.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/mtd/nand.h>
+#include <linux/irqchip/arm-vic.h>
+
+#include <mach/nspire_mmio.h>
+#include <mach/nspire_clock.h>
+#include <mach/irqs.h>
+#include <mach/clkdev.h>
+#include <mach/sram.h>
+#include <mach/keypad.h>
+
+#include <asm/mach/time.h>
+#include <asm/hardware/timer-sp.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "common.h"
+#include "touchpad.h"
+
+/* Clock */
+
+union reg_clk_speed {
+	unsigned long raw;
+	struct {
+		unsigned long __padding0:1;
+		unsigned long base_cpu_ratio:7;
+		unsigned long is_base_48mhz:1;
+		unsigned long __padding1:3;
+		unsigned long cpu_ahb_ratio:3;
+		unsigned long base_val:6;
+		unsigned long unknown:2;
+	} val;
+};
+
+static struct nspire_clk_speeds cx_io_to_clocks(unsigned long val)
+{
+	struct nspire_clk_speeds clks;
+	union reg_clk_speed reg;
+
+	reg.raw = val;
+	reg.val.base_cpu_ratio *= reg.val.unknown;
+	reg.val.cpu_ahb_ratio++;
+
+	BUG_ON(reg.val.base_cpu_ratio == 0);
+
+	clks.base = reg.val.is_base_48mhz ? 48 : 6*reg.val.base_val;
+	clks.base *= 1000000; /* Convert to Hz */
+
+	clks.div.base_cpu = reg.val.base_cpu_ratio;
+	clks.div.cpu_ahb = reg.val.cpu_ahb_ratio;
+
+	return clks;
+}
+
+static unsigned long cx_clocks_to_io(struct nspire_clk_speeds *clks)
+{
+	union reg_clk_speed reg;
+
+	BUG_ON(clks->div.base_cpu < 1);
+	BUG_ON(clks->div.cpu_ahb < 1);
+
+	reg.raw = 0;
+	reg.val.unknown = (clks->div.base_cpu & 0x1) ? 0b01 : 0b10;
+	reg.val.base_cpu_ratio = clks->div.base_cpu / reg.val.unknown;
+	reg.val.cpu_ahb_ratio = clks->div.cpu_ahb - 1;
+	reg.val.is_base_48mhz = (clks->base <= 48000000);
+	reg.val.base_val = (clks->base / 6000000);
+
+	return reg.raw;
+}
+
+/* IRQ */
+static void __init cx_init_irq(void)
+{
+	vic_init(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE), 0, NSPIRE_IRQ_MASK, 0);
+}
+
+/* UART */
+
+static AMBA_APB_DEVICE(uart, "uart", 0, NSPIRE_APB_PHYS(NSPIRE_APB_UART),
+	{ NSPIRE_IRQ_UART }, NULL);
+
+/* TIMER */
+
+void __init cx_timer_init(void)
+{
+	sp804_clockevents_init(NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2),
+		NSPIRE_IRQ_TIMER2, "timer2");
+}
+
+/* FRAMEBUFFER */
+static struct clcd_panel cx_lcd_panel = {
+	.mode		= {
+		.name		= "color lcd",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 50,
+		.left_margin	= 38,
+		.lower_margin	= 3,
+		.upper_margin	= 17,
+	},
+	.width		= 65, /* ~6.50 cm */
+	.height		= 49, /* ~4.87 cm */
+	.tim2		= TIM2_IPC,
+	.cntl		= (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+				CNTL_LCDBPP16_565),
+	.bpp		= 16,
+};
+#define PANEL_SIZE (38 * SZ_4K)
+
+static int cx_clcd_setup(struct clcd_fb *fb)
+{
+	return nspire_clcd_setup(fb, PANEL_SIZE, &cx_lcd_panel);
+}
+
+static struct clcd_board cx_clcd_data = {
+	.name		= "lcd controller",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.setup		= cx_clcd_setup,
+	.mmap		= nspire_clcd_mmap,
+	.remove		= nspire_clcd_remove,
+};
+
+static AMBA_AHB_DEVICE(fb, "fb", 0, NSPIRE_LCD_PHYS_BASE,
+	{ NSPIRE_IRQ_LCD }, &cx_clcd_data);
+
+/* USB HOST */
+
+static struct usb_ehci_pdata cxusbhost_pdata = {
+	.has_tt = 1,
+	.caps_offset = 0x100
+};
+
+static struct resource cxusbhost_resources_pdata[] = {
+	RESOURCE_ENTRY_MEM(OTG),
+	RESOURCE_ENTRY_IRQ(OTG)
+};
+
+static struct platform_device usbhost_device = {
+	.name		= "ehci-platform",
+	.id		= 0,
+	.dev = {
+		.platform_data = &cxusbhost_pdata,
+		.coherent_dma_mask = ~0,
+		.dma_mask = &nspire_usb_dma_mask
+	},
+	.resource = cxusbhost_resources_pdata,
+	.num_resources = ARRAY_SIZE(cxusbhost_resources_pdata)
+};
+
+
+static __init int cx_usb_init(void)
+{
+	int err = 0;
+	unsigned val;
+	void __iomem *hostusb_addr =
+		ioremap(NSPIRE_OTG_PHYS_BASE, NSPIRE_OTG_SIZE);
+
+	if (!hostusb_addr) {
+		pr_warn("Could not allocate enough memory to initialize NSPIRE host USB\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* Disable OTG interrupts */
+	pr_info("Disable OTG interrupts\n");
+	val	 = readl(hostusb_addr + 0x1a4);
+	val &= ~(0x7f<<24);
+	writel(val, hostusb_addr + 0x1a4);
+
+	iounmap(hostusb_addr);
+
+	pr_info("Adding USB controller as platform device\n");
+	err = platform_device_register(&usbhost_device);
+out:
+
+	return err;
+}
+
+static __init int cx_usb_workaround(void)
+{
+	int err = 0;
+	unsigned val;
+	void __iomem *hostusb_addr =
+		ioremap(NSPIRE_OTG_PHYS_BASE, NSPIRE_OTG_SIZE);
+
+	if (!hostusb_addr) {
+		pr_warn("Could not do USB workaround\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	pr_info("Temporary USB hack to force USB to connect as fullspeed\n");
+	val	 = readl(hostusb_addr + 0x184);
+	val |= (1<<24);
+	writel(val, hostusb_addr + 0x184);
+
+	iounmap(hostusb_addr);
+out:
+
+	return err;
+}
+
+/* Backlight driver */
+
+#define CX_BACKLIGHT_UPPER	0x1d0
+#define CX_BACKLIGHT_LOWER	0x100 /* Should be (around about) off */
+
+static void cx_set_backlight(int val)
+{
+	val += CX_BACKLIGHT_LOWER;
+
+	if (val <= CX_BACKLIGHT_UPPER)
+		writel(val, NSPIRE_APB_VIRTIO(NSPIRE_APB_CONTRAST + 0x20));
+}
+
+static struct generic_bl_info cx_bl = {
+	.name		= "nspire_backlight",
+	.max_intensity	= CX_BACKLIGHT_UPPER - CX_BACKLIGHT_LOWER,
+	.default_intensity = (CX_BACKLIGHT_UPPER - CX_BACKLIGHT_LOWER) / 2,
+	.set_bl_intensity = cx_set_backlight
+};
+
+static struct platform_device bl_device = {
+	.name		= "generic-bl",
+	.id		= 0,
+	.dev = {
+		.platform_data = &cx_bl,
+	}
+};
+
+/* Init */
+
+bool cx_use_otg;
+static int __init set_cx_otg(char *dummy __attribute__((unused)))
+{
+	cx_use_otg = 1;
+	return 0;
+}
+early_param("cx_use_otg", set_cx_otg);
+
+static void __init cx_early_init(void)
+{
+	nspire_io_to_clocks = cx_io_to_clocks;
+	nspire_clocks_to_io = cx_clocks_to_io;
+
+	nspire_init_early();
+}
+
+static void __init cx_init(void)
+{
+	nspire_init();
+	amba_device_register(&fb_device, &iomem_resource);
+	amba_device_register(&uart_device, &iomem_resource);
+
+	nspire_keypad_data.evtcodes = nspire_touchpad_evtcode_map;
+	platform_device_register(&nspire_keypad_device);
+	platform_device_register(&bl_device);
+	nspire_touchpad_init();
+
+	if (!cx_use_otg) {
+		pr_info("Selecting USB host only driver for CX\n");
+		cx_usb_init();
+	} else {
+		pr_info("Selecting USB OTG driver for CX\n");
+		platform_device_register(&nspire_otg_device);
+		platform_device_register(&nspire_usb_nop_xceiver);
+	}
+}
+
+static void __init cx_init_late(void)
+{
+	if (!cx_use_otg)
+		cx_usb_workaround();
+	nspire_init_late();
+}
+
+MACHINE_START(NSPIRECX, "TI-NSPIRE CX Calculator")
+	.nr_irqs	= NR_IRQS,
+	.map_io		= nspire_map_io,
+	.init_irq	= cx_init_irq,
+	.init_time	= cx_timer_init,
+	.init_early	= cx_early_init,
+	.init_machine	= cx_init,
+	.init_late	= cx_init_late,
+	.restart	= nspire_restart,
+MACHINE_END
diff --git a/arch/arm/mach-nspire/nspire_tp.c b/arch/arm/mach-nspire/nspire_tp.c
new file mode 100644
index 0000000..cec05b6
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire_tp.c
@@ -0,0 +1,80 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire_clp.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/input.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/mtd/nand.h>
+#include <linux/irq.h>
+#include <linux/i2c-gpio.h>
+
+#include <mach/nspire_mmio.h>
+#include <mach/irqs.h>
+#include <mach/clkdev.h>
+#include <mach/sram.h>
+#include <mach/keypad.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "common.h"
+#include "classic.h"
+#include "touchpad.h"
+
+/* I2C GPIO (touchpad) */
+
+static struct i2c_gpio_platform_data i2c_pdata = {
+	.sda_pin	= 3,
+	.scl_pin	= 1,
+	.udelay		= 1,
+	.timeout	= 1000,
+};
+
+static struct platform_device i2c_device = {
+	.name		= "i2c-gpio",
+	.id		= 0,
+	.dev = {
+		.platform_data = &i2c_pdata,
+	}
+};
+
+static void __init tp_init(void)
+{
+	nspire_keypad_data.evtcodes = nspire_touchpad_evtcode_map;
+	platform_device_register(&i2c_device);
+
+	platform_device_register(&nspire_otg_device);
+	platform_device_register(&nspire_usb_nop_xceiver);
+
+	nspire_classic_init();
+	nspire_touchpad_init();
+}
+
+MACHINE_START(NSPIRETP, "TI-NSPIRE Touchpad Calculator")
+	.map_io		= nspire_map_io,
+	.init_irq	= nspire_classic_init_irq,
+	.handle_irq	= nspire_classic_handle_irq,
+	.init_time	= nspire_classic_timer_init,
+	.init_early	= nspire_classic_init_early,
+	.init_machine	= tp_init,
+	.init_late	= nspire_classic_init_late,
+	.restart	= nspire_restart,
+MACHINE_END
diff --git a/arch/arm/mach-nspire/sram.c b/arch/arm/mach-nspire/sram.c
new file mode 100644
index 0000000..52b8e5c
--- /dev/null
+++ b/arch/arm/mach-nspire/sram.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+static unsigned long sram_phys_base;
+static __iomem void *sram_virt_base;
+static struct gen_pool *sram_pool;
+
+#define sram_phys_to_virt(p) (sram_virt_base + ((p) - sram_phys_base))
+
+void *sram_alloc(unsigned int size, dma_addr_t *dma_addr)
+{
+	if (!sram_pool)
+		return NULL;
+
+	*dma_addr = gen_pool_alloc(sram_pool, size);
+	pr_info("sram alloc - %dB@0x%p\n", size, (void *)*dma_addr);
+	return sram_phys_to_virt(*dma_addr);
+}
+EXPORT_SYMBOL(sram_alloc);
+
+void sram_free(dma_addr_t addr, unsigned int size)
+{
+	if (!sram_pool)
+		return;
+
+	gen_pool_free(sram_pool, addr, size);
+}
+EXPORT_SYMBOL(sram_free);
+
+int __init sram_init(unsigned long base, unsigned long size)
+{
+	sram_phys_base = base;
+
+	sram_pool = gen_pool_create(10, -1);
+	if (!sram_pool) {
+		pr_warn("Cannot create sram pool!\n");
+		return -ENOMEM;
+	}
+	gen_pool_add(sram_pool, base, size, -1);
+	sram_virt_base = ioremap(sram_phys_base, size);
+
+	pr_info("sram pool: %ld KB@0x%p\n", size / 1024, sram_virt_base);
+	return 0;
+}
diff --git a/arch/arm/mach-nspire/touchpad.c b/arch/arm/mach-nspire/touchpad.c
new file mode 100644
index 0000000..2330451
--- /dev/null
+++ b/arch/arm/mach-nspire/touchpad.c
@@ -0,0 +1,30 @@
+/*
+ *	linux/arch/arm/mach-nspire/touchpad.c
+ *
+ *	Copyright (C) 2012 Fabian Vogt <fabian@ritter-vogt.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+
+#include "touchpad.h"
+
+#if defined(CONFIG_MOUSE_SYNAPTICS_I2C) || \
+	defined(CONFIG_MOUSE_SYNAPTICS_I2C_MODULE)
+static struct i2c_board_info synaptics_i2c = {
+	I2C_BOARD_INFO("synaptics_i2c", 0x20),
+	.irq    = 0,
+};
+
+void __init nspire_touchpad_init()
+{
+	i2c_register_board_info(0, &synaptics_i2c, 1);
+}
+
+#else
+inline void nspire_touchpad_init() {}
+#endif
diff --git a/arch/arm/mach-nspire/touchpad.h b/arch/arm/mach-nspire/touchpad.h
new file mode 100644
index 0000000..9222572
--- /dev/null
+++ b/arch/arm/mach-nspire/touchpad.h
@@ -0,0 +1,17 @@
+/*
+ *	linux/arch/arm/mach-nspire/touchpad.c
+ *
+ *	Copyright (C) 2012 Fabian Vogt <fabian@ritter-vogt.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef TOUCHPAD_H
+#define TOUCHPAD_H
+
+void __init nspire_touchpad_init(void);
+
+#endif
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 831e1fd..e76c16b 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1204,3 +1204,6 @@ baileys			MACH_BAILEYS		BAILEYS			4169
 familybox		MACH_FAMILYBOX		FAMILYBOX		4170
 ensemble_mx35		MACH_ENSEMBLE_MX35	ENSEMBLE_MX35		4171
 sc_sps_1		MACH_SC_SPS_1		SC_SPS_1		4172
+nspireclp		MACH_NSPIRECLP		NSPIRECLP		4441
+nspiretp		MACH_NSPIRETP		NSPIRETP		4442
+nspirecx		MACH_NSPIRECX		NSPIRECX		4443
--
1.7.9.6 (Apple Git-31.1)



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-04  9:01 [RFC PATCH arm: initial TI-Nspire support] Daniel Tang
@ 2013-04-04 11:12 ` Arnd Bergmann
  2013-04-06  0:26   ` Daniel Tang
  2013-04-09 11:14 ` Linus Walleij
  1 sibling, 1 reply; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-04 11:12 UTC (permalink / raw)
  To: linux-arm-kernel; +Cc: Daniel Tang, linux, fabian, Lionel Debroux, linux-kernel

On Thursday 04 April 2013, Daniel Tang wrote:
> We're sending out for comments an early patch adding TI-Nspire support
> to Linux.
> 
> Some words on the Nspire platform: it's a series of graphing
> calculators, made of four models: "Clickpad" (2007-2010), "Touchpad"
> (2010-2012?), "CX" (2011-), "CM-C" (2011-).

Very cool! I hope we can get this merged.

> Patch contents
> --------------
> This patch (against mainline, but it also applies to linux-next)
> contains the essential support code required to boot Linux to a shell 
> on all models, but contains nothing else at the moment.
> Code containing drivers for other peripherals exists, and will
> eventually be posted for review as well: we need to do a bit of
> cleanup. If you prefer them to be posted here now, we'll do.
> They're at https://github.com/tangrs/linux .
> 
> A possibly noteworthy fact is that despite the gradual shift to
> using Device Tree definitions for ARM machine types, we've decided not
> to use it, for the following reasons:
> 
>     * the (perceived) extra complexity and code size;
>     * the fact that we're using our own, simple, bootloader, due to
>       the impossibility to bootstrap on most models (because boot1
>       is usually not modifiable) and the fact that the image is stored
>       in a proprietary FS not supported by mainline Linux and
>       common bootloaders...

For new platforms, we want to have only the absolute minimum amount of
code in arch/arm and move everything else into drivers. However, that
is only possible using device tree. It should not add any significant
complexity to your code, and you can easily bundle the device tree blob
with the kernel.
> 
> +config ARCH_NSPIRE
> +	bool "TI-NSPIRE based"
> +	depends on MMU
> +	select CPU_ARM926T
> +	select HAVE_MACH_CLKDEV
> +	select CLKDEV_LOOKUP
> +	select ARM_AMBA
> +	select USB_ARCH_HAS_EHCI
> +	select ARCH_WANT_OPTIONAL_GPIOLIB
> +	select GENERIC_ALLOCATOR
> +	select ARCH_HAS_CPUFREQ
> +	select CPU_FREQ_TABLE

Any new platform should use COMMON_CLK and SPARSE_IRQ in addition
to these.

> diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig
> new file mode 100644
> index 0000000..da032b7
> --- /dev/null
> +++ b/arch/arm/mach-nspire/Kconfig
> @@ -0,0 +1,36 @@
> +if ARCH_NSPIRE
> +
> +choice
> +	prompt "Early printk and boot message serial interface"
> +	help
> +	  Early printk output interface
> +	depends on EARLY_PRINTK
> +	default NSPIRE_EARLYPRINTK_CX
> +
> +config NSPIRE_EARLYPRINTK_CLASSIC
> +	bool "Classic"
> +
> +config NSPIRE_EARLYPRINTK_CX
> +	bool "CX model"
> +endchoice

This should go into arch/arm/Kconfig.debug.

> +
> +menu "Supported models"
> +
> +config MACH_NSPIRECX
> +	select GENERIC_CLOCKEVENTS
> +	select ARM_VIC
> +	select ARM_TIMER_SP804
> +	bool "CX/CX CAS"

The SP804 driver is currently being changed in the move to drivers/clocksource,
which may impact your code as well.

> diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
> new file mode 100644
> index 0000000..7db966b
> --- /dev/null
> +++ b/arch/arm/mach-nspire/Makefile.boot
> @@ -0,0 +1 @@
> +zreladdr-y	:= 0x10008000

Please use AUTO_ZRELADDR

> +static unsigned long classic_clocks_to_io(struct nspire_clk_speeds *clks)
> +{
> +	union reg_clk_speed reg;
> +
> +	BUG_ON(clks->div.base_cpu < 2);
> +	BUG_ON(clks->div.cpu_ahb < 1);
> +
> +	reg.raw = 0;
> +	reg.val.base_cpu_ratio = clks->div.base_cpu / 2;
> +	reg.val.cpu_ahb_ratio = clks->div.cpu_ahb - 1;
> +	reg.val.is_base_27mhz = (clks->base <= 27000000);
> +	reg.val.base_val = (300 - (clks->base / 1000000)) / 6;
> +
> +	return reg.raw;
> +}

Clock code should live in drivers/clk/

> +/* Interrupt handling */
> +
> +static inline int check_interrupt(void __iomem *base, struct pt_regs *regs)
> +{
> +	if (readl(base + 0x0)) {
> +		int irqnr = readl(base + 0x24);
> +		unsigned prev_priority;
> +		handle_IRQ(irqnr, regs);
> +
> +		/* Reset priorities */
> +		prev_priority = readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
> +		writel(prev_priority, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
> +		return 1;
> +	}
> +	return 0;
> +}

Interrupt code should live in drivers/irqchip/

Your method of doing "readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));" has multiple
flaws:

* A FOO_VIRT_BASE constant should already be of type "void __iomem *" and not
  require another IOMEM()
* Normally the base address is generated at runtime using ioremap or of_iomap,
  since in  multiplatform kernel, you have no access to platform specific constants
  from a device driver
* You might want to define symbolic constants for "0x28".

> +void __init nspire_classic_init_irq(void)
> +{
> +	/* No stickies */
> +	writel(0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x204));
> +
> +	/* Disable all interrupts */
> +	writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0xc));
> +	writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x10c));
> +
> +	/* Set all priorities to 0 */
> +	memset_io(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x300), 0, 0x7f);
> +
> +	/* Accept interrupts of all priorities */
> +	writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
> +	writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x12c));
> +
> +	/* Clear existing interrupts */
> +	readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
> +	readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x128));
> +
> +	/* Add chip */
> +	classic_allocate_gc();
> +}

For sparse irq and for devicetree, you need to allocate an irqdomain here.

> +
> +
> +static struct clock_event_device nspire_clkevt = {
> +	.name		= "clockevent",
> +	.features	= CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.rating		= 400,
> +	.set_next_event = classic_timer_set_event,
> +	.set_mode	= classic_timer_set_mode,
> +	.cpumask		= cpu_all_mask,
> +};

clockevent code should live in drivers/clocksource, although there
is ongoing discussion about creating a new directory for clockevent
separate from clocksource. Not in arch/arm though.

> +/* Serial */
> +static struct plat_serial8250_port classic_serial_platform_data[] = {
> +	{
> +		.mapbase	= NSPIRE_APB_PHYS(NSPIRE_APB_UART),
> +		.irq		= NSPIRE_IRQ_UART,
> +		.uartclk	= 29491200,
> +		.iotype		= UPIO_MEM,
> +		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
> +				UPF_IOREMAP,
> +		.regshift	= 2
> +	},
> +	{ }
> +};
> +
> +struct platform_device nspire_classic_serial_device = {
> +	.name		= "serial8250",
> +	.id			= PLAT8250_DEV_PLATFORM,
> +	.dev = {
> +		.platform_data = &classic_serial_platform_data
> +	}
> +};

You can use the of_serial driver to get that information from the device tree.

> > +/* Framebuffer */
> +static struct clcd_panel classic_lcd_panel = {
> +	.mode		= {
> +		.name		= "grayscale lcd",
> +		.refresh	= 60,
> +		.xres		= 320,
> +		.yres		= 240,
> +		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +		.vmode		= FB_VMODE_NONINTERLACED,
> +		.pixclock	= 1,
> +		.hsync_len	= 6,
> +		.vsync_len	= 1,
> +		.right_margin	= 6,
> +		.left_margin	= 6,
> +	},
> +	.width		= 71, /* 7.11cm */
> +	.height		= 53, /* 5.33cm */
> +	.tim2		= 0x80007d0,
> +	.cntl		= CNTL_LCDBPP8 | CNTL_LCDMONO8,
> +	.bpp		= 8,
> +	.grayscale	= 1
> +};
> +#define PANEL_SIZE (19 * SZ_4K)
> +
> +static int classic_clcd_setup(struct clcd_fb *fb)
> +{
> +	return nspire_clcd_setup(fb, PANEL_SIZE, &classic_lcd_panel);
> +}

And drivers/video/of_display_timing.c for these.

> diff --git a/arch/arm/mach-nspire/clock.c b/arch/arm/mach-nspire/clock.c
> new file mode 100644
> index 0000000..c679449
> --- /dev/null
> +++ b/arch/arm/mach-nspire/clock.c

Not needed with COMMON_CLK


> +
> +#define IOTABLE_ENTRY(t) \
> +	{ \
> +		.virtual	= NSPIRE_##t##_VIRT_BASE, \
> +		.pfn		= __phys_to_pfn(NSPIRE_##t##_PHYS_BASE), \
> +		.length		= NSPIRE_##t##_SIZE, \
> +		.type		= MT_DEVICE \
> +	}
> +
> +#define RESOURCE_ENTRY_IRQ(t) \
> +	{ \
> +		.start	= NSPIRE_IRQ_##t, \
> +		.end	= NSPIRE_IRQ_##t, \
> +		.flags	= IORESOURCE_IRQ \
> +	}
> +
> +#define RESOURCE_ENTRY_MEM(t) \
> +	{ \
> +		.start	= NSPIRE_##t##_PHYS_BASE, \
> +		.end	= NSPIRE_##t##_PHYS_BASE + NSPIRE_##t##_SIZE - 1, \
> +		.flags	= IORESOURCE_MEM \
> +	}

Please don't define your own macros for generic functionality. If you think
that macros are good for these, you can submit a patch to make them available
for everyone.

For the resources, we already have macros in include/linux/ioport.h

> +extern struct platform_device nspire_keypad_device;
> +extern struct platform_device nspire_otg_device;
> +extern struct platform_device nspire_usb_nop_xceiver;
> +extern struct nspire_keypad_data nspire_keypad_data;

Do not define "struct platform_devices" as global data structures, it messes
up reference counting. Ideally all platform and AMBA devices get created
from device tree. If that should not be possible for one of them, you can
use platform_device_register_resndata or the associated functions.

> diff --git a/arch/arm/mach-nspire/include/mach/clkdev.h b/arch/arm/mach-nspire/include/mach/clkdev.h
> new file mode 100644
> index 0000000..b4afe65
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/clkdev.h

Not needed with common clk.

> diff --git a/arch/arm/mach-nspire/include/mach/debug-macro.S b/arch/arm/mach-nspire/include/mach/debug-macro.S
> new file mode 100644
> index 0000000..b71daa4
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/debug-macro.S

Move this to arch/arm/include/debug/

> diff --git a/arch/arm/mach-nspire/include/mach/hardware.h b/arch/arm/mach-nspire/include/mach/hardware.h
> new file mode 100644
> index 0000000..7c9c3b6
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/hardware.h

delete this

> diff --git a/arch/arm/mach-nspire/include/mach/irqs.h b/arch/arm/mach-nspire/include/mach/irqs.h
> new file mode 100644
> index 0000000..70be120
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/irqs.h
> @@ -0,0 +1,34 @@
> +/*
> + *  linux/arch/arm/mach-nspire/include/mach/irqs.h
> + *
> + *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2, as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef NSPIRE_IRQS_H
> +#define NSPIRE_IRQS_H
> +
> +#define NSPIRE_IRQ_MASK         0x007FEB9A
> +
> +enum {
> +	NSPIRE_IRQ_UART = 1,
> +	NSPIRE_IRQ_WATCHDOG = 3,
> +	NSPIRE_IRQ_RTC = 4,
> +	NSPIRE_IRQ_GPIO = 7,
> +	NSPIRE_IRQ_OTG = 8,
> +	NSPIRE_IRQ_HOSTUSB = 9,
> +	NSPIRE_IRQ_ADC = 11,
> +	NSPIRE_IRQ_PWR = 15,
> +	NSPIRE_IRQ_KEYPAD = 16,
> +	NSPIRE_IRQ_TIMER2 = 19,
> +	NSPIRE_IRQ_I2C = 20,
> +	NSPIRE_IRQ_LCD = 21
> +};
> +
> +#define NR_IRQS 32
> +
> +#endif

Not needed as a globally visible file with sparse IRQ.

> diff --git a/arch/arm/mach-nspire/include/mach/keypad.h b/arch/arm/mach-nspire/include/mach/keypad.h
> new file mode 100644
> index 0000000..18cf3fd
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/keypad.h

Move this to include/linux/platform_data or delete this once you have converted
to device tree.


> diff --git a/arch/arm/mach-nspire/include/mach/memory.h b/arch/arm/mach-nspire/include/mach/memory.h
> new file mode 100644
> index 0000000..eec3f36
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/memory.h
> @@ -0,0 +1,17 @@
> +/*
> + *  linux/arch/arm/mach-nspire/include/mach/memory.h
> + *
> + *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2, as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef NSPIRE_MEMORY_H
> +#define NSPIRE_MEMORY_H
> +
> +#define PLAT_PHYS_OFFSET 0x10000000
> +
> +#endif

I think you already don't use this.

> diff --git a/arch/arm/mach-nspire/include/mach/nspire_mmio.h b/arch/arm/mach-nspire/include/mach/nspire_mmio.h
> new file mode 100644
> index 0000000..eaeb100
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/nspire_mmio.h

Move to arch/arm/mach-nspire/, drivers should not see this.

> diff --git a/arch/arm/mach-nspire/include/mach/sram.h b/arch/arm/mach-nspire/include/mach/sram.h
> new file mode 100644
> index 0000000..2f652f3
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/sram.h

A new sram subsystem is getting added, so don't provide your own copy.

> diff --git a/arch/arm/mach-nspire/include/mach/timex.h b/arch/arm/mach-nspire/include/mach/timex.h
> new file mode 100644
> index 0000000..2d4449e
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/timex.h

delete this.

> diff --git a/arch/arm/mach-nspire/include/mach/uncompress.h b/arch/arm/mach-nspire/include/mach/uncompress.h
> new file mode 100644
> index 0000000..7be9d06
> --- /dev/null
> +++ b/arch/arm/mach-nspire/include/mach/uncompress.h

You can delete this once you enable CONFIG_ARCH_MULTIPLATFORM

> +#if defined(CONFIG_MOUSE_SYNAPTICS_I2C) || \
> +	defined(CONFIG_MOUSE_SYNAPTICS_I2C_MODULE)
> +static struct i2c_board_info synaptics_i2c = {
> +	I2C_BOARD_INFO("synaptics_i2c", 0x20),
> +	.irq    = 0,
> +};
> +
> +void __init nspire_touchpad_init()
> +{
> +	i2c_register_board_info(0, &synaptics_i2c, 1);
> +}
> +
> +#else
> +inline void nspire_touchpad_init() {}
> +#endif

Device definitions should not be conditional on the presence of the driver.
This will of course be no issue once you move to DT.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-04 11:12 ` Arnd Bergmann
@ 2013-04-06  0:26   ` Daniel Tang
  2013-04-06 11:51     ` Arnd Bergmann
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Tang @ 2013-04-06  0:26 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

Hi,

First of all, thank you for your comments!

On 04/04/2013, at 10:12 PM, Arnd Bergmann <arnd@arndb.de> wrote:

> For new platforms, we want to have only the absolute minimum amount of
> code in arch/arm and move everything else into drivers. However, that
> is only possible using device tree. It should not add any significant
> complexity to your code, and you can easily bundle the device tree blob
> with the kernel.

Given that most of your comments described some very fundamental changes (esp switching to DTB) to the structure of our port, we've decided we'll probably start from scratch and fix the issues you outlined as we reimplement our platform.

At the moment, we're working on getting a basic DTB-booting kernel working so our next patch will be starting from basics.

Cheers,
tangrs

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-06  0:26   ` Daniel Tang
@ 2013-04-06 11:51     ` Arnd Bergmann
  2013-04-06 12:00       ` Daniel Tang
  0 siblings, 1 reply; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-06 11:51 UTC (permalink / raw)
  To: Daniel Tang; +Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

On Saturday 06 April 2013, Daniel Tang wrote:
> Hi,
> 
> First of all, thank you for your comments!
> 
> On 04/04/2013, at 10:12 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> 
> > For new platforms, we want to have only the absolute minimum amount of
> > code in arch/arm and move everything else into drivers. However, that
> > is only possible using device tree. It should not add any significant
> > complexity to your code, and you can easily bundle the device tree blob
> > with the kernel.
> 
> Given that most of your comments described some very fundamental changes
> (esp switching to DTB) to the structure of our port, we've decided we'll
> probably start from scratch and fix the issues you outlined as we
> reimplement our platform.
> 
> At the moment, we're working on getting a basic DTB-booting kernel working
> so our next patch will be starting from basics.

Ok, whichever way you prefer. If you have questions while working on this,
feel free to join #armlinux on irc.freenode.net, there are usually other
people working on the same things.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-06 11:51     ` Arnd Bergmann
@ 2013-04-06 12:00       ` Daniel Tang
  2013-04-06 13:24         ` Arnd Bergmann
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Tang @ 2013-04-06 12:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

Hi,


On 06/04/2013, at 10:51 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> 
> Ok, whichever way you prefer. If you have questions while working on this,
> feel free to join #armlinux on irc.freenode.net, there are usually other
> people working on the same things.
> 

Cheers.

We already have something basic that boots successfully using device trees. 

Some comments before we continue would be greatly appreciated.

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
---
 arch/arm/Kconfig                                |   13 ++
 arch/arm/Makefile                               |    3 +-
 arch/arm/boot/dts/nspire-cx.dts                 |   85 +++++++++++++
 arch/arm/boot/dts/nspire.dtsi                   |  154 +++++++++++++++++++++++
 arch/arm/mach-nspire/Makefile                   |    3 +
 arch/arm/mach-nspire/include/mach/debug-macro.S |   25 ++++
 arch/arm/mach-nspire/include/mach/timex.h       |   15 +++
 arch/arm/mach-nspire/include/mach/uncompress.h  |   25 ++++
 arch/arm/mach-nspire/mmio.h                     |   13 ++
 arch/arm/mach-nspire/nspire.c                   |  107 ++++++++++++++++
 10 files changed, 442 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/nspire-cx.dts
 create mode 100644 arch/arm/boot/dts/nspire.dtsi
 create mode 100644 arch/arm/mach-nspire/Makefile
 create mode 100644 arch/arm/mach-nspire/Makefile.boot
 create mode 100644 arch/arm/mach-nspire/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-nspire/include/mach/timex.h
 create mode 100644 arch/arm/mach-nspire/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-nspire/mmio.h
 create mode 100644 arch/arm/mach-nspire/nspire.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..e8ce316 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -980,6 +980,19 @@ config ARCH_OMAP1
 	help
 	  Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
 
+config ARCH_NSPIRE
+	bool "TI-NSPIRE based"
+	depends on MMU
+	select CPU_ARM926T
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select SPARSE_IRQ
+	select ARM_AMBA
+	select ARM_VIC
+	select ARM_TIMER_SP804
+	help
+	  This enables support for systems using the TI-NSPIRE CPU
+
 endchoice
 
 menu "Multiple platform selection"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..f47a8a7 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -165,6 +165,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
+machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
@@ -313,7 +314,7 @@ define archhelp
   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
   echo  '  uImage        - U-Boot wrapped zImage'
-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+  echo  '  bootpImage    - Combined zImage and initial RAM disk'
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
   echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
diff --git a/arch/arm/boot/dts/nspire-cx.dts b/arch/arm/boot/dts/nspire-cx.dts
new file mode 100644
index 0000000..6ab3c00
--- /dev/null
+++ b/arch/arm/boot/dts/nspire-cx.dts
@@ -0,0 +1,85 @@
+/*
+ *  linux/arch/arm/boot/nspire-cx.dts
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+/dts-v1/;
+
+/include/ "nspire.dtsi"
+
+/ {
+	model = "TI-NSPIRE CX";
+	compatible = "arm,nspire-cx";
+
+	memory {
+		device_type = "memory";
+		reg = <0x10000000 0x4000000>; /* 64 MB */
+	};
+
+	aliases {
+		uart0 = &uart0;
+		timer0 = &timer0;
+		timer1 = &timer1;
+		fast_timer = &fast_timer;
+	};
+
+	uart_clk: uart_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+	};
+
+	/* Not really a fixed clock but we'll fix this later */
+	apb_pclk: apb_pclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <33000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		intc: interrupt-controller@DC000000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xDC000000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		apb@90000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			i2c@90050000 {
+				compatible = "snps,designware-i2c";
+				reg = <0x90050000 0x1000>;
+				interrupts = <20>;
+			};
+
+			fast_timer: timer@90010000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			uart0: uart@90020000 {
+				compatible = "arm,pl011", "arm,primecell";
+			};
+
+			timer0: timer0@900C0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			timer1: timer1@900D0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+		};
+	};
+	chosen {
+		bootargs = "debug earlyprintk console=ttyAMA0,115200n8";
+	};
+};
diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi
new file mode 100644
index 0000000..db7584a
--- /dev/null
+++ b/arch/arm/boot/dts/nspire.dtsi
@@ -0,0 +1,154 @@
+/*
+ *  linux/arch/arm/boot/nspire.dtsi
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926";
+		};
+	};
+
+	bootrom: bootrom@00000000 {
+		reg = <0x00000000 0x80000>;
+	};
+
+	sram: sram@A4000000 {
+		device = "memory";
+		reg = <0xA4000000 0x20000>;
+	};
+
+	timer_clk: timer_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	ahb {
+		compatible = "arm,amba-bus", "simple-bus";
+		interrupt-parent = <&intc>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		spi: spi@A9000000 {
+			reg = <0xA9000000 0x1000>;
+		};
+
+		usb0: usb@B0000000 {
+			reg = <0xB0000000 0x1000>;
+			interrupts = <8>;
+		};
+
+		usb1: usb@B4000000 {
+			reg = <0xB4000000 0x1000>;
+			interrupts = <9>;
+			status = "disabled";
+		};
+
+		lcd: lcd@C0000000 {
+			compatible = "arm,amba-primecell";
+			reg = <0xC0000000 0x1000>;
+			interrupts = <21>;
+		};
+
+		adc: adc@C4000000 {
+			reg = <0xC4000000 0x1000>;
+			interrupts = <11>;
+		};
+
+		tdes: tdes@C8010000 {
+			reg = <0xC8010000 0x1000>;
+		};
+
+		sha256: sha256@CC000000 {
+			reg = <0xCC000000 0x1000>;
+		};
+
+		apb@90000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&apb_pclk>;
+			clock-names = "apb_pclk";
+			clock-ranges;
+			ranges;
+
+			gpio: gpio@90000000 {
+				reg = <0x90000000 0x1000>;
+				interrupts = <7>;
+			};
+
+			fast_timer: timer@90010000 {
+				reg = <0x90010000 0x1000>;
+				interrupts = <17>;
+			};
+
+			uart: uart@90020000 {
+				reg = <0x90020000 0x1000>;
+				interrupts = <1>;
+
+				clocks = <&uart_clk>;
+				clock-names = "uart_clk";
+			};
+
+			timer0: timer0@900C0000 {
+				reg = <0x900C0000 0x1000>;
+				interrupts = <18>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			timer1: timer1@900D0000 {
+				reg = <0x900D0000 0x1000>;
+				interrupts = <19>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			watchdog: watchdog@90060000 {
+				compatible = "arm,amba-primecell";
+				reg = <0x90060000 0x1000>;
+				interrupts = <3>;
+			};
+
+			rtc: rtc@90090000 {
+				reg = <0x90090000 0x1000>;
+				interrupts = <4>;
+			};
+
+			misc: misc@900A0000 {
+				reg = <0x900A0000 0x1000>;
+			};
+
+			pwr: pwr@900B0000 {
+				reg = <0x900B0000 0x1000>;
+				interrupts = <15>;
+			};
+
+			keypad: input@900E0000 {
+				reg = <0x900E0000 0x1000>;
+				interrupts = <16>;
+			};
+
+			contrast: contrast@900F0000 {
+				reg = <0x900F0000 0x1000>;
+			};
+
+			led: led@90110000 {
+				reg = <0x90110000 0x1000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile
new file mode 100644
index 0000000..62b9baa
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile
@@ -0,0 +1,3 @@
+obj-y				:=
+
+obj-y				+= nspire.o
diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-nspire/include/mach/debug-macro.S b/arch/arm/mach-nspire/include/mach/debug-macro.S
new file mode 100644
index 0000000..d583485
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/debug-macro.S
@@ -0,0 +1,25 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/debug-macro.S
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include "../../mmio.h"
+
+.macro	addruart, rp, rv, tmp
+	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
+	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
+.endm
+
+#include <asm/hardware/debug-pl01x.S>
+
+
+/*
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
+*/
diff --git a/arch/arm/mach-nspire/include/mach/timex.h b/arch/arm/mach-nspire/include/mach/timex.h
new file mode 100644
index 0000000..2d4449e
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/timex.h
@@ -0,0 +1,15 @@
+/*
+ *  linux/arch/arm/mach-nspire/include/mach/timex.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_TIMEX_H
+#define NSPIRE_TIMEX_H
+
+#endif
diff --git a/arch/arm/mach-nspire/include/mach/uncompress.h b/arch/arm/mach-nspire/include/mach/uncompress.h
new file mode 100644
index 0000000..d957214
--- /dev/null
+++ b/arch/arm/mach-nspire/include/mach/uncompress.h
@@ -0,0 +1,25 @@
+/*
+ *	linux/arch/arm/mach-nspire/include/mach/uncompress.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *	Copyright (C) 2013 Lionel Debroux <lionel_debroux@yahoo.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef NSPIRE_UNCOMPRESS_H
+#define NSPIRE_UNCOMPRESS_H
+
+#define OFFSET_VAL(var, offset) ((var)[(offset)>>2])
+static inline void putc(int c)
+{
+}
+#undef OFFSET_VAL
+
+#define arch_decomp_setup()
+#define flush()
+
+#endif
diff --git a/arch/arm/mach-nspire/mmio.h b/arch/arm/mach-nspire/mmio.h
new file mode 100644
index 0000000..6e2fe95
--- /dev/null
+++ b/arch/arm/mach-nspire/mmio.h
@@ -0,0 +1,13 @@
+/*
+ *	linux/arch/arm/mach-nspire/mmio.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c
new file mode 100644
index 0000000..ec7734a
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire.c
@@ -0,0 +1,107 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-vic.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware/timer-sp.h>
+
+#include "mmio.h"
+
+static const char *nspire_dt_match[] __initconst = {
+	"arm,nspire",
+	"arm,nspire-cx",
+	"arm,nspire-tp",
+	"arm,nspire-clp",
+	NULL,
+};
+
+static struct map_desc nspire_io_desc[] __initdata = {
+	{
+		.virtual	=  NSPIRE_EARLY_UART_VIRT_BASE,
+		.pfn		= __phys_to_pfn(NSPIRE_EARLY_UART_PHYS_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE
+	}
+};
+
+static void __init nspire_init_timer(void)
+{
+	struct device_node *timer;
+	void __iomem *base;
+	const char *path;
+	struct clk *clk;
+	int irq, err;
+
+	of_clk_init(NULL);
+
+	err = of_property_read_string(of_aliases, "timer0", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	sp804_clocksource_init(base, timer->name);
+
+	err = of_property_read_string(of_aliases, "timer1", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	irq = irq_of_parse_and_map(timer, 0);
+	sp804_clockevents_init(base, irq, timer->name);
+}
+
+static void __init nspire_map_io(void)
+{
+	iotable_init(nspire_io_desc, ARRAY_SIZE(nspire_io_desc));
+}
+
+static void __init nspire_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			NULL, NULL);
+}
+
+static void nspire_restart(char mode, const char *cmd)
+{
+}
+
+DT_MACHINE_START(NSPIRE, "TI-NSPIRE")
+	.map_io		= nspire_map_io,
+	.init_irq	= irqchip_init,
+	.init_time	= nspire_init_timer,
+	.init_machine	= nspire_init,
+	.dt_compat	= nspire_dt_match,
+	.restart	= nspire_restart,
+MACHINE_END
-- 
1.7.9.6 (Apple Git-31.1)



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-06 12:00       ` Daniel Tang
@ 2013-04-06 13:24         ` Arnd Bergmann
  2013-04-07  0:06           ` Daniel Tang
  0 siblings, 1 reply; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-06 13:24 UTC (permalink / raw)
  To: Daniel Tang; +Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

On Saturday 06 April 2013, Daniel Tang wrote:
> Hi,
> 
> 
> On 06/04/2013, at 10:51 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > 
> > Ok, whichever way you prefer. If you have questions while working on this,
> > feel free to join #armlinux on irc.freenode.net, there are usually other
> > people working on the same things.
> > 
> 
> Cheers.
> 
> We already have something basic that boots successfully using device trees. 
> 
> Some comments before we continue would be greatly appreciated.
> 
> Signed-off-by: Daniel Tang <dt.tangr@gmail.com>

Wow, that was quick!

The patch looks great overall, I just found a few details and have some comments
that you might find helpful.

>  arch/arm/Kconfig                                |   13 ++
>  arch/arm/Makefile                               |    3 +-
>  arch/arm/boot/dts/nspire-cx.dts                 |   85 +++++++++++++
>  arch/arm/boot/dts/nspire.dtsi                   |  154 +++++++++++++++++++++++
>  arch/arm/mach-nspire/Makefile                   |    3 +
>  arch/arm/mach-nspire/include/mach/debug-macro.S |   25 ++++
>  arch/arm/mach-nspire/include/mach/timex.h       |   15 +++
>  arch/arm/mach-nspire/include/mach/uncompress.h  |   25 ++++
>  arch/arm/mach-nspire/mmio.h                     |   13 ++
>  arch/arm/mach-nspire/nspire.c                   |  107 ++++++++++++++++

A good next step before doing anything else might be to put it under
CONFIG_ARCH_MULTIPLATFORM and remove the include/mach directory.

The only requirement for that should be to move debug-macro.S to
include/debug/nspire.S

> +config ARCH_NSPIRE
> +	bool "TI-NSPIRE based"
> +	depends on MMU
> +	select CPU_ARM926T
> +	select COMMON_CLK
> +	select GENERIC_CLOCKEVENTS
> +	select SPARSE_IRQ
> +	select ARM_AMBA
> +	select ARM_VIC
> +	select ARM_TIMER_SP804
> +	help
> +	  This enables support for systems using the TI-NSPIRE CPU

Since this has all the required changes already.

> @@ -313,7 +314,7 @@ define archhelp
>    echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
>    echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
>    echo  '  uImage        - U-Boot wrapped zImage'
> -  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
> +  echo  '  bootpImage    - Combined zImage and initial RAM disk'
>    echo  '                  (supply initrd image via make variable INITRD=<path>)'
>    echo  '* dtbs          - Build device tree blobs for enabled boards'
>    echo  '  install       - Install uncompressed kernel'

This looks like it wasn't meant to be in the patch.

> +		tdes: tdes@C8010000 {
> +			reg = <0xC8010000 0x1000>;
> +		};
> +
> +		sha256: sha256@CC000000 {
> +			reg = <0xCC000000 0x1000>;
> +		};

maybe rename the actual nodes to "crypto@c...". The device name should
be a really generic word in general.

> +			uart: uart@90020000 {
> +				reg = <0x90020000 0x1000>;
> +				interrupts = <1>;
> +
> +				clocks = <&uart_clk>;
> +				clock-names = "uart_clk";
> +			};

The name for a uart should be "serial". Since this is a pl01x, please add
the required properties for the device, e.g. 

	compatible = "arm,pl011", "arm,primecell";

You will need the "arm,primecell" bit to make the device appear on the
amba bus rather than the platform bus.

> +			timer0: timer0@900C0000 {
> +				reg = <0x900C0000 0x1000>;
> +				interrupts = <18>;
> +
> +				clocks = <&timer_clk>;
> +				clock-names = "timer_clk";
> +			};
> +
> +			timer1: timer1@900D0000 {
> +				reg = <0x900D0000 0x1000>;
> +				interrupts = <19>;
> +
> +				clocks = <&timer_clk>;
> +				clock-names = "timer_clk";
> +			};

Name the devices "timer", not "timer0" and "timer1", the address after @ is
used to disambiguate them. There are currently patches for sp804 under
discussion on the mailing list, you should probably watch those.

> --- /dev/null
> +++ b/arch/arm/mach-nspire/Makefile
> @@ -0,0 +1,3 @@
> +obj-y				:=
> +
> +obj-y				+= nspire.o

The first line is not actually needed.

> +
> +#include "../../mmio.h"
> +
> +.macro	addruart, rp, rv, tmp
> +	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
> +	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
> +.endm
> +
> +#include <asm/hardware/debug-pl01x.S>
> +

There is no nice solution for getting the addresses here, but the consensus
was to just define the macros in this file rather than try to include a
header from elsewhere.


> +	err = of_property_read_string(of_aliases, "timer0", &path);
> +	if (WARN_ON(err))
> +		return;
> +
> +	timer = of_find_node_by_path(path);
> +	base = of_iomap(timer, 0);
> +	if (WARN_ON(!base))
> +		return;
> +
> +	clk = of_clk_get_by_name(timer, NULL);
> +	clk_register_clkdev(clk, timer->name, "sp804");
> +
> +	sp804_clocksource_init(base, timer->name);
> +
> +	err = of_property_read_string(of_aliases, "timer1", &path);
> +	if (WARN_ON(err))
> +		return;

In particular, I think the method of using aliases to pick the right sp804
instance is being deprecated now. If both timers are identical, the kernel
will now just pick one of them.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-06 13:24         ` Arnd Bergmann
@ 2013-04-07  0:06           ` Daniel Tang
  2013-04-07  3:56             ` Daniel Tang
  2013-04-07 14:32             ` Arnd Bergmann
  0 siblings, 2 replies; 23+ messages in thread
From: Daniel Tang @ 2013-04-07  0:06 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

Hi,

On 07/04/2013, at 12:24 AM, Arnd Bergmann <arnd@arndb.de> wrote:

>> arch/arm/Kconfig                                |   13 ++
>> arch/arm/Makefile                               |    3 +-
>> arch/arm/boot/dts/nspire-cx.dts                 |   85 +++++++++++++
>> arch/arm/boot/dts/nspire.dtsi                   |  154 +++++++++++++++++++++++
>> arch/arm/mach-nspire/Makefile                   |    3 +
>> arch/arm/mach-nspire/include/mach/debug-macro.S |   25 ++++
>> arch/arm/mach-nspire/include/mach/timex.h       |   15 +++
>> arch/arm/mach-nspire/include/mach/uncompress.h  |   25 ++++
>> arch/arm/mach-nspire/mmio.h                     |   13 ++
>> arch/arm/mach-nspire/nspire.c                   |  107 ++++++++++++++++
> 
> A good next step before doing anything else might be to put it under
> CONFIG_ARCH_MULTIPLATFORM and remove the include/mach directory.
> 
> The only requirement for that should be to move debug-macro.S to
> include/debug/nspire.S
> 

Done.
> 
> 
>> @@ -313,7 +314,7 @@ define archhelp
>>   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
>>   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
>>   echo  '  uImage        - U-Boot wrapped zImage'
>> -  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
>> +  echo  '  bootpImage    - Combined zImage and initial RAM disk'
>>   echo  '                  (supply initrd image via make variable INITRD=<path>)'
>>   echo  '* dtbs          - Build device tree blobs for enabled boards'
>>   echo  '  install       - Install uncompressed kernel'
> 
> This looks like it wasn't meant to be in the patch.

It probably isn't. I think there was trailing whitespace on that and my editor happened to remove it automatically.

Should this be a separate patch to fix up formatting or should I leave it in as a drive-by fix?

> 
>> +		tdes: tdes@C8010000 {
>> +			reg = <0xC8010000 0x1000>;
>> +		};
>> +
>> +		sha256: sha256@CC000000 {
>> +			reg = <0xCC000000 0x1000>;
>> +		};
> 
> maybe rename the actual nodes to "crypto@c...". The device name should
> be a really generic word in general.

Done.

> 
>> +			uart: uart@90020000 {
>> +				reg = <0x90020000 0x1000>;
>> +				interrupts = <1>;
>> +
>> +				clocks = <&uart_clk>;
>> +				clock-names = "uart_clk";
>> +			};
> 
> The name for a uart should be "serial". Since this is a pl01x, please add
> the required properties for the device, e.g. 
> 
> 	compatible = "arm,pl011", "arm,primecell";
> 
> You will need the "arm,primecell" bit to make the device appear on the
> amba bus rather than the platform bus.

That was actually deliberate because different models of the TI-NSPIRE have different serial hardware. On the newer CX models, it is a PL01x and on the older models, it has a 8250-like interface. They all reside at the same address with the same IRQ though.

I thought it might be cleaner to specify the interrupts and registers in the common file and leave it to the board specific ones to implement the "compatible" property.

> 
>> +			timer0: timer0@900C0000 {
>> +				reg = <0x900C0000 0x1000>;
>> +				interrupts = <18>;
>> +
>> +				clocks = <&timer_clk>;
>> +				clock-names = "timer_clk";
>> +			};
>> +
>> +			timer1: timer1@900D0000 {
>> +				reg = <0x900D0000 0x1000>;
>> +				interrupts = <19>;
>> +
>> +				clocks = <&timer_clk>;
>> +				clock-names = "timer_clk";
>> +			};
> 
> Name the devices "timer", not "timer0" and "timer1", the address after @ is
> used to disambiguate them. There are currently patches for sp804 under
> discussion on the mailing list, you should probably watch those.
> 

Done. Yep, I also noticed there were patches to have device tree bindings for SP804. I'll integrate them once they're in mainline.

>> --- /dev/null
>> +++ b/arch/arm/mach-nspire/Makefile
>> @@ -0,0 +1,3 @@
>> +obj-y				:=
>> +
>> +obj-y				+= nspire.o
> 
> The first line is not actually needed.

Done.

> 
>> +
>> +#include "../../mmio.h"
>> +
>> +.macro	addruart, rp, rv, tmp
>> +	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
>> +	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
>> +.endm
>> +
>> +#include <asm/hardware/debug-pl01x.S>
>> +
> 
> There is no nice solution for getting the addresses here, but the consensus
> was to just define the macros in this file rather than try to include a
> header from elsewhere.
> 

Fair enough, I've added the macros in.

> 
>> +	err = of_property_read_string(of_aliases, "timer0", &path);
>> +	if (WARN_ON(err))
>> +		return;
>> +
>> +	timer = of_find_node_by_path(path);
>> +	base = of_iomap(timer, 0);
>> +	if (WARN_ON(!base))
>> +		return;
>> +
>> +	clk = of_clk_get_by_name(timer, NULL);
>> +	clk_register_clkdev(clk, timer->name, "sp804");
>> +
>> +	sp804_clocksource_init(base, timer->name);
>> +
>> +	err = of_property_read_string(of_aliases, "timer1", &path);
>> +	if (WARN_ON(err))
>> +		return;
> 
> In particular, I think the method of using aliases to pick the right sp804
> instance is being deprecated now. If both timers are identical, the kernel
> will now just pick one of them.

Sorry, I don't quite understand. 

Out of the timers, I want to add one as a clocksource and one as a clockevent. If they're identical (i.e. without using aliases), how should I tell the kernel, "Take the first timer you see and make it a clocksource, take the next one you see and make it a clockevent"?

> 
> 	Arnd

Here's an updated patch:

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
---
 arch/arm/Kconfig                   |   2 +
 arch/arm/Kconfig.debug             |  16 ++++
 arch/arm/Makefile                  |   3 +-
 arch/arm/boot/dts/nspire-cx.dts    |  85 ++++++++++++++++++++
 arch/arm/boot/dts/nspire.dtsi      | 154 +++++++++++++++++++++++++++++++++++++
 arch/arm/include/debug/nspire.S    |  28 +++++++
 arch/arm/mach-nspire/Kconfig       |  12 +++
 arch/arm/mach-nspire/Makefile      |   1 +
 arch/arm/mach-nspire/Makefile.boot |   0
 arch/arm/mach-nspire/mmio.h        |  13 ++++
 arch/arm/mach-nspire/nspire.c      | 107 ++++++++++++++++++++++++++
 11 files changed, 420 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/nspire-cx.dts
 create mode 100644 arch/arm/boot/dts/nspire.dtsi
 create mode 100644 arch/arm/include/debug/nspire.S
 create mode 100644 arch/arm/mach-nspire/Kconfig
 create mode 100644 arch/arm/mach-nspire/Makefile
 create mode 100644 arch/arm/mach-nspire/Makefile.boot
 create mode 100644 arch/arm/mach-nspire/mmio.h
 create mode 100644 arch/arm/mach-nspire/nspire.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..3f0cd8c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1081,6 +1081,8 @@ source "arch/arm/mach-netx/Kconfig"
 
 source "arch/arm/mach-nomadik/Kconfig"
 
+source "arch/arm/mach-nspire/Kconfig"
+
 source "arch/arm/plat-omap/Kconfig"
 
 source "arch/arm/mach-omap1/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 9b31f43..5da3a50 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -298,6 +298,20 @@ choice
 		  Say Y here if you want kernel low-level debugging support
 		  on MVEBU based platforms.
 
+	config DEBUG_NSPIRE_CLASSIC_UART
+		bool "Kernel low-level debugging via TI-NSPIRE 8250 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE classic models.
+
+	config DEBUG_NSPIRE_CX_UART
+		bool "Kernel low-level debugging via TI-NSPIRE PL011 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE CX models.
+
 	config DEBUG_OMAP2PLUS_UART
 		bool "Kernel low-level debugging messages via OMAP2PLUS UART"
 		depends on ARCH_OMAP2PLUS
@@ -591,6 +605,8 @@ config DEBUG_LL_INCLUDE
 				 DEBUG_IMX6Q_UART
 	default "debug/highbank.S" if DEBUG_HIGHBANK_UART
 	default "debug/mvebu.S" if DEBUG_MVEBU_UART
+	default "debug/nspire.S" if 	DEBUG_NSPIRE_CX_UART || \
+					DEBUG_NSPIRE_CLASSIC_UART
 	default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..f47a8a7 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -165,6 +165,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
+machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
@@ -313,7 +314,7 @@ define archhelp
   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
   echo  '  uImage        - U-Boot wrapped zImage'
-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+  echo  '  bootpImage    - Combined zImage and initial RAM disk'
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
   echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
diff --git a/arch/arm/boot/dts/nspire-cx.dts b/arch/arm/boot/dts/nspire-cx.dts
new file mode 100644
index 0000000..0a80488
--- /dev/null
+++ b/arch/arm/boot/dts/nspire-cx.dts
@@ -0,0 +1,85 @@
+/*
+ *  linux/arch/arm/boot/nspire-cx.dts
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+/dts-v1/;
+
+/include/ "nspire.dtsi"
+
+/ {
+	model = "TI-NSPIRE CX";
+	compatible = "arm,nspire-cx";
+
+	memory {
+		device_type = "memory";
+		reg = <0x10000000 0x4000000>; /* 64 MB */
+	};
+
+	aliases {
+		uart0 = &uart0;
+		timer0 = &timer0;
+		timer1 = &timer1;
+		fast_timer = &fast_timer;
+	};
+
+	uart_clk: uart_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+	};
+
+	/* Not really a fixed clock but we'll fix this later */
+	apb_pclk: apb_pclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <33000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		intc: interrupt-controller@DC000000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xDC000000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		apb@90000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			i2c@90050000 {
+				compatible = "snps,designware-i2c";
+				reg = <0x90050000 0x1000>;
+				interrupts = <20>;
+			};
+
+			fast_timer: timer@90010000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			uart0: serial@90020000 {
+				compatible = "arm,pl011", "arm,primecell";
+			};
+
+			timer0: timer@900C0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			timer1: timer@900D0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+		};
+	};
+	chosen {
+		bootargs = "debug earlyprintk console=ttyAMA0,115200n8";
+	};
+};
diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi
new file mode 100644
index 0000000..7e9681f
--- /dev/null
+++ b/arch/arm/boot/dts/nspire.dtsi
@@ -0,0 +1,154 @@
+/*
+ *  linux/arch/arm/boot/nspire.dtsi
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926";
+		};
+	};
+
+	bootrom: bootrom@00000000 {
+		reg = <0x00000000 0x80000>;
+	};
+
+	sram: sram@A4000000 {
+		device = "memory";
+		reg = <0xA4000000 0x20000>;
+	};
+
+	timer_clk: timer_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	ahb {
+		compatible = "arm,amba-bus", "simple-bus";
+		interrupt-parent = <&intc>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		spi: spi@A9000000 {
+			reg = <0xA9000000 0x1000>;
+		};
+
+		usb0: usb@B0000000 {
+			reg = <0xB0000000 0x1000>;
+			interrupts = <8>;
+		};
+
+		usb1: usb@B4000000 {
+			reg = <0xB4000000 0x1000>;
+			interrupts = <9>;
+			status = "disabled";
+		};
+
+		lcd: lcd@C0000000 {
+			compatible = "arm,amba-primecell";
+			reg = <0xC0000000 0x1000>;
+			interrupts = <21>;
+		};
+
+		adc: adc@C4000000 {
+			reg = <0xC4000000 0x1000>;
+			interrupts = <11>;
+		};
+
+		tdes: crypto@C8010000 {
+			reg = <0xC8010000 0x1000>;
+		};
+
+		sha256: crypto@CC000000 {
+			reg = <0xCC000000 0x1000>;
+		};
+
+		apb@90000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&apb_pclk>;
+			clock-names = "apb_pclk";
+			clock-ranges;
+			ranges;
+
+			gpio: gpio@90000000 {
+				reg = <0x90000000 0x1000>;
+				interrupts = <7>;
+			};
+
+			fast_timer: timer@90010000 {
+				reg = <0x90010000 0x1000>;
+				interrupts = <17>;
+			};
+
+			uart: serial@90020000 {
+				reg = <0x90020000 0x1000>;
+				interrupts = <1>;
+
+				clocks = <&uart_clk>;
+				clock-names = "uart_clk";
+			};
+
+			timer0: timer@900C0000 {
+				reg = <0x900C0000 0x1000>;
+				interrupts = <18>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			timer1: timer@900D0000 {
+				reg = <0x900D0000 0x1000>;
+				interrupts = <19>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			watchdog: watchdog@90060000 {
+				compatible = "arm,amba-primecell";
+				reg = <0x90060000 0x1000>;
+				interrupts = <3>;
+			};
+
+			rtc: rtc@90090000 {
+				reg = <0x90090000 0x1000>;
+				interrupts = <4>;
+			};
+
+			misc: misc@900A0000 {
+				reg = <0x900A0000 0x1000>;
+			};
+
+			pwr: pwr@900B0000 {
+				reg = <0x900B0000 0x1000>;
+				interrupts = <15>;
+			};
+
+			keypad: input@900E0000 {
+				reg = <0x900E0000 0x1000>;
+				interrupts = <16>;
+			};
+
+			contrast: contrast@900F0000 {
+				reg = <0x900F0000 0x1000>;
+			};
+
+			led: led@90110000 {
+				reg = <0x90110000 0x1000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/include/debug/nspire.S b/arch/arm/include/debug/nspire.S
new file mode 100644
index 0000000..3a9729c
--- /dev/null
+++ b/arch/arm/include/debug/nspire.S
@@ -0,0 +1,28 @@
+/*
+ *	linux/arch/arm/include/debug/nspire.S
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
+
+.macro	addruart, rp, rv, tmp
+	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
+	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
+.endm
+
+
+#ifdef CONFIG_DEBUG_NSPIRE_CX_UART
+#include <asm/hardware/debug-pl01x.S>
+#endif
+
+#ifdef CONFIG_DEBUG_NSPIRE_CLASSIC_UART
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
+#endif
diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig
new file mode 100644
index 0000000..b6bf06c
--- /dev/null
+++ b/arch/arm/mach-nspire/Kconfig
@@ -0,0 +1,12 @@
+config ARCH_NSPIRE
+	bool "TI-NSPIRE based"
+	depends on MMU
+	select CPU_ARM926T
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select SPARSE_IRQ
+	select ARM_AMBA
+	select ARM_VIC
+	select ARM_TIMER_SP804
+	help
+	  This enables support for systems using the TI-NSPIRE CPU
diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile
new file mode 100644
index 0000000..c96c2c4
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile
@@ -0,0 +1 @@
+obj-y				+= nspire.o
diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-nspire/mmio.h b/arch/arm/mach-nspire/mmio.h
new file mode 100644
index 0000000..6e2fe95
--- /dev/null
+++ b/arch/arm/mach-nspire/mmio.h
@@ -0,0 +1,13 @@
+/*
+ *	linux/arch/arm/mach-nspire/mmio.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c
new file mode 100644
index 0000000..ec7734a
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire.c
@@ -0,0 +1,107 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-vic.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware/timer-sp.h>
+
+#include "mmio.h"
+
+static const char *nspire_dt_match[] __initconst = {
+	"arm,nspire",
+	"arm,nspire-cx",
+	"arm,nspire-tp",
+	"arm,nspire-clp",
+	NULL,
+};
+
+static struct map_desc nspire_io_desc[] __initdata = {
+	{
+		.virtual	=  NSPIRE_EARLY_UART_VIRT_BASE,
+		.pfn		= __phys_to_pfn(NSPIRE_EARLY_UART_PHYS_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE
+	}
+};
+
+static void __init nspire_init_timer(void)
+{
+	struct device_node *timer;
+	void __iomem *base;
+	const char *path;
+	struct clk *clk;
+	int irq, err;
+
+	of_clk_init(NULL);
+
+	err = of_property_read_string(of_aliases, "timer0", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	sp804_clocksource_init(base, timer->name);
+
+	err = of_property_read_string(of_aliases, "timer1", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	irq = irq_of_parse_and_map(timer, 0);
+	sp804_clockevents_init(base, irq, timer->name);
+}
+
+static void __init nspire_map_io(void)
+{
+	iotable_init(nspire_io_desc, ARRAY_SIZE(nspire_io_desc));
+}
+
+static void __init nspire_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			NULL, NULL);
+}
+
+static void nspire_restart(char mode, const char *cmd)
+{
+}
+
+DT_MACHINE_START(NSPIRE, "TI-NSPIRE")
+	.map_io		= nspire_map_io,
+	.init_irq	= irqchip_init,
+	.init_time	= nspire_init_timer,
+	.init_machine	= nspire_init,
+	.dt_compat	= nspire_dt_match,
+	.restart	= nspire_restart,
+MACHINE_END
-- 
1.8.1.3

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-07  0:06           ` Daniel Tang
@ 2013-04-07  3:56             ` Daniel Tang
  2013-04-07 21:23               ` Arnd Bergmann
  2013-04-07 14:32             ` Arnd Bergmann
  1 sibling, 1 reply; 23+ messages in thread
From: Daniel Tang @ 2013-04-07  3:56 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

Here's an updated patch that enables support for the LCD.

I looked into drivers/video/of_display_timing.c but it doesn't have the fields to describe the PL11x specific options needed in struct clcd_panel. At the moment, it is implemented by hardcoding the values in the kernel and using the device tree to select the correct configuration.

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
---
 arch/arm/Kconfig                   |   2 +
 arch/arm/Kconfig.debug             |  16 +++
 arch/arm/Makefile                  |   3 +-
 arch/arm/boot/dts/nspire-cx.dts    |  89 ++++++++++++++
 arch/arm/boot/dts/nspire.dtsi      | 157 +++++++++++++++++++++++++
 arch/arm/include/debug/nspire.S    |  28 +++++
 arch/arm/mach-nspire/Kconfig       |  12 ++
 arch/arm/mach-nspire/Makefile      |   1 +
 arch/arm/mach-nspire/Makefile.boot |   0
 arch/arm/mach-nspire/mmio.h        |  15 +++
 arch/arm/mach-nspire/nspire.c      | 233 +++++++++++++++++++++++++++++++++++++
 11 files changed, 555 insertions(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..3f0cd8c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1081,6 +1081,8 @@ source "arch/arm/mach-netx/Kconfig"
 
 source "arch/arm/mach-nomadik/Kconfig"
 
+source "arch/arm/mach-nspire/Kconfig"
+
 source "arch/arm/plat-omap/Kconfig"
 
 source "arch/arm/mach-omap1/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 9b31f43..5da3a50 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -298,6 +298,20 @@ choice
 		  Say Y here if you want kernel low-level debugging support
 		  on MVEBU based platforms.
 
+	config DEBUG_NSPIRE_CLASSIC_UART
+		bool "Kernel low-level debugging via TI-NSPIRE 8250 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE classic models.
+
+	config DEBUG_NSPIRE_CX_UART
+		bool "Kernel low-level debugging via TI-NSPIRE PL011 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE CX models.
+
 	config DEBUG_OMAP2PLUS_UART
 		bool "Kernel low-level debugging messages via OMAP2PLUS UART"
 		depends on ARCH_OMAP2PLUS
@@ -591,6 +605,8 @@ config DEBUG_LL_INCLUDE
 				 DEBUG_IMX6Q_UART
 	default "debug/highbank.S" if DEBUG_HIGHBANK_UART
 	default "debug/mvebu.S" if DEBUG_MVEBU_UART
+	default "debug/nspire.S" if 	DEBUG_NSPIRE_CX_UART || \
+					DEBUG_NSPIRE_CLASSIC_UART
 	default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..f47a8a7 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -165,6 +165,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
+machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
@@ -313,7 +314,7 @@ define archhelp
   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
   echo  '  uImage        - U-Boot wrapped zImage'
-  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
+  echo  '  bootpImage    - Combined zImage and initial RAM disk'
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
   echo  '* dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
diff --git a/arch/arm/boot/dts/nspire-cx.dts b/arch/arm/boot/dts/nspire-cx.dts
new file mode 100644
index 0000000..d843e60
--- /dev/null
+++ b/arch/arm/boot/dts/nspire-cx.dts
@@ -0,0 +1,89 @@
+/*
+ *  linux/arch/arm/boot/nspire-cx.dts
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+/dts-v1/;
+
+/include/ "nspire.dtsi"
+
+/ {
+	model = "TI-NSPIRE CX";
+	compatible = "arm,nspire-cx";
+
+	memory {
+		device_type = "memory";
+		reg = <0x10000000 0x4000000>; /* 64 MB */
+	};
+
+	aliases {
+		uart0 = &uart0;
+		timer0 = &timer0;
+		timer1 = &timer1;
+		fast_timer = &fast_timer;
+	};
+
+	uart_clk: uart_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+	};
+
+	/* Not really a fixed clock but we'll fix this later */
+	apb_pclk: apb_pclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <33000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		intc: interrupt-controller@DC000000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xDC000000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		lcd: lcd@C0000000 {
+			lcd-type = "cx";
+		};
+
+		apb@90000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			i2c@90050000 {
+				compatible = "snps,designware-i2c";
+				reg = <0x90050000 0x1000>;
+				interrupts = <20>;
+			};
+
+			fast_timer: timer@90010000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			uart0: serial@90020000 {
+				compatible = "arm,pl011", "arm,primecell";
+			};
+
+			timer0: timer@900C0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			timer1: timer@900D0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+		};
+	};
+	chosen {
+		bootargs = "debug earlyprintk console=ttyAMA0,115200n8 console=tty0";
+	};
+};
diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi
new file mode 100644
index 0000000..5b6fad7
--- /dev/null
+++ b/arch/arm/boot/dts/nspire.dtsi
@@ -0,0 +1,157 @@
+/*
+ *  linux/arch/arm/boot/nspire.dtsi
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926";
+		};
+	};
+
+	bootrom: bootrom@00000000 {
+		reg = <0x00000000 0x80000>;
+	};
+
+	sram: sram@A4000000 {
+		device = "memory";
+		reg = <0xA4000000 0x20000>;
+	};
+
+	timer_clk: timer_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	ahb {
+		compatible = "arm,amba-bus", "simple-bus";
+		interrupt-parent = <&intc>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		spi: spi@A9000000 {
+			reg = <0xA9000000 0x1000>;
+		};
+
+		usb0: usb@B0000000 {
+			reg = <0xB0000000 0x1000>;
+			interrupts = <8>;
+		};
+
+		usb1: usb@B4000000 {
+			reg = <0xB4000000 0x1000>;
+			interrupts = <9>;
+			status = "disabled";
+		};
+
+		lcd: lcd@C0000000 {
+			compatible = "arm,pl111", "arm,primecell";
+			reg = <0xC0000000 0x1000>;
+			interrupts = <21>;
+
+			clocks = <&apb_pclk>;
+			clock-names = "apb_pclk";
+		};
+
+		adc: adc@C4000000 {
+			reg = <0xC4000000 0x1000>;
+			interrupts = <11>;
+		};
+
+		tdes: crypto@C8010000 {
+			reg = <0xC8010000 0x1000>;
+		};
+
+		sha256: crypto@CC000000 {
+			reg = <0xCC000000 0x1000>;
+		};
+
+		apb@90000000 {
+			compatible = "arm,amba-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&apb_pclk>;
+			clock-names = "apb_pclk";
+			clock-ranges;
+			ranges;
+
+			gpio: gpio@90000000 {
+				reg = <0x90000000 0x1000>;
+				interrupts = <7>;
+			};
+
+			fast_timer: timer@90010000 {
+				reg = <0x90010000 0x1000>;
+				interrupts = <17>;
+			};
+
+			uart: serial@90020000 {
+				reg = <0x90020000 0x1000>;
+				interrupts = <1>;
+
+				clocks = <&uart_clk>;
+				clock-names = "uart_clk";
+			};
+
+			timer0: timer@900C0000 {
+				reg = <0x900C0000 0x1000>;
+				interrupts = <18>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			timer1: timer@900D0000 {
+				reg = <0x900D0000 0x1000>;
+				interrupts = <19>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			watchdog: watchdog@90060000 {
+				compatible = "arm,amba-primecell";
+				reg = <0x90060000 0x1000>;
+				interrupts = <3>;
+			};
+
+			rtc: rtc@90090000 {
+				reg = <0x90090000 0x1000>;
+				interrupts = <4>;
+			};
+
+			misc: misc@900A0000 {
+				reg = <0x900A0000 0x1000>;
+			};
+
+			pwr: pwr@900B0000 {
+				reg = <0x900B0000 0x1000>;
+				interrupts = <15>;
+			};
+
+			keypad: input@900E0000 {
+				reg = <0x900E0000 0x1000>;
+				interrupts = <16>;
+			};
+
+			contrast: contrast@900F0000 {
+				reg = <0x900F0000 0x1000>;
+			};
+
+			led: led@90110000 {
+				reg = <0x90110000 0x1000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/include/debug/nspire.S b/arch/arm/include/debug/nspire.S
new file mode 100644
index 0000000..3a9729c
--- /dev/null
+++ b/arch/arm/include/debug/nspire.S
@@ -0,0 +1,28 @@
+/*
+ *	linux/arch/arm/include/debug/nspire.S
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
+
+.macro	addruart, rp, rv, tmp
+	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
+	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
+.endm
+
+
+#ifdef CONFIG_DEBUG_NSPIRE_CX_UART
+#include <asm/hardware/debug-pl01x.S>
+#endif
+
+#ifdef CONFIG_DEBUG_NSPIRE_CLASSIC_UART
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
+#endif
diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig
new file mode 100644
index 0000000..b6bf06c
--- /dev/null
+++ b/arch/arm/mach-nspire/Kconfig
@@ -0,0 +1,12 @@
+config ARCH_NSPIRE
+	bool "TI-NSPIRE based"
+	depends on MMU
+	select CPU_ARM926T
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select SPARSE_IRQ
+	select ARM_AMBA
+	select ARM_VIC
+	select ARM_TIMER_SP804
+	help
+	  This enables support for systems using the TI-NSPIRE CPU
diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile
new file mode 100644
index 0000000..c96c2c4
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile
@@ -0,0 +1 @@
+obj-y				+= nspire.o
diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-nspire/mmio.h b/arch/arm/mach-nspire/mmio.h
new file mode 100644
index 0000000..f0a1fa5
--- /dev/null
+++ b/arch/arm/mach-nspire/mmio.h
@@ -0,0 +1,15 @@
+/*
+ *	linux/arch/arm/mach-nspire/mmio.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	0xfee20000
+
+#define NSPIRE_LCD_PHYS_BASE		0xC0000000
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c
new file mode 100644
index 0000000..e349c80
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire.c
@@ -0,0 +1,233 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-vic.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware/timer-sp.h>
+
+#include "mmio.h"
+
+static const char *nspire_dt_match[] __initconst = {
+	"arm,nspire",
+	"arm,nspire-cx",
+	"arm,nspire-tp",
+	"arm,nspire-clp",
+	NULL,
+};
+
+static struct map_desc nspire_io_desc[] __initdata = {
+	{
+		.virtual	=  NSPIRE_EARLY_UART_VIRT_BASE,
+		.pfn		= __phys_to_pfn(NSPIRE_EARLY_UART_PHYS_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE
+	}
+};
+
+static void __init nspire_init_timer(void)
+{
+	struct device_node *timer;
+	void __iomem *base;
+	const char *path;
+	struct clk *clk;
+	int irq, err;
+
+	of_clk_init(NULL);
+
+	err = of_property_read_string(of_aliases, "timer0", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	sp804_clocksource_init(base, timer->name);
+
+	err = of_property_read_string(of_aliases, "timer1", &path);
+	if (WARN_ON(err))
+		return;
+
+	timer = of_find_node_by_path(path);
+	base = of_iomap(timer, 0);
+	if (WARN_ON(!base))
+		return;
+
+	clk = of_clk_get_by_name(timer, NULL);
+	clk_register_clkdev(clk, timer->name, "sp804");
+
+	irq = irq_of_parse_and_map(timer, 0);
+	sp804_clockevents_init(base, irq, timer->name);
+}
+
+static void __init nspire_map_io(void)
+{
+	iotable_init(nspire_io_desc, ARRAY_SIZE(nspire_io_desc));
+}
+
+static struct clcd_panel nspire_cx_lcd_panel = {
+	.mode		= {
+		.name		= "Color LCD",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 50,
+		.left_margin	= 38,
+		.lower_margin	= 3,
+		.upper_margin	= 17,
+	},
+	.width		= 65, /* ~6.50 cm */
+	.height		= 49, /* ~4.87 cm */
+	.tim2		= TIM2_IPC,
+	.cntl		= (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+				CNTL_LCDBPP16_565),
+	.bpp		= 16,
+};
+
+static struct clcd_panel nspire_classic_lcd_panel = {
+	.mode		= {
+		.name		= "Grayscale LCD",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 6,
+		.left_margin	= 6,
+	},
+	.width		= 71, /* 7.11cm */
+	.height		= 53, /* 5.33cm */
+	.tim2		= 0x80007d0,
+	.cntl		= CNTL_LCDBPP8 | CNTL_LCDMONO8,
+	.bpp		= 8,
+	.grayscale	= 1
+};
+
+static int nspire_clcd_setup(struct clcd_fb *fb)
+{
+	struct clcd_panel *panel;
+	size_t panel_size;
+	const char *type;
+	dma_addr_t dma;
+	int err;
+
+	BUG_ON(!fb->dev->dev.of_node);
+
+	err = of_property_read_string(fb->dev->dev.of_node, "lcd-type", &type);
+	if (err) {
+		pr_err("CLCD: Could not find lcd-type property\n");
+		return err;
+	}
+
+	if (!strcmp(type, "cx"))
+	{
+		panel = &nspire_cx_lcd_panel;
+	}
+	else if (!strcmp(type, "classic"))
+	{
+		panel = &nspire_classic_lcd_panel;
+	}
+	else
+	{
+		pr_err("CLCD: Unknown lcd-type %s\n", type);
+		return -EINVAL;
+	}
+
+	panel_size = ((panel->mode.xres * panel->mode.yres) * panel->bpp) / 8;
+	panel_size = ALIGN(panel_size, PAGE_SIZE);
+
+	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+		panel_size, &dma, GFP_KERNEL);
+
+	if (!fb->fb.screen_base) {
+		pr_err("CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+	fb->fb.fix.smem_start = dma;
+	fb->fb.fix.smem_len = panel_size;
+	fb->panel = panel;
+
+	return 0;
+}
+
+int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+		fb->fb.screen_base, fb->fb.fix.smem_start,
+		fb->fb.fix.smem_len);
+}
+
+void nspire_clcd_remove(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+		fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board nspire_clcd_data = {
+	.name		= "LCD",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.setup		= nspire_clcd_setup,
+	.mmap		= nspire_clcd_mmap,
+	.remove		= nspire_clcd_remove,
+};
+
+
+static struct of_dev_auxdata nspire_auxdata[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl111", NSPIRE_LCD_PHYS_BASE,
+			NULL, &nspire_clcd_data),
+	{ }
+};
+
+static void __init nspire_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			nspire_auxdata, NULL);
+}
+
+static void nspire_restart(char mode, const char *cmd)
+{
+}
+
+DT_MACHINE_START(NSPIRE, "TI-NSPIRE")
+	.map_io		= nspire_map_io,
+	.init_irq	= irqchip_init,
+	.init_time	= nspire_init_timer,
+	.init_machine	= nspire_init,
+	.dt_compat	= nspire_dt_match,
+	.restart	= nspire_restart,
+MACHINE_END


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-07  0:06           ` Daniel Tang
  2013-04-07  3:56             ` Daniel Tang
@ 2013-04-07 14:32             ` Arnd Bergmann
  1 sibling, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-07 14:32 UTC (permalink / raw)
  To: Daniel Tang; +Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel

On Sunday 07 April 2013, Daniel Tang wrote:
> On 07/04/2013, at 12:24 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > 
> >> @@ -313,7 +314,7 @@ define archhelp
> >>   echo  '  Image         - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
> >>   echo  '* xipImage      - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
> >>   echo  '  uImage        - U-Boot wrapped zImage'
> >> -  echo  '  bootpImage    - Combined zImage and initial RAM disk' 
> >> +  echo  '  bootpImage    - Combined zImage and initial RAM disk'
> >>   echo  '                  (supply initrd image via make variable INITRD=<path>)'
> >>   echo  '* dtbs          - Build device tree blobs for enabled boards'
> >>   echo  '  install       - Install uncompressed kernel'
> > 
> > This looks like it wasn't meant to be in the patch.
> 
> It probably isn't. I think there was trailing whitespace on that and my editor happened to remove it automatically.
> 
> Should this be a separate patch to fix up formatting or should I leave it in as a drive-by fix?

Any cleanups like this should be separate patches, and ideally even
part of a different patch series.

> > 
> >> +			uart: uart@90020000 {
> >> +				reg = <0x90020000 0x1000>;
> >> +				interrupts = <1>;
> >> +
> >> +				clocks = <&uart_clk>;
> >> +				clock-names = "uart_clk";
> >> +			};
> > 
> > The name for a uart should be "serial". Since this is a pl01x, please add
> > the required properties for the device, e.g. 
> > 
> > 	compatible = "arm,pl011", "arm,primecell";
> > 
> > You will need the "arm,primecell" bit to make the device appear on the
> > amba bus rather than the platform bus.
> 
> That was actually deliberate because different models of the TI-NSPIRE have different
> serial hardware. On the newer CX models, it is a PL01x and on the older models, it has
> a 8250-like interface. They all reside at the same address with the same IRQ though.
> 
> I thought it might be cleaner to specify the interrupts and registers in the common file
> and leave it to the board specific ones to implement the "compatible" property.

I see. It seems a little confusing to the reader though. I don't have a good answer,
but there are two other options how this can be handled:

* Put both devices in the devicetree and mark them as status="disabled" in the main file,
but enable one of them in the version specific files.

* leave them out of the .dtsi file and only define them in the specific .dts files.
> >> +	err = of_property_read_string(of_aliases, "timer0", &path);
> >> +	if (WARN_ON(err))
> >> +		return;
> >> +
> >> +	timer = of_find_node_by_path(path);
> >> +	base = of_iomap(timer, 0);
> >> +	if (WARN_ON(!base))
> >> +		return;
> >> +
> >> +	clk = of_clk_get_by_name(timer, NULL);
> >> +	clk_register_clkdev(clk, timer->name, "sp804");
> >> +
> >> +	sp804_clocksource_init(base, timer->name);
> >> +
> >> +	err = of_property_read_string(of_aliases, "timer1", &path);
> >> +	if (WARN_ON(err))
> >> +		return;
> > 
> > In particular, I think the method of using aliases to pick the right sp804
> > instance is being deprecated now. If both timers are identical, the kernel
> > will now just pick one of them.
> 
> Sorry, I don't quite understand. 
> 
> Out of the timers, I want to add one as a clocksource and one as a clockevent.
> If they're identical (i.e. without using aliases), how should I tell the kernel,
> "Take the first timer you see and make it a clocksource, take the next one you
> see and make it a clockevent"?

The modified sp804 driver will have logic to do that. I think in the end we
decided that the driver should first look for any device that can be used as
a clocksource and use it that way. If it finds a second device, that can be
used as clockevent.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-07  3:56             ` Daniel Tang
@ 2013-04-07 21:23               ` Arnd Bergmann
  2013-04-08 11:33                 ` Daniel Tang
  2013-04-09 11:23                 ` Linus Walleij
  0 siblings, 2 replies; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-07 21:23 UTC (permalink / raw)
  To: Daniel Tang
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel,
	Linus Walleij

On Sunday 07 April 2013, Daniel Tang wrote:
> Here's an updated patch that enables support for the LCD.
> 
> I looked into drivers/video/of_display_timing.c but it doesn't have the fields to describe the PL11x specific options needed in struct clcd_panel. At the moment, it is implemented by hardcoding the values in the kernel and using the device tree to select the correct configuration.
> 
> Signed-off-by: Daniel Tang <dt.tangr@gmail.com>

I think you should for now keep the clcd stuff in a separate file,
since it will be replaced with DT logic eventually. For now, the
auxdata method is ok, but Linus Walleij might already have thought
about how pl111 should get all its data from the device tree.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-07 21:23               ` Arnd Bergmann
@ 2013-04-08 11:33                 ` Daniel Tang
  2013-04-08 19:16                   ` Fabian Vogt
  2013-04-09 11:23                 ` Linus Walleij
  1 sibling, 1 reply; 23+ messages in thread
From: Daniel Tang @ 2013-04-08 11:33 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux, fabian, Lionel Debroux, linux-kernel,
	Linus Walleij

Changes:

 * Moved CLCD stuff to separate file until DT support for PL11x comes along
 * Whitespace cleanup in arch/arm/Makefile removed from patch
 * Rewrote code to find SP804 devices and use the first available one as a clockevent and the rest as clock sources until DT support comes to the SP804 driver.
 * Fix up platform selection in Kconfig. TI-NSPIRE based option was visible even when ARCH_MULTI_V4_V5 is not selected.
 * Added keypad driver and keymap
 * Support for 'make dtbs'

Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
---
 arch/arm/Kconfig                            |   2 +
 arch/arm/Kconfig.debug                      |  16 ++
 arch/arm/Makefile                           |   1 +
 arch/arm/boot/dts/Makefile                  |   1 +
 arch/arm/boot/dts/nspire-cx.dts             | 110 ++++++++++
 arch/arm/boot/dts/nspire.dtsi               | 168 +++++++++++++++
 arch/arm/include/debug/nspire.S             |  28 +++
 arch/arm/mach-nspire/Kconfig                |  14 ++
 arch/arm/mach-nspire/Makefile               |   2 +
 arch/arm/mach-nspire/Makefile.boot          |   0
 arch/arm/mach-nspire/clcd.c                 | 123 +++++++++++
 arch/arm/mach-nspire/clcd.h                 |  14 ++
 arch/arm/mach-nspire/mmio.h                 |  15 ++
 arch/arm/mach-nspire/nspire.c               | 139 ++++++++++++
 drivers/input/keyboard/Kconfig              |  10 +
 drivers/input/keyboard/Makefile             |   1 +
 drivers/input/keyboard/nspire-keypad.c      | 318 ++++++++++++++++++++++++++++
 include/linux/platform_data/nspire-keypad.h |  28 +++
 18 files changed, 990 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1cacda4..3f0cd8c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1081,6 +1081,8 @@ source "arch/arm/mach-netx/Kconfig"
 
 source "arch/arm/mach-nomadik/Kconfig"
 
+source "arch/arm/mach-nspire/Kconfig"
+
 source "arch/arm/plat-omap/Kconfig"
 
 source "arch/arm/mach-omap1/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 9b31f43..5da3a50 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -298,6 +298,20 @@ choice
 		  Say Y here if you want kernel low-level debugging support
 		  on MVEBU based platforms.
 
+	config DEBUG_NSPIRE_CLASSIC_UART
+		bool "Kernel low-level debugging via TI-NSPIRE 8250 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE classic models.
+
+	config DEBUG_NSPIRE_CX_UART
+		bool "Kernel low-level debugging via TI-NSPIRE PL011 UART"
+		depends on ARCH_NSPIRE
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on TI-NSPIRE CX models.
+
 	config DEBUG_OMAP2PLUS_UART
 		bool "Kernel low-level debugging messages via OMAP2PLUS UART"
 		depends on ARCH_OMAP2PLUS
@@ -591,6 +605,8 @@ config DEBUG_LL_INCLUDE
 				 DEBUG_IMX6Q_UART
 	default "debug/highbank.S" if DEBUG_HIGHBANK_UART
 	default "debug/mvebu.S" if DEBUG_MVEBU_UART
+	default "debug/nspire.S" if 	DEBUG_NSPIRE_CX_UART || \
+					DEBUG_NSPIRE_CLASSIC_UART
 	default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
 	default "debug/picoxcell.S" if DEBUG_PICOXCELL_UART
 	default "debug/socfpga.S" if DEBUG_SOCFPGA_UART
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ee4605f..2580d2b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -165,6 +165,7 @@ machine-$(CONFIG_ARCH_MXS)		+= mxs
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 machine-$(CONFIG_ARCH_NETX)		+= netx
 machine-$(CONFIG_ARCH_NOMADIK)		+= nomadik
+machine-$(CONFIG_ARCH_NSPIRE)		+= nspire
 machine-$(CONFIG_ARCH_OMAP1)		+= omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)	+= omap2
 machine-$(CONFIG_ARCH_ORION5X)		+= orion5x
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9c62558..adf8116 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -114,6 +114,7 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
 	imx28-sps1.dtb \
 	imx28-tx28.dtb
 dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb
+dtb-$(CONFIG_ARCH_NSPIRE) += nspire-cx.dtb
 dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
 	omap3-beagle.dtb \
 	omap3-beagle-xm.dtb \
diff --git a/arch/arm/boot/dts/nspire-cx.dts b/arch/arm/boot/dts/nspire-cx.dts
new file mode 100644
index 0000000..1da2e44
--- /dev/null
+++ b/arch/arm/boot/dts/nspire-cx.dts
@@ -0,0 +1,110 @@
+/*
+ *  linux/arch/arm/boot/nspire-cx.dts
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+/dts-v1/;
+
+/include/ "nspire.dtsi"
+
+/ {
+	model = "TI-NSPIRE CX";
+	compatible = "arm,nspire-cx";
+
+	memory {
+		device_type = "memory";
+		reg = <0x10000000 0x4000000>; /* 64 MB */
+	};
+
+	uart_clk: uart_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+	};
+
+	/* Not really a fixed clock but we'll fix this later */
+	apb_pclk: apb_pclk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <33000000>;
+	};
+
+	ahb {
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		intc: interrupt-controller@DC000000 {
+			compatible = "arm,pl190-vic";
+			interrupt-controller;
+			reg = <0xDC000000 0x1000>;
+			#interrupt-cells = <1>;
+		};
+
+		lcd: lcd@C0000000 {
+			lcd-type = "cx";
+		};
+
+		apb@90000000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			i2c@90050000 {
+				compatible = "snps,designware-i2c";
+				reg = <0x90050000 0x1000>;
+				interrupts = <20>;
+			};
+
+			/*
+			fast_timer: timer@90010000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+			*/
+
+			uart0: serial@90020000 {
+				compatible = "arm,pl011", "arm,primecell";
+			};
+
+			timer0: timer@900C0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			timer1: timer@900D0000 {
+				compatible = "arm,sp804", "arm,primecell";
+			};
+
+			keypad: input@900E0000 {
+				keymap = <
+				0x0000001c 	0x0001001c 	0x00040039
+				0x0005002c 	0x00060015 	0x0007000b
+				0x0008000f 	0x0100002d 	0x01010011
+				0x0102002f 	0x01030004 	0x01040016
+				0x01050014 	0x0106001f 	0x01070002
+				0x010a006a 	0x02000013 	0x02010010
+				0x02020019 	0x02030007 	0x02040018
+				0x02050031 	0x02060032 	0x02070005
+				0x02080028 	0x0209006c 	0x03000026
+				0x03010025 	0x03020024 	0x0303000a
+				0x03040017 	0x03050023 	0x03060022
+				0x03070008 	0x03080035 	0x03090069
+				0x04000021 	0x04010012 	0x04020020
+				0x0404002e 	0x04050030 	0x0406001e
+				0x0407000d 	0x04080037 	0x04090067
+				0x05010038 	0x0502000c 	0x0503001b
+				0x05040034 	0x0505001a 	0x05060006
+				0x05080027 	0x0509000e 	0x050a006f
+				0x0600002b 	0x0602004e 	0x06030068
+				0x06040003 	0x0605006d 	0x06060009
+				0x06070001 	0x0609000f 	0x0708002a
+				0x0709001d 	0x070a0033 	>;
+			};
+		};
+	};
+	chosen {
+		bootargs = "debug earlyprintk console=tty0 console=ttyAMA0,115200n8 root=/dev/ram0";
+	};
+};
diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi
new file mode 100644
index 0000000..d745e3d
--- /dev/null
+++ b/arch/arm/boot/dts/nspire.dtsi
@@ -0,0 +1,168 @@
+/*
+ *  linux/arch/arm/boot/nspire.dtsi
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	interrupt-parent = <&intc>;
+
+	cpus {
+		cpu@0 {
+			compatible = "arm,arm926ejs";
+		};
+	};
+
+	bootrom: bootrom@00000000 {
+		reg = <0x00000000 0x80000>;
+	};
+
+	sram: sram@A4000000 {
+		device = "memory";
+		reg = <0xA4000000 0x20000>;
+	};
+
+	timer_clk: timer_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+
+	lcd_clk: lcd_clk {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <660000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		spi: spi@A9000000 {
+			reg = <0xA9000000 0x1000>;
+		};
+
+		usb0: usb@B0000000 {
+			reg = <0xB0000000 0x1000>;
+			interrupts = <8>;
+		};
+
+		usb1: usb@B4000000 {
+			reg = <0xB4000000 0x1000>;
+			interrupts = <9>;
+			status = "disabled";
+		};
+
+		lcd: lcd@C0000000 {
+			compatible = "arm,pl111", "arm,primecell";
+			reg = <0xC0000000 0x1000>;
+			interrupts = <21>;
+
+			clocks = <&lcd_clk>;
+			clock-names = "apb_pclk";
+		};
+
+		adc: adc@C4000000 {
+			reg = <0xC4000000 0x1000>;
+			interrupts = <11>;
+		};
+
+		tdes: crypto@C8010000 {
+			reg = <0xC8010000 0x1000>;
+		};
+
+		sha256: crypto@CC000000 {
+			reg = <0xCC000000 0x1000>;
+		};
+
+		apb@90000000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clock-ranges;
+			ranges;
+
+			gpio: gpio@90000000 {
+				reg = <0x90000000 0x1000>;
+				interrupts = <7>;
+			};
+
+			fast_timer: timer@90010000 {
+				reg = <0x90010000 0x1000>;
+				interrupts = <17>;
+			};
+
+			uart: serial@90020000 {
+				reg = <0x90020000 0x1000>;
+				interrupts = <1>;
+
+				clocks = <&uart_clk>, <&apb_pclk>;
+				clock-names = "uart_clk", "apb_pclk";
+			};
+
+			timer0: timer@900C0000 {
+				reg = <0x900C0000 0x1000>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			timer1: timer@900D0000 {
+				reg = <0x900D0000 0x1000>;
+				interrupts = <19>;
+
+				clocks = <&timer_clk>;
+				clock-names = "timer_clk";
+			};
+
+			watchdog: watchdog@90060000 {
+				compatible = "arm,amba-primecell";
+				reg = <0x90060000 0x1000>;
+				interrupts = <3>;
+			};
+
+			rtc: rtc@90090000 {
+				reg = <0x90090000 0x1000>;
+				interrupts = <4>;
+			};
+
+			misc: misc@900A0000 {
+				reg = <0x900A0000 0x1000>;
+			};
+
+			pwr: pwr@900B0000 {
+				reg = <0x900B0000 0x1000>;
+				interrupts = <15>;
+			};
+
+			keypad: input@900E0000 {
+				compatible = "nspire-keypad";
+				reg = <0x900E0000 0x1000>;
+				interrupts = <16>;
+
+				scan-interval = <1000>;
+				row-delay = <200>;
+
+				clocks = <&apb_pclk>;
+				clock-names = "apb_pclk";
+			};
+
+			contrast: contrast@900F0000 {
+				reg = <0x900F0000 0x1000>;
+			};
+
+			led: led@90110000 {
+				reg = <0x90110000 0x1000>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/include/debug/nspire.S b/arch/arm/include/debug/nspire.S
new file mode 100644
index 0000000..3a9729c
--- /dev/null
+++ b/arch/arm/include/debug/nspire.S
@@ -0,0 +1,28 @@
+/*
+ *	linux/arch/arm/include/debug/nspire.S
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	   0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	   0xfee20000
+
+.macro	addruart, rp, rv, tmp
+	ldr \rp, =(NSPIRE_EARLY_UART_PHYS_BASE)		@ physical base address
+	ldr \rv, =(NSPIRE_EARLY_UART_VIRT_BASE)		@ virtual base address
+.endm
+
+
+#ifdef CONFIG_DEBUG_NSPIRE_CX_UART
+#include <asm/hardware/debug-pl01x.S>
+#endif
+
+#ifdef CONFIG_DEBUG_NSPIRE_CLASSIC_UART
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
+#endif
diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig
new file mode 100644
index 0000000..d485280
--- /dev/null
+++ b/arch/arm/mach-nspire/Kconfig
@@ -0,0 +1,14 @@
+config ARCH_NSPIRE
+	bool "TI-NSPIRE based"
+	depends on ARCH_MULTI_V4_V5
+	depends on MMU
+	select CPU_ARM926T
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+	select SPARSE_IRQ
+	select ARM_AMBA
+	select ARM_VIC
+	select ARM_TIMER_SP804
+	select USE_OF
+	help
+	  This enables support for systems using the TI-NSPIRE CPU
diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile
new file mode 100644
index 0000000..1bec256
--- /dev/null
+++ b/arch/arm/mach-nspire/Makefile
@@ -0,0 +1,2 @@
+obj-y				+= nspire.o
+obj-y				+= clcd.o
diff --git a/arch/arm/mach-nspire/Makefile.boot b/arch/arm/mach-nspire/Makefile.boot
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/mach-nspire/clcd.c b/arch/arm/mach-nspire/clcd.c
new file mode 100644
index 0000000..ee6ffcb
--- /dev/null
+++ b/arch/arm/mach-nspire/clcd.c
@@ -0,0 +1,123 @@
+/*
+ *	linux/arch/arm/mach-nspire/clcd.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/dma-mapping.h>
+
+static struct clcd_panel nspire_cx_lcd_panel = {
+	.mode		= {
+		.name		= "Color LCD",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 50,
+		.left_margin	= 38,
+		.lower_margin	= 3,
+		.upper_margin	= 17,
+	},
+	.width		= 65, /* ~6.50 cm */
+	.height		= 49, /* ~4.87 cm */
+	.tim2		= TIM2_IPC,
+	.cntl		= (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+				CNTL_LCDBPP16_565),
+	.bpp		= 16,
+};
+
+static struct clcd_panel nspire_classic_lcd_panel = {
+	.mode		= {
+		.name		= "Grayscale LCD",
+		.refresh	= 60,
+		.xres		= 320,
+		.yres		= 240,
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.pixclock	= 1,
+		.hsync_len	= 6,
+		.vsync_len	= 1,
+		.right_margin	= 6,
+		.left_margin	= 6,
+	},
+	.width		= 71, /* 7.11cm */
+	.height		= 53, /* 5.33cm */
+	.tim2		= 0x80007d0,
+	.cntl		= CNTL_LCDBPP8 | CNTL_LCDMONO8,
+	.bpp		= 8,
+	.grayscale	= 1
+};
+
+int nspire_clcd_setup(struct clcd_fb *fb)
+{
+	struct clcd_panel *panel;
+	size_t panel_size;
+	const char *type;
+	dma_addr_t dma;
+	int err;
+
+	BUG_ON(!fb->dev->dev.of_node);
+
+	err = of_property_read_string(fb->dev->dev.of_node, "lcd-type", &type);
+	if (err) {
+		pr_err("CLCD: Could not find lcd-type property\n");
+		return err;
+	}
+
+	if (!strcmp(type, "cx"))
+	{
+		panel = &nspire_cx_lcd_panel;
+	}
+	else if (!strcmp(type, "classic"))
+	{
+		panel = &nspire_classic_lcd_panel;
+	}
+	else
+	{
+		pr_err("CLCD: Unknown lcd-type %s\n", type);
+		return -EINVAL;
+	}
+
+	panel_size = ((panel->mode.xres * panel->mode.yres) * panel->bpp) / 8;
+	panel_size = ALIGN(panel_size, PAGE_SIZE);
+
+	fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+		panel_size, &dma, GFP_KERNEL);
+
+	if (!fb->fb.screen_base) {
+		pr_err("CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+	fb->fb.fix.smem_start = dma;
+	fb->fb.fix.smem_len = panel_size;
+	fb->panel = panel;
+
+	return 0;
+}
+
+int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+		fb->fb.screen_base, fb->fb.fix.smem_start,
+		fb->fb.fix.smem_len);
+}
+
+void nspire_clcd_remove(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+		fb->fb.screen_base, fb->fb.fix.smem_start);
+}
diff --git a/arch/arm/mach-nspire/clcd.h b/arch/arm/mach-nspire/clcd.h
new file mode 100644
index 0000000..7144399
--- /dev/null
+++ b/arch/arm/mach-nspire/clcd.h
@@ -0,0 +1,14 @@
+/*
+ *	linux/arch/arm/mach-nspire/clcd.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+int nspire_clcd_setup(struct clcd_fb *fb);
+int nspire_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma);
+void nspire_clcd_remove(struct clcd_fb *fb);
diff --git a/arch/arm/mach-nspire/mmio.h b/arch/arm/mach-nspire/mmio.h
new file mode 100644
index 0000000..f0a1fa5
--- /dev/null
+++ b/arch/arm/mach-nspire/mmio.h
@@ -0,0 +1,15 @@
+/*
+ *	linux/arch/arm/mach-nspire/mmio.h
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * 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.
+ *
+ */
+
+#define NSPIRE_EARLY_UART_PHYS_BASE	0x90020000
+#define NSPIRE_EARLY_UART_VIRT_BASE	0xfee20000
+
+#define NSPIRE_LCD_PHYS_BASE		0xC0000000
diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c
new file mode 100644
index 0000000..7d972b8
--- /dev/null
+++ b/arch/arm/mach-nspire/nspire.c
@@ -0,0 +1,139 @@
+/*
+ *	linux/arch/arm/mach-nspire/nspire.c
+ *
+ *	Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-vic.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware/timer-sp.h>
+
+#include "mmio.h"
+#include "clcd.h"
+
+static const char *nspire_dt_match[] __initconst = {
+	"arm,nspire",
+	"arm,nspire-cx",
+	"arm,nspire-tp",
+	"arm,nspire-clp",
+	NULL,
+};
+
+static struct map_desc nspire_io_desc[] __initdata = {
+	{
+		.virtual	=  NSPIRE_EARLY_UART_VIRT_BASE,
+		.pfn		= __phys_to_pfn(NSPIRE_EARLY_UART_PHYS_BASE),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE
+	}
+};
+
+#define TIMER_NAME_MAXLEN 32
+static void __init nspire_add_sp804_timers(void)
+{
+	struct device_node *of_timer;
+	int clockevents_found = 0;
+
+	for_each_compatible_node(of_timer, NULL, "arm,sp804") {
+		struct resource res;
+		void __iomem *base;
+		char *timer_name;
+		struct clk *clk;
+		int irq;
+
+		clk = of_clk_get_by_name(of_timer, NULL);
+		if (WARN_ON(!clk))
+			continue;
+
+		timer_name = kzalloc(TIMER_NAME_MAXLEN, GFP_ATOMIC);
+		if (!timer_name)
+			break;
+
+		base = of_iomap(of_timer, 0);
+		if (WARN_ON(!base)) {
+			kfree(timer_name);
+			continue;
+		}
+
+		of_address_to_resource(of_timer, 0, &res);
+		scnprintf(timer_name, TIMER_NAME_MAXLEN, "%llx.%s",
+				(unsigned long long)res.start,
+				of_timer->name);
+
+		clk_register_clkdev(clk, timer_name, "sp804");
+		if (!clockevents_found) {
+			irq = irq_of_parse_and_map(of_timer, 0);
+			if (irq) {
+				sp804_clockevents_init(base, irq,timer_name);
+				clockevents_found = 1;
+				continue;
+			}
+		}
+
+		sp804_clocksource_init(base, timer_name);
+	}
+}
+
+
+static void __init nspire_init_timer(void)
+{
+	of_clk_init(NULL);
+	nspire_add_sp804_timers();
+}
+
+static void __init nspire_map_io(void)
+{
+	iotable_init(nspire_io_desc, ARRAY_SIZE(nspire_io_desc));
+}
+
+static struct clcd_board nspire_clcd_data = {
+	.name		= "LCD",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.setup		= nspire_clcd_setup,
+	.mmap		= nspire_clcd_mmap,
+	.remove		= nspire_clcd_remove,
+};
+
+
+static struct of_dev_auxdata nspire_auxdata[] __initdata = {
+	OF_DEV_AUXDATA("arm,pl111", NSPIRE_LCD_PHYS_BASE,
+			NULL, &nspire_clcd_data),
+	{ }
+};
+
+static void __init nspire_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table,
+			nspire_auxdata, NULL);
+}
+
+static void nspire_restart(char mode, const char *cmd)
+{
+}
+
+DT_MACHINE_START(NSPIRE, "TI-NSPIRE")
+	.map_io		= nspire_map_io,
+	.init_irq	= irqchip_init,
+	.init_time	= nspire_init_timer,
+	.init_machine	= nspire_init,
+	.dt_compat	= nspire_dt_match,
+	.restart	= nspire_restart,
+MACHINE_END
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index ac05006..677adba 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -418,6 +418,16 @@ config KEYBOARD_NOMADIK
 	  To compile this driver as a module, choose M here: the
 	  module will be called nmk-ske-keypad.
 
+config KEYBOARD_NSPIRE
+	tristate "TI-NSPIRE builtin keyboard"
+	depends on ARCH_NSPIRE
+	select INPUT_MATRIXKMAP
+	help
+	  Say Y here if you want to use the builtin keypad on the TI-NSPIRE.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nspire-keypad.
+
 config KEYBOARD_TEGRA
 	tristate "NVIDIA Tegra internal matrix keyboard controller support"
 	depends on ARCH_TEGRA && OF
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 49b1645..89d997b 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_KEYBOARD_MCS)		+= mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_MPR121)		+= mpr121_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_NOMADIK)		+= nomadik-ske-keypad.o
+obj-$(CONFIG_KEYBOARD_NSPIRE)		+= nspire-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP4)		+= omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c
new file mode 100644
index 0000000..5b2b3cc
--- /dev/null
+++ b/drivers/input/keyboard/nspire-keypad.c
@@ -0,0 +1,318 @@
+/*
+ *  linux/drivers/input/keyboard/nspire-keypad.c
+ *
+ *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/input/matrix_keypad.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/platform_data/nspire-keypad.h>
+
+#define KEYPAD_SCAN_MODE	0x00
+#define KEYPAD_CNTL		0x04
+#define KEYPAD_INT		0x08
+#define KEYPAD_INTMSK		0x0C
+
+#define KEYPAD_DATA		0x10
+#define KEYPAD_GPIO		0x30
+
+#define KEYPAD_UNKNOWN_INT	0x40
+#define KEYPAD_UNKNOWN_INT_STS	0x44
+
+
+struct nspire_keypad {
+	spinlock_t lock;
+
+	void __iomem *reg_base;
+	int irq;
+	u32 int_mask;
+
+	struct input_dev *input;
+	struct clk *clk;
+
+	struct nspire_keypad_data options;
+	int row_shift;
+};
+
+static inline void nspire_report_state(struct nspire_keypad *keypad,
+		int row, int col, unsigned int state)
+{
+	int code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+	unsigned short *keymap = keypad->input->keycode;
+
+	state = keypad->options.active_low ? !state : !!state;
+	input_report_key(keypad->input, keymap[code], state);
+}
+
+static irqreturn_t nspire_keypad_irq(int irq, void *dev_id)
+{
+	struct nspire_keypad *keypad = dev_id;
+	u32 int_sts;
+	u16 state[8];
+	int row, col;
+
+	int_sts = readl(keypad->reg_base + KEYPAD_INT) & keypad->int_mask;
+
+	if (!int_sts)
+		return IRQ_NONE;
+
+	spin_lock(&keypad->lock);
+
+	memcpy_fromio(state, keypad->reg_base + KEYPAD_DATA, sizeof(state));
+
+	for (row = 0; row < KEYPAD_BITMASK_ROWS; row++) {
+		u16 bits = state[row];
+		for (col = 0; col < KEYPAD_BITMASK_COLS; col++) {
+			nspire_report_state(keypad, row, col, bits & (1<<col));
+		}
+	}
+	input_sync(keypad->input);
+	writel(0x3, keypad->reg_base + KEYPAD_INT);
+
+	spin_unlock(&keypad->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
+{
+	unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
+
+	cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
+	if (cycles_per_us == 0)
+		cycles_per_us = 1;
+
+	delay_cycles = cycles_per_us * keypad->options.scan_interval;
+	WARN_ON(delay_cycles >= (1<<16)); /* Overflow */
+	delay_cycles &= 0xffff;
+
+	row_delay_cycles = cycles_per_us * keypad->options.row_delay;
+	WARN_ON(row_delay_cycles >= (1<<14)); /* Overflow */
+	row_delay_cycles &= 0x3fff;
+
+
+	val |= (3<<0); /* Set scan mode to 3 (continuous scan) */
+	val |= (row_delay_cycles<<2); /* Delay between scanning each row */
+	val |= (delay_cycles<<16); /* Delay between scans */
+	writel(val, keypad->reg_base + KEYPAD_SCAN_MODE);
+
+	val = (KEYPAD_BITMASK_ROWS & 0xff) | (KEYPAD_BITMASK_COLS & 0xff)<<8;
+	writel(val, keypad->reg_base + KEYPAD_CNTL);
+
+	/* Enable interrupts */
+	keypad->int_mask = (1<<1);
+	writel(keypad->int_mask, keypad->reg_base + 0xc);
+
+	/* Disable GPIO interrupts to prevent hanging on touchpad */
+	/* Possibly used to detect touchpad events */
+	writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
+	/* Acknowledge existing interrupts */
+	writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
+
+	return 0;
+}
+
+static int nspire_keypad_probe(struct platform_device *pdev)
+{
+	const struct nspire_keypad_data *plat = pdev->dev.platform_data;
+	const struct device_node *of_node = pdev->dev.of_node;
+	struct nspire_keypad *keypad;
+	struct input_dev *input;
+	struct resource *res;
+	struct clk *clk;
+	int irq, error;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get keypad irq\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing platform resources\n");
+		return -EINVAL;
+	}
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "unable to get clock\n");
+		return -EINVAL;
+	}
+
+	clk_prepare(clk);
+	error = clk_enable(clk);
+	if (error) {
+		goto err_put_clk;
+	}
+
+	keypad = kzalloc(sizeof(struct nspire_keypad), GFP_KERNEL);
+	input = input_allocate_device();
+	if (!keypad || !input) {
+		dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	if (plat) {
+		memcpy(&keypad->options, plat, sizeof(*plat));
+	} else {
+		/* Load values from device tree */
+
+		error = of_property_read_u32(of_node, "scan-interval",
+				&keypad->options.scan_interval);
+		if (error) {
+			dev_err(&pdev->dev, "failed to get scan-interval\n");
+			goto err_free_mem;
+		}
+
+		error = of_property_read_u32(of_node, "row-delay",
+				&keypad->options.row_delay);
+		if (error) {
+			dev_err(&pdev->dev, "failed to get row-delay\n");
+			goto err_free_mem;
+		}
+
+		keypad->options.active_low = of_property_read_bool(of_node,
+				"active-low");
+
+		keypad->options.keymap = NULL;
+	}
+
+	keypad->row_shift = get_count_order(KEYPAD_BITMASK_COLS);
+	keypad->irq = irq;
+	keypad->clk = clk;
+	keypad->input = input;
+	spin_lock_init(&keypad->lock);
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "failed to request I/O memory\n");
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	keypad->reg_base = ioremap(res->start, resource_size(res));
+	if (!keypad->reg_base) {
+		dev_err(&pdev->dev, "failed to remap I/O memory\n");
+		error = -ENXIO;
+		goto err_free_mem_region;
+	}
+
+	input->id.bustype = BUS_HOST;
+	input->name = "nspire-keypad";
+	input->dev.parent = &pdev->dev;
+
+	set_bit(EV_KEY, input->evbit);
+	set_bit(EV_REP, input->evbit);
+
+	error = matrix_keypad_build_keymap(keypad->options.keymap, "keymap",
+			KEYPAD_BITMASK_ROWS, KEYPAD_BITMASK_COLS, NULL, input);
+	if (error) {
+		dev_err(&pdev->dev, "building keymap failed\n");
+		goto err_iounmap;
+	}
+
+	error = nspire_keypad_chip_init(keypad);
+	if (error) {
+		dev_err(&pdev->dev, "unable to init keypad hardware\n");
+		goto err_iounmap;
+	}
+
+	error = request_irq(keypad->irq, nspire_keypad_irq, 0,
+			"nspire_keypad", keypad);
+	if (error) {
+		dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
+		goto err_iounmap;
+	}
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&pdev->dev,
+				"unable to register input device: %d\n", error);
+		goto err_free_irq;
+	}
+
+	platform_set_drvdata(pdev, keypad);
+
+	dev_info(&pdev->dev, "TI-NSPIRE keypad at %#08x ("
+			"scan_interval=%uus,row_delay=%uus"
+			"%s)\n", res->start,
+			keypad->options.row_delay,
+			keypad->options.scan_interval,
+			keypad->options.active_low ? ",active_low" : "");
+
+	return 0;
+
+err_free_irq:
+	free_irq(keypad->irq, keypad);
+err_iounmap:
+	iounmap(keypad->reg_base);
+err_free_mem_region:
+	release_mem_region(res->start, resource_size(res));
+err_free_mem:
+	input_free_device(input);
+	kfree(keypad);
+
+	clk_disable(clk);
+err_put_clk:
+	clk_unprepare(clk);
+	clk_put(clk);
+	return error;
+}
+
+static int nspire_keypad_remove(struct platform_device *pdev)
+{
+	struct nspire_keypad *keypad = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	free_irq(keypad->irq, keypad);
+
+	input_unregister_device(keypad->input);
+
+	iounmap(keypad->reg_base);
+	release_mem_region(res->start, resource_size(res));
+	kfree(keypad);
+
+	clk_disable(keypad->clk);
+	clk_unprepare(keypad->clk);
+	clk_put(keypad->clk);
+
+	return 0;
+}
+#ifdef CONFIG_OF
+static const struct of_device_id nspire_keypad_dt_match[] = {
+	{ .compatible = "nspire-keypad" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, nspire_keypad_dt_match);
+#endif
+
+static struct platform_driver nspire_keypad_driver = {
+	.driver = {
+		.name = "nspire-keypad",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(nspire_keypad_dt_match),
+	},
+	.remove = nspire_keypad_remove,
+	.probe = nspire_keypad_probe
+};
+
+module_platform_driver(nspire_keypad_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");
diff --git a/include/linux/platform_data/nspire-keypad.h b/include/linux/platform_data/nspire-keypad.h
new file mode 100644
index 0000000..03deb64
--- /dev/null
+++ b/include/linux/platform_data/nspire-keypad.h
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/linux/platform_data/nspire-keypad.h
+ *
+ *  Copyright (C) 2012 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _LINUX_NSPIRE_KEYPAD_H
+#define _LINUX_NSPIRE_KEYPAD_H
+
+#define KEYPAD_BITMASK_COLS	11
+#define KEYPAD_BITMASK_ROWS	8
+
+struct nspire_keypad_data {
+	struct matrix_keymap_data *keymap;
+
+	/* Maximum delay estimated assuming 33MHz APB */
+	u32 scan_interval;	/* In microseconds (~2000us max) */
+	u32 row_delay;		/* In microseconds (~500us max) */
+
+	bool active_low;
+};
+
+#endif


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-08 11:33                 ` Daniel Tang
@ 2013-04-08 19:16                   ` Fabian Vogt
  2013-04-08 19:38                     ` Arnd Bergmann
  2013-04-09  5:59                     ` Daniel Tang
  0 siblings, 2 replies; 23+ messages in thread
From: Fabian Vogt @ 2013-04-08 19:16 UTC (permalink / raw)
  To: Arnd Bergmann, Daniel Tang
  Cc: linux-arm-kernel, linux, Lionel Debroux, linux-kernel, Linus Walleij

The latest kernel it seems to get stuck at
console_lock() in register_framebuffer (drivers/video/fbmem.c:1655)
if the LCD-controller is enabled. (Early printk and serial console works  
fine)
CONFIG_NO_HZ is not activated, it works completely.
Could this be a kernel bug or is this an issue with our timer  
configuration?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-08 19:16                   ` Fabian Vogt
@ 2013-04-08 19:38                     ` Arnd Bergmann
  2013-04-08 20:06                       ` Fabian Vogt
  2013-04-09  5:59                     ` Daniel Tang
  1 sibling, 1 reply; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-08 19:38 UTC (permalink / raw)
  To: Fabian Vogt
  Cc: Daniel Tang, linux-arm-kernel, linux, Lionel Debroux,
	linux-kernel, Linus Walleij

On Monday 08 April 2013, Fabian Vogt wrote:
> The latest kernel it seems to get stuck at
> console_lock() in register_framebuffer (drivers/video/fbmem.c:1655)
> if the LCD-controller is enabled. (Early printk and serial console works  
> fine)
> CONFIG_NO_HZ is not activated, it works completely.
> Could this be a kernel bug or is this an issue with our timer  
> configuration?

This usually happens when the console driver or anything it uses
calls a function that does a printk(), which means you get a recursive
call into the console code and try to get the same lock again.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-08 19:38                     ` Arnd Bergmann
@ 2013-04-08 20:06                       ` Fabian Vogt
  2013-04-08 21:29                         ` Arnd Bergmann
  0 siblings, 1 reply; 23+ messages in thread
From: Fabian Vogt @ 2013-04-08 20:06 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Daniel Tang, linux-arm-kernel, linux, Lionel Debroux,
	linux-kernel, Linus Walleij

> On Monday 08 April 2013, Fabian Vogt wrote:
>> The latest kernel it seems to get stuck at
>> console_lock() in do_register_framebuffer (drivers/video/fbmem.c:1655)
>> if the LCD-controller is enabled. (Early printk and serial console works
>> fine)
>> CONFIG_NO_HZ is not activated, it works completely.
>> Could this be a kernel bug or is this an issue with our timer
>> configuration?
>
> This usually happens when the console driver or anything it uses
> calls a function that does a printk(), which means you get a recursive
> call into the console code and try to get the same lock again.
Yes, I've heard that before, but than it would work/not work independently
of NO_HZ. Can printk's be executet within console_lock() ..  
console_unlock() blocks?
If not, it could be fb_notifier_call_chain, too, but that wouldn't be  
likely at all.
I also tried spinlock/mutex debugging and soft lockup detection,
but neither of them outputs anything.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-08 20:06                       ` Fabian Vogt
@ 2013-04-08 21:29                         ` Arnd Bergmann
  0 siblings, 0 replies; 23+ messages in thread
From: Arnd Bergmann @ 2013-04-08 21:29 UTC (permalink / raw)
  To: Fabian Vogt
  Cc: Daniel Tang, linux-arm-kernel, linux, Lionel Debroux,
	linux-kernel, Linus Walleij

On Monday 08 April 2013, Fabian Vogt wrote:
> Yes, I've heard that before, but than it would work/not work independently
> of NO_HZ. Can printk's be executet within console_lock() ..  
> console_unlock() blocks?

I think it's legal to call printk in that case, but the message will
not be printed until you reach the console_unlock()

> If not, it could be fb_notifier_call_chain, too, but that wouldn't be  
> likely at all.
> I also tried spinlock/mutex debugging and soft lockup detection,
> but neither of them outputs anything.

Unfortunately, lockdep does not help with console_lock, since that
is a weird semaphore variant, not a standard mutex or spinlock.

	Arnd

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-08 19:16                   ` Fabian Vogt
  2013-04-08 19:38                     ` Arnd Bergmann
@ 2013-04-09  5:59                     ` Daniel Tang
  1 sibling, 0 replies; 23+ messages in thread
From: Daniel Tang @ 2013-04-09  5:59 UTC (permalink / raw)
  To: Fabian Vogt
  Cc: Arnd Bergmann, linux-arm-kernel, linux, Lionel Debroux,
	linux-kernel, Linus Walleij


On 09/04/2013, at 5:16 AM, Fabian Vogt <fabian@ritter-vogt.de> wrote:

> The latest kernel it seems to get stuck at
> console_lock() in register_framebuffer (drivers/video/fbmem.c:1655)
> if the LCD-controller is enabled. (Early printk and serial console works fine)
> CONFIG_NO_HZ is not activated, it works completely.
> Could this be a kernel bug or is this an issue with our timer configuration?

Even with the CONFIG_NO_HZ option disabled, I've found that probing of our LCD hardware sometimes still fail with an error of -2.

Depending on how I arrange the device tree or the contents of the boot arguments or, as said, the CONFIG_NO_HZ option, I get different behaviours ranging from: 
 * Getting a -2 error during device probe (possibly due to a clock not being found).
 * LCD hardware is found but boot hangs right after the driver is initialised.
 * LCD hardware is apparently initialised correctly and text appears onscreen but user mode init hangs and I never get to a shell prompt.

This smells of a race condition that occurs before the clcd driver even gets to initialise. Some bug in our timer code? A OF or console bug perhaps? Though, I'm a bit hesitant to blame it on a kernel subsystem bug until it's clear that our code isn't at fault.

Any suggestions?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-04  9:01 [RFC PATCH arm: initial TI-Nspire support] Daniel Tang
  2013-04-04 11:12 ` Arnd Bergmann
@ 2013-04-09 11:14 ` Linus Walleij
  2013-04-09 11:39   ` Daniel Tang
  1 sibling, 1 reply; 23+ messages in thread
From: Linus Walleij @ 2013-04-09 11:14 UTC (permalink / raw)
  To: Daniel Tang
  Cc: linux-arm-kernel, Russell King - ARM Linux, linux-kernel, fabian,
	Lionel Debroux

On Thu, Apr 4, 2013 at 11:01 AM, Daniel Tang <dt.tangr@gmail.com> wrote:

(I suspect I duplicate a lot of Arnd's comments, I haven't really checked.
If we contradict each other, point it out so we can discuss.)

> +config ARCH_NSPIRE
> +       bool "TI-NSPIRE based"
> +       depends on MMU
> +       select CPU_ARM926T
> +       select HAVE_MACH_CLKDEV
> +       select CLKDEV_LOOKUP

For a new platform you should be selecting COMMON_CLK
and implement your clock drivers under drivers/clk/*.

> +       select ARM_AMBA
> +       select USB_ARCH_HAS_EHCI
> +       select ARCH_WANT_OPTIONAL_GPIOLIB
> +       select GENERIC_ALLOCATOR

I wonder what that is used for ... will be fun to see :-)

> +       select ARCH_HAS_CPUFREQ
> +       select CPU_FREQ_TABLE
> +       help
> +         This enables support for systems using the TI-NSPIRE CPU

This does not select GENERIC_CLOCKEVENTS and SPARSE_IRQ
which is not a good sign.

> +choice
> +       prompt "Early printk and boot message serial interface"
> +       help
> +         Early printk output interface
> +       depends on EARLY_PRINTK
> +       default NSPIRE_EARLYPRINTK_CX
> +
> +config NSPIRE_EARLYPRINTK_CLASSIC
> +       bool "Classic"
> +
> +config NSPIRE_EARLYPRINTK_CX
> +       bool "CX model"
> +endchoice

This kind of stuf should go into
arch/arm/Kconfig.debug these days, along with implementation
of debug macro in arch/arm/debug/foo.S

> diff --git a/arch/arm/mach-nspire/classic.c b/arch/arm/mach-nspire/classic.c
(...)

> +union reg_clk_speed {
> +       unsigned long raw;
> +       struct {
> +               unsigned long __padding0:1;
> +               unsigned long base_cpu_ratio:7;
> +               unsigned long is_base_27mhz:1;
> +               unsigned long __padding1:3;
> +               unsigned long cpu_ahb_ratio:3;
> +               unsigned long __padding2:1;
> +               unsigned long base_val:5;
> +       } val;
> +};

Usually to try to fit a struct over a register range is not such a good
idea in Linux.

Instead define abstract representations of what you want to do
(remove everything named "padding" above, use proper data types instead
of these unsigned longs and that complex union) then use offsets to
registers and remap the base offset in memory.

It makes for simpler debugging and ability to properly use read|write[lwb]
macros.

> +static unsigned long classic_clocks_to_io(struct nspire_clk_speeds *clks)
> +{
> +       union reg_clk_speed reg;
> +
> +       BUG_ON(clks->div.base_cpu < 2);
> +       BUG_ON(clks->div.cpu_ahb < 1);
> +
> +       reg.raw = 0;
> +       reg.val.base_cpu_ratio = clks->div.base_cpu / 2;
> +       reg.val.cpu_ahb_ratio = clks->div.cpu_ahb - 1;
> +       reg.val.is_base_27mhz = (clks->base <= 27000000);
> +       reg.val.base_val = (300 - (clks->base / 1000000)) / 6;
> +
> +       return reg.raw;
> +}

And that avoid having to create special helper functions like this.

In integer divisions consider using DIV_ROUND_CLOSEST()
from <linux/kernel.h> where applicable.

> +/* Interrupt handling */

The interrupt controller driver shall be placed in drivers/irqchips
these days.

> +static inline int check_interrupt(void __iomem *base, struct pt_regs *regs)
> +{
> +       if (readl(base + 0x0)) {

Arrow antipattern, turn it around.

if (!readl(base))
   return 0;

Then de-indent the rest of the code.

> +               int irqnr = readl(base + 0x24);
> +               unsigned prev_priority;
> +               handle_IRQ(irqnr, regs);
> +
> +               /* Reset priorities */
> +               prev_priority = readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
> +               writel(prev_priority, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
> +               return 1;
> +       }
> +       return 0;
> +}

I don't understand this, put in  some explanation of what this function
does please.

> +asmlinkage void __exception_irq_entry
> +       nspire_classic_handle_irq(struct pt_regs *regs)
> +{
> +       int serviced;
> +
> +       do {
> +               void __iomem *reg_base = IOMEM(NSPIRE_INTERRUPT_VIRT_BASE);

Instead of casting this in every IRQ entry define a static local
in the irq driver file to point to the base.

Avoids time in the IRQ handler, so it obviously the right thing to do.

Please also use a dynamic remapping ioremap* insteaf of
this static IOMEM() thing.

> +               serviced = 0;
> +
> +               /* IRQ */
> +               serviced += check_interrupt(reg_base, regs);
> +               /* FIQ */
> +               serviced += check_interrupt(reg_base + 0x100, regs);

Should you now handle FIQs first at all times?

> +       } while (serviced > 0);
> +}
> +
> +static void classic_irq_ack(struct irq_data *d)
> +{
> +       readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
> +}

As stated use an ioremap:ed base static local.

(...)
> +void __init nspire_classic_init_irq(void)
> +{
> +       /* No stickies */
> +       writel(0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x204));

0x204???

Use

#define FOO_REGISTER 0x204

to define understandable names for all of this so we can read the code.

Usually this means the comments are no longer needed because the
code becomes self-evident.

> +
> +       /* Disable all interrupts */
> +       writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0xc));
> +       writel(~0, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x10c));
> +
> +       /* Set all priorities to 0 */
> +       memset_io(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x300), 0, 0x7f);
> +
> +       /* Accept interrupts of all priorities */
> +       writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
> +       writel(0xf, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x12c));
> +
> +       /* Clear existing interrupts */
> +       readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
> +       readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x128));

Dito, everywhere.

In the end looking like this:

readl(base + NSPIRE_IRQ_FOO); or something.

No IOMEM, etc.

(...)
> +/* Timer */

Hm, looks like you just forgot to select GENERIC_CLOCKEVENTS?

Strange if it works anyway :-/

We are comtemplating putting these things into drivers/timer,
nothing decided yet.

> +static int classic_timer_set_event(unsigned long delta,
> +                               struct clock_event_device *dev)
> +{
> +       unsigned long flags;
> +
> +       local_irq_save(flags);
> +       writel(delta, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2));
> +       writel(1, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x8));
> +       writel(0, NSPIRE_APB_VIRTIO(NSPIRE_APB_TIMER2 + 0x18));

Remove magic numbers, define register names.

Remap a base, get rid of NSPIRE_APB_VIRTIO().

> +       local_irq_restore(flags);
> +
> +       return 0;
> +}
> +static void classic_timer_set_mode(enum clock_event_mode mode,
> +                                struct clock_event_device *evt)
> +{
> +       evt->mode = mode;
> +}
> +
> +static struct clock_event_device nspire_clkevt = {
> +       .name           = "clockevent",
> +       .features       = CLOCK_EVT_FEAT_ONESHOT,
> +       .shift          = 32,
> +       .rating         = 400,
> +       .set_next_event = classic_timer_set_event,
> +       .set_mode       = classic_timer_set_mode,
> +       .cpumask                = cpu_all_mask,
> +};
> +
> +static irqreturn_t classic_timer_interrupt(int irq, void *dev_id)
> +{
> +       struct clock_event_device *c = dev_id;
> +
> +       /* Acknowledge */
> +       writel((1<<0), NSPIRE_APB_VIRTIO(NSPIRE_APB_MISC + 0x20));

writel((1<<0) isn't very helpful.

#include <linux/bitops.h>

#define NSPIRE_TIMER_ACK_REG 0x20
#define NSPIRE_TIMER_ACK BIT(0)

writel(NSPIRE_TIMER_ACK, base +  NSPIRE_TIMER_ACK_REG);

Then follow a lot of platform data and devices. These have to be moved
over to the device tree instead and deleted.

(...)
> +++ b/arch/arm/mach-nspire/touchpad.c
> @@ -0,0 +1,30 @@
> +/*
> + *     linux/arch/arm/mach-nspire/touchpad.c
> + *
> + *     Copyright (C) 2012 Fabian Vogt <fabian@ritter-vogt.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2, as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/i2c.h>
> +
> +#include "touchpad.h"
> +
> +#if defined(CONFIG_MOUSE_SYNAPTICS_I2C) || \
> +       defined(CONFIG_MOUSE_SYNAPTICS_I2C_MODULE)
> +static struct i2c_board_info synaptics_i2c = {
> +       I2C_BOARD_INFO("synaptics_i2c", 0x20),
> +       .irq    = 0,
> +};
> +
> +void __init nspire_touchpad_init()
> +{
> +       i2c_register_board_info(0, &synaptics_i2c, 1);
> +}


Not only should this be done from devicetree, but exactly which
synaptics driver are you using with this?

I don't think there is one in the kernel tree yet.

> diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
> index 831e1fd..e76c16b 100644
> --- a/arch/arm/tools/mach-types
> +++ b/arch/arm/tools/mach-types
> @@ -1204,3 +1204,6 @@ baileys                   MACH_BAILEYS            BAILEYS                 4169
>  familybox              MACH_FAMILYBOX          FAMILYBOX               4170
>  ensemble_mx35          MACH_ENSEMBLE_MX35      ENSEMBLE_MX35           4171
>  sc_sps_1               MACH_SC_SPS_1           SC_SPS_1                4172
> +nspireclp              MACH_NSPIRECLP          NSPIRECLP               4441
> +nspiretp               MACH_NSPIRETP           NSPIRETP                4442
> +nspirecx               MACH_NSPIRECX           NSPIRECX                4443

We don't patch this file, Russell updates it from the machine registry on
his webpage.

And with device tree it goes irrelevant.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-07 21:23               ` Arnd Bergmann
  2013-04-08 11:33                 ` Daniel Tang
@ 2013-04-09 11:23                 ` Linus Walleij
  2013-04-09 12:01                   ` Pawel Moll
  1 sibling, 1 reply; 23+ messages in thread
From: Linus Walleij @ 2013-04-09 11:23 UTC (permalink / raw)
  To: Arnd Bergmann, Pawel Moll
  Cc: Daniel Tang, linux-arm-kernel, Russell King - ARM Linux, fabian,
	Lionel Debroux, linux-kernel

On Sun, Apr 7, 2013 at 11:23 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Sunday 07 April 2013, Daniel Tang wrote:
>> Here's an updated patch that enables support for the LCD.
>>
>> I looked into drivers/video/of_display_timing.c but it doesn't have the fields to describe the
>> PL11x specific options needed in struct clcd_panel. At the moment, it is implemented by
>> hardcoding the values in the kernel and using the device tree to select the correct
>> configuration.
>>
>> Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
>
> I think you should for now keep the clcd stuff in a separate file,
> since it will be replaced with DT logic eventually. For now, the
> auxdata method is ok, but Linus Walleij might already have thought
> about how pl111 should get all its data from the device tree.

So last thing I heard there was *someone* at ARM working on
device tree support for the PL110/PL111, so I just don't know who
this was.

But I bet Pawel knows, because it will be needed for all
ARM reference designs.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-09 11:14 ` Linus Walleij
@ 2013-04-09 11:39   ` Daniel Tang
  2013-04-09 11:58     ` Linus Walleij
  0 siblings, 1 reply; 23+ messages in thread
From: Daniel Tang @ 2013-04-09 11:39 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-arm-kernel, Russell King - ARM Linux, linux-kernel, fabian,
	Lionel Debroux

Hi,

Thanks for your comments! They're much appreciated. 

Just to bring you up to speed, we decided to begin reimplementing the machine from scratch and slowly pull things in from the original patch. Arnd pointed out a lot of fundamental issues with our patch so we thought it'd be better to just start over instead of patch things up.

The latest copy of our patch is somewhere in this thread (http://archive.arm.linux.org.uk/lurker/message/20130408.113343.585af217.en.html) which will have already addressed some of the problems you've pointed out (using the device tree being a major one). We would also appreciate it if you could take a look at that one too.

On 09/04/2013, at 9:14 PM, Linus Walleij <linus.walleij@linaro.org> wrote:

>> 
>> +union reg_clk_speed {
>> +       unsigned long raw;
>> +       struct {
>> +               unsigned long __padding0:1;
>> +               unsigned long base_cpu_ratio:7;
>> +               unsigned long is_base_27mhz:1;
>> +               unsigned long __padding1:3;
>> +               unsigned long cpu_ahb_ratio:3;
>> +               unsigned long __padding2:1;
>> +               unsigned long base_val:5;
>> +       } val;
>> +};
> Usually to try to fit a struct over a register range is not such a good
> idea in Linux.
> 
> Instead define abstract representations of what you want to do
> (remove everything named "padding" above, use proper data types instead
> of these unsigned longs and that complex union) then use offsets to
> registers and remap the base offset in memory.
> 
> It makes for simpler debugging and ability to properly use read|write[lwb]
> macros.

The structure is actually a bitfield. We'd readl() the raw unsigned long into the 'raw' field and then access the data via the 'val' structure. 

Should we be using bitmasks and bitshifting to get at those values instead?

> 
>> +static unsigned long classic_clocks_to_io(struct nspire_clk_speeds *clks)
>> +{
>> +       union reg_clk_speed reg;
>> +
>> +       BUG_ON(clks->div.base_cpu < 2);
>> +       BUG_ON(clks->div.cpu_ahb < 1);
>> +
>> +       reg.raw = 0;
>> +       reg.val.base_cpu_ratio = clks->div.base_cpu / 2;
>> +       reg.val.cpu_ahb_ratio = clks->div.cpu_ahb - 1;
>> +       reg.val.is_base_27mhz = (clks->base <= 27000000);
>> +       reg.val.base_val = (300 - (clks->base / 1000000)) / 6;
>> +
>> +       return reg.raw;
>> +}
> 
> And that avoid having to create special helper functions like this.
> 

Fair enough.

> 
>> +               int irqnr = readl(base + 0x24);
>> +               unsigned prev_priority;
>> +               handle_IRQ(irqnr, regs);
>> +
>> +               /* Reset priorities */
>> +               prev_priority = readl(IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x28));
>> +               writel(prev_priority, IOMEM(NSPIRE_INTERRUPT_VIRT_BASE + 0x2c));
>> +               return 1;
>> +       }
>> +       return 0;
>> +}
> 
> I don't understand this, put in  some explanation of what this function
> does please.

Yep gotcha. In future patches, we'll also put the magic numbers into proper defines.

> 
>> +asmlinkage void __exception_irq_entry
>> +       nspire_classic_handle_irq(struct pt_regs *regs)
>> +{
>> +       int serviced;
>> +
>> +       do {
>> +               void __iomem *reg_base = IOMEM(NSPIRE_INTERRUPT_VIRT_BASE);
> 
> Instead of casting this in every IRQ entry define a static local
> in the irq driver file to point to the base.
> 
> Avoids time in the IRQ handler, so it obviously the right thing to do.
> 
> Please also use a dynamic remapping ioremap* insteaf of
> this static IOMEM() thing.
> 
>> +               serviced = 0;
>> +
>> +               /* IRQ */
>> +               serviced += check_interrupt(reg_base, regs);
>> +               /* FIQ */
>> +               serviced += check_interrupt(reg_base + 0x100, regs);
> 
> Should you now handle FIQs first at all times?

Ah yes, that would make sense.

> 
> Hm, looks like you just forgot to select GENERIC_CLOCKEVENTS?
> 
> Strange if it works anyway :-/
> 
> We are comtemplating putting these things into drivers/timer,
> nothing decided yet.

That's fine, we'll deal with it when we pull this file into the 'good' patch.

> 
> Not only should this be done from devicetree, but exactly which
> synaptics driver are you using with this?
> 
> I don't think there is one in the kernel tree yet.
> 

It's this one here http://lxr.free-electrons.com/source/drivers/input/mouse/synaptics_i2c.c
> 
> 
> And with device tree it goes irrelevant.

Yep, this has been addressed in our updated patch.

> 
> Yours,
> Linus Walleij


Also, how would you like us to submit updates? Should we continue posting updated patches as replies to this thread?

Cheers,
tangrs

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-09 11:39   ` Daniel Tang
@ 2013-04-09 11:58     ` Linus Walleij
  0 siblings, 0 replies; 23+ messages in thread
From: Linus Walleij @ 2013-04-09 11:58 UTC (permalink / raw)
  To: Daniel Tang
  Cc: linux-arm-kernel, Russell King - ARM Linux, linux-kernel, fabian,
	Lionel Debroux

On Tue, Apr 9, 2013 at 1:39 PM, Daniel Tang <dt.tangr@gmail.com> wrote:

>>> +union reg_clk_speed {
>>> +       unsigned long raw;
>>> +       struct {
>>> +               unsigned long __padding0:1;
>>> +               unsigned long base_cpu_ratio:7;
>>> +               unsigned long is_base_27mhz:1;
>>> +               unsigned long __padding1:3;
>>> +               unsigned long cpu_ahb_ratio:3;
>>> +               unsigned long __padding2:1;
>>> +               unsigned long base_val:5;
>>> +       } val;
>>> +};
>>
>> Usually to try to fit a struct over a register range is not such a good
>> idea in Linux.
>>
>> Instead define abstract representations of what you want to do
>> (remove everything named "padding" above, use proper data types instead
>> of these unsigned longs and that complex union) then use offsets to
>> registers and remap the base offset in memory.
>>
>> It makes for simpler debugging and ability to properly use read|write[lwb]
>> macros.
>
> The structure is actually a bitfield. We'd readl() the raw unsigned long into the 'raw' field and then access the data via the 'val' structure.
>
> Should we be using bitmasks and bitshifting to get at those values instead?

I personally think that is better because it avoids complex structures
and strange helper functions.

When it really shows it's ugly face is when you get a second generation
of the hardware that have some other bits in slightly different places,
and you have to create another struct to map a small difference instead
of being able to just tweak the code slightly.

>> Not only should this be done from devicetree, but exactly which
>> synaptics driver are you using with this?
>>
>> I don't think there is one in the kernel tree yet.
>>
>
> It's this one here http://lxr.free-electrons.com/source/drivers/input/mouse/synaptics_i2c.c

Aha I thought it was one of those modern RMI4 things.
OK then...

> Also, how would you like us to submit updates? Should we continue posting updated patches as replies to this thread?

Just repost it somehow, include relevant people on To/Cc. No need
to use the same thread I think?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-09 11:23                 ` Linus Walleij
@ 2013-04-09 12:01                   ` Pawel Moll
  2013-04-09 12:05                     ` Linus Walleij
  2013-04-09 13:51                     ` Russell King - ARM Linux
  0 siblings, 2 replies; 23+ messages in thread
From: Pawel Moll @ 2013-04-09 12:01 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Arnd Bergmann, Daniel Tang, linux-arm-kernel,
	Russell King - ARM Linux, fabian, Lionel Debroux, linux-kernel

On Tue, 2013-04-09 at 12:23 +0100, Linus Walleij wrote:
> On Sun, Apr 7, 2013 at 11:23 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Sunday 07 April 2013, Daniel Tang wrote:
> >> Here's an updated patch that enables support for the LCD.
> >>
> >> I looked into drivers/video/of_display_timing.c but it doesn't have the fields to describe the
> >> PL11x specific options needed in struct clcd_panel. At the moment, it is implemented by
> >> hardcoding the values in the kernel and using the device tree to select the correct
> >> configuration.
> >>
> >> Signed-off-by: Daniel Tang <dt.tangr@gmail.com>
> >
> > I think you should for now keep the clcd stuff in a separate file,
> > since it will be replaced with DT logic eventually. For now, the
> > auxdata method is ok, but Linus Walleij might already have thought
> > about how pl111 should get all its data from the device tree.
> 
> So last thing I heard there was *someone* at ARM working on
> device tree support for the PL110/PL111, so I just don't know who
> this was.
> 
> But I bet Pawel knows, because it will be needed for all
> ARM reference designs.

So I have PL111 code almost working here, however today it depends on
not-yet-upstream (to my knowledge) generic/common panel/display
framework. If I'm not disturbed again I may get something done this
week, hopefully removing the dependency.

There's also some work going on on a DRM driver for PL111, but I can't
promise any dates.

As to PL110 I have no idea how different is it from the PL111, but
nothing is happening about it anyway.

Paweł



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-09 12:01                   ` Pawel Moll
@ 2013-04-09 12:05                     ` Linus Walleij
  2013-04-09 13:51                     ` Russell King - ARM Linux
  1 sibling, 0 replies; 23+ messages in thread
From: Linus Walleij @ 2013-04-09 12:05 UTC (permalink / raw)
  To: Pawel Moll
  Cc: Arnd Bergmann, Daniel Tang, linux-arm-kernel,
	Russell King - ARM Linux, fabian, Lionel Debroux, linux-kernel

On Tue, Apr 9, 2013 at 2:01 PM, Pawel Moll <pawel.moll@arm.com> wrote:

> As to PL110 I have no idea how different is it from the PL111, but
> nothing is happening about it anyway.

I have that on my Integrator/CP (in working condition!) so I will
be able to test it as it arrives, but basically I think the panel
model will be the same.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH arm: initial TI-Nspire support]
  2013-04-09 12:01                   ` Pawel Moll
  2013-04-09 12:05                     ` Linus Walleij
@ 2013-04-09 13:51                     ` Russell King - ARM Linux
  1 sibling, 0 replies; 23+ messages in thread
From: Russell King - ARM Linux @ 2013-04-09 13:51 UTC (permalink / raw)
  To: Pawel Moll
  Cc: Linus Walleij, Arnd Bergmann, Daniel Tang, linux-arm-kernel,
	fabian, Lionel Debroux, linux-kernel

On Tue, Apr 09, 2013 at 01:01:56PM +0100, Pawel Moll wrote:
> So I have PL111 code almost working here, however today it depends on
> not-yet-upstream (to my knowledge) generic/common panel/display
> framework. If I'm not disturbed again I may get something done this
> week, hopefully removing the dependency.
> 
> There's also some work going on on a DRM driver for PL111, but I can't
> promise any dates.
> 
> As to PL110 I have no idea how different is it from the PL111, but
> nothing is happening about it anyway.

If you're doing PL111, then you might as well do PL110, because the two
are basically the same.  But note that all PL111's aren't equal.  Some
are closer to PL110 than the current PL111, so if you want to support
all PL111s, you also need to have the support in place for PL110.

Also note that the way the bits are assigned in the frame buffer varies
between platforms, and most certainly the TRMs documentation of colour
bitfield layouts can _not_ be relied upon.

I have considerable knowledge in this area, but as seems to be the norm
now, no one cares about that.  I'll go back to twiddling my thumbs now,
waiting for the next email to arrive.  Or maybe I'll go down to the
shops and wander around down there.  Or something.

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2013-04-09 13:52 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-04  9:01 [RFC PATCH arm: initial TI-Nspire support] Daniel Tang
2013-04-04 11:12 ` Arnd Bergmann
2013-04-06  0:26   ` Daniel Tang
2013-04-06 11:51     ` Arnd Bergmann
2013-04-06 12:00       ` Daniel Tang
2013-04-06 13:24         ` Arnd Bergmann
2013-04-07  0:06           ` Daniel Tang
2013-04-07  3:56             ` Daniel Tang
2013-04-07 21:23               ` Arnd Bergmann
2013-04-08 11:33                 ` Daniel Tang
2013-04-08 19:16                   ` Fabian Vogt
2013-04-08 19:38                     ` Arnd Bergmann
2013-04-08 20:06                       ` Fabian Vogt
2013-04-08 21:29                         ` Arnd Bergmann
2013-04-09  5:59                     ` Daniel Tang
2013-04-09 11:23                 ` Linus Walleij
2013-04-09 12:01                   ` Pawel Moll
2013-04-09 12:05                     ` Linus Walleij
2013-04-09 13:51                     ` Russell King - ARM Linux
2013-04-07 14:32             ` Arnd Bergmann
2013-04-09 11:14 ` Linus Walleij
2013-04-09 11:39   ` Daniel Tang
2013-04-09 11:58     ` Linus Walleij

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).