diff options
Diffstat (limited to 'arch/arm/mach-iop32x')
21 files changed, 814 insertions, 116 deletions
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig index c072d94070d..5e8c6f7dfab 100644 --- a/arch/arm/mach-iop32x/Kconfig +++ b/arch/arm/mach-iop32x/Kconfig @@ -4,6 +4,9 @@ menu "IOP32x Implementation Options" comment "IOP32x Platform Types" +config MACH_EP80219 + bool + config MACH_GLANTANK bool "Enable support for the IO-Data GLAN Tank" help @@ -19,6 +22,7 @@ config ARCH_IQ80321 config ARCH_IQ31244 bool "Enable support for EP80219/IQ31244" + select MACH_EP80219 help Say Y here if you want to run your kernel on the Intel EP80219 evaluation kit for the Intel 80219 processor (a IOP321 variant) @@ -30,6 +34,13 @@ config MACH_N2100 Say Y here if you want to run your kernel on the Thecus n2100 NAS appliance. +config MACH_EM7210 + bool "Enable support for the Lanner EM7210" + help + Say Y here if you want to run your kernel on the Lanner EM7210 + board. Say also Y here if you have a SS4000e Baxter Creek NAS + appliance." + endmenu endif diff --git a/arch/arm/mach-iop32x/Makefile b/arch/arm/mach-iop32x/Makefile index 7b05b37e1f9..cfdf8a137c2 100644 --- a/arch/arm/mach-iop32x/Makefile +++ b/arch/arm/mach-iop32x/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_MACH_GLANTANK) += glantank.o obj-$(CONFIG_ARCH_IQ80321) += iq80321.o obj-$(CONFIG_ARCH_IQ31244) += iq31244.o obj-$(CONFIG_MACH_N2100) += n2100.o +obj-$(CONFIG_MACH_EM7210) += em7210.o diff --git a/arch/arm/mach-iop32x/Makefile.boot b/arch/arm/mach-iop32x/Makefile.boot index 47000dccd61..0a833b11e38 100644 --- a/arch/arm/mach-iop32x/Makefile.boot +++ b/arch/arm/mach-iop32x/Makefile.boot @@ -1,3 +1,3 @@ - zreladdr-y := 0xa0008000 + zreladdr-y += 0xa0008000 params_phys-y := 0xa0000100 initrd_phys-y := 0xa0800000 diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c new file mode 100644 index 00000000000..77e1ff05730 --- /dev/null +++ b/arch/arm/mach-iop32x/em7210.c @@ -0,0 +1,231 @@ +/* + * arch/arm/mach-iop32x/em7210.c + * + * Board support code for the Lanner EM7210 platforms. + * + * Based on arch/arm/mach-iop32x/iq31244.c file. + * + * Copyright (C) 2007 Arnaud Patard <arnaud.patard@rtp-net.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/pci.h> +#include <asm/mach/time.h> +#include <asm/mach-types.h> +#include <mach/time.h> +#include "gpio-iop32x.h" + +static void __init em7210_timer_init(void) +{ + /* http://www.kwaak.net/fotos/fotos-nas/slide_24.html */ + /* 33.333 MHz crystal. */ + iop_init_time(200000000); +} + +/* + * EM7210 RTC + */ +static struct i2c_board_info __initdata em7210_i2c_devices[] = { + { + I2C_BOARD_INFO("rs5c372a", 0x32), + }, +}; + +/* + * EM7210 I/O + */ +static struct map_desc em7210_io_desc[] __initdata = { + { /* on-board devices */ + .virtual = IQ31244_UART, + .pfn = __phys_to_pfn(IQ31244_UART), + .length = 0x00100000, + .type = MT_DEVICE, + }, +}; + +void __init em7210_map_io(void) +{ + iop3xx_map_io(); + iotable_init(em7210_io_desc, ARRAY_SIZE(em7210_io_desc)); +} + + +/* + * EM7210 PCI + */ +#define INTA IRQ_IOP32X_XINT0 +#define INTB IRQ_IOP32X_XINT1 +#define INTC IRQ_IOP32X_XINT2 +#define INTD IRQ_IOP32X_XINT3 + +static int __init +em7210_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + static int pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTB, INTB, INTB, INTB}, /* console / uart */ + {INTA, INTA, INTA, INTA}, /* 1st 82541 */ + {INTD, INTD, INTD, INTD}, /* 2nd 82541 */ + {INTC, INTC, INTC, INTC}, /* GD31244 */ + {INTD, INTA, INTA, INTA}, /* mini-PCI */ + {INTD, INTC, INTA, INTA}, /* NEC USB */ + }; + + if (pin < 1 || pin > 4) + return -1; + + return pci_irq_table[slot % 6][pin - 1]; +} + +static struct hw_pci em7210_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit, + .map_irq = em7210_pci_map_irq, +}; + +static int __init em7210_pci_init(void) +{ + if (machine_is_em7210()) + pci_common_init(&em7210_pci); + + return 0; +} + +subsys_initcall(em7210_pci_init); + + +/* + * EM7210 Flash + */ +static struct physmap_flash_data em7210_flash_data = { + .width = 2, +}; + +static struct resource em7210_flash_resource = { + .start = 0xf0000000, + .end = 0xf1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device em7210_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &em7210_flash_data, + }, + .num_resources = 1, + .resource = &em7210_flash_resource, +}; + + +/* + * EM7210 UART + * The physical address of the serial port is 0xfe800000, + * so it can be used for physical and virtual address. + */ +static struct plat_serial8250_port em7210_serial_port[] = { + { + .mapbase = IQ31244_UART, + .membase = (char *)IQ31244_UART, + .irq = IRQ_IOP32X_XINT1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = 1843200, + }, + { }, +}; + +static struct resource em7210_uart_resource = { + .start = IQ31244_UART, + .end = IQ31244_UART + 7, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device em7210_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = em7210_serial_port, + }, + .num_resources = 1, + .resource = &em7210_uart_resource, +}; + +#define EM7210_HARDWARE_POWER 0 + +void em7210_power_off(void) +{ + int ret; + + ret = gpio_direction_output(EM7210_HARDWARE_POWER, 1); + if (ret) + pr_crit("could not drive power off GPIO high\n"); +} + +static int __init em7210_request_gpios(void) +{ + int ret; + + if (!machine_is_em7210()) + return 0; + + ret = gpio_request(EM7210_HARDWARE_POWER, "power"); + if (ret) { + pr_err("could not request power off GPIO\n"); + return 0; + } + + pm_power_off = em7210_power_off; + + return 0; +} +device_initcall(em7210_request_gpios); + +static void __init em7210_init_machine(void) +{ + register_iop32x_gpio(); + platform_device_register(&em7210_serial_device); + platform_device_register(&iop3xx_i2c0_device); + platform_device_register(&iop3xx_i2c1_device); + platform_device_register(&em7210_flash_device); + platform_device_register(&iop3xx_dma_0_channel); + platform_device_register(&iop3xx_dma_1_channel); + + i2c_register_board_info(0, em7210_i2c_devices, + ARRAY_SIZE(em7210_i2c_devices)); +} + +MACHINE_START(EM7210, "Lanner EM7210") + .atag_offset = 0x100, + .map_io = em7210_map_io, + .init_irq = iop32x_init_irq, + .init_time = em7210_timer_init, + .init_machine = em7210_init_machine, + .restart = iop3xx_restart, +MACHINE_END diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c index b9b765057db..547b2342d61 100644 --- a/arch/arm/mach-iop32x/glantank.c +++ b/arch/arm/mach-iop32x/glantank.c @@ -3,7 +3,7 @@ * * Board support code for the GLAN Tank. * - * Copyright (C) 2006 Martin Michlmayr <tbm@cyrius.com> + * Copyright (C) 2006, 2007 Martin Michlmayr <tbm@cyrius.com> * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> * * This program is free software; you can redistribute it and/or modify it @@ -14,16 +14,18 @@ #include <linux/mm.h> #include <linux/init.h> +#include <linux/f75375s.h> #include <linux/kernel.h> #include <linux/pci.h> +#include <linux/pm.h> #include <linux/string.h> -#include <linux/slab.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/mtd/physmap.h> +#include <linux/i2c.h> #include <linux/platform_device.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <linux/io.h> +#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -31,6 +33,8 @@ #include <asm/mach/time.h> #include <asm/mach-types.h> #include <asm/page.h> +#include <mach/time.h> +#include "gpio-iop32x.h" /* * GLAN Tank timer tick configuration. @@ -38,14 +42,9 @@ static void __init glantank_timer_init(void) { /* 33.333 MHz crystal. */ - iop3xx_init_time(200000000); + iop_init_time(200000000); } -static struct sys_timer glantank_timer = { - .init = glantank_timer_init, - .offset = iop3xx_gettimeoffset, -}; - /* * GLAN Tank I/O. @@ -74,8 +73,8 @@ void __init glantank_map_io(void) #define INTC IRQ_IOP32X_XINT2 #define INTD IRQ_IOP32X_XINT3 -static inline int __init -glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int __init +glantank_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { static int pci_irq_table[][4] = { /* @@ -94,11 +93,10 @@ glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } static struct hw_pci glantank_pci __initdata = { - .swizzle = pci_std_swizzle, .nr_controllers = 1, + .ops = &iop3xx_ops, .setup = iop3xx_pci_setup, .preinit = iop3xx_pci_preinit, - .scan = iop3xx_pci_scan_bus, .map_irq = glantank_pci_map_irq, }; @@ -117,7 +115,7 @@ subsys_initcall(glantank_pci_init); * GLAN Tank machine initialization. */ static struct physmap_flash_data glantank_flash_data = { - .width = 1, + .width = 2, }; static struct resource glantank_flash_resource = { @@ -165,9 +163,24 @@ static struct platform_device glantank_serial_device = { .resource = &glantank_uart_resource, }; +static struct f75375s_platform_data glantank_f75375s = { + .pwm = { 255, 255 }, + .pwm_enable = { 0, 0 }, +}; + +static struct i2c_board_info __initdata glantank_i2c_devices[] = { + { + I2C_BOARD_INFO("rs5c372a", 0x32), + }, + { + I2C_BOARD_INFO("f75375", 0x2e), + .platform_data = &glantank_f75375s, + }, +}; + static void glantank_power_off(void) { - __raw_writeb(0x01, 0xfe8d0004); + __raw_writeb(0x01, IOMEM(0xfe8d0004)); while (1) ; @@ -175,21 +188,26 @@ static void glantank_power_off(void) static void __init glantank_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&glantank_flash_device); platform_device_register(&glantank_serial_device); + platform_device_register(&iop3xx_dma_0_channel); + platform_device_register(&iop3xx_dma_1_channel); + + i2c_register_board_info(0, glantank_i2c_devices, + ARRAY_SIZE(glantank_i2c_devices)); pm_power_off = glantank_power_off; } MACHINE_START(GLANTANK, "GLAN Tank") /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = GLANTANK_UART, - .io_pg_offst = ((GLANTANK_UART) >> 18) & 0xfffc, - .boot_params = 0xa0000100, + .atag_offset = 0x100, .map_io = glantank_map_io, .init_irq = iop32x_init_irq, - .timer = &glantank_timer, + .init_time = glantank_timer_init, .init_machine = glantank_init_machine, + .restart = iop3xx_restart, MACHINE_END diff --git a/arch/arm/mach-iop32x/gpio-iop32x.h b/arch/arm/mach-iop32x/gpio-iop32x.h new file mode 100644 index 00000000000..3c7309c0202 --- /dev/null +++ b/arch/arm/mach-iop32x/gpio-iop32x.h @@ -0,0 +1,10 @@ +static struct resource iop32x_gpio_res[] = { + DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x07c4), 0x10), +}; + +static inline void register_iop32x_gpio(void) +{ + platform_device_register_simple("gpio-iop", 0, + iop32x_gpio_res, + ARRAY_SIZE(iop32x_gpio_res)); +} diff --git a/arch/arm/mach-iop32x/include/mach/adma.h b/arch/arm/mach-iop32x/include/mach/adma.h new file mode 100644 index 00000000000..5ed92037dd1 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/adma.h @@ -0,0 +1,5 @@ +#ifndef IOP32X_ADMA_H +#define IOP32X_ADMA_H +#include <asm/hardware/iop3xx-adma.h> +#endif + diff --git a/arch/arm/mach-iop32x/include/mach/entry-macro.S b/arch/arm/mach-iop32x/include/mach/entry-macro.S new file mode 100644 index 00000000000..ea13ae02d9b --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/entry-macro.S @@ -0,0 +1,33 @@ +/* + * arch/arm/mach-iop32x/include/mach/entry-macro.S + * + * Low-level IRQ helper macros for IOP32x-based platforms + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ +#include <mach/iop32x.h> + + .macro get_irqnr_preamble, base, tmp + mrc p15, 0, \tmp, c15, c1, 0 + orr \tmp, \tmp, #(1 << 6) + mcr p15, 0, \tmp, c15, c1, 0 @ Enable cp6 access + mrc p15, 0, \tmp, c15, c1, 0 + mov \tmp, \tmp + sub pc, pc, #4 @ cp_wait + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC + cmp \irqstat, #0 + clzne \irqnr, \irqstat + rsbne \irqnr, \irqnr, #31 + .endm + + .macro arch_ret_to_user, tmp1, tmp2 + mrc p15, 0, \tmp1, c15, c1, 0 + ands \tmp2, \tmp1, #(1 << 6) + bicne \tmp1, \tmp1, #(1 << 6) + mcrne p15, 0, \tmp1, c15, c1, 0 @ Disable cp6 access + .endm diff --git a/arch/arm/mach-iop32x/include/mach/glantank.h b/arch/arm/mach-iop32x/include/mach/glantank.h new file mode 100644 index 00000000000..958eb91c091 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/glantank.h @@ -0,0 +1,13 @@ +/* + * arch/arm/mach-iop32x/include/mach/glantank.h + * + * IO-Data GLAN Tank board registers + */ + +#ifndef __GLANTANK_H +#define __GLANTANK_H + +#define GLANTANK_UART 0xfe800000 /* UART */ + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/hardware.h b/arch/arm/mach-iop32x/include/mach/hardware.h new file mode 100644 index 00000000000..48cb1b20ba9 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/hardware.h @@ -0,0 +1,41 @@ +/* + * arch/arm/mach-iop32x/include/mach/hardware.h + */ + +#ifndef __HARDWARE_H +#define __HARDWARE_H + +#include <asm/types.h> + +/* + * Note about PCI IO space mappings + * + * To make IO space accesses efficient, we store virtual addresses in + * the IO resources. + * + * The PCI IO space is located at virtual 0xfe000000 from physical + * 0x90000000. The PCI BARs must be programmed with physical addresses, + * but when we read them, we convert them to virtual addresses. See + * arch/arm/plat-iop/pci.c. + */ + +#ifndef __ASSEMBLY__ +void iop32x_init_irq(void); +#endif + + +/* + * Generic chipset bits + */ +#include "iop32x.h" + +/* + * Board specific bits + */ +#include "glantank.h" +#include "iq80321.h" +#include "iq31244.h" +#include "n2100.h" + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/iop32x.h b/arch/arm/mach-iop32x/include/mach/iop32x.h new file mode 100644 index 00000000000..56ec864ec31 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/iop32x.h @@ -0,0 +1,34 @@ +/* + * arch/arm/mach-iop32x/include/mach/iop32x.h + * + * Intel IOP32X Chip definitions + * + * Author: Rory Bolt <rorybolt@pacbell.net> + * Copyright (C) 2002 Rory Bolt + * Copyright (C) 2004 Intel Corp. + * + * 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 __IOP32X_H +#define __IOP32X_H + +/* + * Peripherals that are shared between the iop32x and iop33x but + * located at different addresses. + */ +#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg)) + +#include <asm/hardware/iop3xx.h> + +/* ATU Parameters + * set up a 1:1 bus to physical ram relationship + * w/ physical ram on top of pci in the memory map + */ +#define IOP32X_MAX_RAM_SIZE 0x40000000UL +#define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE +#define IOP3XX_PCI_LOWER_MEM_BA 0x80000000 + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/iq31244.h b/arch/arm/mach-iop32x/include/mach/iq31244.h new file mode 100644 index 00000000000..6b6b369e781 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/iq31244.h @@ -0,0 +1,17 @@ +/* + * arch/arm/mach-iop32x/include/mach/iq31244.h + * + * Intel IQ31244 evaluation board registers + */ + +#ifndef __IQ31244_H +#define __IQ31244_H + +#define IQ31244_UART 0xfe800000 /* UART #1 */ +#define IQ31244_7SEG_1 0xfe840000 /* 7-Segment MSB */ +#define IQ31244_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */ +#define IQ31244_ROTARY_SW 0xfe8d0000 /* Rotary Switch */ +#define IQ31244_BATT_STAT 0xfe8f0000 /* Battery Status */ + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/iq80321.h b/arch/arm/mach-iop32x/include/mach/iq80321.h new file mode 100644 index 00000000000..498819b737e --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/iq80321.h @@ -0,0 +1,17 @@ +/* + * arch/arm/mach-iop32x/include/mach/iq80321.h + * + * Intel IQ80321 evaluation board registers + */ + +#ifndef __IQ80321_H +#define __IQ80321_H + +#define IQ80321_UART 0xfe800000 /* UART #1 */ +#define IQ80321_7SEG_1 0xfe840000 /* 7-Segment MSB */ +#define IQ80321_7SEG_0 0xfe850000 /* 7-Segment LSB (WO) */ +#define IQ80321_ROTARY_SW 0xfe8d0000 /* Rotary Switch */ +#define IQ80321_BATT_STAT 0xfe8f0000 /* Battery Status */ + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/irqs.h b/arch/arm/mach-iop32x/include/mach/irqs.h new file mode 100644 index 00000000000..33573e09914 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/irqs.h @@ -0,0 +1,50 @@ +/* + * arch/arm/mach-iop32x/include/mach/irqs.h + * + * Author: Rory Bolt <rorybolt@pacbell.net> + * Copyright: (C) 2002 Rory Bolt + * + * 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 __IRQS_H +#define __IRQS_H + +/* + * IOP80321 chipset interrupts + */ +#define IRQ_IOP32X_DMA0_EOT 0 +#define IRQ_IOP32X_DMA0_EOC 1 +#define IRQ_IOP32X_DMA1_EOT 2 +#define IRQ_IOP32X_DMA1_EOC 3 +#define IRQ_IOP32X_AA_EOT 6 +#define IRQ_IOP32X_AA_EOC 7 +#define IRQ_IOP32X_CORE_PMON 8 +#define IRQ_IOP32X_TIMER0 9 +#define IRQ_IOP32X_TIMER1 10 +#define IRQ_IOP32X_I2C_0 11 +#define IRQ_IOP32X_I2C_1 12 +#define IRQ_IOP32X_MESSAGING 13 +#define IRQ_IOP32X_ATU_BIST 14 +#define IRQ_IOP32X_PERFMON 15 +#define IRQ_IOP32X_CORE_PMU 16 +#define IRQ_IOP32X_BIU_ERR 17 +#define IRQ_IOP32X_ATU_ERR 18 +#define IRQ_IOP32X_MCU_ERR 19 +#define IRQ_IOP32X_DMA0_ERR 20 +#define IRQ_IOP32X_DMA1_ERR 21 +#define IRQ_IOP32X_AA_ERR 23 +#define IRQ_IOP32X_MSG_ERR 24 +#define IRQ_IOP32X_SSP 25 +#define IRQ_IOP32X_XINT0 27 +#define IRQ_IOP32X_XINT1 28 +#define IRQ_IOP32X_XINT2 29 +#define IRQ_IOP32X_XINT3 30 +#define IRQ_IOP32X_HPI 31 + +#define NR_IRQS 32 + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/n2100.h b/arch/arm/mach-iop32x/include/mach/n2100.h new file mode 100644 index 00000000000..40b8a532b06 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/n2100.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-iop32x/include/mach/n2100.h + * + * Thecus N2100 board registers + */ + +#ifndef __N2100_H +#define __N2100_H + +#define N2100_UART 0xfe800000 /* UART */ + +#define N2100_COPY_BUTTON IOP3XX_GPIO_LINE(0) +#define N2100_PCA9532_RESET IOP3XX_GPIO_LINE(2) +#define N2100_RESET_BUTTON IOP3XX_GPIO_LINE(3) +#define N2100_HARDWARE_RESET IOP3XX_GPIO_LINE(4) +#define N2100_POWER_BUTTON IOP3XX_GPIO_LINE(5) + + +#endif diff --git a/arch/arm/mach-iop32x/include/mach/time.h b/arch/arm/mach-iop32x/include/mach/time.h new file mode 100644 index 00000000000..0f28c994962 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/time.h @@ -0,0 +1,4 @@ +#ifndef _IOP32X_TIME_H_ +#define _IOP32X_TIME_H_ +#define IRQ_IOP_TIMER0 IRQ_IOP32X_TIMER0 +#endif diff --git a/arch/arm/mach-iop32x/include/mach/uncompress.h b/arch/arm/mach-iop32x/include/mach/uncompress.h new file mode 100644 index 00000000000..b3d45fd365e --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/uncompress.h @@ -0,0 +1,38 @@ +/* + * arch/arm/mach-iop32x/include/mach/uncompress.h + */ + +#include <asm/types.h> +#include <asm/mach-types.h> +#include <linux/serial_reg.h> +#include <mach/hardware.h> + +volatile u8 *uart_base; + +#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE) + +static inline void putc(char c) +{ + while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE) + barrier(); + uart_base[UART_TX] = c; +} + +static inline void flush(void) +{ +} + +static __inline__ void __arch_decomp_setup(unsigned long arch_id) +{ + if (machine_is_iq80321()) + uart_base = (volatile u8 *)IQ80321_UART; + else if (machine_is_iq31244() || machine_is_em7210()) + uart_base = (volatile u8 *)IQ31244_UART; + else + uart_base = (volatile u8 *)0xfe800000; +} + +/* + * nothing to do + */ +#define arch_decomp_setup() __arch_decomp_setup(arch_id) diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c index be4aedfa0de..0e1392b20d1 100644 --- a/arch/arm/mach-iop32x/iq31244.c +++ b/arch/arm/mach-iop32x/iq31244.c @@ -21,13 +21,13 @@ #include <linux/pci.h> #include <linux/pm.h> #include <linux/string.h> -#include <linux/slab.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/mtd/physmap.h> #include <linux/platform_device.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <asm/cputype.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -36,16 +36,29 @@ #include <asm/mach-types.h> #include <asm/page.h> #include <asm/pgtable.h> - +#include <mach/time.h> +#include "gpio-iop32x.h" /* - * The EP80219 and IQ31244 use the same machine ID. To find out - * which of the two we're running on, we look at the processor ID. + * Until March of 2007 iq31244 platforms and ep80219 platforms shared the + * same machine id, and the processor type was used to select board type. + * However this assumption breaks for an iq80219 board which is an iop219 + * processor on an iq31244 board. The force_ep80219 flag has been added + * for old boot loaders using the iq31244 machine id for an ep80219 platform. */ +static int force_ep80219; + static int is_80219(void) { - extern int processor_id; - return !!((processor_id & 0xffffffe0) == 0x69052e20); + return !!((read_cpuid_id() & 0xffffffe0) == 0x69052e20); +} + +static int is_ep80219(void) +{ + if (machine_is_ep80219() || force_ep80219) + return 1; + else + return 0; } @@ -54,20 +67,15 @@ static int is_80219(void) */ static void __init iq31244_timer_init(void) { - if (is_80219()) { + if (is_ep80219()) { /* 33.333 MHz crystal. */ - iop3xx_init_time(200000000); + iop_init_time(200000000); } else { /* 33.000 MHz crystal. */ - iop3xx_init_time(198000000); + iop_init_time(198000000); } } -static struct sys_timer iq31244_timer = { - .init = iq31244_timer_init, - .offset = iop3xx_gettimeoffset, -}; - /* * IQ31244 I/O. @@ -91,8 +99,8 @@ void __init iq31244_map_io(void) /* * EP80219/IQ31244 PCI. */ -static inline int __init -ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int __init +ep80219_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int irq; @@ -119,16 +127,15 @@ ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } static struct hw_pci ep80219_pci __initdata = { - .swizzle = pci_std_swizzle, .nr_controllers = 1, + .ops = &iop3xx_ops, .setup = iop3xx_pci_setup, .preinit = iop3xx_pci_preinit, - .scan = iop3xx_pci_scan_bus, .map_irq = ep80219_pci_map_irq, }; -static inline int __init -iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int __init +iq31244_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int irq; @@ -155,22 +162,27 @@ iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } static struct hw_pci iq31244_pci __initdata = { - .swizzle = pci_std_swizzle, .nr_controllers = 1, + .ops = &iop3xx_ops, .setup = iop3xx_pci_setup, .preinit = iop3xx_pci_preinit, - .scan = iop3xx_pci_scan_bus, .map_irq = iq31244_pci_map_irq, }; static int __init iq31244_pci_init(void) { - if (machine_is_iq31244()) { + if (is_ep80219()) + pci_common_init(&ep80219_pci); + else if (machine_is_iq31244()) { if (is_80219()) { - pci_common_init(&ep80219_pci); - } else { - pci_common_init(&iq31244_pci); + printk("note: iq31244 board type has been selected\n"); + printk("note: to select ep80219 operation:\n"); + printk("\t1/ specify \"force_ep80219\" on the kernel" + " command line\n"); + printk("\t2/ update boot loader to pass" + " the ep80219 id: %d\n", MACH_TYPE_EP80219); } + pci_common_init(&iq31244_pci); } return 0; @@ -272,22 +284,50 @@ void ep80219_power_off(void) static void __init iq31244_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq31244_flash_device); platform_device_register(&iq31244_serial_device); + platform_device_register(&iop3xx_dma_0_channel); + platform_device_register(&iop3xx_dma_1_channel); - if (is_80219()) + if (is_ep80219()) pm_power_off = ep80219_power_off; + + if (!is_80219()) + platform_device_register(&iop3xx_aau_channel); } +static int __init force_ep80219_setup(char *str) +{ + force_ep80219 = 1; + return 1; +} + +__setup("force_ep80219", force_ep80219_setup); + MACHINE_START(IQ31244, "Intel IQ31244") /* Maintainer: Intel Corp. */ - .phys_io = IQ31244_UART, - .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc, - .boot_params = 0xa0000100, + .atag_offset = 0x100, + .map_io = iq31244_map_io, + .init_irq = iop32x_init_irq, + .init_time = iq31244_timer_init, + .init_machine = iq31244_init_machine, + .restart = iop3xx_restart, +MACHINE_END + +/* There should have been an ep80219 machine identifier from the beginning. + * Boot roms older than March 2007 do not know the ep80219 machine id. Pass + * "force_ep80219" on the kernel command line, otherwise iq31244 operation + * will be selected. + */ +MACHINE_START(EP80219, "Intel EP80219") + /* Maintainer: Intel Corp. */ + .atag_offset = 0x100, .map_io = iq31244_map_io, .init_irq = iop32x_init_irq, - .timer = &iq31244_timer, + .init_time = iq31244_timer_init, .init_machine = iq31244_init_machine, + .restart = iop3xx_restart, MACHINE_END diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c index 1f37b550188..66782ff1f46 100644 --- a/arch/arm/mach-iop32x/iq80321.c +++ b/arch/arm/mach-iop32x/iq80321.c @@ -18,13 +18,12 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/string.h> -#include <linux/slab.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/mtd/physmap.h> #include <linux/platform_device.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <linux/io.h> +#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -33,6 +32,8 @@ #include <asm/mach-types.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <mach/time.h> +#include "gpio-iop32x.h" /* * IQ80321 timer tick configuration. @@ -40,14 +41,9 @@ static void __init iq80321_timer_init(void) { /* 33.333 MHz crystal. */ - iop3xx_init_time(200000000); + iop_init_time(200000000); } -static struct sys_timer iq80321_timer = { - .init = iq80321_timer_init, - .offset = iop3xx_gettimeoffset, -}; - /* * IQ80321 I/O. @@ -71,8 +67,8 @@ void __init iq80321_map_io(void) /* * IQ80321 PCI. */ -static inline int __init -iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int __init +iq80321_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int irq; @@ -102,17 +98,17 @@ iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } static struct hw_pci iq80321_pci __initdata = { - .swizzle = pci_std_swizzle, .nr_controllers = 1, + .ops = &iop3xx_ops, .setup = iop3xx_pci_setup, - .preinit = iop3xx_pci_preinit, - .scan = iop3xx_pci_scan_bus, + .preinit = iop3xx_pci_preinit_cond, .map_irq = iq80321_pci_map_irq, }; static int __init iq80321_pci_init(void) { - if (machine_is_iq80321()) + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80321()) pci_common_init(&iq80321_pci); return 0; @@ -175,19 +171,22 @@ static struct platform_device iq80321_serial_device = { static void __init iq80321_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iq80321_flash_device); platform_device_register(&iq80321_serial_device); + platform_device_register(&iop3xx_dma_0_channel); + platform_device_register(&iop3xx_dma_1_channel); + platform_device_register(&iop3xx_aau_channel); } MACHINE_START(IQ80321, "Intel IQ80321") /* Maintainer: Intel Corp. */ - .phys_io = IQ80321_UART, - .io_pg_offst = ((IQ80321_UART) >> 18) & 0xfffc, - .boot_params = 0xa0000100, + .atag_offset = 0x100, .map_io = iq80321_map_io, .init_irq = iop32x_init_irq, - .timer = &iq80321_timer, + .init_time = iq80321_timer_init, .init_machine = iq80321_init_machine, + .restart = iop3xx_restart, MACHINE_END diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index 69d6302f40c..d7ee2789d89 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -16,61 +16,59 @@ #include <linux/list.h> #include <asm/mach/irq.h> #include <asm/irq.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach-types.h> static u32 iop32x_mask; -static inline void intctl_write(u32 val) +static void intctl_write(u32 val) { - iop3xx_cp6_enable(); asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val)); - iop3xx_cp6_disable(); } -static inline void intstr_write(u32 val) +static void intstr_write(u32 val) { - iop3xx_cp6_enable(); asm volatile("mcr p6, 0, %0, c4, c0, 0" : : "r" (val)); - iop3xx_cp6_disable(); } static void -iop32x_irq_mask(unsigned int irq) +iop32x_irq_mask(struct irq_data *d) { - iop32x_mask &= ~(1 << irq); + iop32x_mask &= ~(1 << d->irq); intctl_write(iop32x_mask); } static void -iop32x_irq_unmask(unsigned int irq) +iop32x_irq_unmask(struct irq_data *d) { - iop32x_mask |= 1 << irq; + iop32x_mask |= 1 << d->irq; intctl_write(iop32x_mask); } struct irq_chip ext_chip = { - .name = "IOP32x", - .ack = iop32x_irq_mask, - .mask = iop32x_irq_mask, - .unmask = iop32x_irq_unmask, + .name = "IOP32x", + .irq_ack = iop32x_irq_mask, + .irq_mask = iop32x_irq_mask, + .irq_unmask = iop32x_irq_unmask, }; void __init iop32x_init_irq(void) { int i; + iop_init_cp6_handler(); + intctl_write(0); intstr_write(0); if (machine_is_glantank() || machine_is_iq80321() || machine_is_iq31244() || - machine_is_n2100()) + machine_is_n2100() || + machine_is_em7210()) *IOP3XX_PCIIRSR = 0x0f; for (i = 0; i < NR_IRQS; i++) { - set_irq_chip(i, &ext_chip); - set_irq_handler(i, do_level_IRQ); + irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); set_irq_flags(i, IRQF_VALID | IRQF_PROBE); } } diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c index a2c94a47b2b..c1cd80ecc21 100644 --- a/arch/arm/mach-iop32x/n2100.c +++ b/arch/arm/mach-iop32x/n2100.c @@ -16,19 +16,22 @@ #include <linux/mm.h> #include <linux/init.h> +#include <linux/f75375s.h> +#include <linux/leds-pca9532.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/pm.h> #include <linux/string.h> -#include <linux/slab.h> #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/mtd/physmap.h> +#include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/reboot.h> -#include <asm/hardware.h> -#include <asm/io.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <mach/hardware.h> #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> @@ -37,6 +40,8 @@ #include <asm/mach-types.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <mach/time.h> +#include "gpio-iop32x.h" /* * N2100 timer tick configuration. @@ -44,14 +49,9 @@ static void __init n2100_timer_init(void) { /* 33.000 MHz crystal. */ - iop3xx_init_time(198000000); + iop_init_time(198000000); } -static struct sys_timer n2100_timer = { - .init = n2100_timer_init, - .offset = iop3xx_gettimeoffset, -}; - /* * N2100 I/O. @@ -75,8 +75,8 @@ void __init n2100_map_io(void) /* * N2100 PCI. */ -static inline int __init -n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +static int __init +n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { int irq; @@ -85,7 +85,7 @@ n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) irq = IRQ_IOP32X_XINT0; } else if (PCI_SLOT(dev->devfn) == 2) { /* RTL8110SB #2 */ - irq = IRQ_IOP32X_XINT1; + irq = IRQ_IOP32X_XINT3; } else if (PCI_SLOT(dev->devfn) == 3) { /* Sil3512 */ irq = IRQ_IOP32X_XINT2; @@ -112,14 +112,27 @@ n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) } static struct hw_pci n2100_pci __initdata = { - .swizzle = pci_std_swizzle, .nr_controllers = 1, + .ops = &iop3xx_ops, .setup = iop3xx_pci_setup, .preinit = iop3xx_pci_preinit, - .scan = iop3xx_pci_scan_bus, .map_irq = n2100_pci_map_irq, }; +/* + * Both r8169 chips on the n2100 exhibit PCI parity problems. Set + * the ->broken_parity_status flag for both ports so that the r8169 + * driver knows it should ignore error interrupts. + */ +static void n2100_fixup_r8169(struct pci_dev *dev) +{ + if (dev->bus->number == 0 && + (dev->devfn == PCI_DEVFN(1, 0) || + dev->devfn == PCI_DEVFN(2, 0))) + dev->broken_parity_status = 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REALTEK, PCI_ANY_ID, n2100_fixup_r8169); + static int __init n2100_pci_init(void) { if (machine_is_n2100()) @@ -160,7 +173,7 @@ static struct plat_serial8250_port n2100_serial_port[] = { .mapbase = N2100_UART, .membase = (char *)N2100_UART, .irq = 0, - .flags = UPF_SKIP_TEST, + .flags = UPF_SKIP_TEST | UPF_AUTO_IRQ | UPF_SHARE_IRQ, .iotype = UPIO_MEM, .regshift = 0, .uartclk = 1843200, @@ -184,6 +197,71 @@ static struct platform_device n2100_serial_device = { .resource = &n2100_uart_resource, }; +static struct f75375s_platform_data n2100_f75375s = { + .pwm = { 255, 255 }, + .pwm_enable = { 0, 0 }, +}; + +static struct pca9532_platform_data n2100_leds = { + .leds = { + { .name = "n2100:red:satafail0", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + { .name = "n2100:red:satafail1", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + { .name = "n2100:blue:usb", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + { .type = PCA9532_TYPE_NONE }, + + { .type = PCA9532_TYPE_NONE }, + { .type = PCA9532_TYPE_NONE }, + { .type = PCA9532_TYPE_NONE }, + { .name = "n2100:red:usb", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + + { .type = PCA9532_TYPE_NONE }, /* power OFF gpio */ + { .type = PCA9532_TYPE_NONE }, /* reset gpio */ + { .type = PCA9532_TYPE_NONE }, + { .type = PCA9532_TYPE_NONE }, + + { .type = PCA9532_TYPE_NONE }, + { .name = "n2100:orange:system", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + { .name = "n2100:red:system", + .state = PCA9532_OFF, + .type = PCA9532_TYPE_LED, + }, + { .name = "N2100 beeper" , + .state = PCA9532_OFF, + .type = PCA9532_TYPE_N2100_BEEP, + }, + }, + .psc = { 0, 0 }, + .pwm = { 0, 0 }, +}; + +static struct i2c_board_info __initdata n2100_i2c_devices[] = { + { + I2C_BOARD_INFO("rs5c372b", 0x32), + }, + { + I2C_BOARD_INFO("f75375", 0x2e), + .platform_data = &n2100_f75375s, + }, + { + I2C_BOARD_INFO("pca9532", 0x60), + .platform_data = &n2100_leds, + }, +}; /* * Pull PCA9532 GPIO #8 low to power off the machine. @@ -210,12 +288,26 @@ static void n2100_power_off(void) ; } +static void n2100_restart(enum reboot_mode mode, const char *cmd) +{ + int ret; + + ret = gpio_direction_output(N2100_HARDWARE_RESET, 0); + if (ret) { + pr_crit("could not drive reset GPIO low\n"); + return; + } + /* Wait for reset to happen */ + while (1) + ; +} + static struct timer_list power_button_poll_timer; static void power_button_poll(unsigned long dummy) { - if (gpio_line_get(N2100_POWER_BUTTON) == 0) { + if (gpio_get_value(N2100_POWER_BUTTON) == 0) { ctrl_alt_del(); return; } @@ -224,28 +316,55 @@ static void power_button_poll(unsigned long dummy) add_timer(&power_button_poll_timer); } +static int __init n2100_request_gpios(void) +{ + int ret; + + if (!machine_is_n2100()) + return 0; + + ret = gpio_request(N2100_HARDWARE_RESET, "reset"); + if (ret) + pr_err("could not request reset GPIO\n"); + + ret = gpio_request(N2100_POWER_BUTTON, "power"); + if (ret) + pr_err("could not request power GPIO\n"); + else { + ret = gpio_direction_input(N2100_POWER_BUTTON); + if (ret) + pr_err("could not set power GPIO as input\n"); + } + /* Set up power button poll timer */ + init_timer(&power_button_poll_timer); + power_button_poll_timer.function = power_button_poll; + power_button_poll_timer.expires = jiffies + (HZ / 10); + add_timer(&power_button_poll_timer); + return 0; +} +device_initcall(n2100_request_gpios); static void __init n2100_init_machine(void) { + register_iop32x_gpio(); platform_device_register(&iop3xx_i2c0_device); platform_device_register(&n2100_flash_device); platform_device_register(&n2100_serial_device); + platform_device_register(&iop3xx_dma_0_channel); + platform_device_register(&iop3xx_dma_1_channel); - pm_power_off = n2100_power_off; + i2c_register_board_info(0, n2100_i2c_devices, + ARRAY_SIZE(n2100_i2c_devices)); - init_timer(&power_button_poll_timer); - power_button_poll_timer.function = power_button_poll; - power_button_poll_timer.expires = jiffies + (HZ / 10); - add_timer(&power_button_poll_timer); + pm_power_off = n2100_power_off; } MACHINE_START(N2100, "Thecus N2100") /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ - .phys_io = N2100_UART, - .io_pg_offst = ((N2100_UART) >> 18) & 0xfffc, - .boot_params = 0xa0000100, + .atag_offset = 0x100, .map_io = n2100_map_io, .init_irq = iop32x_init_irq, - .timer = &n2100_timer, + .init_time = n2100_timer_init, .init_machine = n2100_init_machine, + .restart = n2100_restart, MACHINE_END |
