diff options
Diffstat (limited to 'arch/sh/boards/mach-se/7343')
-rw-r--r-- | arch/sh/boards/mach-se/7343/Makefile | 5 | ||||
-rw-r--r-- | arch/sh/boards/mach-se/7343/io.c | 273 | ||||
-rw-r--r-- | arch/sh/boards/mach-se/7343/irq.c | 80 | ||||
-rw-r--r-- | arch/sh/boards/mach-se/7343/setup.c | 152 |
4 files changed, 510 insertions, 0 deletions
diff --git a/arch/sh/boards/mach-se/7343/Makefile b/arch/sh/boards/mach-se/7343/Makefile new file mode 100644 index 00000000000..3024796c620 --- /dev/null +++ b/arch/sh/boards/mach-se/7343/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the 7343 SolutionEngine specific parts of the kernel +# + +obj-y := setup.o io.o irq.o diff --git a/arch/sh/boards/mach-se/7343/io.c b/arch/sh/boards/mach-se/7343/io.c new file mode 100644 index 00000000000..e2fae32d27d --- /dev/null +++ b/arch/sh/boards/mach-se/7343/io.c @@ -0,0 +1,273 @@ +/* + * arch/sh/boards/se/7343/io.c + * + * I/O routine for SH-Mobile3AS 7343 SolutionEngine. + * + */ +#include <linux/kernel.h> +#include <asm/io.h> +#include <mach/se7343.h> + +#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a) + +struct iop { + unsigned long start, end; + unsigned long base; + struct iop *(*check) (struct iop * p, unsigned long port); + unsigned char (*inb) (struct iop * p, unsigned long port); + unsigned short (*inw) (struct iop * p, unsigned long port); + void (*outb) (struct iop * p, unsigned char value, unsigned long port); + void (*outw) (struct iop * p, unsigned short value, unsigned long port); +}; + +struct iop * +simple_check(struct iop *p, unsigned long port) +{ + static int count; + + if (count < 100) + count++; + + port &= 0xFFFF; + + if ((p->start <= port) && (port <= p->end)) + return p; + else + badio(check, port); +} + +struct iop * +ide_check(struct iop *p, unsigned long port) +{ + if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7)) + return p; + return NULL; +} + +unsigned char +simple_inb(struct iop *p, unsigned long port) +{ + return *(unsigned char *) (p->base + port); +} + +unsigned short +simple_inw(struct iop *p, unsigned long port) +{ + return *(unsigned short *) (p->base + port); +} + +void +simple_outb(struct iop *p, unsigned char value, unsigned long port) +{ + *(unsigned char *) (p->base + port) = value; +} + +void +simple_outw(struct iop *p, unsigned short value, unsigned long port) +{ + *(unsigned short *) (p->base + port) = value; +} + +unsigned char +pcc_inb(struct iop *p, unsigned long port) +{ + unsigned long addr = p->base + port + 0x40000; + unsigned long v; + + if (port & 1) + addr += 0x00400000; + v = *(volatile unsigned char *) addr; + return v; +} + +void +pcc_outb(struct iop *p, unsigned char value, unsigned long port) +{ + unsigned long addr = p->base + port + 0x40000; + + if (port & 1) + addr += 0x00400000; + *(volatile unsigned char *) addr = value; +} + +unsigned char +bad_inb(struct iop *p, unsigned long port) +{ + badio(inb, port); +} + +void +bad_outb(struct iop *p, unsigned char value, unsigned long port) +{ + badio(inw, port); +} + +#ifdef CONFIG_SMC91X +/* MSTLANEX01 LAN at 0xb400:0000 */ +static struct iop laniop = { + .start = 0x00, + .end = 0x0F, + .base = 0x04000000, + .check = simple_check, + .inb = simple_inb, + .inw = simple_inw, + .outb = simple_outb, + .outw = simple_outw, +}; +#endif + +#ifdef CONFIG_NE2000 +/* NE2000 pc card NIC */ +static struct iop neiop = { + .start = 0x280, + .end = 0x29f, + .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */ + .check = simple_check, + .inb = pcc_inb, + .inw = simple_inw, + .outb = pcc_outb, + .outw = simple_outw, +}; +#endif + +#ifdef CONFIG_IDE +/* CF in CF slot */ +static struct iop cfiop = { + .base = 0xb0600000, + .check = ide_check, + .inb = pcc_inb, + .inw = simple_inw, + .outb = pcc_outb, + .outw = simple_outw, +}; +#endif + +static __inline__ struct iop * +port2iop(unsigned long port) +{ + if (0) ; +#if defined(CONFIG_SMC91X) + else if (laniop.check(&laniop, port)) + return &laniop; +#endif +#if defined(CONFIG_NE2000) + else if (neiop.check(&neiop, port)) + return &neiop; +#endif +#if defined(CONFIG_IDE) + else if (cfiop.check(&cfiop, port)) + return &cfiop; +#endif + else + return NULL; +} + +static inline void +delay(void) +{ + ctrl_inw(0xac000000); + ctrl_inw(0xac000000); +} + +unsigned char +sh7343se_inb(unsigned long port) +{ + struct iop *p = port2iop(port); + return (p->inb) (p, port); +} + +unsigned char +sh7343se_inb_p(unsigned long port) +{ + unsigned char v = sh7343se_inb(port); + delay(); + return v; +} + +unsigned short +sh7343se_inw(unsigned long port) +{ + struct iop *p = port2iop(port); + return (p->inw) (p, port); +} + +unsigned int +sh7343se_inl(unsigned long port) +{ + badio(inl, port); +} + +void +sh7343se_outb(unsigned char value, unsigned long port) +{ + struct iop *p = port2iop(port); + (p->outb) (p, value, port); +} + +void +sh7343se_outb_p(unsigned char value, unsigned long port) +{ + sh7343se_outb(value, port); + delay(); +} + +void +sh7343se_outw(unsigned short value, unsigned long port) +{ + struct iop *p = port2iop(port); + (p->outw) (p, value, port); +} + +void +sh7343se_outl(unsigned int value, unsigned long port) +{ + badio(outl, port); +} + +void +sh7343se_insb(unsigned long port, void *addr, unsigned long count) +{ + unsigned char *a = addr; + struct iop *p = port2iop(port); + while (count--) + *a++ = (p->inb) (p, port); +} + +void +sh7343se_insw(unsigned long port, void *addr, unsigned long count) +{ + unsigned short *a = addr; + struct iop *p = port2iop(port); + while (count--) + *a++ = (p->inw) (p, port); +} + +void +sh7343se_insl(unsigned long port, void *addr, unsigned long count) +{ + badio(insl, port); +} + +void +sh7343se_outsb(unsigned long port, const void *addr, unsigned long count) +{ + unsigned char *a = (unsigned char *) addr; + struct iop *p = port2iop(port); + while (count--) + (p->outb) (p, *a++, port); +} + +void +sh7343se_outsw(unsigned long port, const void *addr, unsigned long count) +{ + unsigned short *a = (unsigned short *) addr; + struct iop *p = port2iop(port); + while (count--) + (p->outw) (p, *a++, port); +} + +void +sh7343se_outsl(unsigned long port, const void *addr, unsigned long count) +{ + badio(outsw, port); +} diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c new file mode 100644 index 00000000000..1112e86aa93 --- /dev/null +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -0,0 +1,80 @@ +/* + * linux/arch/sh/boards/se/7343/irq.c + * + * Copyright (C) 2008 Yoshihiro Shimoda + * + * Based on linux/arch/sh/boards/se/7722/irq.c + * Copyright (C) 2007 Nobuhiro Iwamatsu + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/se7343.h> + +static void disable_se7343_irq(unsigned int irq) +{ + unsigned int bit = irq - SE7343_FPGA_IRQ_BASE; + ctrl_outw(ctrl_inw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK); +} + +static void enable_se7343_irq(unsigned int irq) +{ + unsigned int bit = irq - SE7343_FPGA_IRQ_BASE; + ctrl_outw(ctrl_inw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK); +} + +static struct irq_chip se7343_irq_chip __read_mostly = { + .name = "SE7343-FPGA", + .mask = disable_se7343_irq, + .unmask = enable_se7343_irq, + .mask_ack = disable_se7343_irq, +}; + +static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) +{ + unsigned short intv = ctrl_inw(PA_CPLD_ST); + struct irq_desc *ext_desc; + unsigned int ext_irq = SE7343_FPGA_IRQ_BASE; + + intv &= (1 << SE7343_FPGA_IRQ_NR) - 1; + + while (intv) { + if (intv & 1) { + ext_desc = irq_desc + ext_irq; + handle_level_irq(ext_irq, ext_desc); + } + intv >>= 1; + ext_irq++; + } +} + +/* + * Initialize IRQ setting + */ +void __init init_7343se_IRQ(void) +{ + int i; + + ctrl_outw(0, PA_CPLD_IMSK); /* disable all irqs */ + ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ + + for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) + set_irq_chip_and_handler_name(SE7343_FPGA_IRQ_BASE + i, + &se7343_irq_chip, + handle_level_irq, "level"); + + set_irq_chained_handler(IRQ0_IRQ, se7343_irq_demux); + set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); + set_irq_chained_handler(IRQ1_IRQ, se7343_irq_demux); + set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW); + set_irq_chained_handler(IRQ4_IRQ, se7343_irq_demux); + set_irq_type(IRQ4_IRQ, IRQ_TYPE_LEVEL_LOW); + set_irq_chained_handler(IRQ5_IRQ, se7343_irq_demux); + set_irq_type(IRQ5_IRQ, IRQ_TYPE_LEVEL_LOW); +} diff --git a/arch/sh/boards/mach-se/7343/setup.c b/arch/sh/boards/mach-se/7343/setup.c new file mode 100644 index 00000000000..59dc92e20f6 --- /dev/null +++ b/arch/sh/boards/mach-se/7343/setup.c @@ -0,0 +1,152 @@ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <machvec.h> +#include <mach/se7343.h> +#include <asm/heartbeat.h> +#include <asm/irq.h> +#include <asm/io.h> + +static struct resource smc91x_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x1000000F, + .flags = IORESOURCE_MEM, + }, + [1] = { + /* + * shared with other devices via externel + * interrupt controller in FPGA... + */ + .start = SMC_IRQ, + .end = SMC_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +static struct resource heartbeat_resources[] = { + [0] = { + .start = PA_LED, + .end = PA_LED, + .flags = IORESOURCE_MEM, + }, +}; + +static struct heartbeat_data heartbeat_data = { + .regsize = 16, +}; + +static struct platform_device heartbeat_device = { + .name = "heartbeat", + .id = -1, + .dev = { + .platform_data = &heartbeat_data, + }, + .num_resources = ARRAY_SIZE(heartbeat_resources), + .resource = heartbeat_resources, +}; + +static struct mtd_partition nor_flash_partitions[] = { + { + .name = "loader", + .offset = 0x00000000, + .size = 128 * 1024, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = 31 * 1024 * 1024, + }, + { + .name = "data", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct physmap_flash_data nor_flash_data = { + .width = 2, + .parts = nor_flash_partitions, + .nr_parts = ARRAY_SIZE(nor_flash_partitions), +}; + +static struct resource nor_flash_resources[] = { + [0] = { + .start = 0x00000000, + .end = 0x01ffffff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device nor_flash_device = { + .name = "physmap-flash", + .dev = { + .platform_data = &nor_flash_data, + }, + .num_resources = ARRAY_SIZE(nor_flash_resources), + .resource = nor_flash_resources, +}; + +static struct platform_device *sh7343se_platform_devices[] __initdata = { + &smc91x_device, + &heartbeat_device, + &nor_flash_device, +}; + +static int __init sh7343se_devices_setup(void) +{ + return platform_add_devices(sh7343se_platform_devices, + ARRAY_SIZE(sh7343se_platform_devices)); +} +device_initcall(sh7343se_devices_setup); + +/* + * Initialize the board + */ +static void __init sh7343se_setup(char **cmdline_p) +{ + ctrl_outw(0xf900, FPGA_OUT); /* FPGA */ + + ctrl_outw(0x0002, PORT_PECR); /* PORT E 1 = IRQ5 */ + ctrl_outw(0x0020, PORT_PSELD); + + printk(KERN_INFO "MS7343CP01 Setup...done\n"); +} + +/* + * The Machine Vector + */ +static struct sh_machine_vector mv_7343se __initmv = { + .mv_name = "SolutionEngine 7343", + .mv_setup = sh7343se_setup, + .mv_nr_irqs = 108, + .mv_inb = sh7343se_inb, + .mv_inw = sh7343se_inw, + .mv_inl = sh7343se_inl, + .mv_outb = sh7343se_outb, + .mv_outw = sh7343se_outw, + .mv_outl = sh7343se_outl, + + .mv_inb_p = sh7343se_inb_p, + .mv_inw_p = sh7343se_inw, + .mv_inl_p = sh7343se_inl, + .mv_outb_p = sh7343se_outb_p, + .mv_outw_p = sh7343se_outw, + .mv_outl_p = sh7343se_outl, + + .mv_insb = sh7343se_insb, + .mv_insw = sh7343se_insw, + .mv_insl = sh7343se_insl, + .mv_outsb = sh7343se_outsb, + .mv_outsw = sh7343se_outsw, + .mv_outsl = sh7343se_outsl, + + .mv_init_irq = init_7343se_IRQ, +}; |