From 18801be7f805b891876a6676ec7fac2e1acdec13 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 25 Dec 2008 18:17:09 +0900
Subject: sh: make gpio_get/set_value() O(1)

This patch modifies the table based SuperH gpio implementation to
make use of direct table lookups. With this change the functions
gpio_get_value() and gpio_set_value() are O(1).

Tested on Migo-R using bitbanging mmc. Performance is improved from
11 KBytes/s to 26 Kbytes/s.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/gpio.c | 48 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 11 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c
index d3716536103..fe92ba151b8 100644
--- a/arch/sh/kernel/gpio.c
+++ b/arch/sh/kernel/gpio.c
@@ -95,14 +95,13 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width,
 	return 0;
 }
 
-static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
-			struct pinmux_data_reg **drp, int *bitp)
+static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
 {
-	pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
+	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
 	struct pinmux_data_reg *data_reg;
 	int k, n;
 
-	if (!enum_in_range(enum_id, &gpioc->data))
+	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
 		return -1;
 
 	k = 0;
@@ -113,19 +112,38 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
 			break;
 
 		for (n = 0; n < data_reg->reg_width; n++) {
-			if (data_reg->enum_ids[n] == enum_id) {
-				*drp = data_reg;
-				*bitp = n;
+			if (data_reg->enum_ids[n] == gpiop->enum_id) {
+				gpiop->flags &= ~PINMUX_FLAG_DREG;
+				gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
+				gpiop->flags &= ~PINMUX_FLAG_DBIT;
+				gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
 				return 0;
-
 			}
 		}
 		k++;
 	}
 
+	BUG();
+
 	return -1;
 }
 
+static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
+			struct pinmux_data_reg **drp, int *bitp)
+{
+	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
+	int k, n;
+
+	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
+		return -1;
+
+	k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
+	n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
+	*drp = gpioc->data_regs + k;
+	*bitp = n;
+	return 0;
+}
+
 static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
 			  struct pinmux_cfg_reg **crp, int *indexp,
 			  unsigned long **cntp)
@@ -341,7 +359,8 @@ int __gpio_request(unsigned gpio)
 			BUG();
 	}
 
-	gpioc->gpios[gpio].flags = pinmux_type;
+	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+	gpioc->gpios[gpio].flags |= pinmux_type;
 
 	ret = 0;
  err_unlock:
@@ -364,7 +383,8 @@ void gpio_free(unsigned gpio)
 
 	pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
 	pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
-	gpioc->gpios[gpio].flags = PINMUX_TYPE_NONE;
+	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+	gpioc->gpios[gpio].flags |= PINMUX_TYPE_NONE;
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 }
@@ -401,7 +421,8 @@ static int pinmux_direction(struct pinmux_info *gpioc,
 			       GPIO_CFG_REQ) != 0)
 		BUG();
 
-	gpioc->gpios[gpio].flags = new_pinmux_type;
+	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
+	gpioc->gpios[gpio].flags |= new_pinmux_type;
 
 	ret = 0;
  err_out:
@@ -494,9 +515,14 @@ EXPORT_SYMBOL(gpio_set_value);
 
 int register_pinmux(struct pinmux_info *pip)
 {
+	int k;
+
 	registered_gpio = pip;
 	pr_info("pinmux: %s handling gpio %d -> %d\n",
 		pip->name, pip->first_gpio, pip->last_gpio);
 
+	for (k = pip->first_gpio; k <= pip->last_gpio; k++)
+		setup_data_reg(pip, k);
+
 	return 0;
 }
-- 
cgit v1.2.3-18-g5258


From 0fc64cc0a27288e77ee8e12648d59632649371fc Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 25 Dec 2008 18:17:18 +0900
Subject: sh: lockless gpio_get_value()

This patch separates the register read and write functions to
allow lockless gpio_get_value().

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/gpio.c | 126 +++++++++++++++++++++++++-------------------------
 1 file changed, 63 insertions(+), 63 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c
index fe92ba151b8..f8397a09491 100644
--- a/arch/sh/kernel/gpio.c
+++ b/arch/sh/kernel/gpio.c
@@ -46,9 +46,8 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
 	return 1;
 }
 
-static int read_write_reg(unsigned long reg, unsigned long reg_width,
-			  unsigned long field_width, unsigned long in_pos,
-			  unsigned long value, int do_write)
+static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
+			 unsigned long field_width, unsigned long in_pos)
 {
 	unsigned long data, mask, pos;
 
@@ -57,10 +56,9 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width,
 	pos = reg_width - ((in_pos + 1) * field_width);
 
 #ifdef DEBUG
-	pr_info("%s, addr = %lx, value = %ld, pos = %ld, "
+	pr_info("read_reg: addr = %lx, pos = %ld, "
 		"r_width = %ld, f_width = %ld\n",
-		do_write ? "write" : "read", reg, value, pos,
-		reg_width, field_width);
+		reg, pos, reg_width, field_width);
 #endif
 
 	switch (reg_width) {
@@ -75,24 +73,38 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width,
 		break;
 	}
 
-	if (!do_write)
-		return (data >> pos) & mask;
+	return (data >> pos) & mask;
+}
+
+static void gpio_write_reg(unsigned long reg, unsigned long reg_width,
+			   unsigned long field_width, unsigned long in_pos,
+			   unsigned long value)
+{
+	unsigned long mask, pos;
+
+	mask = (1 << field_width) - 1;
+	pos = reg_width - ((in_pos + 1) * field_width);
 
-	data &= ~(mask << pos);
-	data |= value << pos;
+#ifdef DEBUG
+	pr_info("write_reg addr = %lx, value = %ld, pos = %ld, "
+		"r_width = %ld, f_width = %ld\n",
+		reg, value, pos, reg_width, field_width);
+#endif
+
+	mask = ~(mask << pos);
+	value = value << pos;
 
 	switch (reg_width) {
 	case 8:
-		ctrl_outb(data, reg);
+		ctrl_outb((ctrl_inb(reg) & mask) | value, reg);
 		break;
 	case 16:
-		ctrl_outw(data, reg);
+		ctrl_outw((ctrl_inw(reg) & mask) | value, reg);
 		break;
 	case 32:
-		ctrl_outl(data, reg);
+		ctrl_outl((ctrl_inl(reg) & mask) | value, reg);
 		break;
 	}
-	return 0;
 }
 
 static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
@@ -205,9 +217,9 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
 	return -1;
 }
 
-static int write_config_reg(struct pinmux_info *gpioc,
-			    struct pinmux_cfg_reg *crp,
-			    int index)
+static void write_config_reg(struct pinmux_info *gpioc,
+			     struct pinmux_cfg_reg *crp,
+			     int index)
 {
 	unsigned long ncomb, pos, value;
 
@@ -215,8 +227,7 @@ static int write_config_reg(struct pinmux_info *gpioc,
 	pos = index / ncomb;
 	value = index % ncomb;
 
-	return read_write_reg(crp->reg, crp->reg_width,
-			      crp->field_width, pos, value, 1);
+	gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value);
 }
 
 static int check_config_reg(struct pinmux_info *gpioc,
@@ -229,8 +240,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
 	pos = index / ncomb;
 	value = index % ncomb;
 
-	if (read_write_reg(crp->reg, crp->reg_width,
-			   crp->field_width, pos, 0, 0) == value)
+	if (gpio_read_reg(crp->reg, crp->reg_width,
+			  crp->field_width, pos) == value)
 		return 0;
 
 	return -1;
@@ -238,8 +249,8 @@ static int check_config_reg(struct pinmux_info *gpioc,
 
 enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
 
-int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
-		       int pinmux_type, int cfg_mode)
+static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
+			      int pinmux_type, int cfg_mode)
 {
 	struct pinmux_cfg_reg *cr = NULL;
 	pinmux_enum_t enum_id;
@@ -305,8 +316,7 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 			break;
 
 		case GPIO_CFG_REQ:
-			if (write_config_reg(gpioc, cr, index) != 0)
-				goto out_err;
+			write_config_reg(gpioc, cr, index);
 			*cntp = *cntp + 1;
 			break;
 
@@ -393,9 +403,12 @@ EXPORT_SYMBOL(gpio_free);
 static int pinmux_direction(struct pinmux_info *gpioc,
 			    unsigned gpio, int new_pinmux_type)
 {
-	int ret, pinmux_type;
+	int pinmux_type;
+	int ret = -EINVAL;
+
+	if (!gpioc)
+		goto err_out;
 
-	ret = -EINVAL;
 	pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
 
 	switch (pinmux_type) {
@@ -433,68 +446,59 @@ int gpio_direction_input(unsigned gpio)
 {
 	struct pinmux_info *gpioc = gpio_controller(gpio);
 	unsigned long flags;
-	int ret = -EINVAL;
-
-	if (!gpioc)
-		goto err_out;
+	int ret;
 
 	spin_lock_irqsave(&gpio_lock, flags);
 	ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT);
 	spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
 	return ret;
 }
 EXPORT_SYMBOL(gpio_direction_input);
 
-static int __gpio_get_set_value(struct pinmux_info *gpioc,
-				unsigned gpio, int value,
-				int do_write)
+static void __gpio_set_value(struct pinmux_info *gpioc,
+			     unsigned gpio, int value)
 {
 	struct pinmux_data_reg *dr = NULL;
 	int bit = 0;
 
-	if (get_data_reg(gpioc, gpio, &dr, &bit) != 0)
+	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
 		BUG();
 	else
-		value = read_write_reg(dr->reg, dr->reg_width,
-				       1, bit, !!value, do_write);
-
-	return value;
+		gpio_write_reg(dr->reg, dr->reg_width, 1, bit, !!value);
 }
 
 int gpio_direction_output(unsigned gpio, int value)
 {
 	struct pinmux_info *gpioc = gpio_controller(gpio);
 	unsigned long flags;
-	int ret = -EINVAL;
-
-	if (!gpioc)
-		goto err_out;
+	int ret;
 
 	spin_lock_irqsave(&gpio_lock, flags);
-	__gpio_get_set_value(gpioc, gpio, value, 1);
+	__gpio_set_value(gpioc, gpio, value);
 	ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
 	spin_unlock_irqrestore(&gpio_lock, flags);
- err_out:
+
 	return ret;
 }
 EXPORT_SYMBOL(gpio_direction_output);
 
-int gpio_get_value(unsigned gpio)
+static int __gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
-	unsigned long flags;
-	int value = 0;
+	struct pinmux_data_reg *dr = NULL;
+	int bit = 0;
 
-	if (!gpioc)
+	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) {
 		BUG();
-	else {
-		spin_lock_irqsave(&gpio_lock, flags);
-		value = __gpio_get_set_value(gpioc, gpio, 0, 0);
-		spin_unlock_irqrestore(&gpio_lock, flags);
+		return 0;
 	}
 
-	return value;
+	return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio_controller(gpio), gpio);
 }
 EXPORT_SYMBOL(gpio_get_value);
 
@@ -503,13 +507,9 @@ void gpio_set_value(unsigned gpio, int value)
 	struct pinmux_info *gpioc = gpio_controller(gpio);
 	unsigned long flags;
 
-	if (!gpioc)
-		BUG();
-	else {
-		spin_lock_irqsave(&gpio_lock, flags);
-		__gpio_get_set_value(gpioc, gpio, value, 1);
-		spin_unlock_irqrestore(&gpio_lock, flags);
-	}
+	spin_lock_irqsave(&gpio_lock, flags);
+	__gpio_set_value(gpioc, gpio, value);
+	spin_unlock_irqrestore(&gpio_lock, flags);
 }
 EXPORT_SYMBOL(gpio_set_value);
 
-- 
cgit v1.2.3-18-g5258


From 3292094e88ce6b76714dad8ec4b43d7c5c12ada2 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 25 Dec 2008 18:17:26 +0900
Subject: sh: lockless gpio_set_value()

This patch optimizes the gpio data register handling for gpio_set_value().

Instead of using the good old spinlock-plus-read-modify-write strategy
we now use a shadow register and atomic operations.

This improves the bitbanging mmc performance on Migo-R from 26 Kbytes/s
to 40 Kbytes/s.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/gpio.c | 106 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 81 insertions(+), 25 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c
index f8397a09491..28013567372 100644
--- a/arch/sh/kernel/gpio.c
+++ b/arch/sh/kernel/gpio.c
@@ -46,6 +46,62 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
 	return 1;
 }
 
+static unsigned long gpio_read_raw_reg(unsigned long reg,
+				       unsigned long reg_width)
+{
+	switch (reg_width) {
+	case 8:
+		return ctrl_inb(reg);
+	case 16:
+		return ctrl_inw(reg);
+	case 32:
+		return ctrl_inl(reg);
+	}
+
+	BUG();
+	return 0;
+}
+
+static void gpio_write_raw_reg(unsigned long reg,
+			       unsigned long reg_width,
+			       unsigned long data)
+{
+	switch (reg_width) {
+	case 8:
+		ctrl_outb(data, reg);
+		return;
+	case 16:
+		ctrl_outw(data, reg);
+		return;
+	case 32:
+		ctrl_outl(data, reg);
+		return;
+	}
+
+	BUG();
+}
+
+static void gpio_write_bit(struct pinmux_data_reg *dr,
+			   unsigned long in_pos, unsigned long value)
+{
+	unsigned long pos;
+
+	pos = dr->reg_width - (in_pos + 1);
+
+#ifdef DEBUG
+	pr_info("write_bit addr = %lx, value = %ld, pos = %ld, "
+		"r_width = %ld\n",
+		dr->reg, !!value, pos, dr->reg_width);
+#endif
+
+	if (value)
+		set_bit(pos, &dr->reg_shadow);
+	else
+		clear_bit(pos, &dr->reg_shadow);
+
+	gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
+}
+
 static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
 			 unsigned long field_width, unsigned long in_pos)
 {
@@ -61,18 +117,7 @@ static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
 		reg, pos, reg_width, field_width);
 #endif
 
-	switch (reg_width) {
-	case 8:
-		data = ctrl_inb(reg);
-		break;
-	case 16:
-		data = ctrl_inw(reg);
-		break;
-	case 32:
-		data = ctrl_inl(reg);
-		break;
-	}
-
+	data = gpio_read_raw_reg(reg, reg_width);
 	return (data >> pos) & mask;
 }
 
@@ -140,6 +185,26 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
 	return -1;
 }
 
+static void setup_data_regs(struct pinmux_info *gpioc)
+{
+	struct pinmux_data_reg *drp;
+	int k;
+
+	for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
+		setup_data_reg(gpioc, k);
+
+	k = 0;
+	while (1) {
+		drp = gpioc->data_regs + k;
+
+		if (!drp->reg_width)
+			break;
+
+		drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
+		k++;
+	}
+}
+
 static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
 			struct pinmux_data_reg **drp, int *bitp)
 {
@@ -465,7 +530,7 @@ static void __gpio_set_value(struct pinmux_info *gpioc,
 	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
 		BUG();
 	else
-		gpio_write_reg(dr->reg, dr->reg_width, 1, bit, !!value);
+		gpio_write_bit(dr, bit, value);
 }
 
 int gpio_direction_output(unsigned gpio, int value)
@@ -474,8 +539,8 @@ int gpio_direction_output(unsigned gpio, int value)
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&gpio_lock, flags);
 	__gpio_set_value(gpioc, gpio, value);
+	spin_lock_irqsave(&gpio_lock, flags);
 	ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
@@ -504,25 +569,16 @@ EXPORT_SYMBOL(gpio_get_value);
 
 void gpio_set_value(unsigned gpio, int value)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
-	unsigned long flags;
-
-	spin_lock_irqsave(&gpio_lock, flags);
-	__gpio_set_value(gpioc, gpio, value);
-	spin_unlock_irqrestore(&gpio_lock, flags);
+	__gpio_set_value(gpio_controller(gpio), gpio, value);
 }
 EXPORT_SYMBOL(gpio_set_value);
 
 int register_pinmux(struct pinmux_info *pip)
 {
-	int k;
-
 	registered_gpio = pip;
+	setup_data_regs(pip);
 	pr_info("pinmux: %s handling gpio %d -> %d\n",
 		pip->name, pip->first_gpio, pip->last_gpio);
 
-	for (k = pip->first_gpio; k <= pip->last_gpio; k++)
-		setup_data_reg(pip, k);
-
 	return 0;
 }
-- 
cgit v1.2.3-18-g5258


From 69edbba0021a48fe034849501513930f6175cb5d Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 25 Dec 2008 18:17:34 +0900
Subject: sh: use gpiolib

This patch updates the SuperH gpio code to make use of gpiolib. The
gpiolib callbacks get() and set() are lockless, but we use our own
spinlock for the other operations to make sure hardware register
bitfield accesses stay atomic.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/Makefile_32 |   2 +-
 arch/sh/kernel/Makefile_64 |   2 +-
 arch/sh/kernel/gpio.c      | 106 ++++++++++++++++++++++-----------------------
 3 files changed, 55 insertions(+), 55 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
index 2e1b86e16ab..7e7d22b5b4c 100644
--- a/arch/sh/kernel/Makefile_32
+++ b/arch/sh/kernel/Makefile_32
@@ -27,7 +27,7 @@ obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
-obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+obj-$(CONFIG_ARCH_REQUIRE_GPIOLIB)	+= gpio.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
 obj-$(CONFIG_DUMP_CODE)		+= disassemble.o
 
diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64
index fe425d7f687..cbcbbb6c049 100644
--- a/arch/sh/kernel/Makefile_64
+++ b/arch/sh/kernel/Makefile_64
@@ -15,6 +15,6 @@ obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
-obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+obj-$(CONFIG_ARCH_REQUIRE_GPIOLIB)	+= gpio.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c
index 28013567372..d22e5af699f 100644
--- a/arch/sh/kernel/gpio.c
+++ b/arch/sh/kernel/gpio.c
@@ -19,22 +19,6 @@
 #include <linux/bitops.h>
 #include <linux/gpio.h>
 
-static struct pinmux_info *registered_gpio;
-
-static struct pinmux_info *gpio_controller(unsigned gpio)
-{
-	if (!registered_gpio)
-		return NULL;
-
-	if (gpio < registered_gpio->first_gpio)
-		return NULL;
-
-	if (gpio > registered_gpio->last_gpio)
-		return NULL;
-
-	return registered_gpio;
-}
-
 static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
 {
 	if (enum_id < r->begin)
@@ -398,9 +382,14 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
 
 static DEFINE_SPINLOCK(gpio_lock);
 
-int __gpio_request(unsigned gpio)
+static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
+	return container_of(chip, struct pinmux_info, chip);
+}
+
+static int sh_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct pinmux_info *gpioc = chip_to_pinmux(chip);
 	struct pinmux_data_reg *dummy;
 	unsigned long flags;
 	int i, ret, pinmux_type;
@@ -412,30 +401,30 @@ int __gpio_request(unsigned gpio)
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
+	if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
 		goto err_unlock;
 
 	/* setup pin function here if no data is associated with pin */
 
-	if (get_data_reg(gpioc, gpio, &dummy, &i) != 0)
+	if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
 		pinmux_type = PINMUX_TYPE_FUNCTION;
 	else
 		pinmux_type = PINMUX_TYPE_GPIO;
 
 	if (pinmux_type == PINMUX_TYPE_FUNCTION) {
-		if (pinmux_config_gpio(gpioc, gpio,
+		if (pinmux_config_gpio(gpioc, offset,
 				       pinmux_type,
 				       GPIO_CFG_DRYRUN) != 0)
 			goto err_unlock;
 
-		if (pinmux_config_gpio(gpioc, gpio,
+		if (pinmux_config_gpio(gpioc, offset,
 				       pinmux_type,
 				       GPIO_CFG_REQ) != 0)
 			BUG();
 	}
 
-	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
-	gpioc->gpios[gpio].flags |= pinmux_type;
+	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+	gpioc->gpios[offset].flags |= pinmux_type;
 
 	ret = 0;
  err_unlock:
@@ -443,11 +432,10 @@ int __gpio_request(unsigned gpio)
  err_out:
 	return ret;
 }
-EXPORT_SYMBOL(__gpio_request);
 
-void gpio_free(unsigned gpio)
+static void sh_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
+	struct pinmux_info *gpioc = chip_to_pinmux(chip);
 	unsigned long flags;
 	int pinmux_type;
 
@@ -456,14 +444,13 @@ void gpio_free(unsigned gpio)
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
-	pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
-	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
-	gpioc->gpios[gpio].flags |= PINMUX_TYPE_NONE;
+	pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
+	pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
+	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
+	gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 }
-EXPORT_SYMBOL(gpio_free);
 
 static int pinmux_direction(struct pinmux_info *gpioc,
 			    unsigned gpio, int new_pinmux_type)
@@ -507,21 +494,20 @@ static int pinmux_direction(struct pinmux_info *gpioc,
 	return ret;
 }
 
-int gpio_direction_input(unsigned gpio)
+static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
+	struct pinmux_info *gpioc = chip_to_pinmux(chip);
 	unsigned long flags;
 	int ret;
 
 	spin_lock_irqsave(&gpio_lock, flags);
-	ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT);
+	ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	return ret;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
-static void __gpio_set_value(struct pinmux_info *gpioc,
+static void sh_gpio_set_value(struct pinmux_info *gpioc,
 			     unsigned gpio, int value)
 {
 	struct pinmux_data_reg *dr = NULL;
@@ -533,22 +519,22 @@ static void __gpio_set_value(struct pinmux_info *gpioc,
 		gpio_write_bit(dr, bit, value);
 }
 
-int gpio_direction_output(unsigned gpio, int value)
+static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+				    int value)
 {
-	struct pinmux_info *gpioc = gpio_controller(gpio);
+	struct pinmux_info *gpioc = chip_to_pinmux(chip);
 	unsigned long flags;
 	int ret;
 
-	__gpio_set_value(gpioc, gpio, value);
+	sh_gpio_set_value(gpioc, offset, value);
 	spin_lock_irqsave(&gpio_lock, flags);
-	ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
+	ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
 	return ret;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
-static int __gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
+static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
 {
 	struct pinmux_data_reg *dr = NULL;
 	int bit = 0;
@@ -561,24 +547,38 @@ static int __gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
 	return gpio_read_reg(dr->reg, dr->reg_width, 1, bit);
 }
 
-int gpio_get_value(unsigned gpio)
+static int sh_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	return __gpio_get_value(gpio_controller(gpio), gpio);
+	return sh_gpio_get_value(chip_to_pinmux(chip), offset);
 }
-EXPORT_SYMBOL(gpio_get_value);
 
-void gpio_set_value(unsigned gpio, int value)
+static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	__gpio_set_value(gpio_controller(gpio), gpio, value);
+	sh_gpio_set_value(chip_to_pinmux(chip), offset, value);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
 int register_pinmux(struct pinmux_info *pip)
 {
-	registered_gpio = pip;
-	setup_data_regs(pip);
-	pr_info("pinmux: %s handling gpio %d -> %d\n",
+	struct gpio_chip *chip = &pip->chip;
+
+	pr_info("sh pinmux: %s handling gpio %d -> %d\n",
 		pip->name, pip->first_gpio, pip->last_gpio);
 
-	return 0;
+	setup_data_regs(pip);
+
+	chip->request = sh_gpio_request;
+	chip->free = sh_gpio_free;
+	chip->direction_input = sh_gpio_direction_input;
+	chip->get = sh_gpio_get;
+	chip->direction_output = sh_gpio_direction_output;
+	chip->set = sh_gpio_set;
+
+	WARN_ON(pip->first_gpio != 0); /* needs testing */
+
+	chip->label = pip->name;
+	chip->owner = THIS_MODULE;
+	chip->base = pip->first_gpio;
+	chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1;
+
+	return gpiochip_add(chip);
 }
-- 
cgit v1.2.3-18-g5258


From 57e97cb8bedd06e8a2e562454423d58aab5827ce Mon Sep 17 00:00:00 2001
From: Paul Mundt <lethal@linux-sh.org>
Date: Tue, 6 Jan 2009 12:47:12 +0900
Subject: sh: Fix up GENERIC_GPIO build for ARCH_WANT_OPTIONAL_GPIO cases.

CPUs define pinmux tables through the optional interface, while boards
that require demux of their own require it explicitly. Roll the Makefile
rules back to depend on GENERIC_GPIO, which covers both cases.

Fixes a link error with an undefined reference to register_pinmux() on
optional platforms.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/Makefile_32 | 2 +-
 arch/sh/kernel/Makefile_64 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32
index 7e7d22b5b4c..2e1b86e16ab 100644
--- a/arch/sh/kernel/Makefile_32
+++ b/arch/sh/kernel/Makefile_32
@@ -27,7 +27,7 @@ obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
-obj-$(CONFIG_ARCH_REQUIRE_GPIOLIB)	+= gpio.o
+obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
 obj-$(CONFIG_DUMP_CODE)		+= disassemble.o
 
diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64
index cbcbbb6c049..fe425d7f687 100644
--- a/arch/sh/kernel/Makefile_64
+++ b/arch/sh/kernel/Makefile_64
@@ -15,6 +15,6 @@ obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_IO_TRAPPED)	+= io_trapped.o
-obj-$(CONFIG_ARCH_REQUIRE_GPIOLIB)	+= gpio.o
+obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
 
 EXTRA_CFLAGS += -Werror
-- 
cgit v1.2.3-18-g5258


From 955c0778723501cc16fec40501cd54b7e72d3e74 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 22 Jan 2009 09:55:31 +0000
Subject: sh: rework clocksource and sched_clock

Rework and simplify the sched_clock and clocksource code. Instead
of registering the clocksource in a shared file we move it into the
tmu driver. Also, add code to handle sched_clock in the case of no
clocksource.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/time_32.c          | 59 ++++++---------------------------------
 arch/sh/kernel/timers/timer-tmu.c | 10 +++++--
 2 files changed, 17 insertions(+), 52 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
index 8457f83242c..ca22eef669a 100644
--- a/arch/sh/kernel/time_32.c
+++ b/arch/sh/kernel/time_32.c
@@ -41,14 +41,6 @@ static int null_rtc_set_time(const time_t secs)
 	return 0;
 }
 
-/*
- * Null high precision timer functions for systems lacking one.
- */
-static cycle_t null_hpt_read(void)
-{
-	return 0;
-}
-
 void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
 int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
 
@@ -200,42 +192,21 @@ device_initcall(timer_init_sysfs);
 
 void (*board_time_init)(void);
 
-/*
- * Shamelessly based on the MIPS and Sparc64 work.
- */
-static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-unsigned long sh_hpt_frequency = 0;
-
-#define NSEC_PER_CYC_SHIFT	10
-
-static struct clocksource clocksource_sh = {
+struct clocksource clocksource_sh = {
 	.name		= "SuperH",
-	.rating		= 200,
-	.mask		= CLOCKSOURCE_MASK(32),
-	.read		= null_hpt_read,
-	.shift		= 16,
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static void __init init_sh_clocksource(void)
-{
-	if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
-		return;
-
-	clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
-						  clocksource_sh.shift);
-
-	timer_ticks_per_nsec_quotient =
-		clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
-
-	clocksource_register(&clocksource_sh);
-}
-
 #ifdef CONFIG_GENERIC_TIME
 unsigned long long sched_clock(void)
 {
-	unsigned long long ticks = clocksource_sh.read();
-	return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
+	unsigned long long cycles;
+
+	/* jiffies based sched_clock if no clocksource is installed */
+	if (!clocksource_sh.rating)
+		return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ);
+
+	cycles = clocksource_sh.read();
+	return cyc2ns(&clocksource_sh, cycles);
 }
 #endif
 
@@ -260,16 +231,4 @@ void __init time_init(void)
 	 */
 	sys_timer = get_sys_timer();
 	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-
-
-	if (sys_timer->ops->read)
-		clocksource_sh.read = sys_timer->ops->read;
-
-	init_sh_clocksource();
-
-	if (sh_hpt_frequency)
-		printk("Using %lu.%03lu MHz high precision timer.\n",
-		       ((sh_hpt_frequency + 500) / 1000) / 1000,
-		       ((sh_hpt_frequency + 500) / 1000) % 1000);
-
 }
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 0db3f951033..33a24fcf0a1 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -254,7 +254,14 @@ static int tmu_timer_init(void)
 
 	_tmu_start(TMU1);
 
-	sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+	clocksource_sh.rating = 200;
+	clocksource_sh.mask = CLOCKSOURCE_MASK(32);
+	clocksource_sh.read = tmu_timer_read;
+	clocksource_sh.shift = 10;
+	clocksource_sh.mult = clocksource_hz2mult(clk_get_rate(&tmu1_clk),
+						  clocksource_sh.shift);
+	clocksource_sh.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+	clocksource_register(&clocksource_sh);
 
 	tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
 				      tmu0_clockevent.shift);
@@ -274,7 +281,6 @@ static struct sys_timer_ops tmu_timer_ops = {
 	.init		= tmu_timer_init,
 	.start		= tmu_timer_start,
 	.stop		= tmu_timer_stop,
-	.read		= tmu_timer_read,
 };
 
 struct sys_timer tmu_timer = {
-- 
cgit v1.2.3-18-g5258


From 70f0800133b2a6d694c10908b8673a5327b3bfd6 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 22 Jan 2009 09:55:40 +0000
Subject: sh: tmu disable support

Add TMU disable support so we can use other clockevents.
Also, setup the clockevent rating.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/timers/timer-tmu.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 33a24fcf0a1..2b62f9cff22 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -146,7 +146,14 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
 	_tmu_clear_status(TMU0);
 	_tmu_set_irq(TMU0,tmu0_clockevent.mode != CLOCK_EVT_MODE_ONESHOT);
 
-	evt->event_handler(evt);
+	switch (tmu0_clockevent.mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_PERIODIC:
+		evt->event_handler(evt);
+		break;
+	default:
+		break;
+	}
 
 	return IRQ_HANDLED;
 }
@@ -271,6 +278,7 @@ static int tmu_timer_init(void)
 			clockevent_delta2ns(1, &tmu0_clockevent);
 
 	tmu0_clockevent.cpumask = cpumask_of(0);
+	tmu0_clockevent.rating = 100;
 
 	clockevents_register_device(&tmu0_clockevent);
 
-- 
cgit v1.2.3-18-g5258


From 07821d3310996746a2cf1e9c705ffe64223d1112 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 22 Jan 2009 09:55:49 +0000
Subject: sh: fix no sys_timer case

Handle the case with a sys_timer set to NULL.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/time_32.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
index ca22eef669a..766554ba2a5 100644
--- a/arch/sh/kernel/time_32.c
+++ b/arch/sh/kernel/time_32.c
@@ -181,7 +181,12 @@ static struct sysdev_class timer_sysclass = {
 
 static int __init timer_init_sysfs(void)
 {
-	int ret = sysdev_class_register(&timer_sysclass);
+	int ret;
+
+	if (!sys_timer)
+		return 0;
+
+	ret = sysdev_class_register(&timer_sysclass);
 	if (ret != 0)
 		return ret;
 
@@ -230,5 +235,8 @@ void __init time_init(void)
 	 * initialized for us.
 	 */
 	sys_timer = get_sys_timer();
+	if (unlikely(!sys_timer))
+		panic("System timer missing.\n");
+
 	printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
 }
-- 
cgit v1.2.3-18-g5258


From 424f59d04d7450555ef2bf1eb4a5e2cd2ecf08cd Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Thu, 22 Jan 2009 09:56:09 +0000
Subject: sh: CMT platform data for sh7723/sh7722/sh7366/sh7343

CMT platform data for SuperH Mobile sh7723/sh7722/sh7343/sh7366.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh4a/setup-sh7343.c | 34 ++++++++++++++++++++++++++++++++++
 arch/sh/kernel/cpu/sh4a/setup-sh7366.c | 34 ++++++++++++++++++++++++++++++++++
 arch/sh/kernel/cpu/sh4a/setup-sh7722.c | 34 ++++++++++++++++++++++++++++++++++
 arch/sh/kernel/cpu/sh4a/setup-sh7723.c | 34 ++++++++++++++++++++++++++++++++++
 4 files changed, 136 insertions(+)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 4ff4dc64520..c1549382c87 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -12,6 +12,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic0_resources[] = {
@@ -140,6 +141,38 @@ static struct platform_device jpu_device = {
 	.num_resources	= ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+	.name = "CMT",
+	.channel_offset = 0x60,
+	.timer_bit = 5,
+	.clk = "cmt0",
+	.clockevent_rating = 125,
+	.clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+	[0] = {
+		.name	= "CMT",
+		.start	= 0x044a0060,
+		.end	= 0x044a006b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 104,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt_platform_data,
+	},
+	.resource	= cmt_resources,
+	.num_resources	= ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
 	{
 		.mapbase	= 0xffe00000,
@@ -175,6 +208,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7343_devices[] __initdata = {
+	&cmt_device,
 	&iic0_device,
 	&iic1_device,
 	&sci_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 839ae97a7fd..93ecf8ed5c6 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -14,6 +14,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 
 static struct resource iic_resources[] = {
@@ -147,6 +148,38 @@ static struct platform_device veu1_device = {
 	.num_resources	= ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+	.name = "CMT",
+	.channel_offset = 0x60,
+	.timer_bit = 5,
+	.clk = "cmt0",
+	.clockevent_rating = 125,
+	.clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+	[0] = {
+		.name	= "CMT",
+		.start	= 0x044a0060,
+		.end	= 0x044a006b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 104,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt_platform_data,
+	},
+	.resource	= cmt_resources,
+	.num_resources	= ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
 	{
 		.mapbase	= 0xffe00000,
@@ -167,6 +200,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7366_devices[] __initdata = {
+	&cmt_device,
 	&iic_device,
 	&sci_device,
 	&usb_host_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 5146afc156e..0e5d204bc79 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -13,6 +13,7 @@
 #include <linux/serial_sci.h>
 #include <linux/mm.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -176,6 +177,38 @@ static struct platform_device jpu_device = {
 	.num_resources	= ARRAY_SIZE(jpu_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+	.name = "CMT",
+	.channel_offset = 0x60,
+	.timer_bit = 5,
+	.clk = "cmt0",
+	.clockevent_rating = 125,
+	.clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+	[0] = {
+		.name	= "CMT",
+		.start	= 0x044a0060,
+		.end	= 0x044a006b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 104,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt_platform_data,
+	},
+	.resource	= cmt_resources,
+	.num_resources	= ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
 	{
 		.mapbase	= 0xffe00000,
@@ -209,6 +242,7 @@ static struct platform_device sci_device = {
 };
 
 static struct platform_device *sh7722_devices[] __initdata = {
+	&cmt_device,
 	&rtc_device,
 	&usbf_device,
 	&iic_device,
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index 849770d780a..5338dacbcfb 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/sh_cmt.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 
@@ -100,6 +101,38 @@ static struct platform_device veu1_device = {
 	.num_resources	= ARRAY_SIZE(veu1_resources),
 };
 
+static struct sh_cmt_config cmt_platform_data = {
+	.name = "CMT",
+	.channel_offset = 0x60,
+	.timer_bit = 5,
+	.clk = "cmt0",
+	.clockevent_rating = 125,
+	.clocksource_rating = 200,
+};
+
+static struct resource cmt_resources[] = {
+	[0] = {
+		.name	= "CMT",
+		.start	= 0x044a0060,
+		.end	= 0x044a006b,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 104,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cmt_device = {
+	.name		= "sh_cmt",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &cmt_platform_data,
+	},
+	.resource	= cmt_resources,
+	.num_resources	= ARRAY_SIZE(cmt_resources),
+};
+
 static struct plat_sci_port sci_platform_data[] = {
 	{
 		.mapbase        = 0xffe00000,
@@ -221,6 +254,7 @@ static struct platform_device iic_device = {
 };
 
 static struct platform_device *sh7723_devices[] __initdata = {
+	&cmt_device,
 	&sci_device,
 	&rtc_device,
 	&iic_device,
-- 
cgit v1.2.3-18-g5258


From d63f3a5857906851b9c1a39e3871a97f4acc1005 Mon Sep 17 00:00:00 2001
From: Paul Mundt <lethal@linux-sh.org>
Date: Thu, 29 Jan 2009 18:10:13 +0900
Subject: sh: Fix up MTU2 support for SH7203.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/timers/timer-mtu2.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
index c3d237e1d56..9a77ae86b40 100644
--- a/arch/sh/kernel/timers/timer-mtu2.c
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -35,7 +35,8 @@
 #define MTU2_TSR_1	0xfffe4385
 #define MTU2_TCNT_1	0xfffe4386	/* 16-bit counter */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7201)
+#if defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7203)
 #define MTU2_TGRA_1	0xfffe4388
 #else
 #define MTU2_TGRA_1	0xfffe438a
-- 
cgit v1.2.3-18-g5258


From c161e40f45d32b48f8facbee17720e708607002f Mon Sep 17 00:00:00 2001
From: Paul Mundt <lethal@linux-sh.org>
Date: Thu, 29 Jan 2009 18:11:25 +0900
Subject: sh: Don't enable GENERIC_TIME for the CMT clockevent driver yet.

GENERIC_TIME still depends on the clocksource bits being there, which is
presently not supported. This allows the CMT clockevent driver to be used
alongside alternate system timers that do not yet provide a clocksource
of their own (MTU2 and so on in the case of SH-2A).

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/time_32.c | 2 --
 1 file changed, 2 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c
index 766554ba2a5..c34e1e0f9b0 100644
--- a/arch/sh/kernel/time_32.c
+++ b/arch/sh/kernel/time_32.c
@@ -104,7 +104,6 @@ int do_settimeofday(struct timespec *tv)
 EXPORT_SYMBOL(do_settimeofday);
 #endif /* !CONFIG_GENERIC_TIME */
 
-#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /* last time the RTC clock got updated */
 static long last_rtc_update;
 
@@ -148,7 +147,6 @@ void handle_timer_tick(void)
 	update_process_times(user_mode(get_irq_regs()));
 #endif
 }
-#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 #ifdef CONFIG_PM
 int timer_suspend(struct sys_device *dev, pm_message_t state)
-- 
cgit v1.2.3-18-g5258


From 1d015cf02a1fd46385c03cf3ce8958dbea705dd3 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Mon, 23 Feb 2009 07:14:02 +0000
Subject: sh: shared register saving code for sh3/sh4/sh4a

This patch reworks the sh3/sh4/sh4a register saving code in
the following ways:
 - break out prepare_stack_save_dsp() from handle_exception()
 - break out save_regs() from handle_exception()
 - the register saving order is unchanged
 - align new functions to fit in cache lines
 - separate exception code from interrupt code
 - keep main code flow in a single cache line per exception vector
 - use bsr/rts for regular functions (save pr first)
 - keep data in one shared cache line (exception_data)
 - document the functions
 - tie in the hp6xx code

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh3/entry.S | 273 ++++++++++++++++++++++-------------------
 1 file changed, 147 insertions(+), 126 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index b4106d0c68e..f3db143e70b 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -16,6 +16,7 @@
 #include <asm/unistd.h>
 #include <cpu/mmu_context.h>
 #include <asm/page.h>
+#include <asm/cache.h>
 
 ! NOTE:
 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -294,7 +295,7 @@ skip_restore:
 	mov	#0xf0, k1
 	extu.b	k1, k1
 	not	k1, k1
-	and	k1, k2			! Mask orignal SR value
+	and	k1, k2			! Mask original SR value
 	!
 	mov	k3, k0			! Calculate IMASK-bits
 	shlr2	k0
@@ -335,82 +336,54 @@ skip_restore:
 	.balign 	4096,0,4096
 ENTRY(vbr_base)
 	.long	0
+!
+! 0x100: General exception vector
 !
 	.balign 	256,0,256
 general_exception:
-	mov.l	1f, k2
-	mov.l	2f, k3
-#ifdef CONFIG_CPU_SUBTYPE_SHX3
-	mov.l	@k2, k2
+#ifndef CONFIG_CPU_SUBTYPE_SHX3
+	bra	handle_exception
+	 sts	pr, k3		! save original pr value in k3
+#else
+	mov.l	1f, k4
+	mov.l	@k4, k4
 
 	! Is EXPEVT larger than 0x800?
 	mov	#0x8, k0
 	shll8	k0
-	cmp/hs	k0, k2
+	cmp/hs	k0, k4
 	bf	0f
 
 	! then add 0x580 (k2 is 0xd80 or 0xda0)
 	mov	#0x58, k0
 	shll2	k0
 	shll2	k0
-	add	k0, k2
+	add	k0, k4
 0:
-	bra	handle_exception
+	! Setup stack and save DSP context (k0 contains original r15 on return)
+	bsr	prepare_stack_save_dsp
 	 nop
-#else
-	bra	handle_exception
-	 mov.l	@k2, k2
-#endif
-	.align	2
-1:	.long	EXPEVT
-2:	.long	ret_from_exception
-!
-!
 
-	.balign 	1024,0,1024
-tlb_miss:
-	mov.l	1f, k2
-	mov.l	4f, k3
-	bra	handle_exception
-	 mov.l	@k2, k2
-!
-	.balign 	512,0,512
-interrupt:
-	mov.l	3f, k3
-#if defined(CONFIG_KGDB)
-	mov.l	2f, k2
-	! Debounce (filter nested NMI)
-	mov.l	@k2, k0
-	mov.l	5f, k1
-	cmp/eq	k1, k0
-	bf	0f
-	mov.l	6f, k1
-	tas.b	@k1
-	bt	0f
-	rte
+	! Save registers / Switch to bank 0
+	bsr	save_regs	! needs original pr value in k3
+	 mov.l	k4, k2		! keep vector in k2
+
+	bra	handle_exception_special
 	 nop
-	.align	2
-2:	.long	INTEVT
-5:	.long	NMI_VEC
-6:	.long	in_nmi
-0:
-#endif /* defined(CONFIG_KGDB) */
-	bra	handle_exception
-	 mov	#-1, k2		! interrupt exception marker
 
 	.align	2
 1:	.long	EXPEVT
-3:	.long	ret_from_irq
-4:	.long	ret_from_exception
+#endif
 
-!
-!
-	.align	2
-ENTRY(handle_exception)
-	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
-	! save all registers onto stack.
-	!
+! prepare_stack_save_dsp()
+! - roll back gRB
+! - switch to kernel stack
+! - save DSP
+! k0 returns original sp (after roll back)
+! k1 trashed
+! k2 trashed
 
+prepare_stack_save_dsp:
 #ifdef CONFIG_GUSA
 	! Check for roll back gRB (User and Kernel)
 	mov	r15, k0
@@ -430,7 +403,7 @@ ENTRY(handle_exception)
 2:	mov	k1, r15		! SP = r1
 1:
 #endif
-
+	! Switch to kernel stack if needed
 	stc	ssr, k0		! Is it from kernel space?
 	shll	k0		! Check MD bit (bit30) by shifting it into...
 	shll	k0		!       ...the T bit
@@ -443,18 +416,17 @@ ENTRY(handle_exception)
 	add	current, k1
 	mov	k1, r15		! change to kernel stack
 	!
-1:	mov.l	2f, k1
-	!
+1:
 #ifdef CONFIG_SH_DSP
-	mov.l	r2, @-r15		! Save r2, we need another reg
-	stc	sr, k4
-	mov.l	1f, r2
-	tst	r2, k4			! Check if in DSP mode
-	mov.l	@r15+, r2		! Restore r2 now
+	! Save DSP context if needed
+	stc	sr, k1
+	mov	#0x10, k2
+	shll8   k2			! DSP=1 (0x00001000)
+	tst	k2, k1			! Check if in DSP mode (passed in k2)
 	bt/s	skip_save
-	 mov	#0, k4			! Set marker for no stack frame
+	 mov	#0, k1			! Set marker for no stack frame
 
-	mov	r2, k4			! Backup r2 (in k4) for later
+	mov	k2, k1			! Save has-frame marker
 
 	! Save DSP registers on stack
 	stc.l	mod, @-r15
@@ -473,35 +445,73 @@ ENTRY(handle_exception)
 	! as we're not at all interested in supporting ancient toolchains at
 	! this point. -- PFM.
 
-	mov	r15, r2
+	mov	r15, k2
 	.word	0xf653			! movs.l	a1, @-r2
 	.word	0xf6f3			! movs.l	a0g, @-r2
 	.word	0xf6d3			! movs.l	a1g, @-r2
 	.word	0xf6c3			! movs.l	m0, @-r2
 	.word	0xf6e3			! movs.l	m1, @-r2
-	mov	r2, r15
+	mov	k2, r15
 
-	mov	k4, r2			! Restore r2
-	mov.l	1f, k4			! Force DSP stack frame
 skip_save:
-	mov.l	k4, @-r15		! Push DSP mode marker onto stack
+	mov.l	k1, @-r15		! Push DSP mode marker onto stack
 #endif
-	! Save the user registers on the stack.
-	mov.l	k2, @-r15	! EXPEVT
+	rts
+	 nop
+!
+! 0x400: Instruction and Data TLB miss exception vector
+!
+	.balign 	1024,0,1024
+tlb_miss:
+	sts	pr, k3		! save original pr value in k3
 
-	mov	#-1, k4
-	mov.l	k4, @-r15	! set TRA (default: -1)
-	!
+handle_exception:
+	! Setup stack and save DSP context (k0 contains original r15 on return)
+	bsr	prepare_stack_save_dsp
+	 nop
+
+	! Save registers / Switch to bank 0
+	mov.l	5f, k2		! vector register address
+	bsr	save_regs	! needs original pr value in k3
+	 mov.l	@k2, k2		! read out vector and keep in k2
+
+handle_exception_special:
+	! Setup return address and jump to exception handler
+	mov.l	7f, r9		! fetch return address
+	stc	r2_bank, r0	! k2 (vector)
+	mov.l	6f, r10
+	shlr2	r0
+	shlr	r0
+	mov.l	@(r0, r10), r10
+	jmp	@r10
+	 lds	r9, pr		! put return address in pr
+
+	.align	L1_CACHE_SHIFT
+
+! save_regs()
+! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack
+! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
+! - switch bank
+! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
+! k0 contains original stack pointer*
+! k1 trashed
+! k2 passes vector (EXPEVT)
+! k3 passes original pr*
+! k4 trashed
+! BL=1 on entry, on exit BL=0.
+
+save_regs:
+	mov	#-1, r1
+	mov.l	k2, @-r15	! vector in k2
+	mov.l	k1, @-r15	! set TRA (default: -1)
 	sts.l	macl, @-r15
 	sts.l	mach, @-r15
 	stc.l	gbr, @-r15
 	stc.l	ssr, @-r15
-	sts.l	pr, @-r15
+	mov.l	k3, @-r15	! original pr in k3
 	stc.l	spc, @-r15
-	!
-	lds	k3, pr		! Set the return address to pr
-	!
-	mov.l	k0, @-r15	! save orignal stack
+
+	mov.l	k0, @-r15	! original stack pointer in k0
 	mov.l	r14, @-r15
 	mov.l	r13, @-r15
 	mov.l	r12, @-r15
@@ -509,13 +519,15 @@ skip_save:
 	mov.l	r10, @-r15
 	mov.l	r9, @-r15
 	mov.l	r8, @-r15
-	!
-	stc	sr, r8		! Back to normal register bank, and
-	or	k1, r8		! Block all interrupts
-	mov.l	3f, k1
-	and	k1, r8		! ...
-	ldc	r8, sr		! ...changed here.
-	!
+
+	mov.l	0f, k3		! SR bits to set in k3
+	mov.l	1f, k4		! SR bits to clear in k4
+
+	stc	sr, r8
+	or	k3, r8
+	and	k4, r8
+	ldc	r8, sr
+
 	mov.l	r7, @-r15
 	mov.l	r6, @-r15
 	mov.l	r5, @-r15
@@ -523,52 +535,61 @@ skip_save:
 	mov.l	r3, @-r15
 	mov.l	r2, @-r15
 	mov.l	r1, @-r15
-	mov.l	r0, @-r15
-
-	/*
-	 * This gets a bit tricky.. in the INTEVT case we don't want to use
-	 * the VBR offset as a destination in the jump call table, since all
-	 * of the destinations are the same. In this case, (interrupt) sets
-	 * a marker in r2 (now r2_bank since SR.RB changed), which we check
-	 * to determine the exception type. For all other exceptions, we
-	 * forcibly read EXPEVT from memory and fix up the jump address, in
-	 * the interrupt exception case we jump to do_IRQ() and defer the
-	 * INTEVT read until there. As a bonus, we can also clean up the SR.RB
-	 * checks that do_IRQ() was doing..
-	 */
-	stc	r2_bank, r8
-	cmp/pz	r8
-	bf	interrupt_exception
-	shlr2	r8
-	shlr	r8
-	mov.l	4f, r9
-	add	r8, r9
-	mov.l	@r9, r9
-	jmp	@r9
-	 nop
 	rts
-	 nop
+	 mov.l	r0, @-r15
 
+!
+! 0x600: Interrupt / NMI vector
+!
+	.balign 	512,0,512
+ENTRY(handle_interrupt)
+#if defined(CONFIG_KGDB)
+	mov.l	2f, k2
+	! Debounce (filter nested NMI)
+	mov.l	@k2, k0
+	mov.l	9f, k1
+	cmp/eq	k1, k0
+	bf	11f
+	mov.l	10f, k1
+	tas.b	@k1
+	bt	11f
+	rte
+	 nop
 	.align	2
-1:	.long	0x00001000	! DSP=1
-2:	.long	0x000080f0	! FD=1, IMASK=15
-3:	.long	0xcfffffff	! RB=0, BL=0
-4:	.long	exception_handling_table
+9:	.long	NMI_VEC
+10:	.long	in_nmi
+11:
+#endif /* defined(CONFIG_KGDB) */
+	sts	pr, k3		! save original pr value in k3
 
-interrupt_exception:
-	mov.l	1f, r9
-	mov.l	2f, r4
-	mov.l	@r4, r4
-	jmp	@r9
-	 mov	r15, r5
-	rts
+	! Setup stack and save DSP context (k0 contains original r15 on return)
+	bsr	prepare_stack_save_dsp
 	 nop
 
-	.align 2
-1:	.long	do_IRQ
-2:	.long	INTEVT
+	! Save registers / Switch to bank 0
+	bsr	save_regs	! needs original pr value in k3
+	 mov	#-1, k2		! default vector kept in k2
+
+	! Setup return address and jump to do_IRQ
+	mov.l	4f, r9		! fetch return address
+	lds	r9, pr		! put return address in pr
+	mov.l	2f, r4
+	mov.l	3f, r9
+	mov.l	@r4, r4		! pass INTEVT vector as arg0
+	jmp	@r9
+	 mov	r15, r5		! pass saved registers as arg1
 
-	.align	2
 ENTRY(exception_none)
 	rts
 	 nop
+
+	.align	L1_CACHE_SHIFT
+exception_data:
+0:	.long	0x000080f0	! FD=1, IMASK=15
+1:	.long	0xcfffffff	! RB=0, BL=0
+2:	.long	INTEVT
+3:	.long	do_IRQ
+4:	.long	ret_from_irq
+5:	.long	EXPEVT
+6:	.long	exception_handling_table
+7:	.long	ret_from_exception
-- 
cgit v1.2.3-18-g5258


From 1dd22722f6bf9be9821657a2d59fae4d4365fb32 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Mon, 23 Feb 2009 07:15:07 +0000
Subject: sh: rework register restore code for sh3/sh4/sh4a

This patch reworks the sh3/sh4/sh4a register restore code in
the following ways:
 - break out restore_regs() from restore_all()
 - the register saving order is unchanged
 - use restore_regs() in sh_bios_handler and restore_all
 - document the function

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh3/entry.S | 68 ++++++++++++++++++++----------------------
 1 file changed, 33 insertions(+), 35 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index f3db143e70b..cbffbffce35 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -188,44 +188,35 @@ call_dae:
 #if defined(CONFIG_SH_STANDARD_BIOS)
 	/* Unwind the stack and jmp to the debug entry */
 ENTRY(sh_bios_handler)
-	mov.l	@r15+, r0
-	mov.l	@r15+, r1
-	mov.l	@r15+, r2
-	mov.l	@r15+, r3
-	mov.l	@r15+, r4
-	mov.l	@r15+, r5
-	mov.l	@r15+, r6
-	mov.l	@r15+, r7
-	stc	sr, r8
-	mov.l	1f, r9			! BL =1, RB=1, IMASK=0x0F
-	or	r9, r8
-	ldc	r8, sr			! here, change the register bank
-	mov.l	@r15+, r8
-	mov.l	@r15+, r9
-	mov.l	@r15+, r10
-	mov.l	@r15+, r11
-	mov.l	@r15+, r12
-	mov.l	@r15+, r13
-	mov.l	@r15+, r14
-	mov.l	@r15+, k0
-	ldc.l	@r15+, spc
-	lds.l	@r15+, pr
-	mov.l	@r15+, k1
-	ldc.l	@r15+, gbr
-	lds.l	@r15+, mach
-	lds.l	@r15+, macl
-	mov	k0, r15
+	mov.l	1f, r8
+	bsr	restore_regs
+	 nop
+
+	lds	k2, pr			! restore pr
+	mov	k4, r15
 	!
 	mov.l	2f, k0
 	mov.l	@k0, k0
 	jmp	@k0
-	 ldc	k1, ssr
+	 ldc	k3, ssr
 	.align	2
 1:	.long	0x300000f0
 2:	.long	gdb_vbr_vector
 #endif /* CONFIG_SH_STANDARD_BIOS */
 
-restore_all:
+! restore_regs()
+! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
+! - switch bank
+! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
+! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
+! k2 returns original pr
+! k3 returns original sr
+! k4 returns original stack pointer
+! r8 passes SR bitmask, overwritten with restored data on return
+! r9 trashed
+! BL=0 on entry, on exit BL=1 (depending on r8).
+
+restore_regs:
 	mov.l	@r15+, r0
 	mov.l	@r15+, r1
 	mov.l	@r15+, r2
@@ -235,10 +226,9 @@ restore_all:
 	mov.l	@r15+, r6
 	mov.l	@r15+, r7
 	!
-	stc	sr, r8
-	mov.l	7f, r9
-	or	r9, r8			! BL =1, RB=1
-	ldc	r8, sr			! here, change the register bank
+	stc	sr, r9
+	or	r8, r9
+	ldc	r9, sr
 	!
 	mov.l	@r15+, r8
 	mov.l	@r15+, r9
@@ -249,12 +239,20 @@ restore_all:
 	mov.l	@r15+, r14
 	mov.l	@r15+, k4		! original stack pointer
 	ldc.l	@r15+, spc
-	lds.l	@r15+, pr
+	mov.l	@r15+, k2		! original PR
 	mov.l	@r15+, k3		! original SR
 	ldc.l	@r15+, gbr
 	lds.l	@r15+, mach
 	lds.l	@r15+, macl
-	add	#4, r15			! Skip syscall number
+	rts
+	 add	#4, r15			! Skip syscall number
+
+restore_all:
+	mov.l	7f, r8
+	bsr	restore_regs
+	 nop
+
+	lds	k2, pr			! restore pr
 	!
 #ifdef CONFIG_SH_DSP
 	mov.l	@r15+, k0		! DSP mode marker
-- 
cgit v1.2.3-18-g5258


From 4f099ebb27211d378304ddcfa507097f5128f5b9 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Mon, 23 Feb 2009 07:16:34 +0000
Subject: sh: remove EXPEVT vector from stack on sh3/sh4/sh4a

Remove EXPEVT vector from the stack, lookup_exception_vector()
for sh3/sh4/sh4a is already using k2 to get the vector.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh3/entry.S | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index cbffbffce35..0271fe08de2 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -312,7 +312,6 @@ skip_restore:
 	mov	#0, k1
 	mov.b	k1, @k0
 #endif
-	mov.l	@r15+, k2		! restore EXPEVT
 	mov	k4, r15
 	rte
 	 nop
@@ -487,20 +486,18 @@ handle_exception_special:
 	.align	L1_CACHE_SHIFT
 
 ! save_regs()
-! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack
+! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
 ! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
 ! - switch bank
 ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
 ! k0 contains original stack pointer*
 ! k1 trashed
-! k2 passes vector (EXPEVT)
 ! k3 passes original pr*
 ! k4 trashed
 ! BL=1 on entry, on exit BL=0.
 
 save_regs:
 	mov	#-1, r1
-	mov.l	k2, @-r15	! vector in k2
 	mov.l	k1, @-r15	! set TRA (default: -1)
 	sts.l	macl, @-r15
 	sts.l	mach, @-r15
-- 
cgit v1.2.3-18-g5258


From 0197f21ca5c5ed0df2a14a60ef073e8163e6533b Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Fri, 27 Feb 2009 16:41:17 +0900
Subject: sh: prefetch early exception data on sh4/sh4a.

Prefetch early exception data. There is unused space in our
exception handler cache line anyway, so this is almost free.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh3/entry.S | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 0271fe08de2..e984e94394e 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -463,9 +463,11 @@ tlb_miss:
 	sts	pr, k3		! save original pr value in k3
 
 handle_exception:
+	mova	exception_data, k0
+
 	! Setup stack and save DSP context (k0 contains original r15 on return)
 	bsr	prepare_stack_save_dsp
-	 nop
+	 PREF(k0)
 
 	! Save registers / Switch to bank 0
 	mov.l	5f, k2		! vector register address
@@ -556,10 +558,11 @@ ENTRY(handle_interrupt)
 11:
 #endif /* defined(CONFIG_KGDB) */
 	sts	pr, k3		! save original pr value in k3
+	mova	exception_data, k0
 
 	! Setup stack and save DSP context (k0 contains original r15 on return)
 	bsr	prepare_stack_save_dsp
-	 nop
+	 PREF(k0)
 
 	! Save registers / Switch to bank 0
 	bsr	save_regs	! needs original pr value in k3
-- 
cgit v1.2.3-18-g5258


From bdaa6e8062d7f8085d8ed94ff88c99406ad53d79 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Tue, 24 Feb 2009 22:58:57 +0900
Subject: sh: multiple vectors per irq - base

Instead of keeping the single vector -> single linux irq mapping
we extend the intc code to support merging of vectors to a single
linux irq. This helps processors such as sh7750, sh7780 and sh7785
which have more vectors than masking ability. With this patch in
place we can modify the intc tables to use one irq per maskable
irq source. Please note the following:

 - If multiple vectors share the same enum then only the
   first vector will be available as a linux irq.

 - Drivers may need to be rewritten to get pending irq
   source from the hardware block instead of irq number.

This patch together with the sh7785 specific intc tables solves
DMA controller irq issues related to buggy interrupt masking.

Reported-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/irq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 64b7690c664..90d63aefd27 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -106,7 +106,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
 	}
 #endif
 
-	irq = irq_demux(evt2irq(irq));
+	irq = irq_demux(intc_evt2irq(irq));
 
 #ifdef CONFIG_IRQSTACKS
 	curctx = (union irq_ctx *)current_thread_info();
-- 
cgit v1.2.3-18-g5258


From 69977e7e25a291fd71c6dcaf2c5ea9e776afede5 Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Tue, 24 Feb 2009 22:59:04 +0900
Subject: sh: multiple vectors per irq - sh7750

Update intc tables and platform data to use one linux irq
per maskable interrupt source instead of keeping the one-to-one
mapping between vectors and linux irqs.

This fixes potential irq masking issues for sh775x hardware
blocks such as SCI/SCIF/RTC/DMAC/TMU2/REF.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
---
 arch/sh/kernel/cpu/sh4/setup-sh7750.c | 87 ++++++++++-------------------------
 1 file changed, 25 insertions(+), 62 deletions(-)

(limited to 'arch/sh/kernel')

diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index ec884039b91..a1c80d909cd 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -21,17 +21,7 @@ static struct resource rtc_resources[] = {
 		.flags	= IORESOURCE_IO,
 	},
 	[1] = {
-		/* Period IRQ */
-		.start	= 21,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[2] = {
-		/* Carry IRQ */
-		.start	= 22,
-		.flags	= IORESOURCE_IRQ,
-	},
-	[3] = {
-		/* Alarm IRQ */
+		/* Shared Period/Carry/Alarm IRQ */
 		.start	= 20,
 		.flags	= IORESOURCE_IRQ,
 	},
@@ -50,13 +40,13 @@ static struct plat_sci_port sci_platform_data[] = {
 		.mapbase	= 0xffe00000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCI,
-		.irqs		= { 23, 24, 25, 0 },
+		.irqs		= { 23, 23, 23, 0 },
 	}, {
 #endif
 		.mapbase	= 0xffe80000,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.type		= PORT_SCIF,
-		.irqs		= { 40, 41, 43, 42 },
+		.irqs		= { 40, 40, 40, 40 },
 	}, {
 		.flags = 0,
 	}
@@ -87,43 +77,27 @@ enum {
 
 	/* interrupt sources */
 	IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
-	HUDI, GPIOI,
-	DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
-	DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
-	DMAC_DMAE,
+	HUDI, GPIOI, DMAC,
 	PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
 	PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
-	TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
-	RTC_ATI, RTC_PRI, RTC_CUI,
-	SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
-	SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
-	WDT,
-	REF_RCMI, REF_ROVI,
+	TMU3, TMU4, TMU0, TMU1, TMU2, RTC, SCI1, SCIF, WDT, REF,
 
 	/* interrupt groups */
-	DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
+	PCIC1,
 };
 
 static struct intc_vect vectors[] __initdata = {
 	INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
 	INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
-	INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
-	INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
-	INTC_VECT(RTC_CUI, 0x4c0),
-	INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
-	INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
-	INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
-	INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+	INTC_VECT(TMU2, 0x440), INTC_VECT(TMU2, 0x460),
+	INTC_VECT(RTC, 0x480), INTC_VECT(RTC, 0x4a0),
+	INTC_VECT(RTC, 0x4c0),
+	INTC_VECT(SCI1, 0x4e0), INTC_VECT(SCI1, 0x500),
+	INTC_VECT(SCI1, 0x520), INTC_VECT(SCI1, 0x540),
+	INTC_VECT(SCIF, 0x700), INTC_VECT(SCIF, 0x720),
+	INTC_VECT(SCIF, 0x740), INTC_VECT(SCIF, 0x760),
 	INTC_VECT(WDT, 0x560),
-	INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
-};
-
-static struct intc_group groups[] __initdata = {
-	INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
-	INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
-	INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
-	INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
-	INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+	INTC_VECT(REF, 0x580), INTC_VECT(REF, 0x5a0),
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -136,7 +110,7 @@ static struct intc_prio_reg prio_registers[] __initdata = {
 						 PCIC1, PCIC0_PCISERR } },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, NULL,
 			 NULL, prio_registers, NULL);
 
 /* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
@@ -145,39 +119,28 @@ static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
 	defined(CONFIG_CPU_SUBTYPE_SH7751) || \
 	defined(CONFIG_CPU_SUBTYPE_SH7091)
 static struct intc_vect vectors_dma4[] __initdata = {
-	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
-	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
-	INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma4[] __initdata = {
-	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
-		   DMAC_DMTE3, DMAC_DMAE),
+	INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+	INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+	INTC_VECT(DMAC, 0x6c0),
 };
 
 static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
-			 vectors_dma4, groups_dma4,
+			 vectors_dma4, NULL,
 			 NULL, prio_registers, NULL);
 #endif
 
 /* SH7750R and SH7751R both have 8-channel DMA controllers */
 #if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
 static struct intc_vect vectors_dma8[] __initdata = {
-	INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
-	INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
-	INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
-	INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
-	INTC_VECT(DMAC_DMAE, 0x6c0),
-};
-
-static struct intc_group groups_dma8[] __initdata = {
-	INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
-		   DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
-		   DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+	INTC_VECT(DMAC, 0x640), INTC_VECT(DMAC, 0x660),
+	INTC_VECT(DMAC, 0x680), INTC_VECT(DMAC, 0x6a0),
+	INTC_VECT(DMAC, 0x780), INTC_VECT(DMAC, 0x7a0),
+	INTC_VECT(DMAC, 0x7c0), INTC_VECT(DMAC, 0x7e0),
+	INTC_VECT(DMAC, 0x6c0),
 };
 
 static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
-			 vectors_dma8, groups_dma8,
+			 vectors_dma8, NULL,
 			 NULL, prio_registers, NULL);
 #endif
 
-- 
cgit v1.2.3-18-g5258


From a842fb2d11ee478dc2fd09b736b1bc62c386f18a Mon Sep 17 00:00:00 2001
From: Magnus Damm <damm@igel.co.jp>
Date: Tue, 24 Feb 2009 22:59:12 +0900
Subject: sh: multiple vectors per irq - sh7780

Update intc tables and platform data to use one linux irq
per maskable interrupt source instead of keeping the one-to-one
mapping between vect