2008-07-16 19:12:25 +04:00
/*
* RouterBoard 500 Platform devices
*
* Copyright ( C ) 2006 Felix Fietkau < nbd @ openwrt . org >
* Copyright ( C ) 2007 Florian Fainelli < florian @ openwrt . org >
*
* 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 .
*/
# include <linux/kernel.h>
2012-02-29 04:24:46 +04:00
# include <linux/export.h>
2008-07-16 19:12:25 +04:00
# include <linux/init.h>
# include <linux/ctype.h>
# include <linux/string.h>
# include <linux/platform_device.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/partitions.h>
2015-08-02 19:30:11 +03:00
# include <linux/gpio.h>
2008-07-16 19:12:25 +04:00
# include <linux/gpio_keys.h>
# include <linux/input.h>
2009-01-15 17:38:38 +03:00
# include <linux/serial_8250.h>
2008-07-16 19:12:25 +04:00
# include <asm/bootinfo.h>
# include <asm/mach-rc32434/rc32434.h>
# include <asm/mach-rc32434/dma.h>
# include <asm/mach-rc32434/dma_v.h>
# include <asm/mach-rc32434/eth.h>
# include <asm/mach-rc32434/rb.h>
# include <asm/mach-rc32434/integ.h>
# include <asm/mach-rc32434/gpio.h>
2008-08-22 19:00:22 +04:00
# include <asm/mach-rc32434/irq.h>
2008-07-16 19:12:25 +04:00
# define ETH0_RX_DMA_ADDR (DMA0_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
# define ETH0_TX_DMA_ADDR (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
2009-01-15 17:38:38 +03:00
extern unsigned int idt_cpu_freq ;
2009-01-20 01:42:52 +03:00
static struct mpmc_device dev3 ;
void set_latch_u5 ( unsigned char or_mask , unsigned char nand_mask )
{
unsigned long flags ;
spin_lock_irqsave ( & dev3 . lock , flags ) ;
dev3 . state = ( dev3 . state | or_mask ) & ~ nand_mask ;
writeb ( dev3 . state , dev3 . base ) ;
spin_unlock_irqrestore ( & dev3 . lock , flags ) ;
}
EXPORT_SYMBOL ( set_latch_u5 ) ;
unsigned char get_latch_u5 ( void )
{
return dev3 . state ;
}
EXPORT_SYMBOL ( get_latch_u5 ) ;
2008-07-16 19:12:25 +04:00
static struct resource korina_dev0_res [ ] = {
{
. name = " korina_regs " ,
. start = ETH0_BASE_ADDR ,
. end = ETH0_BASE_ADDR + sizeof ( struct eth_regs ) ,
. flags = IORESOURCE_MEM ,
} , {
. name = " korina_rx " ,
. start = ETH0_DMA_RX_IRQ ,
. end = ETH0_DMA_RX_IRQ ,
. flags = IORESOURCE_IRQ
} , {
. name = " korina_tx " ,
. start = ETH0_DMA_TX_IRQ ,
. end = ETH0_DMA_TX_IRQ ,
. flags = IORESOURCE_IRQ
} , {
. name = " korina_ovr " ,
. start = ETH0_RX_OVR_IRQ ,
. end = ETH0_RX_OVR_IRQ ,
. flags = IORESOURCE_IRQ
} , {
. name = " korina_und " ,
. start = ETH0_TX_UND_IRQ ,
. end = ETH0_TX_UND_IRQ ,
. flags = IORESOURCE_IRQ
} , {
. name = " korina_dma_rx " ,
. start = ETH0_RX_DMA_ADDR ,
. end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1 ,
. flags = IORESOURCE_MEM ,
} , {
. name = " korina_dma_tx " ,
. start = ETH0_TX_DMA_ADDR ,
. end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1 ,
. flags = IORESOURCE_MEM ,
}
} ;
static struct korina_device korina_dev0_data = {
. name = " korina0 " ,
. mac = { 0xde , 0xca , 0xff , 0xc0 , 0xff , 0xee }
} ;
static struct platform_device korina_dev0 = {
2008-08-22 19:03:03 +04:00
. id = - 1 ,
2008-07-16 19:12:25 +04:00
. name = " korina " ,
. resource = korina_dev0_res ,
. num_resources = ARRAY_SIZE ( korina_dev0_res ) ,
} ;
static struct resource cf_slot0_res [ ] = {
{
. name = " cf_membase " ,
. flags = IORESOURCE_MEM
} , {
. name = " cf_irq " ,
. start = ( 8 + 4 * 32 + CF_GPIO_NUM ) , /* 149 */
. end = ( 8 + 4 * 32 + CF_GPIO_NUM ) ,
. flags = IORESOURCE_IRQ
}
} ;
static struct cf_device cf_slot0_data = {
2008-08-22 19:00:22 +04:00
. gpio_pin = CF_GPIO_NUM
2008-07-16 19:12:25 +04:00
} ;
static struct platform_device cf_slot0 = {
2008-08-22 19:03:03 +04:00
. id = - 1 ,
2008-07-16 19:12:25 +04:00
. name = " pata-rb532-cf " ,
. dev . platform_data = & cf_slot0_data ,
. resource = cf_slot0_res ,
. num_resources = ARRAY_SIZE ( cf_slot0_res ) ,
} ;
/* Resources and device for NAND */
static int rb532_dev_ready ( struct mtd_info * mtd )
{
2008-10-31 16:24:29 +03:00
return gpio_get_value ( GPIO_RDY ) ;
2008-07-16 19:12:25 +04:00
}
static void rb532_cmd_ctrl ( struct mtd_info * mtd , int cmd , unsigned int ctrl )
{
struct nand_chip * chip = mtd - > priv ;
unsigned char orbits , nandbits ;
if ( ctrl & NAND_CTRL_CHANGE ) {
orbits = ( ctrl & NAND_CLE ) < < 1 ;
orbits | = ( ctrl & NAND_ALE ) > > 1 ;
nandbits = ( ~ ctrl & NAND_CLE ) < < 1 ;
nandbits | = ( ~ ctrl & NAND_ALE ) > > 1 ;
set_latch_u5 ( orbits , nandbits ) ;
}
if ( cmd ! = NAND_CMD_NONE )
writeb ( cmd , chip - > IO_ADDR_W ) ;
}
static struct resource nand_slot0_res [ ] = {
[ 0 ] = {
. name = " nand_membase " ,
. flags = IORESOURCE_MEM
}
} ;
static struct platform_nand_data rb532_nand_data = {
. ctrl . dev_ready = rb532_dev_ready ,
. ctrl . cmd_ctrl = rb532_cmd_ctrl ,
} ;
static struct platform_device nand_slot0 = {
. name = " gen_nand " ,
. id = - 1 ,
. resource = nand_slot0_res ,
. num_resources = ARRAY_SIZE ( nand_slot0_res ) ,
. dev . platform_data = & rb532_nand_data ,
} ;
static struct mtd_partition rb532_partition_info [ ] = {
{
. name = " Routerboard NAND boot " ,
. offset = 0 ,
. size = 4 * 1024 * 1024 ,
} , {
. name = " rootfs " ,
. offset = MTDPART_OFS_NXTBLK ,
. size = MTDPART_SIZ_FULL ,
}
} ;
static struct platform_device rb532_led = {
. name = " rb532-led " ,
2008-08-22 19:03:03 +04:00
. id = - 1 ,
2008-07-16 19:12:25 +04:00
} ;
static struct platform_device rb532_button = {
2009-03-05 10:27:15 +03:00
. name = " rb532-button " ,
2008-07-16 19:12:25 +04:00
. id = - 1 ,
} ;
static struct resource rb532_wdt_res [ ] = {
{
. name = " rb532_wdt_res " ,
. start = INTEG0_BASE_ADDR ,
. end = INTEG0_BASE_ADDR + sizeof ( struct integ ) ,
. flags = IORESOURCE_MEM ,
}
} ;
static struct platform_device rb532_wdt = {
2013-01-22 15:59:30 +04:00
. name = " rc32434_wdt " ,
. id = - 1 ,
. resource = rb532_wdt_res ,
2008-07-16 19:12:25 +04:00
. num_resources = ARRAY_SIZE ( rb532_wdt_res ) ,
} ;
2009-01-15 17:38:38 +03:00
static struct plat_serial8250_port rb532_uart_res [ ] = {
{
2014-07-03 18:17:53 +04:00
. type = PORT_16550A ,
2009-01-15 17:38:38 +03:00
. membase = ( char * ) KSEG1ADDR ( REGBASE + UART0BASE ) ,
. irq = UART0_IRQ ,
. regshift = 2 ,
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
} ,
{
. flags = 0 ,
}
} ;
static struct platform_device rb532_uart = {
2013-01-22 15:59:30 +04:00
. name = " serial8250 " ,
. id = PLAT8250_DEV_PLATFORM ,
2009-01-15 17:38:38 +03:00
. dev . platform_data = & rb532_uart_res ,
} ;
2008-07-16 19:12:25 +04:00
static struct platform_device * rb532_devs [ ] = {
& korina_dev0 ,
& nand_slot0 ,
& cf_slot0 ,
& rb532_led ,
& rb532_button ,
2009-01-15 17:38:38 +03:00
& rb532_uart ,
2008-07-16 19:12:25 +04:00
& rb532_wdt
} ;
/* NAND definitions */
2013-01-22 15:59:30 +04:00
# define NAND_CHIP_DELAY 25
2008-07-16 19:12:25 +04:00
static void __init rb532_nand_setup ( void )
{
switch ( mips_machtype ) {
case MACH_MIKROTIK_RB532A :
set_latch_u5 ( LO_FOFF | LO_CEX ,
LO_ULED | LO_ALE | LO_CLE | LO_WPX ) ;
break ;
default :
set_latch_u5 ( LO_WPX | LO_FOFF | LO_CEX ,
LO_ULED | LO_ALE | LO_CLE ) ;
break ;
}
/* Setup NAND specific settings */
rb532_nand_data . chip . nr_chips = 1 ;
rb532_nand_data . chip . nr_partitions = ARRAY_SIZE ( rb532_partition_info ) ;
rb532_nand_data . chip . partitions = rb532_partition_info ;
rb532_nand_data . chip . chip_delay = NAND_CHIP_DELAY ;
}
static int __init plat_setup_devices ( void )
{
/* Look for the CF card reader */
2008-08-06 00:24:18 +04:00
if ( ! readl ( IDT434_REG_BASE + DEV1MASK ) )
2008-10-27 04:29:57 +03:00
rb532_devs [ 2 ] = NULL ; /* disable cf_slot0 at index 2 */
2008-07-16 19:12:25 +04:00
else {
cf_slot0_res [ 0 ] . start =
2008-08-06 00:24:18 +04:00
readl ( IDT434_REG_BASE + DEV1BASE ) ;
2008-07-16 19:12:25 +04:00
cf_slot0_res [ 0 ] . end = cf_slot0_res [ 0 ] . start + 0x1000 ;
}
/* Read the NAND resources from the device controller */
2008-08-06 00:24:18 +04:00
nand_slot0_res [ 0 ] . start = readl ( IDT434_REG_BASE + DEV2BASE ) ;
2008-07-16 19:12:25 +04:00
nand_slot0_res [ 0 ] . end = nand_slot0_res [ 0 ] . start + 0x1000 ;
2009-01-20 01:42:54 +03:00
/* Read and map device controller 3 */
dev3 . base = ioremap_nocache ( readl ( IDT434_REG_BASE + DEV3BASE ) , 1 ) ;
2009-01-20 01:42:52 +03:00
if ( ! dev3 . base ) {
printk ( KERN_ERR " rb532: cannot remap device controller 3 \n " ) ;
return - ENXIO ;
}
2008-07-16 19:12:25 +04:00
/* Initialise the NAND device */
rb532_nand_setup ( ) ;
2009-01-15 17:38:38 +03:00
/* set the uart clock to the current cpu frequency */
rb532_uart_res [ 0 ] . uartclk = idt_cpu_freq ;
2009-12-02 15:07:01 +03:00
dev_set_drvdata ( & korina_dev0 . dev , & korina_dev0_data ) ;
2008-07-16 19:12:25 +04:00
return platform_add_devices ( rb532_devs , ARRAY_SIZE ( rb532_devs ) ) ;
}
static int __init setup_kmac ( char * s )
{
printk ( KERN_INFO " korina mac = %s \n " , s ) ;
2014-06-24 15:14:26 +04:00
if ( ! mac_pton ( s , korina_dev0_data . mac ) ) {
printk ( KERN_ERR " Invalid mac \n " ) ;
return - EINVAL ;
}
2008-07-16 19:12:25 +04:00
return 0 ;
}
__setup ( " kmac= " , setup_kmac ) ;
arch_initcall ( plat_setup_devices ) ;