362 lines
10 KiB
C
362 lines
10 KiB
C
/*
|
|
* arch/sh/boards/mach-idl4k/setup.c
|
|
*
|
|
* Copyright (C) 2009 STMicroelectronics Limited
|
|
* Author: Pawel Moll (pawel.moll@st.com)
|
|
*
|
|
* 2011-05-20 : modifications for Inverto idl4k (msz@inverto.tv)
|
|
*
|
|
* 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/leds.h>
|
|
#include <linux/tm1668.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/mtd/physmap.h>
|
|
#include <linux/mtd/partitions.h>
|
|
#include <linux/mtd/nand.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/spi_gpio.h>
|
|
#include <linux/spi/flash.h>
|
|
#include <linux/stm/nand.h>
|
|
#include <linux/stm/emi.h>
|
|
#include <linux/stm/pio.h>
|
|
#include <linux/stm/platform.h>
|
|
#include <linux/stm/stx7108.h>
|
|
#include <linux/stm/sysconf.h>
|
|
#include <linux/stm/pm_notify.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/i2c/at24.h>
|
|
#include <asm/sizes.h>
|
|
#include <asm/irq-ilc.h>
|
|
|
|
#undef GMAC_RGMII_MODE
|
|
/*#define GMAC_RGMII_MODE*/
|
|
|
|
/*
|
|
* The FLASH devices are configured according to the boot-mode:
|
|
*
|
|
* boot-from-XXX
|
|
* --------------------------------------------------------------------
|
|
* NOR NAND SPI
|
|
* Mode Pins (x16) (x8, LP, LA) (ST)
|
|
* --------------------------------------------------------------------
|
|
* JH2 1 (M2) 1 (E) 0 (W) 0 (W)
|
|
* 2 (M3) 0 (W) 0 (W) 1 (E)
|
|
* JH4 1 (M4) 1 (E) 1 (E) 0 (W)
|
|
* 2 (M5) 0 (W) 0 (W) 1 (E)
|
|
*
|
|
* CS Routing
|
|
* --------------------------------------------------------------------
|
|
* JF-2 2-1 (E) 2-3 (W) 2-3 (W)
|
|
* JF-3 2-1 (E) 2-3 (W) 2-3 (W)
|
|
*
|
|
* Post-boot Access
|
|
* --------------------------------------------------------------------
|
|
* NOR (limit) EMIA (64MB) EMIB (8MB)[1] EMIB (8MB)[2]
|
|
* NAND EMIB/FLEXB FLEXA FLEXA [2]
|
|
* SPI SPI_PIO/FSM SPI_PIO/FSM SPI_PIO/FSM
|
|
* --------------------------------------------------------------------
|
|
*
|
|
*
|
|
* Switch positions are given in terms of (N)orth, (E)ast, (S)outh, and (W)est,
|
|
* when viewing the board with the LED display to the South and the power
|
|
* connector to the North.
|
|
*
|
|
* [1] It is also possible to map NOR Flash onto EMIC. This gives access to
|
|
* 40MB, but has the side-effect of setting A26 which imposes a 64MB offset
|
|
* from the start of the Flash device.
|
|
*
|
|
* [2] An alternative configuration is map NAND onto EMIB/FLEXB, and NOR onto
|
|
* EMIC (using the boot-from-NOR "CS Routing"). This allows the EMI
|
|
* bit-banging driver to be used for NAND Flash, and gives access to 40MB
|
|
* NOR Flash, subject to the conditions in note [1].
|
|
*
|
|
* [3] Serial Flash setup depends on the board revision and silicon cut:
|
|
* Rev 1.0, cut x.x: GPIO SPI bus (MISO/MOSI swapped) and "m25p80"
|
|
* Serial Flash driver
|
|
* Rev 2.x, cut 1.0: GPIO SPI bus and "m25p80" Serial Flash driver
|
|
* Rev 2.x, cut 2.0: SPI FSM Serial Flash Controller
|
|
*
|
|
* Note, Rev 1.0 kernel builds include only SPI GPIO support. Rev 2.0
|
|
* builds include SPI GPIO and SPI FSM support; the appropriate driver is
|
|
* selected at runtime (see device_init() below).
|
|
*/
|
|
|
|
|
|
#define IDL4K_PIO_POWER_ON stm_gpio(5, 0)
|
|
#define IDL4K_PIO_POWER_ON_ETHERNET stm_gpio(15, 4)
|
|
#define IDL4K_GPIO_MII_SPEED_SEL stm_gpio(21, 7)
|
|
#define IDL4K_GPIO_VLNA_ON stm_gpio(14, 3)
|
|
|
|
#define IDL4K_PIO_LED_POWER_WHITE stm_gpio(3, 1)
|
|
#define IDL4K_PIO_LED_POWER_RED stm_gpio(3, 0)
|
|
|
|
typedef void (*stdby_callback_f)( int stdbyNoWakeUp );
|
|
|
|
static stdby_callback_f stdby_callback_tab[4] = { 0 };
|
|
|
|
static void __init idl4k_setup(char **cmdline_p)
|
|
{
|
|
printk(KERN_INFO "Inverto idl4k 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, });
|
|
}
|
|
|
|
static int idl4k_phy_reset(void *bus)
|
|
{
|
|
static int done;
|
|
|
|
/* This line is shared between both MII interfaces */
|
|
if (!done) {
|
|
gpio_set_value(IDL4K_PIO_POWER_ON_ETHERNET, 0);
|
|
mdelay(10); /* 10 miliseconds is enough for everyone ;-) */
|
|
gpio_set_value(IDL4K_PIO_POWER_ON_ETHERNET, 1);
|
|
mdelay(30); /* 30 miliseconds as for Realtek chip ;-) */
|
|
done = 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void idl4k_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(IDL4K_GPIO_MII_SPEED_SEL, 1);
|
|
else
|
|
gpio_set_value(IDL4K_GPIO_MII_SPEED_SEL, 0);
|
|
}
|
|
|
|
#define STMMAC_PHY_ADDR 1
|
|
#define GMII1_MDINT 25
|
|
static int stmmac_phy_irqs[PHY_MAX_ADDR] = {
|
|
/* PIO15_6 - MII1 Management Data Interrupt ETH_1_MDINT
|
|
* ILC3 input 'External 25'
|
|
* (ST7108 datasheet (8183887) rev C: page 114, 161)
|
|
*/
|
|
[STMMAC_PHY_ADDR] = GMII1_MDINT,
|
|
};
|
|
|
|
static struct stmmac_mdio_bus_data stmmac1_mdio_bus = {
|
|
.bus_id = 1,
|
|
.phy_reset = idl4k_phy_reset,
|
|
.phy_mask = 0,
|
|
.irqs = stmmac_phy_irqs,
|
|
};
|
|
|
|
/* NAND Flash */
|
|
static struct stm_nand_bank_data idl4k_nand_flash = {
|
|
.csn = 0,
|
|
.options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT,
|
|
.nr_partitions = 5,
|
|
.partitions = (struct mtd_partition []) {
|
|
{
|
|
.name = "nand-env",
|
|
.offset = 0,
|
|
.size = 0x0020000
|
|
}, {
|
|
.name = "nand-system",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = 0x0400000
|
|
}, {
|
|
.name = "nand-fw1",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = 0x2000000
|
|
}, {
|
|
.name = "nand-fw2",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = 0x2000000
|
|
}, {
|
|
.name = "nand-data",
|
|
.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 at24_platform_data idl4k_m24lc64 = {
|
|
.byte_len = SZ_64K / 8,
|
|
.page_size = 32,
|
|
.flags=AT24_FLAG_ADDR16,
|
|
};
|
|
|
|
static struct i2c_board_info idl4k_i2c_devices[] = {
|
|
{
|
|
I2C_BOARD_INFO("24c64", 0x50), /* E0=0, E1=0, E2=0 */
|
|
.platform_data = &idl4k_m24lc64,
|
|
},
|
|
};
|
|
|
|
void idl4k_switch_standby_led(int on)
|
|
{
|
|
if ( on )
|
|
{
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_WHITE, 0);
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_RED, 1);
|
|
}
|
|
else
|
|
{
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_WHITE, 1);
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_RED, 0);
|
|
}
|
|
}
|
|
|
|
void pm_suspend_board_ntfy(void)
|
|
{
|
|
int i;
|
|
gpio_direction_output(IDL4K_PIO_POWER_ON, 1);
|
|
gpio_direction_output(IDL4K_GPIO_VLNA_ON, 0);
|
|
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_WHITE, 0);
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_RED, 1);
|
|
mdelay(20);
|
|
|
|
for ( i = 0; i < sizeof(stdby_callback_tab)/sizeof(stdby_callback_tab[0]); ++i)
|
|
{
|
|
if ( stdby_callback_tab[i] == 0 )
|
|
break;
|
|
|
|
stdby_callback_tab[i]( ~0 );
|
|
}
|
|
}
|
|
|
|
void pm_wake_board_ntfy(void)
|
|
{
|
|
int i;
|
|
gpio_direction_output(IDL4K_PIO_POWER_ON, 0);
|
|
gpio_direction_output(IDL4K_GPIO_VLNA_ON, 1);
|
|
|
|
mdelay(20);
|
|
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_WHITE, 1);
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_RED, 0);
|
|
|
|
for ( i = 0; i < sizeof(stdby_callback_tab)/sizeof(stdby_callback_tab[0]); ++i)
|
|
{
|
|
if ( stdby_callback_tab[i] == 0 )
|
|
break;
|
|
|
|
stdby_callback_tab[i]( 0 );
|
|
}
|
|
}
|
|
|
|
static int __init device_init(void)
|
|
{
|
|
/* The "POWER_ON_ETH" line should be rather called "PHY_RESET",
|
|
* but it isn't... ;-) */
|
|
gpio_request(IDL4K_PIO_POWER_ON_ETHERNET, "POWER_ON_ETHERNET");
|
|
gpio_direction_output(IDL4K_PIO_POWER_ON_ETHERNET, 0);
|
|
|
|
/* Some of the peripherals are powered by regulators
|
|
* triggered by the following PIO line... */
|
|
gpio_request(IDL4K_PIO_POWER_ON, "POWER_ON");
|
|
gpio_direction_output(IDL4K_PIO_POWER_ON, 0);
|
|
|
|
/*gpio_request(IDL4K_GPIO_VLNA_ON, "VLNA_ON");
|
|
gpio_direction_output(IDL4K_GPIO_VLNA_ON, 0);*/
|
|
|
|
/* NIM */
|
|
stx7108_configure_ssc_i2c(1, NULL);
|
|
/* SYS - EEPROM */
|
|
stx7108_configure_ssc_i2c(5, NULL);
|
|
/* NIM VLNA */
|
|
/*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, });*/
|
|
|
|
i2c_register_board_info(1, idl4k_i2c_devices, ARRAY_SIZE(idl4k_i2c_devices));
|
|
|
|
stx7108_configure_usb(0);
|
|
stx7108_configure_usb(1);
|
|
stx7108_configure_usb(2);
|
|
|
|
gpio_request(IDL4K_GPIO_MII_SPEED_SEL, "stmmac");
|
|
gpio_direction_output(IDL4K_GPIO_MII_SPEED_SEL, 1);
|
|
|
|
stx7108_configure_ethernet(1, &(struct stx7108_ethernet_config) {
|
|
.mode = stx7108_ethernet_mode_gmii_gtx,
|
|
.ext_clk = 0,
|
|
.phy_bus = 1,
|
|
.txclk_select = idl4k_mii_txclk_select,
|
|
.phy_addr = STMMAC_PHY_ADDR,
|
|
.mdio_bus_data = &stmmac1_mdio_bus,
|
|
});
|
|
|
|
stx7108_configure_nand(&(struct stm_nand_config) {
|
|
.driver = stm_nand_flex,
|
|
.nr_banks = 1,
|
|
.banks = &idl4k_nand_flash,
|
|
.rbn.flex_connected = 1,});
|
|
|
|
gpio_request(IDL4K_PIO_LED_POWER_WHITE, "PWRL_WHITE");
|
|
|
|
gpio_request(IDL4K_PIO_LED_POWER_WHITE, "PWRL_WHITE");
|
|
gpio_request(IDL4K_PIO_LED_POWER_RED, "PWRL_RED");
|
|
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_WHITE, 1);
|
|
gpio_direction_output(IDL4K_PIO_LED_POWER_RED, 0);
|
|
|
|
/* PMEB pio */
|
|
gpio_request(stm_gpio(23, 1), "PMEB_PIO");
|
|
gpio_direction_input(stm_gpio(23, 1));
|
|
|
|
return 0;
|
|
}
|
|
arch_initcall(device_init);
|
|
|
|
|
|
static void __iomem *idl4k_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_idl4k __initmv = {
|
|
.mv_name = "idl4k",
|
|
.mv_setup = idl4k_setup,
|
|
.mv_nr_irqs = NR_IRQS,
|
|
.mv_ioport_map = idl4k_ioport_map,
|
|
};
|
|
|
|
void idl4k_register_stdby_callback( stdby_callback_f stdby_callback )
|
|
{
|
|
int i;
|
|
for ( i = 0; i < sizeof(stdby_callback_tab)/sizeof(stdby_callback_tab[0]); ++i)
|
|
if ( stdby_callback_tab[i] == 0 )
|
|
{
|
|
stdby_callback_tab[i] = stdby_callback;
|
|
break;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(idl4k_register_stdby_callback);
|
|
EXPORT_SYMBOL(idl4k_switch_standby_led);
|