diff options
Diffstat (limited to 'arch/arm/mach-iop32x')
21 files changed, 1763 insertions, 0 deletions
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig new file mode 100644 index 000000000..f1f342cb0 --- /dev/null +++ b/arch/arm/mach-iop32x/Kconfig @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0 +if ARCH_IOP32X + +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 + Say Y here if you want to run your kernel on the GLAN Tank + NAS appliance or machines from IO-Data's HDL-Gxxx, HDL-GWxxx + and HDL-GZxxx series. + +config ARCH_IQ80321 + bool "Enable support for IQ80321" + help + Say Y here if you want to run your kernel on the Intel IQ80321 + evaluation kit for the IOP321 processor. + +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) + or the IQ31244 evaluation kit for the IOP321 processor. + +config MACH_N2100 + bool "Enable support for the Thecus n2100" + help + 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 new file mode 100644 index 000000000..71d62447d --- /dev/null +++ b/arch/arm/mach-iop32x/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the linux kernel. +# + +obj-y := irq.o + +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 new file mode 100644 index 000000000..0a833b11e --- /dev/null +++ b/arch/arm/mach-iop32x/Makefile.boot @@ -0,0 +1,3 @@ + 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 000000000..77e1ff057 --- /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 new file mode 100644 index 000000000..547b2342d --- /dev/null +++ b/arch/arm/mach-iop32x/glantank.c @@ -0,0 +1,213 @@ +/* + * arch/arm/mach-iop32x/glantank.c + * + * Board support code for the GLAN Tank. + * + * 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 + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#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/serial_core.h> +#include <linux/serial_8250.h> +#include <linux/mtd/physmap.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <asm/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 <asm/page.h> +#include <mach/time.h> +#include "gpio-iop32x.h" + +/* + * GLAN Tank timer tick configuration. + */ +static void __init glantank_timer_init(void) +{ + /* 33.333 MHz crystal. */ + iop_init_time(200000000); +} + + +/* + * GLAN Tank I/O. + */ +static struct map_desc glantank_io_desc[] __initdata = { + { /* on-board devices */ + .virtual = GLANTANK_UART, + .pfn = __phys_to_pfn(GLANTANK_UART), + .length = 0x00100000, + .type = MT_DEVICE + }, +}; + +void __init glantank_map_io(void) +{ + iop3xx_map_io(); + iotable_init(glantank_io_desc, ARRAY_SIZE(glantank_io_desc)); +} + + +/* + * GLAN Tank PCI. + */ +#define INTA IRQ_IOP32X_XINT0 +#define INTB IRQ_IOP32X_XINT1 +#define INTC IRQ_IOP32X_XINT2 +#define INTD IRQ_IOP32X_XINT3 + +static int __init +glantank_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 + */ + {INTD, INTD, INTD, INTD}, /* UART (8250) */ + {INTA, INTA, INTA, INTA}, /* Ethernet (E1000) */ + {INTB, INTB, INTB, INTB}, /* IDE (AEC6280R) */ + {INTC, INTC, INTC, INTC}, /* USB (NEC) */ + }; + + BUG_ON(pin < 1 || pin > 4); + + return pci_irq_table[slot % 4][pin - 1]; +} + +static struct hw_pci glantank_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit, + .map_irq = glantank_pci_map_irq, +}; + +static int __init glantank_pci_init(void) +{ + if (machine_is_glantank()) + pci_common_init(&glantank_pci); + + return 0; +} + +subsys_initcall(glantank_pci_init); + + +/* + * GLAN Tank machine initialization. + */ +static struct physmap_flash_data glantank_flash_data = { + .width = 2, +}; + +static struct resource glantank_flash_resource = { + .start = 0xf0000000, + .end = 0xf007ffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device glantank_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &glantank_flash_data, + }, + .num_resources = 1, + .resource = &glantank_flash_resource, +}; + +static struct plat_serial8250_port glantank_serial_port[] = { + { + .mapbase = GLANTANK_UART, + .membase = (char *)GLANTANK_UART, + .irq = IRQ_IOP32X_XINT3, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = 1843200, + }, + { }, +}; + +static struct resource glantank_uart_resource = { + .start = GLANTANK_UART, + .end = GLANTANK_UART + 7, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device glantank_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = glantank_serial_port, + }, + .num_resources = 1, + .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, IOMEM(0xfe8d0004)); + + while (1) + ; +} + +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> */ + .atag_offset = 0x100, + .map_io = glantank_map_io, + .init_irq = iop32x_init_irq, + .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 000000000..20af87e4c --- /dev/null +++ b/arch/arm/mach-iop32x/gpio-iop32x.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +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 000000000..2b2006312 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/adma.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#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 000000000..ea13ae02d --- /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 000000000..b9df2e461 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/glantank.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 000000000..6e5303e60 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/hardware.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 000000000..56ec864ec --- /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 000000000..e62da5da6 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/iq31244.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 000000000..faf62c26f --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/iq80321.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 000000000..33573e099 --- /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 000000000..70bb660b6 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/n2100.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 000000000..d08950cce --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/time.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#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 000000000..ed4ac3e28 --- /dev/null +++ b/arch/arm/mach-iop32x/include/mach/uncompress.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 new file mode 100644 index 000000000..0e1392b20 --- /dev/null +++ b/arch/arm/mach-iop32x/iq31244.c @@ -0,0 +1,333 @@ +/* + * arch/arm/mach-iop32x/iq31244.c + * + * Board support code for the Intel EP80219 and IQ31244 platforms. + * + * Author: Rory Bolt <rorybolt@pacbell.net> + * Copyright (C) 2002 Rory Bolt + * Copyright 2003 (c) MontaVista, Software, Inc. + * 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/string.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.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> +#include <asm/mach/pci.h> +#include <asm/mach/time.h> +#include <asm/mach-types.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <mach/time.h> +#include "gpio-iop32x.h" + +/* + * 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) +{ + return !!((read_cpuid_id() & 0xffffffe0) == 0x69052e20); +} + +static int is_ep80219(void) +{ + if (machine_is_ep80219() || force_ep80219) + return 1; + else + return 0; +} + + +/* + * EP80219/IQ31244 timer tick configuration. + */ +static void __init iq31244_timer_init(void) +{ + if (is_ep80219()) { + /* 33.333 MHz crystal. */ + iop_init_time(200000000); + } else { + /* 33.000 MHz crystal. */ + iop_init_time(198000000); + } +} + + +/* + * IQ31244 I/O. + */ +static struct map_desc iq31244_io_desc[] __initdata = { + { /* on-board devices */ + .virtual = IQ31244_UART, + .pfn = __phys_to_pfn(IQ31244_UART), + .length = 0x00100000, + .type = MT_DEVICE, + }, +}; + +void __init iq31244_map_io(void) +{ + iop3xx_map_io(); + iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc)); +} + + +/* + * EP80219/IQ31244 PCI. + */ +static int __init +ep80219_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + if (slot == 0) { + /* CFlash */ + irq = IRQ_IOP32X_XINT1; + } else if (slot == 1) { + /* 82551 Pro 100 */ + irq = IRQ_IOP32X_XINT0; + } else if (slot == 2) { + /* PCI-X Slot */ + irq = IRQ_IOP32X_XINT3; + } else if (slot == 3) { + /* SATA */ + irq = IRQ_IOP32X_XINT2; + } else { + printk(KERN_ERR "ep80219_pci_map_irq() called for unknown " + "device PCI:%d:%d:%d\n", dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + irq = -1; + } + + return irq; +} + +static struct hw_pci ep80219_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit, + .map_irq = ep80219_pci_map_irq, +}; + +static int __init +iq31244_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + if (slot == 0) { + /* CFlash */ + irq = IRQ_IOP32X_XINT1; + } else if (slot == 1) { + /* SATA */ + irq = IRQ_IOP32X_XINT2; + } else if (slot == 2) { + /* PCI-X Slot */ + irq = IRQ_IOP32X_XINT3; + } else if (slot == 3) { + /* 82546 GigE */ + irq = IRQ_IOP32X_XINT0; + } else { + printk(KERN_ERR "iq31244_pci_map_irq called for unknown " + "device PCI:%d:%d:%d\n", dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + irq = -1; + } + + return irq; +} + +static struct hw_pci iq31244_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit, + .map_irq = iq31244_pci_map_irq, +}; + +static int __init iq31244_pci_init(void) +{ + if (is_ep80219()) + pci_common_init(&ep80219_pci); + else if (machine_is_iq31244()) { + if (is_80219()) { + 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; +} + +subsys_initcall(iq31244_pci_init); + + +/* + * IQ31244 machine initialisation. + */ +static struct physmap_flash_data iq31244_flash_data = { + .width = 2, +}; + +static struct resource iq31244_flash_resource = { + .start = 0xf0000000, + .end = 0xf07fffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device iq31244_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &iq31244_flash_data, + }, + .num_resources = 1, + .resource = &iq31244_flash_resource, +}; + +static struct plat_serial8250_port iq31244_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 iq31244_uart_resource = { + .start = IQ31244_UART, + .end = IQ31244_UART + 7, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device iq31244_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = iq31244_serial_port, + }, + .num_resources = 1, + .resource = &iq31244_uart_resource, +}; + +/* + * This function will send a SHUTDOWN_COMPLETE message to the PIC + * controller over I2C. We are not using the i2c subsystem since + * we are going to power off and it may be removed + */ +void ep80219_power_off(void) +{ + /* + * Send the Address byte w/ the start condition + */ + *IOP3XX_IDBR1 = 0x60; + *IOP3XX_ICR1 = 0xE9; + mdelay(1); + + /* + * Send the START_MSG byte w/ no start or stop condition + */ + *IOP3XX_IDBR1 = 0x0F; + *IOP3XX_ICR1 = 0xE8; + mdelay(1); + + /* + * Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or + * stop condition + */ + *IOP3XX_IDBR1 = 0x03; + *IOP3XX_ICR1 = 0xE8; + mdelay(1); + + /* + * Send an ignored byte w/ stop condition + */ + *IOP3XX_IDBR1 = 0x00; + *IOP3XX_ICR1 = 0xEA; + + while (1) + ; +} + +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_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. */ + .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, + .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 new file mode 100644 index 000000000..66782ff1f --- /dev/null +++ b/arch/arm/mach-iop32x/iq80321.c @@ -0,0 +1,192 @@ +/* + * arch/arm/mach-iop32x/iq80321.c + * + * Board support code for the Intel IQ80321 platform. + * + * 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <asm/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 <asm/page.h> +#include <asm/pgtable.h> +#include <mach/time.h> +#include "gpio-iop32x.h" + +/* + * IQ80321 timer tick configuration. + */ +static void __init iq80321_timer_init(void) +{ + /* 33.333 MHz crystal. */ + iop_init_time(200000000); +} + + +/* + * IQ80321 I/O. + */ +static struct map_desc iq80321_io_desc[] __initdata = { + { /* on-board devices */ + .virtual = IQ80321_UART, + .pfn = __phys_to_pfn(IQ80321_UART), + .length = 0x00100000, + .type = MT_DEVICE, + }, +}; + +void __init iq80321_map_io(void) +{ + iop3xx_map_io(); + iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc)); +} + + +/* + * IQ80321 PCI. + */ +static int __init +iq80321_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + if ((slot == 2 || slot == 6) && pin == 1) { + /* PCI-X Slot INTA */ + irq = IRQ_IOP32X_XINT2; + } else if ((slot == 2 || slot == 6) && pin == 2) { + /* PCI-X Slot INTA */ + irq = IRQ_IOP32X_XINT3; + } else if ((slot == 2 || slot == 6) && pin == 3) { + /* PCI-X Slot INTA */ + irq = IRQ_IOP32X_XINT0; + } else if ((slot == 2 || slot == 6) && pin == 4) { + /* PCI-X Slot INTA */ + irq = IRQ_IOP32X_XINT1; + } else if (slot == 4 || slot == 8) { + /* Gig-E */ + irq = IRQ_IOP32X_XINT0; + } else { + printk(KERN_ERR "iq80321_pci_map_irq() called for unknown " + "device PCI:%d:%d:%d\n", dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + irq = -1; + } + + return irq; +} + +static struct hw_pci iq80321_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit_cond, + .map_irq = iq80321_pci_map_irq, +}; + +static int __init iq80321_pci_init(void) +{ + if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) && + machine_is_iq80321()) + pci_common_init(&iq80321_pci); + + return 0; +} + +subsys_initcall(iq80321_pci_init); + + +/* + * IQ80321 machine initialisation. + */ +static struct physmap_flash_data iq80321_flash_data = { + .width = 1, +}; + +static struct resource iq80321_flash_resource = { + .start = 0xf0000000, + .end = 0xf07fffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device iq80321_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &iq80321_flash_data, + }, + .num_resources = 1, + .resource = &iq80321_flash_resource, +}; + +static struct plat_serial8250_port iq80321_serial_port[] = { + { + .mapbase = IQ80321_UART, + .membase = (char *)IQ80321_UART, + .irq = IRQ_IOP32X_XINT1, + .flags = UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = 1843200, + }, + { }, +}; + +static struct resource iq80321_uart_resource = { + .start = IQ80321_UART, + .end = IQ80321_UART + 7, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device iq80321_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = iq80321_serial_port, + }, + .num_resources = 1, + .resource = &iq80321_uart_resource, +}; + +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. */ + .atag_offset = 0x100, + .map_io = iq80321_map_io, + .init_irq = iop32x_init_irq, + .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 new file mode 100644 index 000000000..2d1f69a68 --- /dev/null +++ b/arch/arm/mach-iop32x/irq.c @@ -0,0 +1,74 @@ +/* + * arch/arm/mach-iop32x/irq.c + * + * Generic IOP32X IRQ handling functionality + * + * 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. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> + +static u32 iop32x_mask; + +static void intctl_write(u32 val) +{ + asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val)); +} + +static void intstr_write(u32 val) +{ + asm volatile("mcr p6, 0, %0, c4, c0, 0" : : "r" (val)); +} + +static void +iop32x_irq_mask(struct irq_data *d) +{ + iop32x_mask &= ~(1 << d->irq); + intctl_write(iop32x_mask); +} + +static void +iop32x_irq_unmask(struct irq_data *d) +{ + iop32x_mask |= 1 << d->irq; + intctl_write(iop32x_mask); +} + +struct irq_chip ext_chip = { + .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_em7210()) + *IOP3XX_PCIIRSR = 0x0f; + + for (i = 0; i < NR_IRQS; i++) { + irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); + } +} diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c new file mode 100644 index 000000000..23e8c9351 --- /dev/null +++ b/arch/arm/mach-iop32x/n2100.c @@ -0,0 +1,368 @@ +/* + * arch/arm/mach-iop32x/n2100.c + * + * Board support code for the Thecus N2100 platform. + * + * Author: Rory Bolt <rorybolt@pacbell.net> + * Copyright (C) 2002 Rory Bolt + * Copyright 2003 (c) MontaVista, Software, Inc. + * 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#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/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 <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> +#include <asm/mach/pci.h> +#include <asm/mach/time.h> +#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. + */ +static void __init n2100_timer_init(void) +{ + /* 33.000 MHz crystal. */ + iop_init_time(198000000); +} + + +/* + * N2100 I/O. + */ +static struct map_desc n2100_io_desc[] __initdata = { + { /* on-board devices */ + .virtual = N2100_UART, + .pfn = __phys_to_pfn(N2100_UART), + .length = 0x00100000, + .type = MT_DEVICE + }, +}; + +void __init n2100_map_io(void) +{ + iop3xx_map_io(); + iotable_init(n2100_io_desc, ARRAY_SIZE(n2100_io_desc)); +} + + +/* + * N2100 PCI. + */ +static int n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + int irq; + + if (PCI_SLOT(dev->devfn) == 1) { + /* RTL8110SB #1 */ + irq = IRQ_IOP32X_XINT0; + } else if (PCI_SLOT(dev->devfn) == 2) { + /* RTL8110SB #2 */ + irq = IRQ_IOP32X_XINT3; + } else if (PCI_SLOT(dev->devfn) == 3) { + /* Sil3512 */ + irq = IRQ_IOP32X_XINT2; + } else if (PCI_SLOT(dev->devfn) == 4 && pin == 1) { + /* VT6212 INTA */ + irq = IRQ_IOP32X_XINT1; + } else if (PCI_SLOT(dev->devfn) == 4 && pin == 2) { + /* VT6212 INTB */ + irq = IRQ_IOP32X_XINT0; + } else if (PCI_SLOT(dev->devfn) == 4 && pin == 3) { + /* VT6212 INTC */ + irq = IRQ_IOP32X_XINT2; + } else if (PCI_SLOT(dev->devfn) == 5) { + /* Mini-PCI slot */ + irq = IRQ_IOP32X_XINT3; + } else { + printk(KERN_ERR "n2100_pci_map_irq() called for unknown " + "device PCI:%d:%d:%d\n", dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + irq = -1; + } + + return irq; +} + +static struct hw_pci n2100_pci __initdata = { + .nr_controllers = 1, + .ops = &iop3xx_ops, + .setup = iop3xx_pci_setup, + .preinit = iop3xx_pci_preinit, + .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()) + pci_common_init(&n2100_pci); + + return 0; +} + +subsys_initcall(n2100_pci_init); + + +/* + * N2100 machine initialisation. + */ +static struct physmap_flash_data n2100_flash_data = { + .width = 2, +}; + +static struct resource n2100_flash_resource = { + .start = 0xf0000000, + .end = 0xf0ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device n2100_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &n2100_flash_data, + }, + .num_resources = 1, + .resource = &n2100_flash_resource, +}; + + +static struct plat_serial8250_port n2100_serial_port[] = { + { + .mapbase = N2100_UART, + .membase = (char *)N2100_UART, + .irq = 0, + .flags = UPF_SKIP_TEST | UPF_AUTO_IRQ | UPF_SHARE_IRQ, + .iotype = UPIO_MEM, + .regshift = 0, + .uartclk = 1843200, + }, + { }, +}; + +static struct resource n2100_uart_resource = { + .start = N2100_UART, + .end = N2100_UART + 7, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device n2100_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = n2100_serial_port, + }, + .num_resources = 1, + .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. + */ +static void n2100_power_off(void) +{ + local_irq_disable(); + + /* Start condition, I2C address of PCA9532, write transaction. */ + *IOP3XX_IDBR0 = 0xc0; + *IOP3XX_ICR0 = 0xe9; + mdelay(1); + + /* Write address 0x08. */ + *IOP3XX_IDBR0 = 0x08; + *IOP3XX_ICR0 = 0xe8; + mdelay(1); + + /* Write data 0x01, stop condition. */ + *IOP3XX_IDBR0 = 0x01; + *IOP3XX_ICR0 = 0xea; + + while (1) + ; +} + +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(struct timer_list *unused) +{ + if (gpio_get_value(N2100_POWER_BUTTON) == 0) { + ctrl_alt_del(); + return; + } + + power_button_poll_timer.expires = jiffies + (HZ / 10); + 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 */ + timer_setup(&power_button_poll_timer, power_button_poll, 0); + 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); + + i2c_register_board_info(0, n2100_i2c_devices, + ARRAY_SIZE(n2100_i2c_devices)); + + pm_power_off = n2100_power_off; +} + +MACHINE_START(N2100, "Thecus N2100") + /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ + .atag_offset = 0x100, + .map_io = n2100_map_io, + .init_irq = iop32x_init_irq, + .init_time = n2100_timer_init, + .init_machine = n2100_init_machine, + .restart = n2100_restart, +MACHINE_END |