M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,13 @@
#
# Alchemy Develboards
#
obj-y += prom.o bcsr.o platform.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_MIPS_PB1100) += pb1100.o
obj-$(CONFIG_MIPS_PB1500) += pb1500.o
obj-$(CONFIG_MIPS_PB1550) += pb1550.o
obj-$(CONFIG_MIPS_DB1000) += db1000.o
obj-$(CONFIG_MIPS_DB1200) += db1200.o
obj-$(CONFIG_MIPS_DB1300) += db1300.o
obj-$(CONFIG_MIPS_DB1550) += db1550.o
+146
View File
@@ -0,0 +1,146 @@
/*
* 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 <linux/irq.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);
disable_irq_nosync(irq);
for ( ; bisr; bisr &= bisr - 1)
generic_handle_irq(bcsr_csc_base + __ffs(bisr));
enable_irq(irq);
}
static void bcsr_irq_mask(struct irq_data *d)
{
unsigned short v = 1 << (d->irq - bcsr_csc_base);
__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
wmb();
}
static void bcsr_irq_maskack(struct irq_data *d)
{
unsigned short v = 1 << (d->irq - bcsr_csc_base);
__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT); /* ack */
wmb();
}
static void bcsr_irq_unmask(struct irq_data *d)
{
unsigned short v = 1 << (d->irq - bcsr_csc_base);
__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
wmb();
}
static struct irq_chip bcsr_irq_type = {
.name = "CPLD",
.irq_mask = bcsr_irq_mask,
.irq_mask_ack = bcsr_irq_maskack,
.irq_unmask = bcsr_irq_unmask,
};
void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
{
unsigned int irq;
/* mask & enable & ack all */
__raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSET);
__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
wmb();
bcsr_csc_base = csc_start;
for (irq = csc_start; irq <= csc_end; irq++)
irq_set_chip_and_handler_name(irq, &bcsr_irq_type,
handle_level_irq, "level");
irq_set_chained_handler(hook_irq, bcsr_csc_handler);
}
+565
View File
@@ -0,0 +1,565 @@
/*
* DBAu1000/1500/1100 board support
*
* Copyright 2000, 2008 MontaVista Software Inc.
* Author: MontaVista Software, Inc. <source@mvista.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 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/init.h>
#include <linux/interrupt.h>
#include <linux/leds.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_gpio.h>
#include <linux/spi/ads7846.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1000_dma.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-db1x00/bcsr.h>
#include <asm/reboot.h>
#include <prom.h>
#include "platform.h"
#define F_SWAPPED (bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT)
struct pci_dev;
static const char *board_type_str(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
case BCSR_WHOAMI_DB1000:
return "DB1000";
case BCSR_WHOAMI_DB1500:
return "DB1500";
case BCSR_WHOAMI_DB1100:
return "DB1100";
default:
return "(unknown)";
}
}
const char *get_system_type(void)
{
return board_type_str();
}
void __init board_setup(void)
{
/* initialize board register space */
bcsr_init(DB1000_BCSR_PHYS_ADDR,
DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
printk(KERN_INFO "AMD Alchemy %s Board\n", board_type_str());
}
static int db1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 12) || (slot > 13) || pin == 0)
return -1;
if (slot == 12)
return (pin == 1) ? AU1500_PCI_INTA : 0xff;
if (slot == 13) {
switch (pin) {
case 1: return AU1500_PCI_INTA;
case 2: return AU1500_PCI_INTB;
case 3: return AU1500_PCI_INTC;
case 4: return AU1500_PCI_INTD;
}
}
return -1;
}
static struct resource alchemy_pci_host_res[] = {
[0] = {
.start = AU1500_PCI_PHYS_ADDR,
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
};
static struct alchemy_pci_platdata db1500_pci_pd = {
.board_map_irq = db1500_map_pci_irq,
};
static struct platform_device db1500_pci_host_dev = {
.dev.platform_data = &db1500_pci_pd,
.name = "alchemy-pci",
.id = 0,
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
.resource = alchemy_pci_host_res,
};
static int __init db1500_pci_init(void)
{
if (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) == BCSR_WHOAMI_DB1500)
return platform_device_register(&db1500_pci_host_dev);
return 0;
}
/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
arch_initcall(db1500_pci_init);
static struct resource au1100_lcd_resources[] = {
[0] = {
.start = AU1100_LCD_PHYS_ADDR,
.end = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1100_LCD_INT,
.end = AU1100_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
static struct platform_device au1100_lcd_device = {
.name = "au1100-lcd",
.id = 0,
.dev = {
.dma_mask = &au1100_lcd_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(au1100_lcd_resources),
.resource = au1100_lcd_resources,
};
static struct resource alchemy_ac97c_res[] = {
[0] = {
.start = AU1000_AC97_PHYS_ADDR,
.end = AU1000_AC97_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMA_ID_AC97C_TX,
.end = DMA_ID_AC97C_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMA_ID_AC97C_RX,
.end = DMA_ID_AC97C_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device alchemy_ac97c_dev = {
.name = "alchemy-ac97c",
.id = -1,
.resource = alchemy_ac97c_res,
.num_resources = ARRAY_SIZE(alchemy_ac97c_res),
};
static struct platform_device alchemy_ac97c_dma_dev = {
.name = "alchemy-pcm-dma",
.id = 0,
};
static struct platform_device db1x00_codec_dev = {
.name = "ac97-codec",
.id = -1,
};
static struct platform_device db1x00_audio_dev = {
.name = "db1000-audio",
};
/******************************************************************************/
static irqreturn_t db1100_mmc_cd(int irq, void *ptr)
{
void (*mmc_cd)(struct mmc_host *, unsigned long);
/* link against CONFIG_MMC=m */
mmc_cd = symbol_get(mmc_detect_change);
mmc_cd(ptr, msecs_to_jiffies(500));
symbol_put(mmc_detect_change);
return IRQ_HANDLED;
}
static int db1100_mmc_cd_setup(void *mmc_host, int en)
{
int ret = 0;
if (en) {
irq_set_irq_type(AU1100_GPIO19_INT, IRQ_TYPE_EDGE_BOTH);
ret = request_irq(AU1100_GPIO19_INT, db1100_mmc_cd, 0,
"sd0_cd", mmc_host);
} else
free_irq(AU1100_GPIO19_INT, mmc_host);
return ret;
}
static int db1100_mmc1_cd_setup(void *mmc_host, int en)
{
int ret = 0;
if (en) {
irq_set_irq_type(AU1100_GPIO20_INT, IRQ_TYPE_EDGE_BOTH);
ret = request_irq(AU1100_GPIO20_INT, db1100_mmc_cd, 0,
"sd1_cd", mmc_host);
} else
free_irq(AU1100_GPIO20_INT, mmc_host);
return ret;
}
static int db1100_mmc_card_readonly(void *mmc_host)
{
/* testing suggests that this bit is inverted */
return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 0 : 1;
}
static int db1100_mmc_card_inserted(void *mmc_host)
{
return !alchemy_gpio_get_value(19);
}
static void db1100_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 void db1100_mmcled_set(struct led_classdev *led, enum led_brightness b)
{
if (b != LED_OFF)
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
else
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
}
static struct led_classdev db1100_mmc_led = {
.brightness_set = db1100_mmcled_set,
};
static int db1100_mmc1_card_readonly(void *mmc_host)
{
return (bcsr_read(BCSR_BOARD) & BCSR_BOARD_SD1WP) ? 1 : 0;
}
static int db1100_mmc1_card_inserted(void *mmc_host)
{
return !alchemy_gpio_get_value(20);
}
static void db1100_mmc1_set_power(void *mmc_host, int state)
{
if (state) {
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
msleep(400); /* stabilization time */
} else
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
}
static void db1100_mmc1led_set(struct led_classdev *led, enum led_brightness b)
{
if (b != LED_OFF)
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
else
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
}
static struct led_classdev db1100_mmc1_led = {
.brightness_set = db1100_mmc1led_set,
};
static struct au1xmmc_platform_data db1100_mmc_platdata[2] = {
[0] = {
.cd_setup = db1100_mmc_cd_setup,
.set_power = db1100_mmc_set_power,
.card_inserted = db1100_mmc_card_inserted,
.card_readonly = db1100_mmc_card_readonly,
.led = &db1100_mmc_led,
},
[1] = {
.cd_setup = db1100_mmc1_cd_setup,
.set_power = db1100_mmc1_set_power,
.card_inserted = db1100_mmc1_card_inserted,
.card_readonly = db1100_mmc1_card_readonly,
.led = &db1100_mmc1_led,
},
};
static struct resource au1100_mmc0_resources[] = {
[0] = {
.start = AU1100_SD0_PHYS_ADDR,
.end = AU1100_SD0_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1100_SD_INT,
.end = AU1100_SD_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = DMA_ID_SD0_TX,
.end = DMA_ID_SD0_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMA_ID_SD0_RX,
.end = DMA_ID_SD0_RX,
.flags = IORESOURCE_DMA,
}
};
static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1100_mmc0_dev = {
.name = "au1xxx-mmc",
.id = 0,
.dev = {
.dma_mask = &au1xxx_mmc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1100_mmc_platdata[0],
},
.num_resources = ARRAY_SIZE(au1100_mmc0_resources),
.resource = au1100_mmc0_resources,
};
static struct resource au1100_mmc1_res[] = {
[0] = {
.start = AU1100_SD1_PHYS_ADDR,
.end = AU1100_SD1_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1100_SD_INT,
.end = AU1100_SD_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = DMA_ID_SD1_TX,
.end = DMA_ID_SD1_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMA_ID_SD1_RX,
.end = DMA_ID_SD1_RX,
.flags = IORESOURCE_DMA,
}
};
static struct platform_device db1100_mmc1_dev = {
.name = "au1xxx-mmc",
.id = 1,
.dev = {
.dma_mask = &au1xxx_mmc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1100_mmc_platdata[1],
},
.num_resources = ARRAY_SIZE(au1100_mmc1_res),
.resource = au1100_mmc1_res,
};
/******************************************************************************/
static void db1000_irda_set_phy_mode(int mode)
{
unsigned short mask = BCSR_RESETS_IRDA_MODE_MASK | BCSR_RESETS_FIR_SEL;
switch (mode) {
case AU1000_IRDA_PHY_MODE_OFF:
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_OFF);
break;
case AU1000_IRDA_PHY_MODE_SIR:
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL);
break;
case AU1000_IRDA_PHY_MODE_FIR:
bcsr_mod(BCSR_RESETS, mask, BCSR_RESETS_IRDA_MODE_FULL |
BCSR_RESETS_FIR_SEL);
break;
}
}
static struct au1k_irda_platform_data db1000_irda_platdata = {
.set_phy_mode = db1000_irda_set_phy_mode,
};
static struct resource au1000_irda_res[] = {
[0] = {
.start = AU1000_IRDA_PHYS_ADDR,
.end = AU1000_IRDA_PHYS_ADDR + 0x0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1000_IRDA_TX_INT,
.end = AU1000_IRDA_TX_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1000_IRDA_RX_INT,
.end = AU1000_IRDA_RX_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device db1000_irda_dev = {
.name = "au1000-irda",
.id = -1,
.dev = {
.platform_data = &db1000_irda_platdata,
},
.resource = au1000_irda_res,
.num_resources = ARRAY_SIZE(au1000_irda_res),
};
/******************************************************************************/
static struct ads7846_platform_data db1100_touch_pd = {
.model = 7846,
.vref_mv = 3300,
.gpio_pendown = 21,
};
static struct spi_gpio_platform_data db1100_spictl_pd = {
.sck = 209,
.mosi = 208,
.miso = 207,
.num_chipselect = 1,
};
static struct spi_board_info db1100_spi_info[] __initdata = {
[0] = {
.modalias = "ads7846",
.max_speed_hz = 3250000,
.bus_num = 0,
.chip_select = 0,
.mode = 0,
.irq = AU1100_GPIO21_INT,
.platform_data = &db1100_touch_pd,
.controller_data = (void *)210, /* for spi_gpio: CS# GPIO210 */
},
};
static struct platform_device db1100_spi_dev = {
.name = "spi_gpio",
.id = 0,
.dev = {
.platform_data = &db1100_spictl_pd,
},
};
static struct platform_device *db1x00_devs[] = {
&db1x00_codec_dev,
&alchemy_ac97c_dma_dev,
&alchemy_ac97c_dev,
&db1x00_audio_dev,
};
static struct platform_device *db1000_devs[] = {
&db1000_irda_dev,
};
static struct platform_device *db1100_devs[] = {
&au1100_lcd_device,
&db1100_mmc0_dev,
&db1100_mmc1_dev,
&db1000_irda_dev,
&db1100_spi_dev,
};
static int __init db1000_dev_init(void)
{
int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
int c0, c1, d0, d1, s0, s1;
unsigned long pfc;
if (board == BCSR_WHOAMI_DB1500) {
c0 = AU1500_GPIO2_INT;
c1 = AU1500_GPIO5_INT;
d0 = AU1500_GPIO0_INT;
d1 = AU1500_GPIO3_INT;
s0 = AU1500_GPIO1_INT;
s1 = AU1500_GPIO4_INT;
} else if (board == BCSR_WHOAMI_DB1100) {
c0 = AU1100_GPIO2_INT;
c1 = AU1100_GPIO5_INT;
d0 = AU1100_GPIO0_INT;
d1 = AU1100_GPIO3_INT;
s0 = AU1100_GPIO1_INT;
s1 = AU1100_GPIO4_INT;
gpio_direction_input(19); /* sd0 cd# */
gpio_direction_input(20); /* sd1 cd# */
gpio_direction_input(21); /* touch pendown# */
gpio_direction_input(207); /* SPI MISO */
gpio_direction_output(208, 0); /* SPI MOSI */
gpio_direction_output(209, 1); /* SPI SCK */
gpio_direction_output(210, 1); /* SPI CS# */
/* spi_gpio on SSI0 pins */
pfc = __raw_readl((void __iomem *)SYS_PINFUNC);
pfc |= (1 << 0); /* SSI0 pins as GPIOs */
__raw_writel(pfc, (void __iomem *)SYS_PINFUNC);
wmb();
spi_register_board_info(db1100_spi_info,
ARRAY_SIZE(db1100_spi_info));
platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs));
} else if (board == BCSR_WHOAMI_DB1000) {
c0 = AU1000_GPIO2_INT;
c1 = AU1000_GPIO5_INT;
d0 = AU1000_GPIO0_INT;
d1 = AU1000_GPIO3_INT;
s0 = AU1000_GPIO1_INT;
s1 = AU1000_GPIO4_INT;
platform_add_devices(db1000_devs, ARRAY_SIZE(db1000_devs));
} else
return 0; /* unknown board, no further dev setup to do */
irq_set_irq_type(d0, IRQ_TYPE_EDGE_BOTH);
irq_set_irq_type(d1, IRQ_TYPE_EDGE_BOTH);
irq_set_irq_type(c0, IRQ_TYPE_LEVEL_LOW);
irq_set_irq_type(c1, IRQ_TYPE_LEVEL_LOW);
irq_set_irq_type(s0, IRQ_TYPE_LEVEL_LOW);
irq_set_irq_type(s1, IRQ_TYPE_LEVEL_LOW);
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
c0, d0, /*s0*/0, 0, 0);
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
c1, d1, /*s1*/0, 0, 1);
platform_add_devices(db1x00_devs, ARRAY_SIZE(db1x00_devs));
db1x_register_norflash(32 << 20, 4 /* 32bit */, F_SWAPPED);
return 0;
}
device_initcall(db1000_dev_init);
+927
View File
@@ -0,0 +1,927 @@
/*
* DBAu1200/PBAu1200 board platform device registration
*
* Copyright (C) 2008-2011 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/interrupt.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/au1000.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1550_spi.h>
#include <asm/mach-db1x00/bcsr.h>
#include <asm/mach-db1x00/db1200.h>
#include "platform.h"
static const char *board_type_str(void)
{
switch (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
case BCSR_WHOAMI_PB1200_DDR1:
case BCSR_WHOAMI_PB1200_DDR2:
return "PB1200";
case BCSR_WHOAMI_DB1200:
return "DB1200";
default:
return "(unknown)";
}
}
const char *get_system_type(void)
{
return board_type_str();
}
static int __init detect_board(void)
{
int bid;
/* try the DB1200 first */
bcsr_init(DB1200_BCSR_PHYS_ADDR,
DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
if (BCSR_WHOAMI_DB1200 == BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI))) {
unsigned short t = bcsr_read(BCSR_HEXLEDS);
bcsr_write(BCSR_HEXLEDS, ~t);
if (bcsr_read(BCSR_HEXLEDS) != t) {
bcsr_write(BCSR_HEXLEDS, t);
return 0;
}
}
/* okay, try the PB1200 then */
bcsr_init(PB1200_BCSR_PHYS_ADDR,
PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
(bid == BCSR_WHOAMI_PB1200_DDR2)) {
unsigned short t = bcsr_read(BCSR_HEXLEDS);
bcsr_write(BCSR_HEXLEDS, ~t);
if (bcsr_read(BCSR_HEXLEDS) != t) {
bcsr_write(BCSR_HEXLEDS, t);
return 0;
}
}
return 1; /* it's neither */
}
void __init board_setup(void)
{
unsigned long freq0, clksrc, div, pfc;
unsigned short whoami;
if (detect_board()) {
printk(KERN_ERR "NOT running on a DB1200/PB1200 board!\n");
return;
}
whoami = bcsr_read(BCSR_WHOAMI);
printk(KERN_INFO "Alchemy/AMD/RMI %s Board, CPLD Rev %d"
" Board-ID %d Daughtercard ID %d\n", board_type_str(),
(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();
}
/******************************************************************************/
static struct mtd_partition db1200_spiflash_parts[] = {
{
.name = "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 = {
{ I2C_BOARD_INFO("24c04", 0x52), }, /* AT24C04-10 I2C eeprom */
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec WM8731 */
};
/**********************************************************************/
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,
},
[2] = {
.start = AU1200_DSCR_CMD0_DMA_REQ1,
.end = AU1200_DSCR_CMD0_DMA_REQ1,
.flags = IORESOURCE_DMA,
},
};
static u64 au1200_ide_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_ide_dev = {
.name = "au1200-ide",
.id = 0,
.dev = {
.dma_mask = &au1200_ide_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(db1200_ide_res),
.resource = db1200_ide_res,
};
/**********************************************************************/
/* 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,
0, "sd_insert", mmc_host);
if (ret)
goto out;
ret = request_irq(DB1200_SD0_EJECT_INT, db1200_mmc_cd,
0, "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,
};
/* -- */
static irqreturn_t pb1200_mmc1_cd(int irq, void *ptr)
{
void(*mmc_cd)(struct mmc_host *, unsigned long);
if (irq == PB1200_SD1_INSERT_INT) {
disable_irq_nosync(PB1200_SD1_INSERT_INT);
enable_irq(PB1200_SD1_EJECT_INT);
} else {
disable_irq_nosync(PB1200_SD1_EJECT_INT);
enable_irq(PB1200_SD1_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 pb1200_mmc1_cd_setup(void *mmc_host, int en)
{
int ret;
if (en) {
ret = request_irq(PB1200_SD1_INSERT_INT, pb1200_mmc1_cd, 0,
"sd1_insert", mmc_host);
if (ret)
goto out;
ret = request_irq(PB1200_SD1_EJECT_INT, pb1200_mmc1_cd, 0,
"sd1_eject", mmc_host);
if (ret) {
free_irq(PB1200_SD1_INSERT_INT, mmc_host);
goto out;
}
if (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT)
enable_irq(PB1200_SD1_EJECT_INT);
else
enable_irq(PB1200_SD1_INSERT_INT);
} else {
free_irq(PB1200_SD1_INSERT_INT, mmc_host);
free_irq(PB1200_SD1_EJECT_INT, mmc_host);
}
ret = 0;
out:
return ret;
}
static void pb1200_mmc1led_set(struct led_classdev *led,
enum led_brightness brightness)
{
if (brightness != LED_OFF)
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
else
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
}
static struct led_classdev pb1200_mmc1_led = {
.brightness_set = pb1200_mmc1led_set,
};
static void pb1200_mmc1_set_power(void *mmc_host, int state)
{
if (state) {
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
msleep(400); /* stabilization time */
} else
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
}
static int pb1200_mmc1_card_readonly(void *mmc_host)
{
return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
}
static int pb1200_mmc1_card_inserted(void *mmc_host)
{
return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
}
static struct au1xmmc_platform_data db1200_mmc_platdata[2] = {
[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,
},
[1] = {
.cd_setup = pb1200_mmc1_cd_setup,
.set_power = pb1200_mmc1_set_power,
.card_inserted = pb1200_mmc1_card_inserted,
.card_readonly = pb1200_mmc1_card_readonly,
.led = &pb1200_mmc1_led,
},
};
static struct resource au1200_mmc0_resources[] = {
[0] = {
.start = AU1100_SD0_PHYS_ADDR,
.end = AU1100_SD0_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_SD_INT,
.end = AU1200_SD_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1200_DSCR_CMD0_SDMS_TX0,
.end = AU1200_DSCR_CMD0_SDMS_TX0,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1200_DSCR_CMD0_SDMS_RX0,
.end = AU1200_DSCR_CMD0_SDMS_RX0,
.flags = IORESOURCE_DMA,
}
};
static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1200_mmc0_dev = {
.name = "au1xxx-mmc",
.id = 0,
.dev = {
.dma_mask = &au1xxx_mmc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1200_mmc_platdata[0],
},
.num_resources = ARRAY_SIZE(au1200_mmc0_resources),
.resource = au1200_mmc0_resources,
};
static struct resource au1200_mmc1_res[] = {
[0] = {
.start = AU1100_SD1_PHYS_ADDR,
.end = AU1100_SD1_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_SD_INT,
.end = AU1200_SD_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1200_DSCR_CMD0_SDMS_TX1,
.end = AU1200_DSCR_CMD0_SDMS_TX1,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1200_DSCR_CMD0_SDMS_RX1,
.end = AU1200_DSCR_CMD0_SDMS_RX1,
.flags = IORESOURCE_DMA,
}
};
static struct platform_device pb1200_mmc1_dev = {
.name = "au1xxx-mmc",
.id = 1,
.dev = {
.dma_mask = &au1xxx_mmc_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1200_mmc_platdata[1],
},
.num_resources = ARRAY_SIZE(au1200_mmc1_res),
.resource = au1200_mmc1_res,
};
/**********************************************************************/
static int db1200fb_panel_index(void)
{
return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
}
static int db1200fb_panel_init(void)
{
/* Apply power */
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
BCSR_BOARD_LCDBL);
return 0;
}
static int db1200fb_panel_shutdown(void)
{
/* Remove power */
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
BCSR_BOARD_LCDBL, 0);
return 0;
}
static struct au1200fb_platdata db1200fb_pd = {
.panel_index = db1200fb_panel_index,
.panel_init = db1200fb_panel_init,
.panel_shutdown = db1200fb_panel_shutdown,
};
static struct resource au1200_lcd_res[] = {
[0] = {
.start = AU1200_LCD_PHYS_ADDR,
.end = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_LCD_INT,
.end = AU1200_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32);
static struct platform_device au1200_lcd_dev = {
.name = "au1200-lcd",
.id = 0,
.dev = {
.dma_mask = &au1200_lcd_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1200fb_pd,
},
.num_resources = ARRAY_SIZE(au1200_lcd_res),
.resource = au1200_lcd_res,
};
/**********************************************************************/
static struct resource au1200_psc0_res[] = {
[0] = {
.start = AU1550_PSC0_PHYS_ADDR,
.end = AU1550_PSC0_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_PSC0_INT,
.end = AU1200_PSC0_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1200_DSCR_CMD0_PSC0_TX,
.end = AU1200_DSCR_CMD0_PSC0_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1200_DSCR_CMD0_PSC0_RX,
.end = AU1200_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_BIT_MASK(32);
static struct platform_device db1200_spi_dev = {
.dev = {
.dma_mask = &spi_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.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 = AU1550_PSC1_PHYS_ADDR,
.end = AU1550_PSC1_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1200_PSC1_INT,
.end = AU1200_PSC1_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1200_DSCR_CMD0_PSC1_TX,
.end = AU1200_DSCR_CMD0_PSC1_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1200_DSCR_CMD0_PSC1_RX,
.end = AU1200_DSCR_CMD0_PSC1_RX,
.flags = IORESOURCE_DMA,
},
};
/* AC97 or I2S device */
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,
};
/* DB1200 ASoC card device */
static struct platform_device db1200_sound_dev = {
/* name assigned later based on switch setting */
.id = 1, /* PSC ID */
};
static struct platform_device db1200_stac_dev = {
.name = "ac97-codec",
.id = 1, /* on PSC1 */
};
static struct platform_device db1200_audiodma_dev = {
.name = "au1xpsc-pcm",
.id = 1, /* PSC ID */
};
static struct platform_device *db1200_devs[] __initdata = {
NULL, /* PSC0, selected by S6.8 */
&db1200_ide_dev,
&db1200_mmc0_dev,
&au1200_lcd_dev,
&db1200_eth_dev,
&db1200_nand_dev,
&db1200_audiodma_dev,
&db1200_audio_dev,
&db1200_stac_dev,
&db1200_sound_dev,
};
static struct platform_device *pb1200_devs[] __initdata = {
&pb1200_mmc1_dev,
};
/* Some peripheral base addresses differ on the PB1200 */
static int __init pb1200_res_fixup(void)
{
/* CPLD Revs earlier than 4 cause problems */
if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
printk(KERN_ERR "WARNING!!!\n");
printk(KERN_ERR "WARNING!!!\n");
printk(KERN_ERR "PB1200 must be at CPLD rev 4. Please have\n");
printk(KERN_ERR "the board updated to latest revisions.\n");
printk(KERN_ERR "This software will not work reliably\n");
printk(KERN_ERR "on anything older than CPLD rev 4.!\n");
printk(KERN_ERR "WARNING!!!\n");
printk(KERN_ERR "WARNING!!!\n");
return 1;
}
db1200_nand_res[0].start = PB1200_NAND_PHYS_ADDR;
db1200_nand_res[0].end = PB1200_NAND_PHYS_ADDR + 0xff;
db1200_ide_res[0].start = PB1200_IDE_PHYS_ADDR;
db1200_ide_res[0].end = PB1200_IDE_PHYS_ADDR + DB1200_IDE_PHYS_LEN - 1;
db1200_eth_res[0].start = PB1200_ETH_PHYS_ADDR;
db1200_eth_res[0].end = PB1200_ETH_PHYS_ADDR + 0xff;
return 0;
}
static int __init db1200_dev_init(void)
{
unsigned long pfc;
unsigned short sw;
int swapped, bid;
bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
(bid == BCSR_WHOAMI_PB1200_DDR2)) {
if (pb1200_res_fixup())
return -ENODEV;
}
/* GPIO7 is low-level triggered CPLD cascade */
irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW);
bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT);
/* insert/eject pairs: one of both is always screaming. To avoid
* issues they must not be automatically enabled when initially
* requested.
*/
irq_set_status_flags(DB1200_SD0_INSERT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1200_SD0_EJECT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1200_PC0_INSERT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1200_PC0_EJECT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1200_PC1_INSERT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1200_PC1_EJECT_INT, IRQ_NOAUTOEN);
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)
* or S12 on the PB1200.
*/
/* 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 "%s device configuration:\n", board_type_str());
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";
db1200_sound_dev.name = "db1200-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";
db1200_sound_dev.name = "db1200-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(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_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(
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
AU1000_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);
platform_add_devices(db1200_devs, ARRAY_SIZE(db1200_devs));
/* PB1200 is a DB1200 with a 2nd MMC and Camera connector */
if ((bid == BCSR_WHOAMI_PB1200_DDR1) ||
(bid == BCSR_WHOAMI_PB1200_DDR2))
platform_add_devices(pb1200_devs, ARRAY_SIZE(pb1200_devs));
return 0;
}
device_initcall(db1200_dev_init);
+785
View File
@@ -0,0 +1,785 @@
/*
* DBAu1300 init and platform device setup.
*
* (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com>
*/
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/init.h>
#include <linux/input.h> /* KEY_* codes */
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/ata_platform.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/platform_device.h>
#include <linux/smsc911x.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1100_mmc.h>
#include <asm/mach-au1x00/au1200fb.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-db1x00/db1300.h>
#include <asm/mach-db1x00/bcsr.h>
#include <asm/mach-au1x00/prom.h>
#include "platform.h"
static struct i2c_board_info db1300_i2c_devs[] __initdata = {
{ I2C_BOARD_INFO("wm8731", 0x1b), }, /* I2S audio codec */
{ I2C_BOARD_INFO("ne1619", 0x2d), }, /* adm1025-compat hwmon */
};
/* multifunction pins to assign to GPIO controller */
static int db1300_gpio_pins[] __initdata = {
AU1300_PIN_LCDPWM0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_WAKE1,
AU1300_PIN_WAKE2, AU1300_PIN_WAKE3, AU1300_PIN_FG3AUX,
AU1300_PIN_EXTCLK1,
-1, /* terminator */
};
/* multifunction pins to assign to device functions */
static int db1300_dev_pins[] __initdata = {
/* wake-from-str pins 0-3 */
AU1300_PIN_WAKE0,
/* external clock sources for PSC0 */
AU1300_PIN_EXTCLK0,
/* 8bit MMC interface on SD0: 6-9 */
AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
AU1300_PIN_SD0DAT7,
/* UART1 pins: 11-18 */
AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
AU1300_PIN_U1RX, AU1300_PIN_U1TX,
/* UART0 pins: 19-24 */
AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
/* UART2: 25-26 */
AU1300_PIN_U2RX, AU1300_PIN_U2TX,
/* UART3: 27-28 */
AU1300_PIN_U3RX, AU1300_PIN_U3TX,
/* LCD controller PWMs, ext pixclock: 30-31 */
AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
/* SD1 interface: 32-37 */
AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
/* SD2 interface: 38-43 */
AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
/* PSC0/1 clocks: 44-45 */
AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
/* PSCs: 46-49/50-53/54-57/58-61 */
AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
AU1300_PIN_PSC0D1,
AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
AU1300_PIN_PSC1D1,
AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2D0,
AU1300_PIN_PSC2D1,
AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
AU1300_PIN_PSC3D1,
/* PCMCIA interface: 62-70 */
AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
/* camera interface H/V sync inputs: 71-72 */
AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
/* PSC2/3 clocks: 73-74 */
AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
-1, /* terminator */
};
static void __init db1300_gpio_config(void)
{
int *i;
i = &db1300_dev_pins[0];
while (*i != -1)
au1300_pinfunc_to_dev(*i++);
i = &db1300_gpio_pins[0];
while (*i != -1)
au1300_gpio_direction_input(*i++);/* implies pin_to_gpio */
au1300_set_dbdma_gpio(1, AU1300_PIN_FG3AUX);
}
char *get_system_type(void)
{
return "DB1300";
}
/**********************************************************************/
static void au1300_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 au1300_nand_device_ready(struct mtd_info *mtd)
{
return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
}
static const char *db1300_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition db1300_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 db1300_nand_platdata = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
.nr_partitions = ARRAY_SIZE(db1300_nand_parts),
.partitions = db1300_nand_parts,
.chip_delay = 20,
.part_probe_types = db1300_part_probes,
},
.ctrl = {
.dev_ready = au1300_nand_device_ready,
.cmd_ctrl = au1300_nand_cmd_ctrl,
},
};
static struct resource db1300_nand_res[] = {
[0] = {
.start = DB1300_NAND_PHYS_ADDR,
.end = DB1300_NAND_PHYS_ADDR + 0xff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device db1300_nand_dev = {
.name = "gen_nand",
.num_resources = ARRAY_SIZE(db1300_nand_res),
.resource = db1300_nand_res,
.id = -1,
.dev = {
.platform_data = &db1300_nand_platdata,
}
};
/**********************************************************************/
static struct resource db1300_eth_res[] = {
[0] = {
.start = DB1300_ETH_PHYS_ADDR,
.end = DB1300_ETH_PHYS_END,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DB1300_ETH_INT,
.end = DB1300_ETH_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct smsc911x_platform_config db1300_eth_config = {
.phy_interface = PHY_INTERFACE_MODE_MII,
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
.flags = SMSC911X_USE_32BIT,
};
static struct platform_device db1300_eth_dev = {
.name = "smsc911x",
.id = -1,
.num_resources = ARRAY_SIZE(db1300_eth_res),
.resource = db1300_eth_res,
.dev = {
.platform_data = &db1300_eth_config,
},
};
/**********************************************************************/
static struct resource au1300_psc1_res[] = {
[0] = {
.start = AU1300_PSC1_PHYS_ADDR,
.end = AU1300_PSC1_PHYS_ADDR + 0x0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_PSC1_INT,
.end = AU1300_PSC1_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1300_DSCR_CMD0_PSC1_TX,
.end = AU1300_DSCR_CMD0_PSC1_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1300_DSCR_CMD0_PSC1_RX,
.end = AU1300_DSCR_CMD0_PSC1_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1300_ac97_dev = {
.name = "au1xpsc_ac97",
.id = 1, /* PSC ID. match with AC97 codec ID! */
.num_resources = ARRAY_SIZE(au1300_psc1_res),
.resource = au1300_psc1_res,
};
/**********************************************************************/
static struct resource au1300_psc2_res[] = {
[0] = {
.start = AU1300_PSC2_PHYS_ADDR,
.end = AU1300_PSC2_PHYS_ADDR + 0x0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_PSC2_INT,
.end = AU1300_PSC2_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1300_DSCR_CMD0_PSC2_TX,
.end = AU1300_DSCR_CMD0_PSC2_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1300_DSCR_CMD0_PSC2_RX,
.end = AU1300_DSCR_CMD0_PSC2_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1300_i2s_dev = {
.name = "au1xpsc_i2s",
.id = 2, /* PSC ID */
.num_resources = ARRAY_SIZE(au1300_psc2_res),
.resource = au1300_psc2_res,
};
/**********************************************************************/
static struct resource au1300_psc3_res[] = {
[0] = {
.start = AU1300_PSC3_PHYS_ADDR,
.end = AU1300_PSC3_PHYS_ADDR + 0x0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_PSC3_INT,
.end = AU1300_PSC3_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1300_DSCR_CMD0_PSC3_TX,
.end = AU1300_DSCR_CMD0_PSC3_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1300_DSCR_CMD0_PSC3_RX,
.end = AU1300_DSCR_CMD0_PSC3_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1300_i2c_dev = {
.name = "au1xpsc_smbus",
.id = 0, /* bus number */
.num_resources = ARRAY_SIZE(au1300_psc3_res),
.resource = au1300_psc3_res,
};
/**********************************************************************/
/* proper key assignments when facing the LCD panel. For key assignments
* according to the schematics swap up with down and left with right.
* I chose to use it to emulate the arrow keys of a keyboard.
*/
static struct gpio_keys_button db1300_5waysw_arrowkeys[] = {
{
.code = KEY_DOWN,
.gpio = AU1300_PIN_LCDPWM0,
.type = EV_KEY,
.debounce_interval = 1,
.active_low = 1,
.desc = "5waysw-down",
},
{
.code = KEY_UP,
.gpio = AU1300_PIN_PSC2SYNC1,
.type = EV_KEY,
.debounce_interval = 1,
.active_low = 1,
.desc = "5waysw-up",
},
{
.code = KEY_RIGHT,
.gpio = AU1300_PIN_WAKE3,
.type = EV_KEY,
.debounce_interval = 1,
.active_low = 1,
.desc = "5waysw-right",
},
{
.code = KEY_LEFT,
.gpio = AU1300_PIN_WAKE2,
.type = EV_KEY,
.debounce_interval = 1,
.active_low = 1,
.desc = "5waysw-left",
},
{
.code = KEY_ENTER,
.gpio = AU1300_PIN_WAKE1,
.type = EV_KEY,
.debounce_interval = 1,
.active_low = 1,
.desc = "5waysw-push",
},
};
static struct gpio_keys_platform_data db1300_5waysw_data = {
.buttons = db1300_5waysw_arrowkeys,
.nbuttons = ARRAY_SIZE(db1300_5waysw_arrowkeys),
.rep = 1,
.name = "db1300-5wayswitch",
};
static struct platform_device db1300_5waysw_dev = {
.name = "gpio-keys",
.dev = {
.platform_data = &db1300_5waysw_data,
},
};
/**********************************************************************/
static struct pata_platform_info db1300_ide_info = {
.ioport_shift = DB1300_IDE_REG_SHIFT,
};
#define IDE_ALT_START (14 << DB1300_IDE_REG_SHIFT)
static struct resource db1300_ide_res[] = {
[0] = {
.start = DB1300_IDE_PHYS_ADDR,
.end = DB1300_IDE_PHYS_ADDR + IDE_ALT_START - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DB1300_IDE_PHYS_ADDR + IDE_ALT_START,
.end = DB1300_IDE_PHYS_ADDR + DB1300_IDE_PHYS_LEN - 1,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = DB1300_IDE_INT,
.end = DB1300_IDE_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device db1300_ide_dev = {
.dev = {
.platform_data = &db1300_ide_info,
},
.name = "pata_platform",
.resource = db1300_ide_res,
.num_resources = ARRAY_SIZE(db1300_ide_res),
};
/**********************************************************************/
static irqreturn_t db1300_mmc_cd(int irq, void *ptr)
{
void(*mmc_cd)(struct mmc_host *, unsigned long);
/* disable the one currently screaming. No other way to shut it up */
if (irq == DB1300_SD1_INSERT_INT) {
disable_irq_nosync(DB1300_SD1_INSERT_INT);
enable_irq(DB1300_SD1_EJECT_INT);
} else {
disable_irq_nosync(DB1300_SD1_EJECT_INT);
enable_irq(DB1300_SD1_INSERT_INT);
}
/* link against CONFIG_MMC=m. We can only be called once MMC core has
* initialized the controller, so symbol_get() should always succeed.
*/
mmc_cd = symbol_get(mmc_detect_change);
mmc_cd(ptr, msecs_to_jiffies(500));
symbol_put(mmc_detect_change);
return IRQ_HANDLED;
}
static int db1300_mmc_card_readonly(void *mmc_host)
{
/* it uses SD1 interface, but the DB1200's SD0 bit in the CPLD */
return bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP;
}
static int db1300_mmc_card_inserted(void *mmc_host)
{
return bcsr_read(BCSR_SIGSTAT) & (1 << 12); /* insertion irq signal */
}
static int db1300_mmc_cd_setup(void *mmc_host, int en)
{
int ret;
if (en) {
ret = request_irq(DB1300_SD1_INSERT_INT, db1300_mmc_cd, 0,
"sd_insert", mmc_host);
if (ret)
goto out;
ret = request_irq(DB1300_SD1_EJECT_INT, db1300_mmc_cd, 0,
"sd_eject", mmc_host);
if (ret) {
free_irq(DB1300_SD1_INSERT_INT, mmc_host);
goto out;
}
if (db1300_mmc_card_inserted(mmc_host))
enable_irq(DB1300_SD1_EJECT_INT);
else
enable_irq(DB1300_SD1_INSERT_INT);
} else {
free_irq(DB1300_SD1_INSERT_INT, mmc_host);
free_irq(DB1300_SD1_EJECT_INT, mmc_host);
}
ret = 0;
out:
return ret;
}
static void db1300_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 db1300_mmc_led = {
.brightness_set = db1300_mmcled_set,
};
struct au1xmmc_platform_data db1300_sd1_platdata = {
.cd_setup = db1300_mmc_cd_setup,
.card_inserted = db1300_mmc_card_inserted,
.card_readonly = db1300_mmc_card_readonly,
.led = &db1300_mmc_led,
};
static struct resource au1300_sd1_res[] = {
[0] = {
.start = AU1300_SD1_PHYS_ADDR,
.end = AU1300_SD1_PHYS_ADDR,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_SD1_INT,
.end = AU1300_SD1_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1300_DSCR_CMD0_SDMS_TX1,
.end = AU1300_DSCR_CMD0_SDMS_TX1,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1300_DSCR_CMD0_SDMS_RX1,
.end = AU1300_DSCR_CMD0_SDMS_RX1,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1300_sd1_dev = {
.dev = {
.platform_data = &db1300_sd1_platdata,
},
.name = "au1xxx-mmc",
.id = 1,
.resource = au1300_sd1_res,
.num_resources = ARRAY_SIZE(au1300_sd1_res),
};
/**********************************************************************/
static int db1300_movinand_inserted(void *mmc_host)
{
return 0; /* disable for now, it doesn't work yet */
}
static int db1300_movinand_readonly(void *mmc_host)
{
return 0;
}
static void db1300_movinand_led_set(struct led_classdev *led,
enum led_brightness brightness)
{
if (brightness != LED_OFF)
bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED1, 0);
else
bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED1);
}
static struct led_classdev db1300_movinand_led = {
.brightness_set = db1300_movinand_led_set,
};
struct au1xmmc_platform_data db1300_sd0_platdata = {
.card_inserted = db1300_movinand_inserted,
.card_readonly = db1300_movinand_readonly,
.led = &db1300_movinand_led,
.mask_host_caps = MMC_CAP_NEEDS_POLL,
};
static struct resource au1300_sd0_res[] = {
[0] = {
.start = AU1100_SD0_PHYS_ADDR,
.end = AU1100_SD0_PHYS_ADDR,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_SD0_INT,
.end = AU1300_SD0_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1300_DSCR_CMD0_SDMS_TX0,
.end = AU1300_DSCR_CMD0_SDMS_TX0,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1300_DSCR_CMD0_SDMS_RX0,
.end = AU1300_DSCR_CMD0_SDMS_RX0,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1300_sd0_dev = {
.dev = {
.platform_data = &db1300_sd0_platdata,
},
.name = "au1xxx-mmc",
.id = 0,
.resource = au1300_sd0_res,
.num_resources = ARRAY_SIZE(au1300_sd0_res),
};
/**********************************************************************/
static struct platform_device db1300_wm9715_dev = {
.name = "wm9712-codec",
.id = 1, /* ID of PSC for AC97 audio, see asoc glue! */
};
static struct platform_device db1300_ac97dma_dev = {
.name = "au1xpsc-pcm",
.id = 1, /* PSC ID */
};
static struct platform_device db1300_i2sdma_dev = {
.name = "au1xpsc-pcm",
.id = 2, /* PSC ID */
};
static struct platform_device db1300_sndac97_dev = {
.name = "db1300-ac97",
};
static struct platform_device db1300_sndi2s_dev = {
.name = "db1300-i2s",
};
/**********************************************************************/
static int db1300fb_panel_index(void)
{
return 9; /* DB1300_800x480 */
}
static int db1300fb_panel_init(void)
{
/* Apply power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD,
BCSR_BOARD_LCDBL);
return 0;
}
static int db1300fb_panel_shutdown(void)
{
/* Remove power (Vee/Vdd logic is inverted on Panel DB1300_800x480) */
bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDBL,
BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD);
return 0;
}
static struct au1200fb_platdata db1300fb_pd = {
.panel_index = db1300fb_panel_index,
.panel_init = db1300fb_panel_init,
.panel_shutdown = db1300fb_panel_shutdown,
};
static struct resource au1300_lcd_res[] = {
[0] = {
.start = AU1200_LCD_PHYS_ADDR,
.end = AU1200_LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1300_LCD_INT,
.end = AU1300_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1300_lcd_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1300_lcd_dev = {
.name = "au1200-lcd",
.id = 0,
.dev = {
.dma_mask = &au1300_lcd_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1300fb_pd,
},
.num_resources = ARRAY_SIZE(au1300_lcd_res),
.resource = au1300_lcd_res,
};
/**********************************************************************/
static struct platform_device *db1300_dev[] __initdata = {
&db1300_eth_dev,
&db1300_i2c_dev,
&db1300_5waysw_dev,
&db1300_nand_dev,
&db1300_ide_dev,
&db1300_sd0_dev,
&db1300_sd1_dev,
&db1300_lcd_dev,
&db1300_ac97_dev,
&db1300_i2s_dev,
&db1300_wm9715_dev,
&db1300_ac97dma_dev,
&db1300_i2sdma_dev,
&db1300_sndac97_dev,
&db1300_sndi2s_dev,
};
static int __init db1300_device_init(void)
{
int swapped, cpldirq;
/* setup CPLD IRQ muxer */
cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1);
irq_set_irq_type(cpldirq, IRQ_TYPE_LEVEL_HIGH);
bcsr_init_irq(DB1300_FIRST_INT, DB1300_LAST_INT, cpldirq);
/* insert/eject IRQs: one always triggers so don't enable them
* when doing request_irq() on them. DB1200 has this bug too.
*/
irq_set_status_flags(DB1300_SD1_INSERT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1300_SD1_EJECT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1300_CF_INSERT_INT, IRQ_NOAUTOEN);
irq_set_status_flags(DB1300_CF_EJECT_INT, IRQ_NOAUTOEN);
/*
* setup board
*/
prom_get_ethernet_addr(&db1300_eth_config.mac[0]);
i2c_register_board_info(0, db1300_i2c_devs,
ARRAY_SIZE(db1300_i2c_devs));
/* Audio PSC clock is supplied by codecs (PSC1, 2) */
__raw_writel(PSC_SEL_CLK_SERCLK,
(void __iomem *)KSEG1ADDR(AU1300_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
__raw_writel(PSC_SEL_CLK_SERCLK,
(void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
/* I2C uses internal 48MHz EXTCLK1 */
__raw_writel(PSC_SEL_CLK_INTCLK,
(void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
/* enable power to USB ports */
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_USBHPWR | BCSR_RESETS_OTGPWR);
/* although it is socket #0, it uses the CPLD bits which previous boards
* have used for socket #1.
*/
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x00400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x00400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x00010000 - 1,
DB1300_CF_INT, DB1300_CF_INSERT_INT, 0, DB1300_CF_EJECT_INT, 1);
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1200_SWAPBOOT;
db1x_register_norflash(64 << 20, 2, swapped);
return platform_add_devices(db1300_dev, ARRAY_SIZE(db1300_dev));
}
device_initcall(db1300_device_init);
void __init board_setup(void)
{
unsigned short whoami;
db1300_gpio_config();
bcsr_init(DB1300_BCSR_PHYS_ADDR,
DB1300_BCSR_PHYS_ADDR + DB1300_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI);
printk(KERN_INFO "NetLogic DBAu1300 Development Platform.\n\t"
"BoardID %d CPLD Rev %d DaughtercardID %d\n",
BCSR_WHOAMI_BOARD(whoami), BCSR_WHOAMI_CPLD(whoami),
BCSR_WHOAMI_DCID(whoami));
/* enable UARTs, YAMON only enables #2 */
alchemy_uart_enable(AU1300_UART0_PHYS_ADDR);
alchemy_uart_enable(AU1300_UART1_PHYS_ADDR);
alchemy_uart_enable(AU1300_UART3_PHYS_ADDR);
}
+498
View File
@@ -0,0 +1,498 @@
/*
* Alchemy Db1550 board support
*
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
*/
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_eth.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-au1x00/au1550_spi.h>
#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
#include "platform.h"
const char *get_system_type(void)
{
return "DB1550";
}
static void __init db1550_hw_setup(void)
{
void __iomem *base;
alchemy_gpio_direction_output(203, 0); /* red led on */
/* complete SPI setup: link psc0_intclk to a 48MHz source,
* and assign GPIO16 to PSC0_SYNC1 (SPI cs# line)
*/
base = (void __iomem *)SYS_CLKSRC;
__raw_writel(__raw_readl(base) | 0x000001e0, base);
base = (void __iomem *)SYS_PINFUNC;
__raw_writel(__raw_readl(base) | 1, base);
wmb();
/* reset the AC97 codec now, the reset time in the psc-ac97 driver
* is apparently too short although it's ridiculous as it is.
*/
base = (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR);
__raw_writel(PSC_SEL_CLK_SERCLK | PSC_SEL_PS_AC97MODE,
base + PSC_SEL_OFFSET);
__raw_writel(PSC_CTRL_DISABLE, base + PSC_CTRL_OFFSET);
wmb();
__raw_writel(PSC_AC97RST_RST, base + PSC_AC97RST_OFFSET);
wmb();
alchemy_gpio_direction_output(202, 0); /* green led on */
}
void __init board_setup(void)
{
unsigned short whoami;
bcsr_init(DB1550_BCSR_PHYS_ADDR,
DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS);
whoami = bcsr_read(BCSR_WHOAMI);
printk(KERN_INFO "Alchemy/AMD DB1550 Board, CPLD Rev %d"
" Board-ID %d Daughtercard ID %d\n",
(whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf);
db1550_hw_setup();
}
/*****************************************************************************/
static struct mtd_partition db1550_spiflash_parts[] = {
{
.name = "spi_flash",
.offset = 0,
.size = MTDPART_SIZ_FULL,
},
};
static struct flash_platform_data db1550_spiflash_data = {
.name = "s25fl010",
.parts = db1550_spiflash_parts,
.nr_parts = ARRAY_SIZE(db1550_spiflash_parts),
.type = "m25p10",
};
static struct spi_board_info db1550_spi_devs[] __initdata = {
{
/* TI TMP121AIDBVR temp sensor */
.modalias = "tmp121",
.max_speed_hz = 2400000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
},
{
/* Spansion S25FL001D0FMA SPI flash */
.modalias = "m25p80",
.max_speed_hz = 2400000,
.bus_num = 0,
.chip_select = 1,
.mode = SPI_MODE_0,
.platform_data = &db1550_spiflash_data,
},
};
static struct i2c_board_info db1550_i2c_devs[] __initdata = {
{ I2C_BOARD_INFO("24c04", 0x52),}, /* AT24C04-10 I2C eeprom */
{ I2C_BOARD_INFO("ne1619", 0x2d),}, /* adm1025-compat hwmon */
{ I2C_BOARD_INFO("wm8731", 0x1b),}, /* I2S audio codec WM8731 */
};
/**********************************************************************/
static void au1550_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 au1550_nand_device_ready(struct mtd_info *mtd)
{
return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
}
static const char *db1550_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition db1550_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 db1550_nand_platdata = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
.nr_partitions = ARRAY_SIZE(db1550_nand_parts),
.partitions = db1550_nand_parts,
.chip_delay = 20,
.part_probe_types = db1550_part_probes,
},
.ctrl = {
.dev_ready = au1550_nand_device_ready,
.cmd_ctrl = au1550_nand_cmd_ctrl,
},
};
static struct resource db1550_nand_res[] = {
[0] = {
.start = 0x20000000,
.end = 0x200000ff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device db1550_nand_dev = {
.name = "gen_nand",
.num_resources = ARRAY_SIZE(db1550_nand_res),
.resource = db1550_nand_res,
.id = -1,
.dev = {
.platform_data = &db1550_nand_platdata,
}
};
/**********************************************************************/
static struct resource au1550_psc0_res[] = {
[0] = {
.start = AU1550_PSC0_PHYS_ADDR,
.end = AU1550_PSC0_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1550_PSC0_INT,
.end = AU1550_PSC0_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1550_DSCR_CMD0_PSC0_TX,
.end = AU1550_DSCR_CMD0_PSC0_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1550_DSCR_CMD0_PSC0_RX,
.end = AU1550_DSCR_CMD0_PSC0_RX,
.flags = IORESOURCE_DMA,
},
};
static void db1550_spi_cs_en(struct au1550_spi_info *spi, int cs, int pol)
{
if (cs)
bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SPISEL);
else
bcsr_mod(BCSR_BOARD, BCSR_BOARD_SPISEL, 0);
}
static struct au1550_spi_info db1550_spi_platdata = {
.mainclk_hz = 48000000, /* PSC0 clock: max. 2.4MHz SPI clk */
.num_chipselect = 2,
.activate_cs = db1550_spi_cs_en,
};
static u64 spi_dmamask = DMA_BIT_MASK(32);
static struct platform_device db1550_spi_dev = {
.dev = {
.dma_mask = &spi_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &db1550_spi_platdata,
},
.name = "au1550-spi",
.id = 0, /* bus number */
.num_resources = ARRAY_SIZE(au1550_psc0_res),
.resource = au1550_psc0_res,
};
/**********************************************************************/
static struct resource au1550_psc1_res[] = {
[0] = {
.start = AU1550_PSC1_PHYS_ADDR,
.end = AU1550_PSC1_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1550_PSC1_INT,
.end = AU1550_PSC1_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1550_DSCR_CMD0_PSC1_TX,
.end = AU1550_DSCR_CMD0_PSC1_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1550_DSCR_CMD0_PSC1_RX,
.end = AU1550_DSCR_CMD0_PSC1_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1550_ac97_dev = {
.name = "au1xpsc_ac97",
.id = 1, /* PSC ID */
.num_resources = ARRAY_SIZE(au1550_psc1_res),
.resource = au1550_psc1_res,
};
static struct resource au1550_psc2_res[] = {
[0] = {
.start = AU1550_PSC2_PHYS_ADDR,
.end = AU1550_PSC2_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1550_PSC2_INT,
.end = AU1550_PSC2_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1550_DSCR_CMD0_PSC2_TX,
.end = AU1550_DSCR_CMD0_PSC2_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1550_DSCR_CMD0_PSC2_RX,
.end = AU1550_DSCR_CMD0_PSC2_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1550_i2c_dev = {
.name = "au1xpsc_smbus",
.id = 0, /* bus number */
.num_resources = ARRAY_SIZE(au1550_psc2_res),
.resource = au1550_psc2_res,
};
/**********************************************************************/
static struct resource au1550_psc3_res[] = {
[0] = {
.start = AU1550_PSC3_PHYS_ADDR,
.end = AU1550_PSC3_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1550_PSC3_INT,
.end = AU1550_PSC3_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1550_DSCR_CMD0_PSC3_TX,
.end = AU1550_DSCR_CMD0_PSC3_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1550_DSCR_CMD0_PSC3_RX,
.end = AU1550_DSCR_CMD0_PSC3_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device db1550_i2s_dev = {
.name = "au1xpsc_i2s",
.id = 3, /* PSC ID */
.num_resources = ARRAY_SIZE(au1550_psc3_res),
.resource = au1550_psc3_res,
};
/**********************************************************************/
static struct platform_device db1550_stac_dev = {
.name = "ac97-codec",
.id = 1, /* on PSC1 */
};
static struct platform_device db1550_ac97dma_dev = {
.name = "au1xpsc-pcm",
.id = 1, /* on PSC3 */
};
static struct platform_device db1550_i2sdma_dev = {
.name = "au1xpsc-pcm",
.id = 3, /* on PSC3 */
};
static struct platform_device db1550_sndac97_dev = {
.name = "db1550-ac97",
};
static struct platform_device db1550_sndi2s_dev = {
.name = "db1550-i2s",
};
/**********************************************************************/
static int db1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 11) || (slot > 13) || pin == 0)
return -1;
if (slot == 11)
return (pin == 1) ? AU1550_PCI_INTC : 0xff;
if (slot == 12) {
switch (pin) {
case 1: return AU1550_PCI_INTB;
case 2: return AU1550_PCI_INTC;
case 3: return AU1550_PCI_INTD;
case 4: return AU1550_PCI_INTA;
}
}
if (slot == 13) {
switch (pin) {
case 1: return AU1550_PCI_INTA;
case 2: return AU1550_PCI_INTB;
case 3: return AU1550_PCI_INTC;
case 4: return AU1550_PCI_INTD;
}
}
return -1;
}
static struct resource alchemy_pci_host_res[] = {
[0] = {
.start = AU1500_PCI_PHYS_ADDR,
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
};
static struct alchemy_pci_platdata db1550_pci_pd = {
.board_map_irq = db1550_map_pci_irq,
};
static struct platform_device db1550_pci_host_dev = {
.dev.platform_data = &db1550_pci_pd,
.name = "alchemy-pci",
.id = 0,
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
.resource = alchemy_pci_host_res,
};
/**********************************************************************/
static struct platform_device *db1550_devs[] __initdata = {
&db1550_nand_dev,
&db1550_i2c_dev,
&db1550_ac97_dev,
&db1550_spi_dev,
&db1550_i2s_dev,
&db1550_stac_dev,
&db1550_ac97dma_dev,
&db1550_i2sdma_dev,
&db1550_sndac97_dev,
&db1550_sndi2s_dev,
};
/* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */
static int __init db1550_pci_init(void)
{
return platform_device_register(&db1550_pci_host_dev);
}
arch_initcall(db1550_pci_init);
static int __init db1550_dev_init(void)
{
int swapped;
irq_set_irq_type(AU1550_GPIO0_INT, IRQ_TYPE_EDGE_BOTH); /* CD0# */
irq_set_irq_type(AU1550_GPIO1_INT, IRQ_TYPE_EDGE_BOTH); /* CD1# */
irq_set_irq_type(AU1550_GPIO3_INT, IRQ_TYPE_LEVEL_LOW); /* CARD0# */
irq_set_irq_type(AU1550_GPIO5_INT, IRQ_TYPE_LEVEL_LOW); /* CARD1# */
irq_set_irq_type(AU1550_GPIO21_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG0# */
irq_set_irq_type(AU1550_GPIO22_INT, IRQ_TYPE_LEVEL_LOW); /* STSCHG1# */
i2c_register_board_info(0, db1550_i2c_devs,
ARRAY_SIZE(db1550_i2c_devs));
spi_register_board_info(db1550_spi_devs,
ARRAY_SIZE(db1550_i2c_devs));
/* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */
__raw_writel(PSC_SEL_CLK_SERCLK,
(void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
__raw_writel(PSC_SEL_CLK_SERCLK,
(void __iomem *)KSEG1ADDR(AU1550_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
/* SPI/I2C use internally supplied 50MHz source */
__raw_writel(PSC_SEL_CLK_INTCLK,
(void __iomem *)KSEG1ADDR(AU1550_PSC0_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
__raw_writel(PSC_SEL_CLK_INTCLK,
(void __iomem *)KSEG1ADDR(AU1550_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET);
wmb();
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
AU1550_GPIO3_INT, AU1550_GPIO0_INT,
/*AU1550_GPIO21_INT*/0, 0, 0);
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x004400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004000000,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x004010000 - 1,
AU1550_GPIO5_INT, AU1550_GPIO1_INT,
/*AU1550_GPIO22_INT*/0, 0, 1);
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT;
db1x_register_norflash(128 << 20, 4, swapped);
return platform_add_devices(db1550_devs, ARRAY_SIZE(db1550_devs));
}
device_initcall(db1550_dev_init);
+167
View File
@@ -0,0 +1,167 @@
/*
* 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/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
#include "platform.h"
const char *get_system_type(void)
{
return "PB1100";
}
void __init board_setup(void)
{
volatile void __iomem *base = (volatile void __iomem *)0xac000000UL;
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);
alchemy_gpio1_input_enable();
udelay(100);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
{
u32 pin_func, sys_freqctrl, sys_clksrc;
/* Configure pins GPIO[14:9] as GPIO */
pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3;
/* Zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* Zero and disable USBH/USBD/IrDA clock */
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~(SYS_CS_CIR | SYS_CS_DIR | SYS_CS_MIR_MASK);
au_writel(sys_clksrc, SYS_CLKSRC);
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~(SYS_CS_CIR | SYS_CS_DIR | SYS_CS_MIR_MASK);
/* FREQ2 = aux / 2 = 48 MHz */
sys_freqctrl |= (0 << SYS_FC_FRDIV2_BIT) |
SYS_FC_FE2 | SYS_FC_FS2;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/*
* Route 48 MHz FREQ2 into USBH/USBD/IrDA
*/
sys_clksrc |= SYS_CS_MUX_FQ2 << SYS_CS_MIR_BIT;
au_writel(sys_clksrc, SYS_CLKSRC);
/* Setup the static bus controller */
au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */
au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
/*
* Get USB Functionality pin state (device vs host drive pins).
*/
pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_USB;
/* 2nd USB port is USB host. */
pin_func |= SYS_PF_USB;
au_writel(pin_func, SYS_PINFUNC);
}
#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
/* Enable sys bus clock divider when IDLE state or no bus activity. */
au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
/* Enable the RTC if not already enabled. */
if (!(readb(base + 0x28) & 0x20)) {
writeb(readb(base + 0x28) | 0x20, base + 0x28);
au_sync();
}
/* Put the clock in BCD mode. */
if (readb(base + 0x2C) & 0x4) { /* reg B */
writeb(readb(base + 0x2c) & ~0x4, base + 0x2c);
au_sync();
}
}
/******************************************************************************/
static struct resource au1100_lcd_resources[] = {
[0] = {
.start = AU1100_LCD_PHYS_ADDR,
.end = AU1100_LCD_PHYS_ADDR + 0x800 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1100_LCD_INT,
.end = AU1100_LCD_INT,
.flags = IORESOURCE_IRQ,
}
};
static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);
static struct platform_device au1100_lcd_device = {
.name = "au1100-lcd",
.id = 0,
.dev = {
.dma_mask = &au1100_lcd_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(au1100_lcd_resources),
.resource = au1100_lcd_resources,
};
static int __init pb1100_dev_init(void)
{
int swapped;
irq_set_irq_type(AU1100_GPIO9_INT, IRQF_TRIGGER_LOW); /* PCCD# */
irq_set_irq_type(AU1100_GPIO10_INT, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
irq_set_irq_type(AU1100_GPIO11_INT, IRQF_TRIGGER_LOW); /* PCCard# */
irq_set_irq_type(AU1100_GPIO13_INT, IRQF_TRIGGER_LOW); /* DC_IRQ# */
/* PCMCIA. single socket, identical to Pb1500 */
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
AU1100_GPIO11_INT, AU1100_GPIO9_INT, /* card / insert */
/*AU1100_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT;
db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
platform_device_register(&au1100_lcd_device);
return 0;
}
device_initcall(pb1100_dev_init);
+198
View File
@@ -0,0 +1,198 @@
/*
* Pb1500 board support.
*
* 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/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-db1x00/bcsr.h>
#include <prom.h>
#include "platform.h"
const char *get_system_type(void)
{
return "PB1500";
}
void __init board_setup(void)
{
u32 pin_func;
u32 sys_freqctrl, sys_clksrc;
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 */
au_writel(8, SYS_AUXPLL);
alchemy_gpio1_input_enable();
udelay(100);
/* GPIO201 is input for PCMCIA card detect */
/* GPIO203 is input for PCMCIA interrupt request */
alchemy_gpio_direction_input(201);
alchemy_gpio_direction_input(203);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
/* Zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* zero and disable USBH/USBD clocks */
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK |
SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK);
au_writel(sys_clksrc, SYS_CLKSRC);
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~(SYS_CS_CUD | SYS_CS_DUD | SYS_CS_MUD_MASK |
SYS_CS_CUH | SYS_CS_DUH | SYS_CS_MUH_MASK);
/* FREQ2 = aux/2 = 48 MHz */
sys_freqctrl |= (0 << SYS_FC_FRDIV2_BIT) | SYS_FC_FE2 | SYS_FC_FS2;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/*
* Route 48MHz FREQ2 into USB Host and/or Device
*/
sys_clksrc |= SYS_CS_MUX_FQ2 << SYS_CS_MUH_BIT;
au_writel(sys_clksrc, SYS_CLKSRC);
pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_USB;
/* 2nd USB port is USB host */
pin_func |= SYS_PF_USB;
au_writel(pin_func, SYS_PINFUNC);
#endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */
#ifdef CONFIG_PCI
{
void __iomem *base =
(void __iomem *)KSEG1ADDR(AU1500_PCI_PHYS_ADDR);
/* Setup PCI bus controller */
__raw_writel(0x00003fff, base + PCI_REG_CMEM);
__raw_writel(0xf0000000, base + PCI_REG_MWMASK_DEV);
__raw_writel(0, base + PCI_REG_MWBASE_REV_CCL);
__raw_writel(0x02a00356, base + PCI_REG_STATCMD);
__raw_writel(0x00003c04, base + PCI_REG_PARAM);
__raw_writel(0x00000008, base + PCI_REG_MBAR);
wmb();
}
#endif
/* Enable sys bus clock divider when IDLE state or no bus activity. */
au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
/* Enable the RTC if not already enabled */
if (!(au_readl(0xac000028) & 0x20)) {
printk(KERN_INFO "enabling clock ...\n");
au_writel((au_readl(0xac000028) | 0x20), 0xac000028);
}
/* Put the clock in BCD mode */
if (au_readl(0xac00002c) & 0x4) { /* reg B */
au_writel(au_readl(0xac00002c) & ~0x4, 0xac00002c);
au_sync();
}
}
/******************************************************************************/
static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 12) || (slot > 13) || pin == 0)
return -1;
if (slot == 12)
return (pin == 1) ? AU1500_PCI_INTA : 0xff;
if (slot == 13) {
switch (pin) {
case 1: return AU1500_PCI_INTA;
case 2: return AU1500_PCI_INTB;
case 3: return AU1500_PCI_INTC;
case 4: return AU1500_PCI_INTD;
}
}
return -1;
}
static struct resource alchemy_pci_host_res[] = {
[0] = {
.start = AU1500_PCI_PHYS_ADDR,
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
};
static struct alchemy_pci_platdata pb1500_pci_pd = {
.board_map_irq = pb1500_map_pci_irq,
.pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H |
PCI_CONFIG_CH |
#if defined(__MIPSEB__)
PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM,
#else
0,
#endif
};
static struct platform_device pb1500_pci_host = {
.dev.platform_data = &pb1500_pci_pd,
.name = "alchemy-pci",
.id = 0,
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
.resource = alchemy_pci_host_res,
};
static int __init pb1500_dev_init(void)
{
int swapped;
irq_set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW); /* CD0# */
irq_set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW); /* CARD0 */
irq_set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
irq_set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
irq_set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
irq_set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
irq_set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
/* PCMCIA. single socket, identical to Pb1100 */
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
AU1500_GPIO11_INT, AU1500_GPIO9_INT, /* card / insert */
/*AU1500_GPIO10_INT*/0, 0, 0); /* stschg / eject / id */
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT;
db1x_register_norflash(64 * 1024 * 1024, 4, swapped);
platform_device_register(&pb1500_pci_host);
return 0;
}
arch_initcall(pb1500_dev_init);
+244
View File
@@ -0,0 +1,244 @@
/*
* Pb1550 board support.
*
* Copyright (C) 2009-2011 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/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1550nd.h>
#include <asm/mach-au1x00/gpio.h>
#include <asm/mach-db1x00/bcsr.h>
#include "platform.h"
const char *get_system_type(void)
{
return "PB1550";
}
void __init board_setup(void)
{
u32 pin_func;
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,
* but it is board specific code, so put it here.
*/
pin_func = au_readl(SYS_PINFUNC);
au_sync();
pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
au_writel(pin_func, SYS_PINFUNC);
bcsr_write(BCSR_PCMCIA, 0); /* turn off PCMCIA power */
printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
}
/******************************************************************************/
static int pb1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin)
{
if ((slot < 12) || (slot > 13) || pin == 0)
return -1;
if (slot == 12) {
switch (pin) {
case 1: return AU1500_PCI_INTB;
case 2: return AU1500_PCI_INTC;
case 3: return AU1500_PCI_INTD;
case 4: return AU1500_PCI_INTA;
}
}
if (slot == 13) {
switch (pin) {
case 1: return AU1500_PCI_INTA;
case 2: return AU1500_PCI_INTB;
case 3: return AU1500_PCI_INTC;
case 4: return AU1500_PCI_INTD;
}
}
return -1;
}
static struct resource alchemy_pci_host_res[] = {
[0] = {
.start = AU1500_PCI_PHYS_ADDR,
.end = AU1500_PCI_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
};
static struct alchemy_pci_platdata pb1550_pci_pd = {
.board_map_irq = pb1550_map_pci_irq,
};
static struct platform_device pb1550_pci_host = {
.dev.platform_data = &pb1550_pci_pd,
.name = "alchemy-pci",
.id = 0,
.num_resources = ARRAY_SIZE(alchemy_pci_host_res),
.resource = alchemy_pci_host_res,
};
static struct resource au1550_psc2_res[] = {
[0] = {
.start = AU1550_PSC2_PHYS_ADDR,
.end = AU1550_PSC2_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AU1550_PSC2_INT,
.end = AU1550_PSC2_INT,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = AU1550_DSCR_CMD0_PSC2_TX,
.end = AU1550_DSCR_CMD0_PSC2_TX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = AU1550_DSCR_CMD0_PSC2_RX,
.end = AU1550_DSCR_CMD0_PSC2_RX,
.flags = IORESOURCE_DMA,
},
};
static struct platform_device pb1550_i2c_dev = {
.name = "au1xpsc_smbus",
.id = 0, /* bus number */
.num_resources = ARRAY_SIZE(au1550_psc2_res),
.resource = au1550_psc2_res,
};
static struct mtd_partition pb1550_nand_parts[] = {
[0] = {
.name = "NAND FS 0",
.offset = 0,
.size = 8 * 1024 * 1024,
},
[1] = {
.name = "NAND FS 1",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
static struct au1550nd_platdata pb1550_nand_pd = {
.parts = pb1550_nand_parts,
.num_parts = ARRAY_SIZE(pb1550_nand_parts),
.devwidth = 0, /* x8 NAND default, needs fixing up */
};
static struct resource pb1550_nand_res[] = {
[0] = {
.start = 0x20000000,
.end = 0x20000fff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device pb1550_nand_dev = {
.name = "au1550-nand",
.id = -1,
.resource = pb1550_nand_res,
.num_resources = ARRAY_SIZE(pb1550_nand_res),
.dev = {
.platform_data = &pb1550_nand_pd,
},
};
static void __init pb1550_nand_setup(void)
{
int boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) |
((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
switch (boot_swapboot) {
case 0:
case 2:
case 8:
case 0xC:
case 0xD:
/* x16 NAND Flash */
pb1550_nand_pd.devwidth = 1;
/* fallthrough */
case 1:
case 9:
case 3:
case 0xE:
case 0xF:
/* x8 NAND, already set up */
platform_device_register(&pb1550_nand_dev);
}
}
static int __init pb1550_dev_init(void)
{
int swapped;
irq_set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);
irq_set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);
irq_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);
/* 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(
AU1000_PCMCIA_ATTR_PHYS_ADDR,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x000400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x000010000 - 1,
AU1550_GPIO201_205_INT, AU1550_GPIO0_INT, 0, 0, 0);
db1x_register_pcmcia_socket(
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008000000,
AU1000_PCMCIA_ATTR_PHYS_ADDR + 0x008400000 - 1,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008000000,
AU1000_PCMCIA_MEM_PHYS_ADDR + 0x008400000 - 1,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x008000000,
AU1000_PCMCIA_IO_PHYS_ADDR + 0x008010000 - 1,
AU1550_GPIO201_205_INT, AU1550_GPIO1_INT, 0, 0, 1);
/* NAND setup */
gpio_direction_input(206); /* GPIO206 high */
pb1550_nand_setup();
swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT;
db1x_register_norflash(128 * 1024 * 1024, 4, swapped);
platform_device_register(&pb1550_pci_host);
platform_device_register(&pb1550_i2c_dev);
return 0;
}
arch_initcall(pb1550_dev_init);
@@ -0,0 +1,231 @@
/*
* 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 struct platform_device db1x00_rtc_dev = {
.name = "rtc-au1xxx",
.id = -1,
};
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_late_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;
platform_device_register(&db1x00_rtc_dev);
return 0;
}
device_initcall(db1x_late_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;
}
@@ -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
+262
View File
@@ -0,0 +1,262 @@
/*
* Alchemy Development Board example suspend userspace interface.
*
* (c) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
*/
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/suspend.h>
#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.
* This code exports a few sysfs nodes under /sys/power/db1x/ which
* can be used by userspace to en/disable all au1x-provided wakeup
* sources and configure the timeout after which the the TOYMATCH2 irq
* is to trigger a wakeup.
*/
static unsigned long db1x_pm_sleep_secs;
static unsigned long db1x_pm_wakemsk;
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();
/* clear and setup wake cause and source */
au_writel(0, SYS_WAKEMSK);
au_sync();
au_writel(0, SYS_WAKESRC);
au_sync();
au_writel(db1x_pm_wakemsk, SYS_WAKEMSK);
au_sync();
/* setup 1Hz-timer-based wakeup: wait for reg access */
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
asm volatile ("nop");
au_writel(au_readl(SYS_TOYREAD) + db1x_pm_sleep_secs, SYS_TOYMATCH2);
au_sync();
/* wait for value to really hit the register */
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20)
asm volatile ("nop");
/* ...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;
}
static int db1x_pm_begin(suspend_state_t state)
{
if (!db1x_pm_wakemsk) {
printk(KERN_ERR "db1x: no wakeup source activated!\n");
return -EINVAL;
}
return 0;
}
static void db1x_pm_end(void)
{
/* read and store wakeup source, the clear the register. To
* be able to clear it, WAKEMSK must be cleared first.
*/
db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
au_writel(0, SYS_WAKEMSK);
au_writel(0, SYS_WAKESRC);
au_sync();
}
static const struct platform_suspend_ops db1x_pm_ops = {
.valid = suspend_valid_only_mem,
.begin = db1x_pm_begin,
.enter = db1x_pm_enter,
.end = db1x_pm_end,
};
#define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
static ssize_t db1x_pmattr_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int idx;
if (ATTRCMP(timer_timeout))
return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);
else if (ATTRCMP(timer))
return sprintf(buf, "%u\n",
!!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));
else if (ATTRCMP(wakesrc))
return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);
else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
idx = (attr->attr.name)[4] - '0';
return sprintf(buf, "%d\n",
!!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));
} else if (ATTRCMP(wakemsk)) {
return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
}
return -ENOENT;
}
static ssize_t db1x_pmattr_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *instr,
size_t bytes)
{
unsigned long l;
int tmp;
if (ATTRCMP(timer_timeout)) {
tmp = strict_strtoul(instr, 0, &l);
if (tmp)
return tmp;
db1x_pm_sleep_secs = l;
} else if (ATTRCMP(timer)) {
if (instr[0] != '0')
db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
else
db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;
} else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
tmp = (attr->attr.name)[4] - '0';
if (instr[0] != '0') {
db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
} else {
db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
}
} else if (ATTRCMP(wakemsk)) {
tmp = strict_strtoul(instr, 0, &l);
if (tmp)
return tmp;
db1x_pm_wakemsk = l & 0x0000003f;
} else
bytes = -ENOENT;
return bytes;
}
#define ATTR(x) \
static struct kobj_attribute x##_attribute = \
__ATTR(x, 0664, db1x_pmattr_show, \
db1x_pmattr_store);
ATTR(gpio0) /* GPIO-based wakeup enable */
ATTR(gpio1)
ATTR(gpio2)
ATTR(gpio3)
ATTR(gpio4)
ATTR(gpio5)
ATTR(gpio6)
ATTR(gpio7)
ATTR(timer) /* TOYMATCH2-based wakeup enable */
ATTR(timer_timeout) /* timer-based wakeup timeout value, in seconds */
ATTR(wakesrc) /* contents of SYS_WAKESRC after last wakeup */
ATTR(wakemsk) /* direct access to SYS_WAKEMSK */
#define ATTR_LIST(x) & x ## _attribute.attr
static struct attribute *db1x_pmattrs[] = {
ATTR_LIST(gpio0),
ATTR_LIST(gpio1),
ATTR_LIST(gpio2),
ATTR_LIST(gpio3),
ATTR_LIST(gpio4),
ATTR_LIST(gpio5),
ATTR_LIST(gpio6),
ATTR_LIST(gpio7),
ATTR_LIST(timer),
ATTR_LIST(timer_timeout),
ATTR_LIST(wakesrc),
ATTR_LIST(wakemsk),
NULL, /* terminator */
};
static struct attribute_group db1x_pmattr_group = {
.name = "db1x",
.attrs = db1x_pmattrs,
};
/*
* Initialize suspend interface
*/
static int __init pm_init(void)
{
/* init TOY to tick at 1Hz if not already done. No need to wait
* for confirmation since there's plenty of time from here to
* the next suspend cycle.
*/
if (au_readl(SYS_TOYTRIM) != 32767) {
au_writel(32767, SYS_TOYTRIM);
au_sync();
}
db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC);
au_writel(0, SYS_WAKESRC);
au_sync();
au_writel(0, SYS_WAKEMSK);
au_sync();
suspend_set_ops(&db1x_pm_ops);
return sysfs_create_group(power_kobj, &db1x_pmattr_group);
}
late_initcall(pm_init);
+69
View File
@@ -0,0 +1,69 @@
/*
* Common code used by all Alchemy develboards.
*
* Extracted from files which had this to say:
*
* Copyright 2000, 2008 MontaVista Software Inc.
* Author: MontaVista Software, Inc. <source@mvista.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/kernel.h>
#include <asm/bootinfo.h>
#include <asm/mach-au1x00/au1000.h>
#include <prom.h>
#if defined(CONFIG_MIPS_DB1000) || \
defined(CONFIG_MIPS_PB1100) || \
defined(CONFIG_MIPS_PB1500)
#define ALCHEMY_BOARD_DEFAULT_MEMSIZE 0x04000000
#else /* Au1550/Au1200-based develboards */
#define ALCHEMY_BOARD_DEFAULT_MEMSIZE 0x08000000
#endif
void __init prom_init(void)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = (int)fw_arg0;
prom_argv = (char **)fw_arg1;
prom_envp = (char **)fw_arg2;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE;
add_memory_region(0, memsize, BOOT_MEM_RAM);
}
void prom_putchar(unsigned char c)
{
#ifdef CONFIG_MIPS_DB1300
alchemy_uart_putchar(AU1300_UART2_PHYS_ADDR, c);
#else
alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
#endif
}