350 lines
8.1 KiB
C
350 lines
8.1 KiB
C
/*
|
|
* arch/sh/boards/st/common/mb705.c
|
|
*
|
|
* Copyright (C) 2008 STMicroelectronics Limited
|
|
* Author: Stuart Menefy <stuart.menefy@st.com>
|
|
*
|
|
* May be copied or modified under the terms of the GNU General Public
|
|
* License. See linux/COPYING for more information.
|
|
*
|
|
* STMicroelectronics STB peripherals board support.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/leds.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/stm/sysconf.h>
|
|
#include <linux/stm/platform.h>
|
|
#include <linux/stm/stx7105.h>
|
|
#include <linux/stm/emi.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/nand.h>
|
|
#include <linux/stm/nand.h>
|
|
#include <linux/mtd/physmap.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/flash.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/irq.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/irq-ilc.h>
|
|
#include <mach/common.h>
|
|
#include "mb705-epld.h"
|
|
|
|
|
|
/*
|
|
* NOR/NAND CS routing should be configured according to main board's
|
|
* boot-device:
|
|
* NOR NAND [SPI]
|
|
* ------ ------ -------
|
|
* SW8-1 ON OFF OFF
|
|
* EMIA -> NOR NAND NAND
|
|
* EMIB -> NAND NOR NOR
|
|
*
|
|
*/
|
|
|
|
static DEFINE_SPINLOCK(misc_lock);
|
|
char mb705_rev = '?';
|
|
|
|
static struct platform_device mb705_gpio_led = {
|
|
.name = "leds-gpio",
|
|
.id = 1,
|
|
.dev.platform_data = &(struct gpio_led_platform_data) {
|
|
.num_leds = 1,
|
|
.leds = (struct gpio_led[]) {
|
|
{
|
|
.name = "HB",
|
|
.default_trigger = "heartbeat",
|
|
.gpio = stm_gpio(2, 0),
|
|
.active_low = 1,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
static struct platform_device epld_device = {
|
|
.name = "epld",
|
|
.id = -1,
|
|
.num_resources = 1,
|
|
.resource = (struct resource[]) {
|
|
{
|
|
.start = 0x04800000,
|
|
.end = 0x048002ff,
|
|
.flags = IORESOURCE_MEM,
|
|
}
|
|
},
|
|
.dev.platform_data = &(struct plat_epld_data) {
|
|
.opsize = 16,
|
|
},
|
|
};
|
|
|
|
|
|
static struct platform_device mb705_display_device = {
|
|
.name = "mb705-display",
|
|
.id = -1,
|
|
.num_resources = 1,
|
|
.resource = (struct resource[]) {
|
|
{
|
|
.start = 0x04800140,
|
|
.end = 0x048001bf,
|
|
.flags = IORESOURCE_MEM,
|
|
}
|
|
},
|
|
};
|
|
|
|
#ifdef CONFIG_SH_ST_MB680
|
|
static struct platform_device mb705_fpbutton_device = {
|
|
.name = "mb705-fpbutton",
|
|
.id = -1,
|
|
.num_resources = 2,
|
|
.resource = (struct resource[]) {
|
|
{
|
|
.start = ILC_EXT_IRQ(0),
|
|
.end = ILC_EXT_IRQ(0),
|
|
.flags = IORESOURCE_IRQ,
|
|
}, {
|
|
/* Mask for the EPLD status register */
|
|
.name = "mask",
|
|
.start = 1<<9,
|
|
.end = 1<<9,
|
|
.flags = IORESOURCE_IRQ,
|
|
}
|
|
},
|
|
};
|
|
#endif
|
|
|
|
/* NOR Flash */
|
|
static void nor_set_vpp(struct map_info *info, int enable)
|
|
{
|
|
u16 reg;
|
|
|
|
spin_lock(&misc_lock);
|
|
|
|
reg = epld_read(EPLD_EMI_MISC);
|
|
if (enable)
|
|
reg |= EPLD_EMI_MISC_NORFLASHVPPEN;
|
|
else
|
|
reg &= ~EPLD_EMI_MISC_NORFLASHVPPEN;
|
|
epld_write(reg, EPLD_EMI_MISC);
|
|
|
|
spin_unlock(&misc_lock);
|
|
}
|
|
|
|
static struct platform_device mb705_nor_flash = {
|
|
.name = "physmap-flash",
|
|
.id = -1,
|
|
.num_resources = 1,
|
|
.resource = (struct resource[]) {
|
|
{
|
|
.start = 0x00000000,
|
|
.end = 32*1024*1024 - 1,
|
|
.flags = IORESOURCE_MEM,
|
|
}
|
|
},
|
|
.dev.platform_data = &(struct physmap_flash_data) {
|
|
.width = 2,
|
|
.set_vpp = nor_set_vpp,
|
|
.nr_parts = 3,
|
|
.parts = (struct mtd_partition []) {
|
|
{
|
|
.name = "NOR Flash 1",
|
|
.size = 0x00080000,
|
|
.offset = 0x00000000,
|
|
}, {
|
|
.name = "NOR Flash 2",
|
|
.size = 0x00200000,
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
}, {
|
|
.name = "NOR Flash 3",
|
|
.size = MTDPART_SIZ_FULL,
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
}
|
|
},
|
|
},
|
|
};
|
|
|
|
/* Serial Flash */
|
|
static struct spi_board_info mb705_serial_flash = {
|
|
/* .bus_num and .chip_select set by processor board */
|
|
.modalias = "m25p80",
|
|
.max_speed_hz = 7000000,
|
|
.mode = SPI_MODE_3,
|
|
.platform_data = &(struct flash_platform_data) {
|
|
.name = "m25p80",
|
|
.type = "m25p32",
|
|
.nr_parts = 2,
|
|
.parts = (struct mtd_partition []) {
|
|
{
|
|
.name = "Serial Flash 1",
|
|
.size = 0x00080000,
|
|
.offset = 0,
|
|
}, {
|
|
.name = "Serial Flash 2",
|
|
.size = MTDPART_SIZ_FULL,
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
/* NAND Device */
|
|
struct stm_nand_bank_data mb705_nand_flash = {
|
|
.csn = 1,
|
|
.options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT,
|
|
.nr_partitions = 2,
|
|
.partitions = (struct mtd_partition []) {
|
|
{
|
|
.name = "NAND Flash 1",
|
|
.offset = 0,
|
|
.size = 0x00800000
|
|
}, {
|
|
.name = "NAND Flash 2",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = MTDPART_SIZ_FULL
|
|
},
|
|
},
|
|
.timing_data = &(struct stm_nand_timing_data) {
|
|
.sig_setup = 50, /* times in ns */
|
|
.sig_hold = 50,
|
|
.CE_deassert = 0,
|
|
.WE_to_RBn = 100,
|
|
.wr_on = 10,
|
|
.wr_off = 40,
|
|
.rd_on = 10,
|
|
.rd_off = 40,
|
|
.chip_delay = 30, /* in us */
|
|
},
|
|
};
|
|
|
|
static struct platform_device *mb705_devices[] __initdata = {
|
|
&epld_device,
|
|
&mb705_gpio_led,
|
|
&mb705_display_device,
|
|
#ifdef CONFIG_SH_ST_MB680
|
|
&mb705_fpbutton_device,
|
|
#endif
|
|
&mb705_nor_flash,
|
|
};
|
|
|
|
static DEFINE_SPINLOCK(mb705_reset_lock);
|
|
|
|
void mb705_reset(int mask, unsigned long usdelay)
|
|
{
|
|
u16 reg;
|
|
|
|
spin_lock(&mb705_reset_lock);
|
|
reg = epld_read(EPLD_EMI_RESET);
|
|
reg |= mask;
|
|
epld_write(reg, EPLD_EMI_RESET);
|
|
spin_unlock(&mb705_reset_lock);
|
|
|
|
udelay(usdelay);
|
|
|
|
spin_lock(&mb705_reset_lock);
|
|
reg = epld_read(EPLD_EMI_RESET);
|
|
reg &= ~mask;
|
|
epld_write(reg, EPLD_EMI_RESET);
|
|
spin_unlock(&mb705_reset_lock);
|
|
}
|
|
|
|
static int __init mb705_init(void)
|
|
{
|
|
int i;
|
|
unsigned long nor_bank_base = 0;
|
|
unsigned long nor_bank_size = 0;
|
|
|
|
/* We are't actually doing this early here... */
|
|
epld_early_init(&epld_device);
|
|
|
|
/* Check out the EPLDs */
|
|
for (i=0; i<3; i++) {
|
|
int ident_offset = (0x100 * i) + 0;
|
|
int test_offset = (0x100 * i) + 2;
|
|
u16 ident;
|
|
u16 test;
|
|
u16 mask = (i==0) ? 0xffff : 0xff;
|
|
|
|
ident = epld_read(ident_offset);
|
|
epld_write(0xab12+i, test_offset);
|
|
test = epld_read(test_offset);
|
|
|
|
printk(KERN_INFO
|
|
"mb705 %s_EPLD: board rev %c, EPLD rev %d, test %s\n",
|
|
(char*[3]){"EMI", "TS", "AUD" }[i],
|
|
((ident >> 4) & 0xf) - 1 + 'A', ident & 0xf,
|
|
(((test ^ (0xab12+i)) & mask) == mask) ?
|
|
"passed" : "failed");
|
|
}
|
|
|
|
mb705_rev = ((epld_read(EPLD_EMI_IDENT) >> 4) & 0xf) - 1 + 'A';
|
|
|
|
i = epld_read(EPLD_EMI_SWITCH);
|
|
if (i & EPLD_EMI_SWITCH_BOOTFROMNOR) {
|
|
pr_info("mb705: EMIA -> NAND; EMIB -> NOR\n");
|
|
nor_bank_base = emi_bank_base(1);
|
|
nor_bank_size = emi_bank_base(2) - nor_bank_base;
|
|
mb705_nand_flash.csn = 0;
|
|
} else {
|
|
pr_info("mb705: EMIA -> NOR; EMIB -> NAND\n");
|
|
nor_bank_base = emi_bank_base(0);
|
|
nor_bank_size = emi_bank_base(1) - nor_bank_base;
|
|
mb705_nand_flash.csn = 1;
|
|
}
|
|
|
|
/* Update NOR Flash base address and size: */
|
|
/* - limit bank size to 64MB (some targetpacks define 128MB!) */
|
|
if (nor_bank_size > 64*1024*1024)
|
|
nor_bank_size = 64*1024*1024;
|
|
/* - reduce visibility of NOR flash to EMI bank size */
|
|
if (mb705_nor_flash.resource[0].end > nor_bank_size - 1)
|
|
mb705_nor_flash.resource[0].end = nor_bank_size - 1;
|
|
/* - update resource parameters */
|
|
mb705_nor_flash.resource[0].start += nor_bank_base;
|
|
mb705_nor_flash.resource[0].end += nor_bank_base;
|
|
|
|
/*
|
|
* The MTD NAND code doesn't understand the concept of VPP,
|
|
* (or hardware write protect) so permanently enable it.
|
|
* Also disable NOR VPP enable just in case.
|
|
*/
|
|
i = epld_read(EPLD_EMI_MISC);
|
|
i &= ~EPLD_EMI_MISC_NORFLASHVPPEN;
|
|
i |= EPLD_EMI_MISC_NOTNANDFLASHWP;
|
|
epld_write(i, EPLD_EMI_MISC);
|
|
|
|
mbxxx_configure_nand_flash(&(struct stm_nand_config) {
|
|
.driver = stm_nand_flex,
|
|
.nr_banks = 1,
|
|
.banks = &mb705_nand_flash,
|
|
.rbn.flex_connected = 1,});
|
|
|
|
/* Interrupt routing.
|
|
* At the moment we only care about a small number of
|
|
* interrupts, so simply set up a static one-to-one routing.
|
|
*
|
|
* Interrupt sources:
|
|
* 0 : MAFE
|
|
* 1 : VOIP
|
|
* 2 : SPDIF out
|
|
* 3 : STRec status
|
|
* 4 : STEM0 (-> SysIrq(2) this matches the mb680 but active high)
|
|
* 5 : STEM1 (-> SysIrq(1) this matches the mb680 but active high))
|
|
* 6 : DVB
|
|
* 7 : DVB CD1
|
|
* 8 : DVB CD2
|
|
* 9 : FButton (-> SysIrq(0))
|
|
* 10 : EPLD intr in
|
|
*/
|
|
epld_write(0, EPLD_EMI_INT_PRI(9));
|
|
epld_write(1, EPLD_EMI_INT_PRI(5));
|
|
epld_write(2, EPLD_EMI_INT_PRI(4));
|
|
epld_write((1<<4)|(1<<5)|(1<<9), EPLD_EMI_INT_MASK);
|
|
|
|
mbxxx_configure_serial_flash(&mb705_serial_flash);
|
|
|
|
return platform_add_devices(mb705_devices, ARRAY_SIZE(mb705_devices));
|
|
}
|
|
arch_initcall(mb705_init);
|