2009-06-10 00:28:15 +04:00
/*
* TI DaVinci DM365 EVM board support
*
* Copyright ( C ) 2009 Texas Instruments Incorporated
*
* 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 version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/init.h>
2009-10-02 22:05:29 +04:00
# include <linux/err.h>
2009-06-10 00:28:15 +04:00
# include <linux/i2c.h>
# include <linux/io.h>
# include <linux/clk.h>
2009-06-20 20:23:39 +04:00
# include <linux/i2c/at24.h>
2009-06-22 01:50:12 +04:00
# include <linux/leds.h>
2009-06-20 22:15:51 +04:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/partitions.h>
# include <linux/mtd/nand.h>
2009-10-13 23:57:07 +04:00
# include <linux/input.h>
2009-10-02 22:05:29 +04:00
2009-06-10 00:28:15 +04:00
# include <asm/mach-types.h>
# include <asm/mach/arch.h>
2009-10-02 22:05:29 +04:00
2009-06-20 20:23:39 +04:00
# include <mach/mux.h>
2009-06-10 00:28:15 +04:00
# include <mach/dm365.h>
# include <mach/common.h>
# include <mach/i2c.h>
# include <mach/serial.h>
2009-06-20 22:00:52 +04:00
# include <mach/mmc.h>
2009-06-20 22:15:51 +04:00
# include <mach/nand.h>
2009-10-13 23:57:07 +04:00
# include <mach/keyscan.h>
2009-06-20 22:15:51 +04:00
2009-06-22 01:50:12 +04:00
static inline int have_imager ( void )
{
/* REVISIT when it's supported, trigger via Kconfig */
return 0 ;
}
static inline int have_tvp7002 ( void )
{
/* REVISIT when it's supported, trigger via Kconfig */
return 0 ;
}
2009-06-20 22:15:51 +04:00
# define DM365_ASYNC_EMIF_CONTROL_BASE 0x01d10000
# define DM365_ASYNC_EMIF_DATA_CE0_BASE 0x02000000
2009-06-22 01:50:12 +04:00
# define DM365_ASYNC_EMIF_DATA_CE1_BASE 0x04000000
2009-06-10 00:28:15 +04:00
2009-06-20 20:23:39 +04:00
# define DM365_EVM_PHY_MASK (0x2)
# define DM365_EVM_MDIO_FREQUENCY (2200000) /* PHY bus frequency */
2009-06-22 01:50:12 +04:00
/*
* A MAX - II CPLD is used for various board control functions .
*/
# define CPLD_OFFSET(a13a8,a2a1) (((a13a8) << 10) + ((a2a1) << 3))
# define CPLD_VERSION CPLD_OFFSET(0,0) /* r/o */
# define CPLD_TEST CPLD_OFFSET(0,1)
# define CPLD_LEDS CPLD_OFFSET(0,2)
# define CPLD_MUX CPLD_OFFSET(0,3)
# define CPLD_SWITCH CPLD_OFFSET(1,0) /* r/o */
# define CPLD_POWER CPLD_OFFSET(1,1)
# define CPLD_VIDEO CPLD_OFFSET(1,2)
# define CPLD_CARDSTAT CPLD_OFFSET(1,3) /* r/o */
# define CPLD_DILC_OUT CPLD_OFFSET(2,0)
# define CPLD_DILC_IN CPLD_OFFSET(2,1) /* r/o */
# define CPLD_IMG_DIR0 CPLD_OFFSET(2,2)
# define CPLD_IMG_MUX0 CPLD_OFFSET(2,3)
# define CPLD_IMG_MUX1 CPLD_OFFSET(3,0)
# define CPLD_IMG_DIR1 CPLD_OFFSET(3,1)
# define CPLD_IMG_MUX2 CPLD_OFFSET(3,2)
# define CPLD_IMG_MUX3 CPLD_OFFSET(3,3)
# define CPLD_IMG_DIR2 CPLD_OFFSET(4,0)
# define CPLD_IMG_MUX4 CPLD_OFFSET(4,1)
# define CPLD_IMG_MUX5 CPLD_OFFSET(4,2)
# define CPLD_RESETS CPLD_OFFSET(4,3)
# define CPLD_CCD_DIR1 CPLD_OFFSET(0x3e,0)
# define CPLD_CCD_IO1 CPLD_OFFSET(0x3e,1)
# define CPLD_CCD_DIR2 CPLD_OFFSET(0x3e,2)
# define CPLD_CCD_IO2 CPLD_OFFSET(0x3e,3)
# define CPLD_CCD_DIR3 CPLD_OFFSET(0x3f,0)
# define CPLD_CCD_IO3 CPLD_OFFSET(0x3f,1)
static void __iomem * cpld ;
2009-06-20 22:15:51 +04:00
/* NOTE: this is geared for the standard config, with a socketed
* 2 GByte Micron NAND ( MT29F16G08FAA ) using 128 KB sectors . If you
* swap chips with a different block size , partitioning will
* need to be changed . This NAND chip MT29F16G08FAA is the default
* NAND shipped with the Spectrum Digital DM365 EVM
*/
# define NAND_BLOCK_SIZE SZ_128K
static struct mtd_partition davinci_nand_partitions [ ] = {
{
/* UBL (a few copies) plus U-Boot */
. name = " bootloader " ,
. offset = 0 ,
. size = 28 * NAND_BLOCK_SIZE ,
. mask_flags = MTD_WRITEABLE , /* force read-only */
} , {
/* U-Boot environment */
. name = " params " ,
. offset = MTDPART_OFS_APPEND ,
. size = 2 * NAND_BLOCK_SIZE ,
. mask_flags = 0 ,
} , {
. name = " kernel " ,
. offset = MTDPART_OFS_APPEND ,
. size = SZ_4M ,
. mask_flags = 0 ,
} , {
. name = " filesystem1 " ,
. offset = MTDPART_OFS_APPEND ,
. size = SZ_512M ,
. mask_flags = 0 ,
} , {
. name = " filesystem2 " ,
. offset = MTDPART_OFS_APPEND ,
. size = MTDPART_SIZ_FULL ,
. mask_flags = 0 ,
}
/* two blocks with bad block table (and mirror) at the end */
} ;
static struct davinci_nand_pdata davinci_nand_data = {
. mask_chipsel = BIT ( 14 ) ,
. parts = davinci_nand_partitions ,
. nr_parts = ARRAY_SIZE ( davinci_nand_partitions ) ,
. ecc_mode = NAND_ECC_HW ,
. options = NAND_USE_FLASH_BBT ,
2009-09-17 07:00:13 +04:00
. ecc_bits = 4 ,
2009-06-20 22:15:51 +04:00
} ;
static struct resource davinci_nand_resources [ ] = {
{
. start = DM365_ASYNC_EMIF_DATA_CE0_BASE ,
. end = DM365_ASYNC_EMIF_DATA_CE0_BASE + SZ_32M - 1 ,
. flags = IORESOURCE_MEM ,
} , {
. start = DM365_ASYNC_EMIF_CONTROL_BASE ,
. end = DM365_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1 ,
. flags = IORESOURCE_MEM ,
} ,
} ;
static struct platform_device davinci_nand_device = {
. name = " davinci_nand " ,
. id = 0 ,
. num_resources = ARRAY_SIZE ( davinci_nand_resources ) ,
. resource = davinci_nand_resources ,
. dev = {
. platform_data = & davinci_nand_data ,
} ,
} ;
2009-06-20 20:23:39 +04:00
static struct at24_platform_data eeprom_info = {
. byte_len = ( 256 * 1024 ) / 8 ,
. page_size = 64 ,
. flags = AT24_FLAG_ADDR16 ,
. setup = davinci_get_mac_addr ,
. context = ( void * ) 0x7f00 ,
} ;
2009-09-03 01:33:29 +04:00
static struct snd_platform_data dm365_evm_snd_data ;
2009-06-20 20:23:39 +04:00
static struct i2c_board_info i2c_info [ ] = {
{
I2C_BOARD_INFO ( " 24c256 " , 0x50 ) ,
. platform_data = & eeprom_info ,
} ,
2009-09-03 01:33:29 +04:00
{
I2C_BOARD_INFO ( " tlv320aic3x " , 0x18 ) ,
} ,
2009-06-20 20:23:39 +04:00
} ;
2009-06-10 00:28:15 +04:00
static struct davinci_i2c_platform_data i2c_pdata = {
. bus_freq = 400 /* kHz */ ,
. bus_delay = 0 /* usec */ ,
} ;
2009-10-13 23:57:07 +04:00
# ifdef CONFIG_KEYBOARD_DAVINCI
static unsigned short dm365evm_keymap [ ] = {
KEY_KP2 ,
KEY_LEFT ,
KEY_EXIT ,
KEY_DOWN ,
KEY_ENTER ,
KEY_UP ,
KEY_KP1 ,
KEY_RIGHT ,
KEY_MENU ,
KEY_RECORD ,
KEY_REWIND ,
KEY_KPMINUS ,
KEY_STOP ,
KEY_FASTFORWARD ,
KEY_KPPLUS ,
KEY_PLAYPAUSE ,
0
} ;
static struct davinci_ks_platform_data dm365evm_ks_data = {
. keymap = dm365evm_keymap ,
. keymapsize = ARRAY_SIZE ( dm365evm_keymap ) ,
. rep = 1 ,
/* Scan period = strobe + interval */
. strobe = 0x5 ,
. interval = 0x2 ,
. matrix_type = DAVINCI_KEYSCAN_MATRIX_4X4 ,
} ;
# endif
2009-06-22 01:50:12 +04:00
static int cpld_mmc_get_cd ( int module )
{
if ( ! cpld )
return - ENXIO ;
/* low == card present */
return ! ( __raw_readb ( cpld + CPLD_CARDSTAT ) & BIT ( module ? 4 : 0 ) ) ;
}
static int cpld_mmc_get_ro ( int module )
{
if ( ! cpld )
return - ENXIO ;
/* high == card's write protect switch active */
return ! ! ( __raw_readb ( cpld + CPLD_CARDSTAT ) & BIT ( module ? 5 : 1 ) ) ;
}
2009-06-20 22:00:52 +04:00
static struct davinci_mmc_config dm365evm_mmc_config = {
2009-06-22 01:50:12 +04:00
. get_cd = cpld_mmc_get_cd ,
. get_ro = cpld_mmc_get_ro ,
2009-06-20 22:00:52 +04:00
. wires = 4 ,
. max_freq = 50000000 ,
. caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED ,
. version = MMC_CTLR_VERSION_2 ,
} ;
2009-06-20 20:23:39 +04:00
static void dm365evm_emac_configure ( void )
{
/*
* EMAC pins are multiplexed with GPIO and UART
* Further details are available at the DM365 ARM
* Subsystem Users Guide ( sprufg5 . pdf ) pages 125 - 127
*/
davinci_cfg_reg ( DM365_EMAC_TX_EN ) ;
davinci_cfg_reg ( DM365_EMAC_TX_CLK ) ;
davinci_cfg_reg ( DM365_EMAC_COL ) ;
davinci_cfg_reg ( DM365_EMAC_TXD3 ) ;
davinci_cfg_reg ( DM365_EMAC_TXD2 ) ;
davinci_cfg_reg ( DM365_EMAC_TXD1 ) ;
davinci_cfg_reg ( DM365_EMAC_TXD0 ) ;
davinci_cfg_reg ( DM365_EMAC_RXD3 ) ;
davinci_cfg_reg ( DM365_EMAC_RXD2 ) ;
davinci_cfg_reg ( DM365_EMAC_RXD1 ) ;
davinci_cfg_reg ( DM365_EMAC_RXD0 ) ;
davinci_cfg_reg ( DM365_EMAC_RX_CLK ) ;
davinci_cfg_reg ( DM365_EMAC_RX_DV ) ;
davinci_cfg_reg ( DM365_EMAC_RX_ER ) ;
davinci_cfg_reg ( DM365_EMAC_CRS ) ;
davinci_cfg_reg ( DM365_EMAC_MDIO ) ;
davinci_cfg_reg ( DM365_EMAC_MDCLK ) ;
/*
* EMAC interrupts are multiplexed with GPIO interrupts
* Details are available at the DM365 ARM
* Subsystem Users Guide ( sprufg5 . pdf ) pages 133 - 134
*/
davinci_cfg_reg ( DM365_INT_EMAC_RXTHRESH ) ;
davinci_cfg_reg ( DM365_INT_EMAC_RXPULSE ) ;
davinci_cfg_reg ( DM365_INT_EMAC_TXPULSE ) ;
davinci_cfg_reg ( DM365_INT_EMAC_MISCPULSE ) ;
}
2009-06-20 22:00:52 +04:00
static void dm365evm_mmc_configure ( void )
{
/*
* MMC / SD pins are multiplexed with GPIO and EMIF
* Further details are available at the DM365 ARM
* Subsystem Users Guide ( sprufg5 . pdf ) pages 118 , 128 - 131
*/
davinci_cfg_reg ( DM365_SD1_CLK ) ;
davinci_cfg_reg ( DM365_SD1_CMD ) ;
davinci_cfg_reg ( DM365_SD1_DATA3 ) ;
davinci_cfg_reg ( DM365_SD1_DATA2 ) ;
davinci_cfg_reg ( DM365_SD1_DATA1 ) ;
davinci_cfg_reg ( DM365_SD1_DATA0 ) ;
}
2009-06-10 00:28:15 +04:00
static void __init evm_init_i2c ( void )
{
davinci_init_i2c ( & i2c_pdata ) ;
2009-06-20 20:23:39 +04:00
i2c_register_board_info ( 1 , i2c_info , ARRAY_SIZE ( i2c_info ) ) ;
2009-06-10 00:28:15 +04:00
}
2009-06-22 01:50:12 +04:00
static struct platform_device * dm365_evm_nand_devices [ ] __initdata = {
2009-06-20 22:15:51 +04:00
& davinci_nand_device ,
} ;
2009-06-22 01:50:12 +04:00
static inline int have_leds ( void )
{
# ifdef CONFIG_LEDS_CLASS
return 1 ;
# else
return 0 ;
# endif
}
struct cpld_led {
struct led_classdev cdev ;
u8 mask ;
} ;
static const struct {
const char * name ;
const char * trigger ;
} cpld_leds [ ] = {
{ " dm365evm::ds2 " , } ,
{ " dm365evm::ds3 " , } ,
{ " dm365evm::ds4 " , } ,
{ " dm365evm::ds5 " , } ,
{ " dm365evm::ds6 " , " nand-disk " , } ,
{ " dm365evm::ds7 " , " mmc1 " , } ,
{ " dm365evm::ds8 " , " mmc0 " , } ,
{ " dm365evm::ds9 " , " heartbeat " , } ,
} ;
static void cpld_led_set ( struct led_classdev * cdev , enum led_brightness b )
{
struct cpld_led * led = container_of ( cdev , struct cpld_led , cdev ) ;
u8 reg = __raw_readb ( cpld + CPLD_LEDS ) ;
if ( b ! = LED_OFF )
reg & = ~ led - > mask ;
else
reg | = led - > mask ;
__raw_writeb ( reg , cpld + CPLD_LEDS ) ;
}
static enum led_brightness cpld_led_get ( struct led_classdev * cdev )
{
struct cpld_led * led = container_of ( cdev , struct cpld_led , cdev ) ;
u8 reg = __raw_readb ( cpld + CPLD_LEDS ) ;
return ( reg & led - > mask ) ? LED_OFF : LED_FULL ;
}
static int __init cpld_leds_init ( void )
{
int i ;
if ( ! have_leds ( ) | | ! cpld )
return 0 ;
/* setup LEDs */
__raw_writeb ( 0xff , cpld + CPLD_LEDS ) ;
for ( i = 0 ; i < ARRAY_SIZE ( cpld_leds ) ; i + + ) {
struct cpld_led * led ;
led = kzalloc ( sizeof ( * led ) , GFP_KERNEL ) ;
if ( ! led )
break ;
led - > cdev . name = cpld_leds [ i ] . name ;
led - > cdev . brightness_set = cpld_led_set ;
led - > cdev . brightness_get = cpld_led_get ;
led - > cdev . default_trigger = cpld_leds [ i ] . trigger ;
led - > mask = BIT ( i ) ;
if ( led_classdev_register ( NULL , & led - > cdev ) < 0 ) {
kfree ( led ) ;
break ;
}
}
return 0 ;
}
/* run after subsys_initcall() for LEDs */
fs_initcall ( cpld_leds_init ) ;
static void __init evm_init_cpld ( void )
{
u8 mux , resets ;
const char * label ;
struct clk * aemif_clk ;
/* Make sure we can configure the CPLD through CS1. Then
* leave it on for later access to MMC and LED registers .
*/
aemif_clk = clk_get ( NULL , " aemif " ) ;
if ( IS_ERR ( aemif_clk ) )
return ;
clk_enable ( aemif_clk ) ;
if ( request_mem_region ( DM365_ASYNC_EMIF_DATA_CE1_BASE , SECTION_SIZE ,
" cpld " ) = = NULL )
goto fail ;
cpld = ioremap ( DM365_ASYNC_EMIF_DATA_CE1_BASE , SECTION_SIZE ) ;
if ( ! cpld ) {
release_mem_region ( DM365_ASYNC_EMIF_DATA_CE1_BASE ,
SECTION_SIZE ) ;
fail :
pr_err ( " ERROR: can't map CPLD \n " ) ;
clk_disable ( aemif_clk ) ;
return ;
}
/* External muxing for some signals */
mux = 0 ;
/* Read SW5 to set up NAND + keypad _or_ OneNAND (sync read).
* NOTE : SW4 bus width setting must match !
*/
if ( ( __raw_readb ( cpld + CPLD_SWITCH ) & BIT ( 5 ) ) = = 0 ) {
/* external keypad mux */
mux | = BIT ( 7 ) ;
platform_add_devices ( dm365_evm_nand_devices ,
ARRAY_SIZE ( dm365_evm_nand_devices ) ) ;
} else {
/* no OneNAND support yet */
}
/* Leave external chips in reset when unused. */
resets = BIT ( 3 ) | BIT ( 2 ) | BIT ( 1 ) | BIT ( 0 ) ;
/* Static video input config with SN74CBT16214 1-of-3 mux:
* - port b1 = = tvp7002 ( mux lowbits = = 1 or 6 )
* - port b2 = = imager ( mux lowbits = = 2 or 7 )
* - port b3 = = tvp5146 ( mux lowbits = = 5 )
*
* Runtime switching could work too , with limitations .
*/
if ( have_imager ( ) ) {
label = " HD imager " ;
mux | = 1 ;
/* externally mux MMC1/ENET/AIC33 to imager */
mux | = BIT ( 6 ) | BIT ( 5 ) | BIT ( 3 ) ;
} else {
struct davinci_soc_info * soc_info = & davinci_soc_info ;
/* we can use MMC1 ... */
dm365evm_mmc_configure ( ) ;
davinci_setup_mmc ( 1 , & dm365evm_mmc_config ) ;
/* ... and ENET ... */
dm365evm_emac_configure ( ) ;
soc_info - > emac_pdata - > phy_mask = DM365_EVM_PHY_MASK ;
soc_info - > emac_pdata - > mdio_max_freq = DM365_EVM_MDIO_FREQUENCY ;
resets & = ~ BIT ( 3 ) ;
/* ... and AIC33 */
resets & = ~ BIT ( 1 ) ;
if ( have_tvp7002 ( ) ) {
mux | = 2 ;
resets & = ~ BIT ( 2 ) ;
label = " tvp7002 HD " ;
} else {
/* default to tvp5146 */
mux | = 5 ;
resets & = ~ BIT ( 0 ) ;
label = " tvp5146 SD " ;
}
}
__raw_writeb ( mux , cpld + CPLD_MUX ) ;
__raw_writeb ( resets , cpld + CPLD_RESETS ) ;
pr_info ( " EVM: %s video input \n " , label ) ;
/* REVISIT export switches: NTSC/PAL (SW5.6), EXTRA1 (SW5.2), etc */
}
2009-06-10 00:28:15 +04:00
static struct davinci_uart_config uart_config __initdata = {
. enabled_uarts = ( 1 < < 0 ) ,
} ;
static void __init dm365_evm_map_io ( void )
{
dm365_init ( ) ;
}
static __init void dm365_evm_init ( void )
{
evm_init_i2c ( ) ;
davinci_serial_init ( & uart_config ) ;
2009-06-20 20:23:39 +04:00
dm365evm_emac_configure ( ) ;
2009-06-20 22:00:52 +04:00
dm365evm_mmc_configure ( ) ;
davinci_setup_mmc ( 0 , & dm365evm_mmc_config ) ;
2009-06-20 20:23:39 +04:00
2009-06-22 01:50:12 +04:00
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld ( ) ;
2009-09-03 01:33:29 +04:00
dm365_init_asp ( & dm365_evm_snd_data ) ;
2009-11-05 17:52:05 +03:00
dm365_init_rtc ( ) ;
2009-10-13 23:57:07 +04:00
# ifdef CONFIG_KEYBOARD_DAVINCI
dm365_init_ks ( & dm365evm_ks_data ) ;
# endif
2009-06-10 00:28:15 +04:00
}
static __init void dm365_evm_irq_init ( void )
{
davinci_irq_init ( ) ;
}
MACHINE_START ( DAVINCI_DM365_EVM , " DaVinci DM365 EVM " )
. phys_io = IO_PHYS ,
. io_pg_offst = ( __IO_ADDRESS ( IO_PHYS ) > > 18 ) & 0xfffc ,
. boot_params = ( 0x80000100 ) ,
. map_io = dm365_evm_map_io ,
. init_irq = dm365_evm_irq_init ,
. timer = & davinci_timer ,
. init_machine = dm365_evm_init ,
MACHINE_END