380 lines
9.6 KiB
C
380 lines
9.6 KiB
C
/*
|
|
* arch/sh/boards/mach-adi7108/setup.c
|
|
*
|
|
* Copyright (C) 2011 STMicroelectronics Limited
|
|
* Author: Srinivas Kandagatla (srinivas.kandagatla@st.com)
|
|
*
|
|
* May be copied or modified under the terms of the GNU General Public
|
|
* License. See linux/COPYING for more information.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/io.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/physmap.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/mtd/nand.h>
|
|
#include <linux/stm/nand.h>
|
|
#include <linux/stm/emi.h>
|
|
#include <linux/stm/platform.h>
|
|
#include <linux/stm/stx7108.h>
|
|
#include <linux/stm/sysconf.h>
|
|
#include <asm/irq-ilc.h>
|
|
|
|
|
|
#define ADI7108_PIO_POWER_ON_ETHERNET0 stm_gpio(19, 7)
|
|
#define ADI7108_PIO_POWER_ON_ETHERNET1 stm_gpio(15, 4)
|
|
#define ADI7108_GPIO_MII1_SPEED_SEL stm_gpio(21, 7)
|
|
|
|
|
|
static void __init adi7108_setup(char **cmdline_p)
|
|
{
|
|
printk(KERN_INFO "STMicroelectronics STi7108-ADI Board "
|
|
"initialisation\n");
|
|
|
|
stx7108_early_device_init();
|
|
|
|
stx7108_configure_asc(3, &(struct stx7108_asc_config) {
|
|
.routing.asc3.txd = stx7108_asc3_txd_pio24_4,
|
|
.routing.asc3.rxd = stx7108_asc3_rxd_pio24_5,
|
|
.hw_flow_control = 0,
|
|
.is_console = 1, });
|
|
|
|
stx7108_configure_asc(1, &(struct stx7108_asc_config) {
|
|
.hw_flow_control = 1, });
|
|
}
|
|
|
|
|
|
static int adi7108_phy1_reset(void *bus)
|
|
{
|
|
static int done;
|
|
if (!done) {
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET1, 0);
|
|
udelay(10000); /* 10 miliseconds is enough for everyone ;-) */
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET1, 1);
|
|
done = 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void adi7108_mii_txclk_select(int txclk_250_not_25_mhz)
|
|
{
|
|
/* When 1000 speed is negotiated we have to set the PIO21[7]. */
|
|
if (txclk_250_not_25_mhz)
|
|
gpio_set_value(ADI7108_GPIO_MII1_SPEED_SEL, 1);
|
|
else
|
|
gpio_set_value(ADI7108_GPIO_MII1_SPEED_SEL, 0);
|
|
}
|
|
|
|
#ifdef CONFIG_SH_ST_ADI7108_STMMAC0
|
|
static int adi7108_phy0_reset(void *bus)
|
|
{
|
|
static int done;
|
|
|
|
if (!done) {
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET0, 0);
|
|
udelay(10000); /* 10 miliseconds is enough for everyone ;-) */
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET0, 1);
|
|
done = 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static struct stmmac_mdio_bus_data stmmac0_mdio_bus = {
|
|
.bus_id = 0,
|
|
.phy_reset = adi7108_phy0_reset,
|
|
.phy_mask = 0,
|
|
};
|
|
#endif /* CONFIG_SH_ST_ADI7108_STMMAC0 */
|
|
|
|
static struct stmmac_mdio_bus_data stmmac1_mdio_bus = {
|
|
.bus_id = 1,
|
|
.phy_reset = adi7108_phy1_reset,
|
|
.phy_mask = 0,
|
|
};
|
|
|
|
/* NOR FLASH */
|
|
static struct platform_device adi7108_nor_flash = {
|
|
.name = "physmap-flash",
|
|
.id = -1,
|
|
.num_resources = 1,
|
|
.resource = (struct resource[]) {
|
|
{
|
|
.start = 0x00000000,
|
|
.end = 256*1024*1024 - 1,
|
|
.flags = IORESOURCE_MEM,
|
|
}
|
|
},
|
|
.dev.platform_data = &(struct physmap_flash_data) {
|
|
.width = 2,
|
|
.set_vpp = NULL,
|
|
.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 stm_plat_spifsm_data adi7108_serial_flash = {
|
|
.name = "m25p128",
|
|
.nr_parts = 2,
|
|
.parts = (struct mtd_partition []) {
|
|
{
|
|
.name = "Serial Flash 1",
|
|
.size = 0x00200000,
|
|
.offset = 0,
|
|
}, {
|
|
.name = "Serial Flash 2",
|
|
.size = MTDPART_SIZ_FULL,
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
},
|
|
},
|
|
};
|
|
|
|
/* NAND FLASH */
|
|
static struct stm_nand_bank_data adi7108_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 = 10, /* times in ns */
|
|
.sig_hold = 10,
|
|
.CE_deassert = 0,
|
|
.WE_to_RBn = 100,
|
|
.wr_on = 10,
|
|
.wr_off = 30,
|
|
.rd_on = 10,
|
|
.rd_off = 30,
|
|
.chip_delay = 30, /* in us */
|
|
},
|
|
};
|
|
|
|
static struct platform_device *adi7108_devices[] __initdata = {
|
|
&adi7108_nor_flash,
|
|
};
|
|
|
|
static int __init device_init(void)
|
|
{
|
|
struct sysconf_field *sc;
|
|
unsigned long nor_bank_base = 0;
|
|
unsigned long nor_bank_size = 0;
|
|
|
|
/*
|
|
*
|
|
* BootUp RE32 & RE35 RE33 & RE34
|
|
* NOR 0R NC
|
|
* NAND/SPI NC 0R
|
|
*
|
|
*/
|
|
|
|
/* Configure Flash according to boot-device
|
|
*
|
|
* [Only tested on boot-from-NOR, board-mod required for
|
|
* boot-from-NAND/SPI]
|
|
*/
|
|
sc = sysconf_claim(SYS_STA_BANK1, 3, 2, 6, "boot_device");
|
|
switch (sysconf_read(sc)) {
|
|
case 0x15:
|
|
pr_info("Configuring FLASH for boot-from-NOR\n");
|
|
nor_bank_base = emi_bank_base(0);
|
|
nor_bank_size = emi_bank_base(1) - nor_bank_base;
|
|
adi7108_nand_flash.csn = 1;
|
|
break;
|
|
case 0x14:
|
|
pr_info("Configuring FLASH for boot-from-NAND\n");
|
|
nor_bank_base = emi_bank_base(1);
|
|
nor_bank_size = emi_bank_base(2) - nor_bank_base;
|
|
adi7108_nand_flash.csn = 0;
|
|
break;
|
|
case 0x1a:
|
|
pr_info("Configuring FLASH for boot-from-SPI\n");
|
|
nor_bank_base = emi_bank_base(1);
|
|
nor_bank_size = emi_bank_base(2) - nor_bank_base;
|
|
adi7108_nand_flash.csn = 0;
|
|
break;
|
|
default:
|
|
BUG();
|
|
break;
|
|
}
|
|
sysconf_release(sc);
|
|
|
|
/* 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 (adi7108_nor_flash.resource[0].end > nor_bank_size - 1)
|
|
adi7108_nor_flash.resource[0].end = nor_bank_size - 1;
|
|
/* - update resource parameters */
|
|
adi7108_nor_flash.resource[0].start += nor_bank_base;
|
|
adi7108_nor_flash.resource[0].end += nor_bank_base;
|
|
|
|
|
|
/* NIM */
|
|
stx7108_configure_ssc_i2c(1, NULL);
|
|
|
|
/* AV */
|
|
stx7108_configure_ssc_i2c(2, &(struct stx7108_ssc_config) {
|
|
.routing.ssc2.sclk = stx7108_ssc2_sclk_pio14_4,
|
|
.routing.ssc2.mtsr = stx7108_ssc2_mtsr_pio14_5, });
|
|
|
|
/* EEPROM */
|
|
stx7108_configure_ssc_i2c(5, NULL);
|
|
|
|
/* HDMI */
|
|
stx7108_configure_ssc_i2c(6, NULL);
|
|
|
|
stx7108_configure_lirc(&(struct stx7108_lirc_config) {
|
|
.rx_mode = stx7108_lirc_rx_mode_ir, });
|
|
|
|
stx7108_configure_usb(0);
|
|
stx7108_configure_usb(1);
|
|
stx7108_configure_usb(2);
|
|
|
|
/*-------------------------------------------------------------
|
|
* | Ver1.0 VerB VerC VerD
|
|
* SATA 0/1 connector | E-sata0+1 E-sata0 E-sata0 Sata on board
|
|
* PCI-e Connector | √ √
|
|
*-------------------------------------------------------------*/
|
|
#if defined(CONFIG_SH_ST_ADI7108_VER_B_BOARD) || \
|
|
defined(CONFIG_SH_ST_ADI7108_VER_C_BOARD)
|
|
|
|
stx7108_configure_miphy(&(struct stx7108_miphy_config) {
|
|
.modes = (enum miphy_mode[2]) {
|
|
SATA_MODE, PCIE_MODE },
|
|
});
|
|
|
|
stx7108_configure_sata(0, &(struct stx7108_sata_config) { });
|
|
|
|
#elif defined(CONFIG_SH_ST_ADI7108_VER_D_BOARD) || \
|
|
defined(CONFIG_SH_ST_ADI7108_VER_1_0_BOARD)
|
|
stx7108_configure_miphy(&(struct stx7108_miphy_config) {
|
|
.modes = (enum miphy_mode[2]) {
|
|
SATA_MODE, SATA_MODE },
|
|
});
|
|
|
|
stx7108_configure_sata(0, &(struct stx7108_sata_config) { });
|
|
stx7108_configure_sata(1, &(struct stx7108_sata_config) { });
|
|
#endif
|
|
|
|
#ifdef CONFIG_SH_ST_ADI7108_STMMAC0
|
|
/* By default the RJ45 connector is removed on this board. */
|
|
|
|
gpio_request(ADI7108_PIO_POWER_ON_ETHERNET0, "POWER_ON_ETHERNET");
|
|
gpio_direction_output(ADI7108_PIO_POWER_ON_ETHERNET0, 0);
|
|
|
|
|
|
stx7108_configure_ethernet(0, &(struct stx7108_ethernet_config) {
|
|
.mode = stx7108_ethernet_mode_mii,
|
|
.ext_clk = 1,
|
|
.phy_bus = 0,
|
|
.phy_addr = -1,
|
|
.mdio_bus_data = &stmmac0_mdio_bus,
|
|
});
|
|
#endif /* CONFIG_SH_ST_ADI7108_STMMAC0 */
|
|
/* To use the MII/GMII mode.
|
|
*
|
|
* RP1 MII1_EN
|
|
* GMII NC 1
|
|
* MII 51R 0
|
|
*
|
|
*/
|
|
/* The "POWER_ON_ETH" line should be rather called "PHY_RESET",
|
|
* but it isn't... ;-) */
|
|
gpio_request(ADI7108_PIO_POWER_ON_ETHERNET1, "POWER_ON_ETHERNET");
|
|
gpio_direction_output(ADI7108_PIO_POWER_ON_ETHERNET1, 0);
|
|
|
|
gpio_request(ADI7108_GPIO_MII1_SPEED_SEL, "stmmac");
|
|
gpio_direction_output(ADI7108_GPIO_MII1_SPEED_SEL, 0);
|
|
|
|
stx7108_configure_ethernet(1, &(struct stx7108_ethernet_config) {
|
|
.mode = stx7108_ethernet_mode_gmii_gtx,
|
|
.ext_clk = 0,
|
|
.phy_bus = 1,
|
|
.txclk_select = adi7108_mii_txclk_select,
|
|
.phy_addr = 1,
|
|
.mdio_bus_data = &stmmac1_mdio_bus,
|
|
});
|
|
|
|
stx7108_configure_nand(&(struct stm_nand_config) {
|
|
.driver = stm_nand_flex,
|
|
.nr_banks = 1,
|
|
.banks = &adi7108_nand_flash,
|
|
.rbn.flex_connected = 1,});
|
|
|
|
stx7108_configure_spifsm(&adi7108_serial_flash);
|
|
|
|
stx7108_configure_mmc(0);
|
|
|
|
return platform_add_devices(adi7108_devices,
|
|
ARRAY_SIZE(adi7108_devices));
|
|
}
|
|
arch_initcall(device_init);
|
|
|
|
|
|
static void __iomem *adi7108_ioport_map(unsigned long port, unsigned int size)
|
|
{
|
|
/* If we have PCI then this should never be called because we
|
|
* are using the generic iomap implementation. If we don't
|
|
* have PCI then there are no IO mapped devices, so it still
|
|
* shouldn't be called. */
|
|
BUG();
|
|
return NULL;
|
|
}
|
|
|
|
struct sh_machine_vector mv_adi7108 __initmv = {
|
|
.mv_name = "adi7108",
|
|
.mv_setup = adi7108_setup,
|
|
.mv_nr_irqs = NR_IRQS,
|
|
.mv_ioport_map = adi7108_ioport_map,
|
|
};
|
|
|
|
#ifdef CONFIG_HIBERNATION_ON_MEMORY
|
|
int stm_defrost_board(void *data)
|
|
{
|
|
gpio_direction_output(ADI7108_PIO_POWER_ON_ETHERNET1, 0);
|
|
|
|
gpio_direction_output(ADI7108_GPIO_MII1_SPEED_SEL, 0);
|
|
|
|
/*
|
|
* adi7108_phy_reset(...);
|
|
*/
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET1, 0);
|
|
udelay(10000); /* 10 miliseconds is enough for everyone ;-) */
|
|
gpio_set_value(ADI7108_PIO_POWER_ON_ETHERNET1, 1);
|
|
|
|
return 0;
|
|
}
|
|
#endif
|