diff options
Diffstat (limited to 'arch/mips/alchemy/devboards')
27 files changed, 1735 insertions, 454 deletions
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile index 730f9f2b30e..ecbd37f9ee8 100644 --- a/arch/mips/alchemy/devboards/Makefile +++ b/arch/mips/alchemy/devboards/Makefile @@ -2,7 +2,7 @@ # Alchemy Develboards # -obj-y += prom.o +obj-y += prom.o bcsr.o platform.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_MIPS_PB1000) += pb1000/ obj-$(CONFIG_MIPS_PB1100) += pb1100/ @@ -11,8 +11,10 @@ obj-$(CONFIG_MIPS_PB1500) += pb1500/ obj-$(CONFIG_MIPS_PB1550) += pb1550/ obj-$(CONFIG_MIPS_DB1000) += db1x00/ obj-$(CONFIG_MIPS_DB1100) += db1x00/ -obj-$(CONFIG_MIPS_DB1200) += pb1200/ +obj-$(CONFIG_MIPS_DB1200) += db1200/ obj-$(CONFIG_MIPS_DB1500) += db1x00/ obj-$(CONFIG_MIPS_DB1550) += db1x00/ obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/ obj-$(CONFIG_MIPS_MIRAGE) += db1x00/ + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c new file mode 100644 index 00000000000..3bc4fd2155d --- /dev/null +++ b/arch/mips/alchemy/devboards/bcsr.c @@ -0,0 +1,148 @@ +/* + * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction. + * + * All Alchemy development boards (except, of course, the weird PB1000) + * have a few registers in a CPLD with standardised layout; they mostly + * only differ in base address. + * All registers are 16bits wide with 32bit spacing. + */ + +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/mach-db1x00/bcsr.h> + +static struct bcsr_reg { + void __iomem *raddr; + spinlock_t lock; +} bcsr_regs[BCSR_CNT]; + +static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */ +static int bcsr_csc_base; /* linux-irq of first cascaded irq */ + +void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys) +{ + int i; + + bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys)); + bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys)); + + bcsr_virt = (void __iomem *)bcsr1_phys; + + for (i = 0; i < BCSR_CNT; i++) { + if (i >= BCSR_HEXLEDS) + bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys + + (0x04 * (i - BCSR_HEXLEDS)); + else + bcsr_regs[i].raddr = (void __iomem *)bcsr1_phys + + (0x04 * i); + + spin_lock_init(&bcsr_regs[i].lock); + } +} + +unsigned short bcsr_read(enum bcsr_id reg) +{ + unsigned short r; + unsigned long flags; + + spin_lock_irqsave(&bcsr_regs[reg].lock, flags); + r = __raw_readw(bcsr_regs[reg].raddr); + spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags); + return r; +} +EXPORT_SYMBOL_GPL(bcsr_read); + +void bcsr_write(enum bcsr_id reg, unsigned short val) +{ + unsigned long flags; + + spin_lock_irqsave(&bcsr_regs[reg].lock, flags); + __raw_writew(val, bcsr_regs[reg].raddr); + wmb(); + spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags); +} +EXPORT_SYMBOL_GPL(bcsr_write); + +void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set) +{ + unsigned short r; + unsigned long flags; + + spin_lock_irqsave(&bcsr_regs[reg].lock, flags); + r = __raw_readw(bcsr_regs[reg].raddr); + r &= ~clr; + r |= set; + __raw_writew(r, bcsr_regs[reg].raddr); + wmb(); + spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags); +} +EXPORT_SYMBOL_GPL(bcsr_mod); + +/* + * DB1200/PB1200 CPLD IRQ muxer + */ +static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) +{ + unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); + + for ( ; bisr; bisr &= bisr - 1) + generic_handle_irq(bcsr_csc_base + __ffs(bisr)); +} + +/* NOTE: both the enable and mask bits must be cleared, otherwise the + * CPLD generates tons of spurious interrupts (at least on my DB1200). + * -- mlau + */ +static void bcsr_irq_mask(unsigned int irq_nr) +{ + unsigned short v = 1 << (irq_nr - bcsr_csc_base); + __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); + __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); + wmb(); +} + +static void bcsr_irq_maskack(unsigned int irq_nr) +{ + unsigned short v = 1 << (irq_nr - bcsr_csc_base); + __raw_writew(v, bcsr_virt + BCSR_REG_INTCLR); + __raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR); + __raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */ + wmb(); +} + +static void bcsr_irq_unmask(unsigned int irq_nr) +{ + unsigned short v = 1 << (irq_nr - bcsr_csc_base); + __raw_writew(v, bcsr_virt + BCSR_REG_INTSET); + __raw_writew(v, bcsr_virt + BCSR_REG_MASKSET); + wmb(); +} + +static struct irq_chip bcsr_irq_type = { + .name = "CPLD", + .mask = bcsr_irq_mask, + .mask_ack = bcsr_irq_maskack, + .unmask = bcsr_irq_unmask, +}; + +void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq) +{ + unsigned int irq; + + /* mask & disable & ack all */ + __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTCLR); + __raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR); + __raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT); + wmb(); + + bcsr_csc_base = csc_start; + + for (irq = csc_start; irq <= csc_end; irq++) + set_irq_chip_and_handler_name(irq, &bcsr_irq_type, + handle_level_irq, "level"); + + set_irq_chained_handler(hook_irq, bcsr_csc_handler); +} diff --git a/arch/mips/alchemy/devboards/db1200/Makefile b/arch/mips/alchemy/devboards/db1200/Makefile new file mode 100644 index 00000000000..17840a5e273 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1200/Makefile @@ -0,0 +1 @@ +obj-y += setup.o platform.o diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c new file mode 100644 index 00000000000..3cb95a98ab3 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1200/platform.c @@ -0,0 +1,561 @@ +/* + * DBAu1200 board platform device registration + * + * Copyright (C) 2008-2009 Manuel Lauss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/mmc/host.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/smc91x.h> + +#include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1550_spi.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/mach-db1x00/db1200.h> + +#include "../platform.h" + +static struct mtd_partition db1200_spiflash_parts[] = { + { + .name = "DB1200 SPI flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data db1200_spiflash_data = { + .name = "s25fl001", + .parts = db1200_spiflash_parts, + .nr_parts = ARRAY_SIZE(db1200_spiflash_parts), + .type = "m25p10", +}; + +static struct spi_board_info db1200_spi_devs[] __initdata = { + { + /* TI TMP121AIDBVR temp sensor */ + .modalias = "tmp121", + .max_speed_hz = 2000000, + .bus_num = 0, + .chip_select = 0, + .mode = 0, + }, + { + /* Spansion S25FL001D0FMA SPI flash */ + .modalias = "m25p80", + .max_speed_hz = 50000000, + .bus_num = 0, + .chip_select = 1, + .mode = 0, + .platform_data = &db1200_spiflash_data, + }, +}; + +static struct i2c_board_info db1200_i2c_devs[] __initdata = { + { + /* AT24C04-10 I2C eeprom */ + I2C_BOARD_INFO("24c04", 0x52), + }, + { + /* Philips NE1619 temp/voltage sensor (adm1025 drv) */ + I2C_BOARD_INFO("ne1619", 0x2d), + }, + { + /* I2S audio codec WM8731 */ + I2C_BOARD_INFO("wm8731", 0x1b), + }, +}; + +/**********************************************************************/ + +static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + unsigned long ioaddr = (unsigned long)this->IO_ADDR_W; + + ioaddr &= 0xffffff00; + + if (ctrl & NAND_CLE) { + ioaddr += MEM_STNAND_CMD; + } else if (ctrl & NAND_ALE) { + ioaddr += MEM_STNAND_ADDR; + } else { + /* assume we want to r/w real data by default */ + ioaddr += MEM_STNAND_DATA; + } + this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr; + if (cmd != NAND_CMD_NONE) { + __raw_writeb(cmd, this->IO_ADDR_W); + wmb(); + } +} + +static int au1200_nand_device_ready(struct mtd_info *mtd) +{ + return __raw_readl((void __iomem *)MEM_STSTAT) & 1; +} + +static const char *db1200_part_probes[] = { "cmdlinepart", NULL }; + +static struct mtd_partition db1200_nand_parts[] = { + { + .name = "NAND FS 0", + .offset = 0, + .size = 8 * 1024 * 1024, + }, + { + .name = "NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL + }, +}; + +struct platform_nand_data db1200_nand_platdata = { + .chip = { + .nr_chips = 1, + .chip_offset = 0, + .nr_partitions = ARRAY_SIZE(db1200_nand_parts), + .partitions = db1200_nand_parts, + .chip_delay = 20, + .part_probe_types = db1200_part_probes, + }, + .ctrl = { + .dev_ready = au1200_nand_device_ready, + .cmd_ctrl = au1200_nand_cmd_ctrl, + }, +}; + +static struct resource db1200_nand_res[] = { + [0] = { + .start = DB1200_NAND_PHYS_ADDR, + .end = DB1200_NAND_PHYS_ADDR + 0xff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device db1200_nand_dev = { + .name = "gen_nand", + .num_resources = ARRAY_SIZE(db1200_nand_res), + .resource = db1200_nand_res, + .id = -1, + .dev = { + .platform_data = &db1200_nand_platdata, + } +}; + +/**********************************************************************/ + +static struct smc91x_platdata db1200_eth_data = { + .flags = SMC91X_NOWAIT | SMC91X_USE_16BIT, + .leda = RPC_LED_100_10, + .ledb = RPC_LED_TX_RX, +}; + +static struct resource db1200_eth_res[] = { + [0] = { + .start = DB1200_ETH_PHYS_ADDR, + .end = DB1200_ETH_PHYS_ADDR + 0xf, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DB1200_ETH_INT, + .end = DB1200_ETH_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device db1200_eth_dev = { + .dev = { + .platform_data = &db1200_eth_data, + }, + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(db1200_eth_res), + .resource = db1200_eth_res, +}; + +/**********************************************************************/ + +static struct resource db1200_ide_res[] = { + [0] = { + .start = DB1200_IDE_PHYS_ADDR, + .end = DB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DB1200_IDE_INT, + .end = DB1200_IDE_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 ide_dmamask = DMA_32BIT_MASK; + +static struct platform_device db1200_ide_dev = { + .name = "au1200-ide", + .id = 0, + .dev = { + .dma_mask = &ide_dmamask, + .coherent_dma_mask = DMA_32BIT_MASK, + }, + .num_resources = ARRAY_SIZE(db1200_ide_res), + .resource = db1200_ide_res, +}; + +/**********************************************************************/ + +static struct platform_device db1200_rtc_dev = { + .name = "rtc-au1xxx", + .id = -1, +}; + +/**********************************************************************/ + +/* SD carddetects: they're supposed to be edge-triggered, but ack + * doesn't seem to work (CPLD Rev 2). Instead, the screaming one + * is disabled and its counterpart enabled. The 500ms timeout is + * because the carddetect isn't debounced in hardware. + */ +static irqreturn_t db1200_mmc_cd(int irq, void *ptr) +{ + void(*mmc_cd)(struct mmc_host *, unsigned long); + + if (irq == DB1200_SD0_INSERT_INT) { + disable_irq_nosync(DB1200_SD0_INSERT_INT); + enable_irq(DB1200_SD0_EJECT_INT); + } else { + disable_irq_nosync(DB1200_SD0_EJECT_INT); + enable_irq(DB1200_SD0_INSERT_INT); + } + + /* link against CONFIG_MMC=m */ + mmc_cd = symbol_get(mmc_detect_change); + if (mmc_cd) { + mmc_cd(ptr, msecs_to_jiffies(500)); + symbol_put(mmc_detect_change); + } + + return IRQ_HANDLED; +} + +static int db1200_mmc_cd_setup(void *mmc_host, int en) +{ + int ret; + + if (en) { + ret = request_irq(DB1200_SD0_INSERT_INT, db1200_mmc_cd, + IRQF_DISABLED, "sd_insert", mmc_host); + if (ret) + goto out; + + ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd, + IRQF_DISABLED, "sd_eject", mmc_host); + if (ret) { + free_irq(DB1200_SD0_INSERT_INT, mmc_host); + goto out; + } + + if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) + enable_irq(DB1200_SD0_EJECT_INT); + else + enable_irq(DB1200_SD0_INSERT_INT); + + } else { + free_irq(DB1200_SD0_INSERT_INT, mmc_host); + free_irq(DB1200_SD0_EJECT_INT, mmc_host); + } + ret = 0; +out: + return ret; +} + +static void db1200_mmc_set_power(void *mmc_host, int state) +{ + if (state) { + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR); + msleep(400); /* stabilization time */ + } else + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0); +} + +static int db1200_mmc_card_readonly(void *mmc_host) +{ + return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0; +} + +static int db1200_mmc_card_inserted(void *mmc_host) +{ + return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0; +} + +static void db1200_mmcled_set(struct led_classdev *led, + enum led_brightness brightness) +{ + if (brightness != LED_OFF) + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); + else + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); +} + +static struct led_classdev db1200_mmc_led = { + .brightness_set = db1200_mmcled_set, +}; + +/* needed by arch/mips/alchemy/common/platform.c */ +struct au1xmmc_platform_data au1xmmc_platdata[] = { + [0] = { + .cd_setup = db1200_mmc_cd_setup, + .set_power = db1200_mmc_set_power, + .card_inserted = db1200_mmc_card_inserted, + .card_readonly = db1200_mmc_card_readonly, + .led = &db1200_mmc_led, + }, +}; + +/**********************************************************************/ + +static struct resource au1200_psc0_res[] = { + [0] = { + .start = PSC0_PHYS_ADDR, + .end = PSC0_PHYS_ADDR + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_PSC0_INT, + .end = AU1200_PSC0_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DSCR_CMD0_PSC0_TX, + .end = DSCR_CMD0_PSC0_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DSCR_CMD0_PSC0_RX, + .end = DSCR_CMD0_PSC0_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1200_i2c_dev = { + .name = "au1xpsc_smbus", + .id = 0, /* bus number */ + .num_resources = ARRAY_SIZE(au1200_psc0_res), + .resource = au1200_psc0_res, +}; + +static void db1200_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol) +{ + if (cs) + bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_SPISEL); + else + bcsr_mod(BCSR_RESETS, BCSR_RESETS_SPISEL, 0); +} + +static struct au1550_spi_info db1200_spi_platdata = { + .mainclk_hz = 50000000, /* PSC0 clock */ + .num_chipselect = 2, + .activate_cs = db1200_spi_cs_en, +}; + +static u64 spi_dmamask = DMA_32BIT_MASK; + +static struct platform_device db1200_spi_dev = { + .dev = { + .dma_mask = &spi_dmamask, + .coherent_dma_mask = DMA_32BIT_MASK, + .platform_data = &db1200_spi_platdata, + }, + .name = "au1550-spi", + .id = 0, /* bus number */ + .num_resources = ARRAY_SIZE(au1200_psc0_res), + .resource = au1200_psc0_res, +}; + +static struct resource au1200_psc1_res[] = { + [0] = { + .start = PSC1_PHYS_ADDR, + .end = PSC1_PHYS_ADDR + 0x000fffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_PSC1_INT, + .end = AU1200_PSC1_INT, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = DSCR_CMD0_PSC1_TX, + .end = DSCR_CMD0_PSC1_TX, + .flags = IORESOURCE_DMA, + }, + [3] = { + .start = DSCR_CMD0_PSC1_RX, + .end = DSCR_CMD0_PSC1_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device db1200_audio_dev = { + /* name assigned later based on switch setting */ + .id = 1, /* PSC ID */ + .num_resources = ARRAY_SIZE(au1200_psc1_res), + .resource = au1200_psc1_res, +}; + +static struct platform_device *db1200_devs[] __initdata = { + NULL, /* PSC0, selected by S6.8 */ + &db1200_ide_dev, + &db1200_eth_dev, + &db1200_rtc_dev, + &db1200_nand_dev, + &db1200_audio_dev, +}; + +static int __init db1200_dev_init(void) +{ + unsigned long pfc; + unsigned short sw; + int swapped; + + i2c_register_board_info(0, db1200_i2c_devs, + ARRAY_SIZE(db1200_i2c_devs)); + spi_register_board_info(db1200_spi_devs, + ARRAY_SIZE(db1200_i2c_devs)); + + /* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI) + * S6.7 AC97/I2S selector (OFF=AC97 ON=I2S) + */ + + /* NOTE: GPIO215 controls OTG VBUS supply. In SPI mode however + * this pin is claimed by PSC0 (unused though, but pinmux doesn't + * allow to free it without crippling the SPI interface). + * As a result, in SPI mode, OTG simply won't work (PSC0 uses + * it as an input pin which is pulled high on the boards). + */ + pfc = __raw_readl((void __iomem *)SYS_PINFUNC) & ~SYS_PINFUNC_P0A; + + /* switch off OTG VBUS supply */ + gpio_request(215, "otg-vbus"); + gpio_direction_output(215, 1); + + printk(KERN_INFO "DB1200 device configuration:\n"); + + sw = bcsr_read(BCSR_SWITCHES); + if (sw & BCSR_SWITCHES_DIP_8) { + db1200_devs[0] = &db1200_i2c_dev; + bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0); + + pfc |= (2 << 17); /* GPIO2 block owns GPIO215 */ + + printk(KERN_INFO " S6.8 OFF: PSC0 mode I2C\n"); + printk(KERN_INFO " OTG port VBUS supply available!\n"); + } else { + db1200_devs[0] = &db1200_spi_dev; + bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC0MUX); + + pfc |= (1 << 17); /* PSC0 owns GPIO215 */ + + printk(KERN_INFO " S6.8 ON : PSC0 mode SPI\n"); + printk(KERN_INFO " OTG port VBUS supply disabled\n"); + } + __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); + wmb(); + + /* Audio: DIP7 selects I2S(0)/AC97(1), but need I2C for I2S! + * so: DIP7=1 || DIP8=0 => AC97, DIP7=0 && DIP8=1 => I2S + */ + sw &= BCSR_SWITCHES_DIP_8 | BCSR_SWITCHES_DIP_7; + if (sw == BCSR_SWITCHES_DIP_8) { + bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC1MUX); + db1200_audio_dev.name = "au1xpsc_i2s"; + printk(KERN_INFO " S6.7 ON : PSC1 mode I2S\n"); + } else { + bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC1MUX, 0); + db1200_audio_dev.name = "au1xpsc_ac97"; + printk(KERN_INFO " S6.7 OFF: PSC1 mode AC97\n"); + } + + /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */ + __raw_writel(PSC_SEL_CLK_SERCLK, + (void __iomem *)KSEG1ADDR(PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); + wmb(); + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + DB1200_PC0_INT, + DB1200_PC0_INSERT_INT, + /*DB1200_PC0_STSCHG_INT*/0, + DB1200_PC0_EJECT_INT, + 0); + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x004000000, + PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1, + PCMCIA_MEM_PHYS_ADDR + 0x004000000, + PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1, + PCMCIA_IO_PHYS_ADDR + 0x004000000, + PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1, + DB1200_PC1_INT, + DB1200_PC1_INSERT_INT, + /*DB1200_PC1_STSCHG_INT*/0, + DB1200_PC1_EJECT_INT, + 1); + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; + db1x_register_norflash(64 << 20, 2, swapped); + + return platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs)); +} +device_initcall(db1200_dev_init); + +/* au1200fb calls these: STERBT EINEN TRAGISCHEN TOD!!! */ +int board_au1200fb_panel(void) +{ + return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f; +} + +int board_au1200fb_panel_init(void) +{ + /* Apply power */ + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL); + return 0; +} + +int board_au1200fb_panel_shutdown(void) +{ + /* Remove power */ + bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL, 0); + return 0; +} diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c new file mode 100644 index 00000000000..379536e3abd --- /dev/null +++ b/arch/mips/alchemy/devboards/db1200/setup.c @@ -0,0 +1,118 @@ +/* + * Alchemy/AMD/RMI DB1200 board setup. + * + * Licensed under the terms outlined in the file COPYING in the root of + * this source archive. + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/mach-db1x00/db1200.h> + +const char *get_system_type(void) +{ + return "Alchemy Db1200"; +} + +void __init board_setup(void) +{ + unsigned long freq0, clksrc, div, pfc; + unsigned short whoami; + + bcsr_init(DB1200_BCSR_PHYS_ADDR, + DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS); + + whoami = bcsr_read(BCSR_WHOAMI); + printk(KERN_INFO "Alchemy/AMD/RMI DB1200 Board, CPLD Rev %d" + " Board-ID %d Daughtercard ID %d\n", + (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); + + /* SMBus/SPI on PSC0, Audio on PSC1 */ + pfc = __raw_readl((void __iomem *)SYS_PINFUNC); + pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); + pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); + pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ + __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); + wmb(); + + /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from + * CPU clock; all other clock generators off/unused. + */ + div = (get_au1x00_speed() + 25000000) / 50000000; + if (div & 1) + div++; + div = ((div >> 1) - 1) & 0xff; + + freq0 = div << SYS_FC_FRDIV0_BIT; + __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); + wmb(); + freq0 |= SYS_FC_FE0; /* enable F0 */ + __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); + wmb(); + + /* psc0_intclk comes 1:1 from F0 */ + clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT; + __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC); + wmb(); +} + +/* use the hexleds to count the number of times the cpu has entered + * wait, the dots to indicate whether the CPU is currently idle or + * active (dots off = sleeping, dots on = working) for cases where + * the number doesn't change for a long(er) period of time. + */ +static void db1200_wait(void) +{ + __asm__(" .set push \n" + " .set mips3 \n" + " .set noreorder \n" + " cache 0x14, 0(%0) \n" + " cache 0x14, 32(%0) \n" + " cache 0x14, 64(%0) \n" + /* dots off: we're about to call wait */ + " lui $26, 0xb980 \n" + " ori $27, $0, 3 \n" + " sb $27, 0x18($26) \n" + " sync \n" + " nop \n" + " wait \n" + " nop \n" + " nop \n" + " nop \n" + " nop \n" + " nop \n" + /* dots on: there's work to do, increment cntr */ + " lui $26, 0xb980 \n" + " sb $0, 0x18($26) \n" + " lui $26, 0xb9c0 \n" + " lb $27, 0($26) \n" + " addiu $27, $27, 1 \n" + " sb $27, 0($26) \n" + " sync \n" + " .set pop \n" + : : "r" (db1200_wait)); +} + +static int __init db1200_arch_init(void) +{ + /* GPIO7 is low-level triggered CPLD cascade */ + set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW); + bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT); + + /* do not autoenable these: CPLD has broken edge int handling, + * and the CD handler setup requires manual enabling to work + * around that. + */ + irq_to_desc(DB1200_SD0_INSERT_INT)->status |= IRQ_NOAUTOEN; + irq_to_desc(DB1200_SD0_EJECT_INT)->status |= IRQ_NOAUTOEN; + + if (cpu_wait) + cpu_wait = db1200_wait; + + return 0; +} +arch_initcall(db1200_arch_init); diff --git a/arch/mips/alchemy/devboards/db1x00/Makefile b/arch/mips/alchemy/devboards/db1x00/Makefile index 432241ab867..613c0c0c8be 100644 --- a/arch/mips/alchemy/devboards/db1x00/Makefile +++ b/arch/mips/alchemy/devboards/db1x00/Makefile @@ -5,4 +5,4 @@ # Makefile for the Alchemy Semiconductor DBAu1xx0 boards. # -obj-y := board_setup.o irqmap.o +obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c index de30d8ea717..50c9bef99da 100644 --- a/arch/mips/alchemy/devboards/db1x00/board_setup.c +++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c @@ -29,59 +29,139 @@ #include <linux/gpio.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pm.h> #include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx_eth.h> #include <asm/mach-db1x00/db1x00.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/reboot.h> #include <prom.h> +#ifdef CONFIG_MIPS_DB1500 +char irq_tab_alchemy[][5] __initdata = { + [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT371 */ + [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ +}; + +#endif -static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR; + +#ifdef CONFIG_MIPS_DB1550 +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, AU1550_PCI_INTC, 0xff, 0xff, 0xff }, /* IDSEL 11 - on-board HPT371 */ + [12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */ + [13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */ +}; +#endif + + +#ifdef CONFIG_MIPS_BOSPORUS +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI */ + [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741 */ + [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ +}; + +/* + * Micrel/Kendin 5 port switch attached to MAC0, + * MAC0 is associated with PHY address 5 (== WAN port) + * MAC1 is not associated with any PHY, since it's connected directly + * to the switch. + * no interrupts are used + */ +static struct au1000_eth_platform_data eth0_pdata = { + .phy_static_config = 1, + .phy_addr = 5, +}; + +static void bosporus_power_off(void) +{ + printk(KERN_INFO "It's now safe to turn off power\n"); + while (1) + asm volatile (".set mips3 ; wait ; .set mips0"); +} const char *get_system_type(void) { -#ifdef CONFIG_MIPS_BOSPORUS return "Alchemy Bosporus Gateway Reference"; -#else - return "Alchemy Db1x00"; +} #endif + + +#ifdef CONFIG_MIPS_MIRAGE +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, AU1500_PCI_INTD, 0xff, 0xff, 0xff }, /* IDSEL 11 - SMI VGX */ + [12] = { -1, 0xff, 0xff, AU1500_PCI_INTC, 0xff }, /* IDSEL 12 - PNX1300 */ + [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 13 - miniPCI */ +}; + +static void mirage_power_off(void) +{ + alchemy_gpio_direction_output(210, 1); +} + +const char *get_system_type(void) +{ + return "Alchemy Mirage"; +} +#endif + + +#if defined(CONFIG_MIPS_BOSPORUS) || defined(CONFIG_MIPS_MIRAGE) +static void mips_softreset(void) +{ + asm volatile ("jr\t%0" : : "r"(0xbfc00000)); } -void board_reset(void) +#else + +const char *get_system_type(void) { - /* Hit BCSR.SW_RESET[RESET] */ - bcsr->swreset = 0x0000; + return "Alchemy Db1x00"; } +#endif + void __init board_setup(void) { - u32 pin_func = 0; - char *argptr; - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_8250_CONSOLE - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } + unsigned long bcsr1, bcsr2; + u32 pin_func; + + bcsr1 = DB1000_BCSR_PHYS_ADDR; + bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS; + + pin_func = 0; + +#ifdef CONFIG_MIPS_DB1000 + printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1500 + printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n"); #endif +#ifdef CONFIG_MIPS_DB1100 + printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n"); +#endif +#ifdef CONFIG_MIPS_BOSPORUS + au1xxx_override_eth_cfg(0, ð0_pdata); -#ifdef CONFIG_FB_AU1100 - argptr = strstr(argptr, "video="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - /* default panel */ - /*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/ - } + printk(KERN_INFO "AMD Alchemy Bosporus Board\n"); #endif +#ifdef CONFIG_MIPS_MIRAGE + printk(KERN_INFO "AMD Alchemy Mirage Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1550 + printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n"); -#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000) - /* au1000 does not support vra, au1500 and au1100 do */ - strcat(argptr, " au1000_audio=vra"); - argptr = prom_getcmdline(); + bcsr1 = DB1550_BCSR_PHYS_ADDR; + bcsr2 = DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS; #endif + /* initialize board register space */ + bcsr_init(bcsr1, bcsr2); + /* Not valid for Au1550 */ #if defined(CONFIG_IRDA) && \ (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100)) @@ -89,11 +169,10 @@ void __init board_setup(void) pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF; au_writel(pin_func, SYS_PINFUNC); /* Power off until the driver is in use */ - bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK; - bcsr->resets |= BCSR_RESETS_IRDA_MODE_OFF; - au_sync(); + bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, + BCSR_RESETS_IRDA_MODE_OFF); #endif - bcsr->pcmcia = 0x0000; /* turn off PCMCIA power */ + bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ /* Enable GPIO[31:0] inputs */ alchemy_gpio1_input_enable(); @@ -120,26 +199,53 @@ void __init board_setup(void) * be part of the audio driver. */ alchemy_gpio_direction_output(209, 1); -#endif - - au_sync(); -#ifdef CONFIG_MIPS_DB1000 - printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1500 - printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1100 - printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n"); + pm_power_off = mirage_power_off; + _machine_halt = mirage_power_off; + _machine_restart = (void(*)(char *))mips_softreset; #endif + #ifdef CONFIG_MIPS_BOSPORUS - printk(KERN_INFO "AMD Alchemy Bosporus Board\n"); + pm_power_off = bosporus_power_off; + _machine_halt = bosporus_power_off; + _machine_restart = (void(*)(char *))mips_softreset; #endif -#ifdef CONFIG_MIPS_MIRAGE - printk(KERN_INFO "AMD Alchemy Mirage Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1550 - printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n"); + au_sync(); +} + +static int __init db1x00_init_irq(void) +{ +#if defined(CONFIG_MIPS_MIRAGE) + set_irq_type(AU1500_GPIO7_INT, IRQF_TRIGGER_RISING); /* TS pendown */ +#elif defined(CONFIG_MIPS_DB1550) + set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ + set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW); /* CD1# */ + set_irq_type(AU1550_GPIO3_INT, IRQF_TRIGGER_LOW); /* CARD0# */ + set_irq_type(AU1550_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ + set_irq_type(AU1550_GPIO21_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + set_irq_type(AU1550_GPIO22_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ +#elif defined(CONFIG_MIPS_DB1500) + set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ + set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ + set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ + set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ + set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ +#elif defined(CONFIG_MIPS_DB1100) + set_irq_type(AU1100_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ + set_irq_type(AU1100_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ + set_irq_type(AU1100_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ + set_irq_type(AU1100_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ + set_irq_type(AU1100_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + set_irq_type(AU1100_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ +#elif defined(CONFIG_MIPS_DB1000) + set_irq_type(AU1000_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */ + set_irq_type(AU1000_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */ + set_irq_type(AU1000_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */ + set_irq_type(AU1000_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */ + set_irq_type(AU1000_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + set_irq_type(AU1000_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */ #endif + return 0; } +arch_initcall(db1x00_init_irq); diff --git a/arch/mips/alchemy/devboards/db1x00/irqmap.c b/arch/mips/alchemy/devboards/db1x00/irqmap.c deleted file mode 100644 index 0b09025087c..00000000000 --- a/arch/mips/alchemy/devboards/db1x00/irqmap.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Au1xxx irq map table - * - * Copyright 2003 Embedded Edge, LLC - * dan@embeddededge.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/mach-au1x00/au1000.h> - -#ifdef CONFIG_MIPS_DB1500 -char irq_tab_alchemy[][5] __initdata = { - [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371 */ - [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */ -}; -#endif - -#ifdef CONFIG_MIPS_BOSPORUS -char irq_tab_alchemy[][5] __initdata = { - [11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI */ - [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741 */ - [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */ -}; -#endif - -#ifdef CONFIG_MIPS_MIRAGE -char irq_tab_alchemy[][5] __initdata = { - [11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */ - [12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */ - [13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */ -}; -#endif - -#ifdef CONFIG_MIPS_DB1550 -char irq_tab_alchemy[][5] __initdata = { - [11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */ - [12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */ - [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */ -}; -#endif - - -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - -#ifndef CONFIG_MIPS_MIRAGE -#ifdef CONFIG_MIPS_DB1550 - { AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */ - { AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */ -#else - { AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 Fully_Interted# */ - { AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 STSCHG# */ - { AU1000_GPIO_2, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */ - - { AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 Fully_Interted# */ - { AU1000_GPIO_4, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 STSCHG# */ - { AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */ -#endif -#else - { AU1000_GPIO_7, IRQF_TRIGGER_RISING, 0 }, /* touchscreen pen down */ -#endif - -}; - -void __init board_init_irq(void) -{ - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); -} diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c new file mode 100644 index 00000000000..978d5ab3d67 --- /dev/null +++ b/arch/mips/alchemy/devboards/db1x00/platform.c @@ -0,0 +1,118 @@ +/* + * DBAu1xxx board platform device registration + * + * Copyright (C) 2009 Manuel Lauss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <linux/platform_device.h> + +#include <asm/mach-au1x00/au1xxx.h> +#include <asm/mach-db1x00/bcsr.h> +#include "../platform.h" + +/* DB1xxx PCMCIA interrupt sources: + * CD0/1 GPIO0/3 + * STSCHG0/1 GPIO1/4 + * CARD0/1 GPIO2/5 + * Db1550: 0/1, 21/22, 3/5 + */ + +#define DB1XXX_HAS_PCMCIA +#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT) + +#if defined(CONFIG_MIPS_DB1000) +#define DB1XXX_PCMCIA_CD0 AU1000_GPIO0_INT +#define DB1XXX_PCMCIA_STSCHG0 AU1000_GPIO1_INT +#define DB1XXX_PCMCIA_CARD0 AU1000_GPIO2_INT +#define DB1XXX_PCMCIA_CD1 AU1000_GPIO3_INT +#define DB1XXX_PCMCIA_STSCHG1 AU1000_GPIO4_INT +#define DB1XXX_PCMCIA_CARD1 AU1000_GPIO5_INT +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#elif defined(CONFIG_MIPS_DB1100) +#define DB1XXX_PCMCIA_CD0 AU1100_GPIO0_INT +#define DB1XXX_PCMCIA_STSCHG0 AU1100_GPIO1_INT +#define DB1XXX_PCMCIA_CARD0 AU1100_GPIO2_INT +#define DB1XXX_PCMCIA_CD1 AU1100_GPIO3_INT +#define DB1XXX_PCMCIA_STSCHG1 AU1100_GPIO4_INT +#define DB1XXX_PCMCIA_CARD1 AU1100_GPIO5_INT +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#elif defined(CONFIG_MIPS_DB1500) +#define DB1XXX_PCMCIA_CD0 AU1500_GPIO0_INT +#define DB1XXX_PCMCIA_STSCHG0 AU1500_GPIO1_INT +#define DB1XXX_PCMCIA_CARD0 AU1500_GPIO2_INT +#define DB1XXX_PCMCIA_CD1 AU1500_GPIO3_INT +#define DB1XXX_PCMCIA_STSCHG1 AU1500_GPIO4_INT +#define DB1XXX_PCMCIA_CARD1 AU1500_GPIO5_INT +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#elif defined(CONFIG_MIPS_DB1550) +#define DB1XXX_PCMCIA_CD0 AU1550_GPIO0_INT +#define DB1XXX_PCMCIA_STSCHG0 AU1550_GPIO21_INT +#define DB1XXX_PCMCIA_CARD0 AU1550_GPIO3_INT +#define DB1XXX_PCMCIA_CD1 AU1550_GPIO1_INT +#define DB1XXX_PCMCIA_STSCHG1 AU1550_GPIO22_INT +#define DB1XXX_PCMCIA_CARD1 AU1550_GPIO5_INT +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#else +/* other board: no PCMCIA */ +#undef DB1XXX_HAS_PCMCIA +#undef F_SWAPPED +#define F_SWAPPED 0 +#if defined(CONFIG_MIPS_BOSPORUS) +#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#elif defined(CONFIG_MIPS_MIRAGE) +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif +#endif + +static int __init db1xxx_dev_init(void) +{ +#ifdef DB1XXX_HAS_PCMCIA + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + DB1XXX_PCMCIA_CARD0, + DB1XXX_PCMCIA_CD0, + /*DB1XXX_PCMCIA_STSCHG0*/0, + 0, + 0); + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x004000000, + PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1, + PCMCIA_MEM_PHYS_ADDR + 0x004000000, + PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1, + PCMCIA_IO_PHYS_ADDR + 0x004000000, + PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1, + DB1XXX_PCMCIA_CARD1, + DB1XXX_PCMCIA_CD1, + /*DB1XXX_PCMCIA_STSCHG1*/0, + 0, + 1); +#endif + db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED); + return 0; +} +device_initcall(db1xxx_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c index cd273545e81..b5311d8a29a 100644 --- a/arch/mips/alchemy/devboards/pb1000/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c @@ -31,11 +31,7 @@ #include <asm/mach-pb1x00/pb1000.h> #include <prom.h> - -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - { AU1000_GPIO_15, IRQF_TRIGGER_LOW, 0 }, -}; - +#include "../platform.h" const char *get_system_type(void) { @@ -46,25 +42,14 @@ void board_reset(void) { } -void __init board_init_irq(void) -{ - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); -} - void __init board_setup(void) { u32 pin_func, static_cfg0; u32 sys_freqctrl, sys_clksrc; u32 prid = read_c0_prid(); -#ifdef CONFIG_SERIAL_8250_CONSOLE - char *argptr = prom_getcmdline(); - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif + sys_freqctrl = 0; + sys_clksrc = 0; /* Set AUX clock to 12 MHz * 8 = 96 MHz */ au_writel(8, SYS_AUXPLL); @@ -193,3 +178,16 @@ void __init board_setup(void) break; } } + +static int __init pb1000_init_irq(void) +{ + set_irq_type(AU1000_GPIO15_INT, IRQF_TRIGGER_LOW); + return 0; +} +arch_initcall(pb1000_init_irq); + +static int __init pb1000_device_init(void) +{ + return db1x_register_norflash(8 * 1024 * 1024, 4, 0); +} +device_initcall(pb1000_device_init); diff --git a/arch/mips/alchemy/devboards/pb1100/Makefile b/arch/mips/alchemy/devboards/pb1100/Makefile index c586dd7e91d..7e3756c83fe 100644 --- a/arch/mips/alchemy/devboards/pb1100/Makefile +++ b/arch/mips/alchemy/devboards/pb1100/Makefile @@ -5,4 +5,4 @@ # Makefile for the Alchemy Semiconductor Pb1100 board. # -obj-y := board_setup.o +obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c index 61263081ef5..c7b4caa81a3 100644 --- a/arch/mips/alchemy/devboards/pb1100/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c @@ -29,19 +29,11 @@ #include <linux/interrupt.h> #include <asm/mach-au1x00/au1000.h> -#include <asm/mach-pb1x00/pb1100.h> +#include <asm/mach-db1x00/bcsr.h> #include <prom.h> -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - { AU1000_GPIO_9, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card Fully_Inserted# */ - { AU1000_GPIO_10, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card STSCHG# */ - { AU1000_GPIO_11, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card IRQ# */ - { AU1000_GPIO_13, IRQF_TRIGGER_LOW, 0 }, /* DC_IRQ# */ -}; - - const char *get_system_type(void) { return "Alchemy Pb1100"; @@ -49,43 +41,15 @@ const char *get_system_type(void) void board_reset(void) { - /* Hit BCSR.RST_VDDI[SOFT_RESET] */ - au_writel(0x00000000, PB1100_RST_VDDI); -} - -void __init board_init_irq(void) -{ - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); + bcsr_write(BCSR_SYSTEM, 0); } void __init board_setup(void) { volatile void __iomem *base = (volatile void __iomem *)0xac000000UL; - char *argptr; - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_8250_CONSOLE - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif - -#ifdef CONFIG_FB_AU1100 - argptr = strstr(argptr, "video="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - /* default panel */ - /*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/ - } -#endif -#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000) - /* au1000 does not support vra, au1500 and au1100 do */ - strcat(argptr, " au1000_audio=vra"); - argptr = prom_getcmdline(); -#endif + bcsr_init(DB1000_BCSR_PHYS_ADDR, + DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS); /* Set AUX clock to 12 MHz * 8 = 96 MHz */ au_writel(8, SYS_AUXPLL); @@ -155,3 +119,14 @@ void __init board_setup(void) au_sync(); } } + +static int __init pb1100_init_irq(void) +{ + set_irq_type(AU1100_GPIO9_INT, IRQF_TRIGGER_LOW); /* PCCD# */ + set_irq_type(AU1100_GPIO10_INT, IRQF_TRIGGER_LOW); /* PCSTSCHG# */ + set_irq_type(AU1100_GPIO11_INT, IRQF_TRIGGER_LOW); /* PCCard# */ + set_irq_type(AU1100_GPIO13_INT, IRQF_TRIGGER_LOW); /* DC_IRQ# */ + + return 0; +} +arch_initcall(pb1100_init_irq); diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c new file mode 100644 index 00000000000..2c8dc29759f --- /dev/null +++ b/arch/mips/alchemy/devboards/pb1100/platform.c @@ -0,0 +1,50 @@ +/* + * Pb1100 board platform device registration + * + * Copyright (C) 2009 Manuel Lauss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> + +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-db1x00/bcsr.h> + +#include "../platform.h" + +static int __init pb1100_dev_init(void) +{ + int swapped; + + /* PCMCIA. single socket, identical to Pb1500 */ + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1100_GPIO11_INT, /* card */ + AU1100_GPIO9_INT, /* insert */ + /*AU1100_GPIO10_INT*/0, /* stschg */ + 0, /* eject */ + 0); /* id */ + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; + db1x_register_norflash(64 * 1024 * 1024, 4, swapped); + + return 0; +} +device_initcall(pb1100_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile index c8c3a99fb68..2ea9b02ef09 100644 --- a/arch/mips/alchemy/devboards/pb1200/Makefile +++ b/arch/mips/alchemy/devboards/pb1200/Makefile @@ -2,6 +2,6 @@ # Makefile for the Alchemy Semiconductor Pb1200/DBAu1200 boards. # -obj-y := board_setup.o irqmap.o platform.o +obj-y := board_setup.o platform.o EXTRA_CFLAGS += -Werror diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c index 94e6b7e7753..3184063f804 100644 --- a/arch/mips/alchemy/devboards/pb1200/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1200/board_setup.c @@ -25,11 +25,23 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/sched.h> -#include <prom.h> -#include <au1xxx.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-db1x00/bcsr.h> + +#ifdef CONFIG_MIPS_PB1200 +#include <asm/mach-pb1x00/pb1200.h> +#endif + +#ifdef CONFIG_MIPS_DB1200 +#include <asm/mach-db1x00/db1200.h> +#define PB1200_INT_BEGIN DB1200_INT_BEGIN +#define PB1200_INT_END DB1200_INT_END +#endif +#include <prom.h> const char *get_system_type(void) { @@ -38,25 +50,15 @@ const char *get_system_type(void) void board_reset(void) { - bcsr->resets = 0; - bcsr->system = 0; + bcsr_write(BCSR_RESETS, 0); + bcsr_write(BCSR_SYSTEM, 0); } void __init board_setup(void) { - char *argptr; - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_8250_CONSOLE - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif -#ifdef CONFIG_FB_AU1200 - strcat(argptr, " video=au1200fb:panel:bs"); -#endif + printk(KERN_INFO "AMD Alchemy Pb1200 Board\n"); + bcsr_init(PB1200_BCSR_PHYS_ADDR, + PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS); #if 0 { @@ -82,7 +84,7 @@ void __init board_setup(void) u32 pin_func; /* Select SMBus in CPLD */ - bcsr->resets &= ~BCSR_RESETS_PCS0MUX; + bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0); pin_func = au_readl(SYS_PINFUNC); au_sync(); @@ -116,38 +118,54 @@ void __init board_setup(void) /* * The Pb1200 development board uses external MUX for PSC0 to - * support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI + * support SMB/SPI. bcsr_resets bit 12: 0=SMB 1=SPI */ #ifdef CONFIG_I2C_AU1550 - bcsr->resets &= ~BCSR_RESETS_PCS0MUX; + bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0); #endif au_sync(); +} -#ifdef CONFIG_MIPS_PB1200 - printk(KERN_INFO "AMD Alchemy Pb1200 Board\n"); -#endif -#ifdef CONFIG_MIPS_DB1200 - printk(KERN_INFO "AMD Alchemy Db1200 Board\n"); -#endif +static int __init pb1200_init_irq(void) +{ + /* We have a problem with CPLD rev 3. */ + if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) { + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n"); + printk(KERN_ERR "updated to latest revision. This software will\n"); + printk(KERN_ERR "not work on anything less than CPLD rev 4.\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + printk(KERN_ERR "WARNING!!!\n"); + panic("Game over. Your score is 0."); + } + + set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW); + bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1200_GPIO7_INT); + + return 0; } +arch_initcall(pb1200_init_irq); + int board_au1200fb_panel(void) { - BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; - int p; - - p = bcsr->switches; - p >>= 8; - p &= 0x0F; - return p; + return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f; } int board_au1200fb_panel_init(void) { /* Apply power */ - BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; - - bcsr->board |= BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL; + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL); /* printk(KERN_DEBUG "board_au1200fb_panel_init()\n"); */ return 0; } @@ -155,10 +173,8 @@ int board_au1200fb_panel_init(void) int board_au1200fb_panel_shutdown(void) { /* Remove power */ - BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; - - bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | - BCSR_BOARD_LCDBL); + bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | + BCSR_BOARD_LCDBL, 0); /* printk(KERN_DEBUG "board_au1200fb_panel_shutdown()\n"); */ return 0; } diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c deleted file mode 100644 index fe47498da28..00000000000 --- a/arch/mips/alchemy/devboards/pb1200/irqmap.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Au1xxx irq map table - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/mach-au1x00/au1000.h> - -#ifdef CONFIG_MIPS_PB1200 -#include <asm/mach-pb1x00/pb1200.h> -#endif - -#ifdef CONFIG_MIPS_DB1200 -#include <asm/mach-db1x00/db1200.h> -#define PB1200_INT_BEGIN DB1200_INT_BEGIN -#define PB1200_INT_END DB1200_INT_END -#endif - -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - /* This is external interrupt cascade */ - { AU1000_GPIO_7, IRQF_TRIGGER_LOW, 0 }, -}; - - -/* - * Support for External interrupts on the Pb1200 Development platform. - */ - -static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d) -{ - unsigned short bisr = bcsr->int_status; - - for ( ; bisr; bisr &= bisr - 1) - generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr)); -} - -/* NOTE: both the enable and mask bits must be cleared, otherwise the - * CPLD generates tons of spurious interrupts (at least on the DB1200). - */ -static void pb1200_mask_irq(unsigned int irq_nr) -{ - bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN); - bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN); - au_sync(); -} - -static void pb1200_maskack_irq(unsigned int irq_nr) -{ - bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN); - bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN); - bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN); /* ack */ - au_sync(); -} - -static void pb1200_unmask_irq(unsigned int irq_nr) -{ - bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN); - bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN); - au_sync(); -} - -static struct irq_chip pb1200_cpld_irq_type = { -#ifdef CONFIG_MIPS_PB1200 - .name = "Pb1200 Ext", -#endif -#ifdef CONFIG_MIPS_DB1200 - .name = "Db1200 Ext", -#endif - .mask = pb1200_mask_irq, - .mask_ack = pb1200_maskack_irq, - .unmask = pb1200_unmask_irq, -}; - -void __init board_init_irq(void) -{ - unsigned int irq; - - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); - -#ifdef CONFIG_MIPS_PB1200 - /* We have a problem with CPLD rev 3. */ - if (((bcsr->whoami & BCSR_WHOAMI_CPLD) >> 4) <= 3) { - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n"); - printk(KERN_ERR "updated to latest revision. This software will\n"); - printk(KERN_ERR "not work on anything less than CPLD rev 4.\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - printk(KERN_ERR "WARNING!!!\n"); - panic("Game over. Your score is 0."); - } -#endif - /* mask & disable & ack all */ - bcsr->intclr_mask = 0xffff; - bcsr->intclr = 0xffff; - bcsr->int_status = 0xffff; - au_sync(); - - for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++) - set_irq_chip_and_handler_name(irq, &pb1200_cpld_irq_type, - handle_level_irq, "level"); - - set_irq_chained_handler(AU1000_GPIO_7, pb1200_cascade_handler); -} diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c index b93dff4a678..3ef2dceeb79 100644 --- a/arch/mips/alchemy/devboards/pb1200/platform.c +++ b/arch/mips/alchemy/devboards/pb1200/platform.c @@ -26,27 +26,30 @@ #include <asm/mach-au1x00/au1xxx.h> #include <asm/mach-au1x00/au1100_mmc.h> +#include <asm/mach-db1x00/bcsr.h> + +#include "../platform.h" static int mmc_activity; static void pb1200mmc0_set_power(void *mmc_host, int state) { if (state) - bcsr->board |= BCSR_BOARD_SD0PWR; + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR); else - bcsr->board &= ~BCSR_BOARD_SD0PWR; + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0); - au_sync_delay(1); + msleep(1); } static int pb1200mmc0_card_readonly(void *mmc_host) { - return (bcsr->status & BCSR_STATUS_SD0WP) ? 1 : 0; + return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0; } static int pb1200mmc0_card_inserted(void *mmc_host) { - return (bcsr->sig_status & BCSR_INT_SD0INSERT) ? 1 : 0; + return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0; } static void pb1200_mmcled_set(struct led_classdev *led, @@ -54,10 +57,10 @@ static void pb1200_mmcled_set(struct led_classdev *led, { if (brightness != LED_OFF) { if (++mmc_activity == 1) - bcsr->disk_leds &= ~(1 << 8); + bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0); } else { if (--mmc_activity == 0) - bcsr->disk_leds |= (1 << 8); + bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0); } } @@ -65,27 +68,25 @@ static struct led_classdev pb1200mmc_led = { .brightness_set = pb1200_mmcled_set, }; -#ifndef CONFIG_MIPS_DB1200 static void pb1200mmc1_set_power(void *mmc_host, int state) { if (state) - bcsr->board |= BCSR_BOARD_SD1PWR; + bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR); else - bcsr->board &= ~BCSR_BOARD_SD1PWR; + bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0); - au_sync_delay(1); + msleep(1); } static int pb1200mmc1_card_readonly(void *mmc_host) { - return (bcsr->status & BCSR_STATUS_SD1WP) ? 1 : 0; + return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0; } static int pb1200mmc1_card_inserted(void *mmc_host) { - return (bcsr->sig_status & BCSR_INT_SD1INSERT) ? 1 : 0; + return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0; } -#endif const struct au1xmmc_platform_data au1xmmc_platdata[2] = { [0] = { @@ -95,7 +96,6 @@ const struct au1xmmc_platform_data au1xmmc_platdata[2] = { .cd_setup = NULL, /* use poll-timer in driver */ .led = &pb1200mmc_led, }, -#ifndef CONFIG_MIPS_DB1200 [1] = { .set_power = pb1200mmc1_set_power, .card_inserted = pb1200mmc1_card_inserted, @@ -103,7 +103,6 @@ const struct au1xmmc_platform_data au1xmmc_platdata[2] = { .cd_setup = NULL, /* use poll-timer in driver */ .led = &pb1200mmc_led, }, -#endif }; static struct resource ide_resources[] = { @@ -169,8 +168,36 @@ static struct platform_device *board_platform_devices[] __initdata = { static int __init board_register_devices(void) { + int swapped; + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + PB1200_PC0_INT, + PB1200_PC0_INSERT_INT, + /*PB1200_PC0_STSCHG_INT*/0, + PB1200_PC0_EJECT_INT, + 0); + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x008000000, + PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1, + PCMCIA_MEM_PHYS_ADDR + 0x008000000, + PCMCIA_MEM_PHYS_ADDR + 0x008400000 - 1, + PCMCIA_IO_PHYS_ADDR + 0x008000000, + PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1, + PB1200_PC1_INT, + PB1200_PC1_INSERT_INT, + /*PB1200_PC1_STSCHG_INT*/0, + PB1200_PC1_EJECT_INT, + 1); + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT; + db1x_register_norflash(128 * 1024 * 1024, 2, swapped); + return platform_add_devices(board_platform_devices, ARRAY_SIZE(board_platform_devices)); } - -arch_initcall(board_register_devices); +device_initcall(board_register_devices); diff --git a/arch/mips/alchemy/devboards/pb1500/Makefile b/arch/mips/alchemy/devboards/pb1500/Makefile index 173b419a747..e83b151b5b6 100644 --- a/arch/mips/alchemy/devboards/pb1500/Makefile +++ b/arch/mips/alchemy/devboards/pb1500/Makefile @@ -5,4 +5,4 @@ # Makefile for the Alchemy Semiconductor Pb1500 board. # -obj-y := board_setup.o +obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c index d7a56569e7e..fa9770ac358 100644 --- a/arch/mips/alchemy/devboards/pb1500/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c @@ -29,22 +29,14 @@ #include <linux/interrupt.h> #include <asm/mach-au1x00/au1000.h> -#include <asm/mach-pb1x00/pb1500.h> +#include <asm/mach-db1x00/bcsr.h> #include <prom.h> char irq_tab_alchemy[][5] __initdata = { - [12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT370 */ - [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */ -}; - -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - { AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 }, - { AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 }, - { AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 }, - { AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 }, - { AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 }, + [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT370 */ + [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ }; @@ -55,35 +47,16 @@ const char *get_system_type(void) void board_reset(void) { - /* Hit BCSR.RST_VDDI[SOFT_RESET] */ - au_writel(0x00000000, PB1500_RST_VDDI); -} - -void __init board_init_irq(void) -{ - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); + bcsr_write(BCSR_SYSTEM, 0); } void __init board_setup(void) { u32 pin_func; u32 sys_freqctrl, sys_clksrc; - char *argptr; - - argptr = prom_getcmdline(); -#ifdef CONFIG_SERIAL_8250_CONSOLE - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif -#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000) - /* au1000 does not support vra, au1500 and au1100 do */ - strcat(argptr, " au1000_audio=vra"); - argptr = prom_getcmdline(); -#endif + bcsr_init(DB1000_BCSR_PHYS_ADDR, + DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS); sys_clksrc = sys_freqctrl = pin_func = 0; /* Set AUX clock to 12 MHz * 8 = 96 MHz */ @@ -163,3 +136,18 @@ void __init board_setup(void) au_sync(); } } + +static int __init pb1500_init_irq(void) +{ + set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW); /* CD0# */ + set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW); /* CARD0 */ + set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */ + set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); + set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW); + set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW); + set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW); + set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW); + + return 0; +} +arch_initcall(pb1500_init_irq); diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c new file mode 100644 index 00000000000..d443bc7aa76 --- /dev/null +++ b/arch/mips/alchemy/devboards/pb1500/platform.c @@ -0,0 +1,49 @@ +/* + * Pb1500 board platform device registration + * + * Copyright (C) 2009 Manuel Lauss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-db1x00/bcsr.h> + +#include "../platform.h" + +static int __init pb1500_dev_init(void) +{ + int swapped; + + /* PCMCIA. single socket, identical to Pb1500 */ + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1500_GPIO11_INT, /* card */ + AU1500_GPIO9_INT, /* insert */ + /*AU1500_GPIO10_INT*/0, /* stschg */ + 0, /* eject */ + 0); /* id */ + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; + db1x_register_norflash(64 * 1024 * 1024, 4, swapped); + + return 0; +} +device_initcall(pb1500_dev_init); diff --git a/arch/mips/alchemy/devboards/pb1550/Makefile b/arch/mips/alchemy/devboards/pb1550/Makefile index cff95bcdb2c..9661b6ec5dd 100644 --- a/arch/mips/alchemy/devboards/pb1550/Makefile +++ b/arch/mips/alchemy/devboards/pb1550/Makefile @@ -5,4 +5,4 @@ # Makefile for the Alchemy Semiconductor Pb1550 board. # -obj-y := board_setup.o +obj-y := board_setup.o platform.o diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c index b6e9e7d247a..1e8fb3ddd72 100644 --- a/arch/mips/alchemy/devboards/pb1550/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c @@ -32,18 +32,15 @@ #include <asm/mach-au1x00/au1000.h> #include <asm/mach-pb1x00/pb1550.h> +#include <asm/mach-db1x00/bcsr.h> +#include <asm/mach-au1x00/gpio.h> #include <prom.h> char irq_tab_alchemy[][5] __initdata = { - [12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */ - [13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */ -}; - -struct au1xxx_irqmap __initdata au1xxx_irq_map[] = { - { AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 }, - { AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 }, + [12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */ + [13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */ }; const char *get_system_type(void) @@ -53,28 +50,17 @@ const char *get_system_type(void) void board_reset(void) { - /* Hit BCSR.SYSTEM[RESET] */ - au_writew(au_readw(0xAF00001C) & ~BCSR_SYSTEM_RESET, 0xAF00001C); -} - -void __init board_init_irq(void) -{ - au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map)); + bcsr_write(BCSR_SYSTEM, 0); } void __init board_setup(void) { u32 pin_func; -#ifdef CONFIG_SERIAL_8250_CONSOLE - char *argptr; - argptr = prom_getcmdline(); - argptr = strstr(argptr, "console="); - if (argptr == NULL) { - argptr = prom_getcmdline(); - strcat(argptr, " console=ttyS0,115200"); - } -#endif + bcsr_init(PB1550_BCSR_PHYS_ADDR, + PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS); + + alchemy_gpio2_enable(); /* * Enable PSC1 SYNC for AC'97. Normaly done in audio driver, @@ -85,8 +71,21 @@ void __init board_setup(void) pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1; au_writel(pin_func, SYS_PINFUNC); - au_writel(0, (u32)bcsr | 0x10); /* turn off PCMCIA power */ - au_sync(); + bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */ printk(KERN_INFO "AMD Alchemy Pb1550 Board\n"); } + +static int __init pb1550_init_irq(void) +{ + set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW); + set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW); + set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH); + + /* enable both PCMCIA card irqs in the shared line */ + alchemy_gpio2_enable_int(201); + alchemy_gpio2_enable_int(202); + + return 0; +} +arch_initcall(pb1550_init_irq); diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c new file mode 100644 index 00000000000..d7150d0f49c --- /dev/null +++ b/arch/mips/alchemy/devboards/pb1550/platform.c @@ -0,0 +1,69 @@ +/* + * Pb1550 board platform device registration + * + * Copyright (C) 2009 Manuel Lauss + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <linux/init.h> + +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-pb1x00/pb1550.h> +#include <asm/mach-db1x00/bcsr.h> + +#include "../platform.h" + +static int __init pb1550_dev_init(void) +{ + int swapped; + + /* Pb1550, like all others, also has statuschange irqs; however they're + * wired up on one of the Au1550's shared GPIO201_205 line, which also + * services the PCMCIA card interrupts. So we ignore statuschange and + * use the GPIO201_205 exclusively for card interrupts, since a) pcmcia + * drivers are used to shared irqs and b) statuschange isn't really use- + * ful anyway. + */ + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR, + PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_MEM_PHYS_ADDR, + PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1, + PCMCIA_IO_PHYS_ADDR, + PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1, + AU1550_GPIO201_205_INT, + AU1550_GPIO0_INT, + 0, + 0, + 0); + + db1x_register_pcmcia_socket(PCMCIA_ATTR_PHYS_ADDR + 0x008000000, + PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1, + PCMCIA_MEM_PHYS_ADDR + 0x008000000, + PCMCIA_MEM_PHYS_ADDR + 0x008400000 - 1, + PCMCIA_IO_PHYS_ADDR + 0x008000000, + PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1, + AU1550_GPIO201_205_INT, + AU1550_GPIO1_INT, + 0, + 0, + 1); + + swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT; + db1x_register_norflash(128 * 1024 * 1024, 4, swapped); + + return 0; +} +device_initcall(pb1550_dev_init); diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c new file mode 100644 index 00000000000..49a4b3244d8 --- /dev/null +++ b/arch/mips/alchemy/devboards/platform.c @@ -0,0 +1,222 @@ +/* + * devoard misc stuff. + */ + +#include <linux/init.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/pm.h> + +#include <asm/reboot.h> +#include <asm/mach-db1x00/bcsr.h> + +static void db1x_power_off(void) +{ + bcsr_write(BCSR_RESETS, 0); + bcsr_write(BCSR_SYSTEM, BCSR_SYSTEM_PWROFF | BCSR_SYSTEM_RESET); +} + +static void db1x_reset(char *c) +{ + bcsr_write(BCSR_RESETS, 0); + bcsr_write(BCSR_SYSTEM, 0); +} + +static int __init db1x_poweroff_setup(void) +{ + if (!pm_power_off) + pm_power_off = db1x_power_off; + if (!_machine_halt) + _machine_halt = db1x_power_off; + if (!_machine_restart) + _machine_restart = db1x_reset; + + return 0; +} +late_initcall(db1x_poweroff_setup); + +/* register a pcmcia socket */ +int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start, + phys_addr_t pcmcia_attr_end, + phys_addr_t pcmcia_mem_start, + phys_addr_t pcmcia_mem_end, + phys_addr_t pcmcia_io_start, + phys_addr_t pcmcia_io_end, + int card_irq, + int cd_irq, + int stschg_irq, + int eject_irq, + int id) +{ + int cnt, i, ret; + struct resource *sr; + struct platform_device *pd; + + cnt = 5; + if (eject_irq) + cnt++; + if (stschg_irq) + cnt++; + + sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL); + if (!sr) + return -ENOMEM; + + pd = platform_device_alloc("db1xxx_pcmcia", id); + if (!pd) { + ret = -ENOMEM; + goto out; + } + + sr[0].name = "pcmcia-attr"; + sr[0].flags = IORESOURCE_MEM; + sr[0].start = pcmcia_attr_start; + sr[0].end = pcmcia_attr_end; + + sr[1].name = "pcmcia-mem"; + sr[1].flags = IORESOURCE_MEM; + sr[1].start = pcmcia_mem_start; + sr[1].end = pcmcia_mem_end; + + sr[2].name = "pcmcia-io"; + sr[2].flags = IORESOURCE_MEM; + sr[2].start = pcmcia_io_start; + sr[2].end = pcmcia_io_end; + + sr[3].name = "insert"; + sr[3].flags = IORESOURCE_IRQ; + sr[3].start = sr[3].end = cd_irq; + + sr[4].name = "card"; + sr[4].flags = IORESOURCE_IRQ; + sr[4].start = sr[4].end = card_irq; + + i = 5; + if (stschg_irq) { + sr[i].name = "stschg"; + sr[i].flags = IORESOURCE_IRQ; + sr[i].start = sr[i].end = stschg_irq; + i++; + } + if (eject_irq) { + sr[i].name = "eject"; + sr[i].flags = IORESOURCE_IRQ; + sr[i].start = sr[i].end = eject_irq; + } + + pd->resource = sr; + pd->num_resources = cnt; + + ret = platform_device_add(pd); + if (!ret) + return 0; + + platform_device_put(pd); +out: + kfree(sr); + return ret; +} + +#define YAMON_SIZE 0x00100000 +#define YAMON_ENV_SIZE 0x00040000 + +int __init db1x_register_norflash(unsigned long size, int width, + int swapped) +{ + struct physmap_flash_data *pfd; + struct platform_device *pd; + struct mtd_partition *parts; + struct resource *res; + int ret, i; + + if (size < (8 * 1024 * 1024)) + return -EINVAL; + + ret = -ENOMEM; + parts = kzalloc(sizeof(struct mtd_partition) * 5, GFP_KERNEL); + if (!parts) + goto out; + + res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (!res) + goto out1; + + pfd = kzalloc(sizeof(struct physmap_flash_data), GFP_KERNEL); + if (!pfd) + goto out2; + + pd = platform_device_alloc("physmap-flash", 0); + if (!pd) + goto out3; + + /* NOR flash ends at 0x20000000, regardless of size */ + res->start = 0x20000000 - size; + res->end = 0x20000000 - 1; + res->flags = IORESOURCE_MEM; + + /* partition setup. Most Develboards have a switch which allows + * to swap the physical locations of the 2 NOR flash banks. + */ + i = 0; + if (!swapped) { + /* first NOR chip */ + parts[i].offset = 0; + parts[i].name = "User FS"; + parts[i].size = size / 2; + i++; + } + + parts[i].offset = MTDPART_OFS_APPEND; + parts[i].name = "User FS 2"; + parts[i].size = (size / 2) - (0x20000000 - 0x1fc00000); + i++; + + parts[i].offset = MTDPART_OFS_APPEND; + parts[i].name = "YAMON"; + parts[i].size = YAMON_SIZE; + parts[i].mask_flags = MTD_WRITEABLE; + i++; + + parts[i].offset = MTDPART_OFS_APPEND; + parts[i].name = "raw kernel"; + parts[i].size = 0x00400000 - YAMON_SIZE - YAMON_ENV_SIZE; + i++; + + parts[i].offset = MTDPART_OFS_APPEND; + parts[i].name = "YAMON Env"; + parts[i].size = YAMON_ENV_SIZE; + parts[i].mask_flags = MTD_WRITEABLE; + i++; + + if (swapped) { + parts[i].offset = MTDPART_OFS_APPEND; + parts[i].name = "User FS"; + parts[i].size = size / 2; + i++; + } + + pfd->width = width; + pfd->parts = parts; + pfd->nr_parts = 5; + + pd->dev.platform_data = pfd; + pd->resource = res; + pd->num_resources = 1; + + ret = platform_device_add(pd); + if (!ret) + return ret; + + platform_device_put(pd); +out3: + kfree(pfd); +out2: + kfree(res); +out1: + kfree(parts); +out: + return ret; +} diff --git a/arch/mips/alchemy/devboards/platform.h b/arch/mips/alchemy/devboards/platform.h new file mode 100644 index 00000000000..5ac055d2cda --- /dev/null +++ b/arch/mips/alchemy/devboards/platform.h @@ -0,0 +1,21 @@ +#ifndef _DEVBOARD_PLATFORM_H_ +#define _DEVBOARD_PLATFORM_H_ + +#include <linux/init.h> + +int __init db1x_register_pcmcia_socket(phys_addr_t pcmcia_attr_start, + phys_addr_t pcmcia_attr_len, + phys_addr_t pcmcia_mem_start, + phys_addr_t pcmcia_mem_end, + phys_addr_t pcmcia_io_start, + phys_addr_t pcmcia_io_end, + int card_irq, + int cd_irq, + int stschg_irq, + int eject_irq, + int id); + +int __init db1x_register_norflash(unsigned long size, int width, + int swapped); + +#endif diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index 632f9862a0f..4bbd3133e45 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c @@ -10,6 +10,7 @@ #include <linux/sysfs.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/gpio.h> +#include <asm/mach-db1x00/bcsr.h> /* * Generic suspend userspace interface for Alchemy development boards. @@ -26,6 +27,20 @@ static unsigned long db1x_pm_last_wakesrc; static int db1x_pm_enter(suspend_state_t state) { + unsigned short bcsrs[16]; + int i, j, hasint; + + /* save CPLD regs */ + hasint = bcsr_read(BCSR_WHOAMI); + hasint = BCSR_WHOAMI_BOARD(hasint) >= BCSR_WHOAMI_DB1200; + j = (hasint) ? BCSR_MASKSET : BCSR_SYSTEM; + + for (i = BCSR_STATUS; i <= j; i++) + bcsrs[i] = bcsr_read(i); + + /* shut off hexleds */ + bcsr_write(BCSR_HEXCLEAR, 3); + /* enable GPIO based wakeup */ alchemy_gpio1_input_enable(); @@ -52,6 +67,23 @@ static int db1x_pm_enter(suspend_state_t state) /* ...and now the sandman can come! */ au_sleep(); + + /* restore CPLD regs */ + for (i = BCSR_STATUS; i <= BCSR_SYSTEM; i++) + bcsr_write(i, bcsrs[i]); + + /* restore CPLD int registers */ + if (hasint) { + bcsr_write(BCSR_INTCLR, 0xffff); + bcsr_write(BCSR_MASKCLR, 0xffff); + bcsr_write(BCSR_INTSTAT, 0xffff); + bcsr_write(BCSR_INTSET, bcsrs[BCSR_INTSET]); + bcsr_write(BCSR_MASKSET, bcsrs[BCSR_MASKSET]); + } + + /* light up hexleds */ + bcsr_write(BCSR_HEXCLEAR, 0); + return 0; } diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c index 0042bd6b1d7..b30df5c97ad 100644 --- a/arch/mips/alchemy/devboards/prom.c +++ b/arch/mips/alchemy/devboards/prom.c @@ -60,3 +60,8 @@ void __init prom_init(void) strict_strtoul(memsize_str, 0, &memsize); add_memory_region(0, memsize, BOOT_MEM_RAM); } + +void prom_putchar(unsigned char c) +{ + alchemy_uart_putchar(UART0_PHYS_ADDR, c); +} |