2007-05-12 04:55:53 +04:00
/*
* Platform device setup for Marvell mv64360 / mv64460 host bridges ( Discovery )
*
* Author : Dale Farnsworth < dale @ farnsworth . org >
*
* 2007 ( c ) MontaVista , Software , Inc . This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed " as is " without any warranty of any kind , whether express
* or implied .
*/
# include <linux/stddef.h>
# include <linux/kernel.h>
# include <linux/init.h>
2007-06-07 04:38:00 +04:00
# include <linux/console.h>
2007-05-12 04:55:53 +04:00
# include <linux/mv643xx.h>
# include <linux/platform_device.h>
2008-05-01 04:40:44 +04:00
# include <linux/of_platform.h>
2010-10-27 02:07:13 +04:00
# include <linux/of_net.h>
2010-02-03 08:08:17 +03:00
# include <linux/dma-mapping.h>
2007-05-12 04:55:53 +04:00
# include <asm/prom.h>
2010-06-08 17:48:21 +04:00
/* These functions provide the necessary setup for the mv64x60 drivers. */
2007-05-12 04:55:53 +04:00
2008-05-01 04:40:44 +04:00
static struct of_device_id __initdata of_mv64x60_devices [ ] = {
{ . compatible = " marvell,mv64306-devctrl " , } ,
{ }
} ;
2007-05-12 04:55:53 +04:00
/*
* Create MPSC platform devices
*/
static int __init mv64x60_mpsc_register_shared_pdev ( struct device_node * np )
{
struct platform_device * pdev ;
struct resource r [ 2 ] ;
struct mpsc_shared_pdata pdata ;
const phandle * ph ;
struct device_node * mpscrouting , * mpscintr ;
int err ;
ph = of_get_property ( np , " mpscrouting " , NULL ) ;
mpscrouting = of_find_node_by_phandle ( * ph ) ;
if ( ! mpscrouting )
return - ENODEV ;
err = of_address_to_resource ( mpscrouting , 0 , & r [ 0 ] ) ;
of_node_put ( mpscrouting ) ;
if ( err )
return err ;
ph = of_get_property ( np , " mpscintr " , NULL ) ;
mpscintr = of_find_node_by_phandle ( * ph ) ;
if ( ! mpscintr )
return - ENODEV ;
err = of_address_to_resource ( mpscintr , 0 , & r [ 1 ] ) ;
of_node_put ( mpscintr ) ;
if ( err )
return err ;
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
pdev = platform_device_alloc ( MPSC_SHARED_NAME , 0 ) ;
if ( ! pdev )
return - ENOMEM ;
err = platform_device_add_resources ( pdev , r , 2 ) ;
if ( err )
goto error ;
err = platform_device_add_data ( pdev , & pdata , sizeof ( pdata ) ) ;
if ( err )
goto error ;
err = platform_device_add ( pdev ) ;
if ( err )
goto error ;
return 0 ;
error :
platform_device_put ( pdev ) ;
return err ;
}
static int __init mv64x60_mpsc_device_setup ( struct device_node * np , int id )
{
struct resource r [ 5 ] ;
struct mpsc_pdata pdata ;
struct platform_device * pdev ;
const unsigned int * prop ;
const phandle * ph ;
struct device_node * sdma , * brg ;
int err ;
int port_number ;
/* only register the shared platform device the first time through */
if ( id = = 0 & & ( err = mv64x60_mpsc_register_shared_pdev ( np ) ) )
return err ;
memset ( r , 0 , sizeof ( r ) ) ;
err = of_address_to_resource ( np , 0 , & r [ 0 ] ) ;
if ( err )
return err ;
of_irq_to_resource ( np , 0 , & r [ 4 ] ) ;
ph = of_get_property ( np , " sdma " , NULL ) ;
sdma = of_find_node_by_phandle ( * ph ) ;
if ( ! sdma )
return - ENODEV ;
of_irq_to_resource ( sdma , 0 , & r [ 3 ] ) ;
err = of_address_to_resource ( sdma , 0 , & r [ 1 ] ) ;
of_node_put ( sdma ) ;
if ( err )
return err ;
ph = of_get_property ( np , " brg " , NULL ) ;
brg = of_find_node_by_phandle ( * ph ) ;
if ( ! brg )
return - ENODEV ;
err = of_address_to_resource ( brg , 0 , & r [ 2 ] ) ;
of_node_put ( brg ) ;
if ( err )
return err ;
2008-04-08 02:10:34 +04:00
prop = of_get_property ( np , " cell-index " , NULL ) ;
2007-05-12 04:55:53 +04:00
if ( ! prop )
return - ENODEV ;
port_number = * ( int * ) prop ;
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
pdata . cache_mgmt = 1 ; /* All current revs need this set */
2008-04-08 02:10:34 +04:00
pdata . max_idle = 40 ; /* default */
2007-05-12 04:55:53 +04:00
prop = of_get_property ( np , " max_idle " , NULL ) ;
if ( prop )
pdata . max_idle = * prop ;
prop = of_get_property ( brg , " current-speed " , NULL ) ;
if ( prop )
pdata . default_baud = * prop ;
/* Default is 8 bits, no parity, no flow control */
pdata . default_bits = 8 ;
pdata . default_parity = ' n ' ;
pdata . default_flow = ' n ' ;
prop = of_get_property ( np , " chr_1 " , NULL ) ;
if ( prop )
pdata . chr_1_val = * prop ;
prop = of_get_property ( np , " chr_2 " , NULL ) ;
if ( prop )
pdata . chr_2_val = * prop ;
prop = of_get_property ( np , " chr_10 " , NULL ) ;
if ( prop )
pdata . chr_10_val = * prop ;
prop = of_get_property ( np , " mpcr " , NULL ) ;
if ( prop )
pdata . mpcr_val = * prop ;
prop = of_get_property ( brg , " bcr " , NULL ) ;
if ( prop )
pdata . bcr_val = * prop ;
pdata . brg_can_tune = 1 ; /* All current revs need this set */
prop = of_get_property ( brg , " clock-src " , NULL ) ;
if ( prop )
pdata . brg_clk_src = * prop ;
prop = of_get_property ( brg , " clock-frequency " , NULL ) ;
if ( prop )
pdata . brg_clk_freq = * prop ;
pdev = platform_device_alloc ( MPSC_CTLR_NAME , port_number ) ;
if ( ! pdev )
return - ENOMEM ;
2010-02-03 08:08:17 +03:00
pdev - > dev . coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
2007-05-12 04:55:53 +04:00
err = platform_device_add_resources ( pdev , r , 5 ) ;
if ( err )
goto error ;
err = platform_device_add_data ( pdev , & pdata , sizeof ( pdata ) ) ;
if ( err )
goto error ;
err = platform_device_add ( pdev ) ;
if ( err )
goto error ;
return 0 ;
error :
platform_device_put ( pdev ) ;
return err ;
}
2007-05-12 04:56:24 +04:00
/*
* Create mv64x60_eth platform devices
*/
2008-04-08 02:11:27 +04:00
static struct platform_device * __init mv64x60_eth_register_shared_pdev (
struct device_node * np , int id )
2007-05-12 04:56:24 +04:00
{
struct platform_device * pdev ;
2013-03-22 07:39:28 +04:00
struct resource r [ 2 ] ;
2007-05-12 04:56:24 +04:00
int err ;
err = of_address_to_resource ( np , 0 , & r [ 0 ] ) ;
if ( err )
2008-04-08 02:11:27 +04:00
return ERR_PTR ( err ) ;
2007-05-12 04:56:24 +04:00
2013-03-22 07:39:28 +04:00
/* register an orion mdio bus driver */
r [ 1 ] . start = r [ 0 ] . start + 0x4 ;
r [ 1 ] . end = r [ 0 ] . start + 0x84 - 1 ;
r [ 1 ] . flags = IORESOURCE_MEM ;
if ( id = = 0 ) {
pdev = platform_device_register_simple ( " orion-mdio " , - 1 , & r [ 1 ] , 1 ) ;
2013-10-25 13:30:24 +04:00
if ( IS_ERR ( pdev ) )
2013-03-22 07:39:28 +04:00
return pdev ;
}
2008-04-08 02:11:27 +04:00
pdev = platform_device_register_simple ( MV643XX_ETH_SHARED_NAME , id ,
2013-03-22 07:39:28 +04:00
& r [ 0 ] , 1 ) ;
2008-04-08 02:11:27 +04:00
return pdev ;
2007-05-12 04:56:24 +04:00
}
2008-04-08 02:11:27 +04:00
static int __init mv64x60_eth_device_setup ( struct device_node * np , int id ,
struct platform_device * shared_pdev )
2007-05-12 04:56:24 +04:00
{
struct resource r [ 1 ] ;
struct mv643xx_eth_platform_data pdata ;
struct platform_device * pdev ;
struct device_node * phy ;
const u8 * mac_addr ;
const int * prop ;
const phandle * ph ;
int err ;
memset ( r , 0 , sizeof ( r ) ) ;
of_irq_to_resource ( np , 0 , & r [ 0 ] ) ;
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
2008-04-24 03:27:02 +04:00
pdata . shared = shared_pdev ;
2008-04-08 02:11:27 +04:00
prop = of_get_property ( np , " reg " , NULL ) ;
2007-05-12 04:56:24 +04:00
if ( ! prop )
return - ENODEV ;
pdata . port_number = * prop ;
mac_addr = of_get_mac_address ( np ) ;
if ( mac_addr )
memcpy ( pdata . mac_addr , mac_addr , 6 ) ;
prop = of_get_property ( np , " speed " , NULL ) ;
if ( prop )
pdata . speed = * prop ;
prop = of_get_property ( np , " tx_queue_size " , NULL ) ;
if ( prop )
pdata . tx_queue_size = * prop ;
prop = of_get_property ( np , " rx_queue_size " , NULL ) ;
if ( prop )
pdata . rx_queue_size = * prop ;
prop = of_get_property ( np , " tx_sram_addr " , NULL ) ;
if ( prop )
pdata . tx_sram_addr = * prop ;
prop = of_get_property ( np , " tx_sram_size " , NULL ) ;
if ( prop )
pdata . tx_sram_size = * prop ;
prop = of_get_property ( np , " rx_sram_addr " , NULL ) ;
if ( prop )
pdata . rx_sram_addr = * prop ;
prop = of_get_property ( np , " rx_sram_size " , NULL ) ;
if ( prop )
pdata . rx_sram_size = * prop ;
ph = of_get_property ( np , " phy " , NULL ) ;
if ( ! ph )
return - ENODEV ;
phy = of_find_node_by_phandle ( * ph ) ;
if ( phy = = NULL )
return - ENODEV ;
prop = of_get_property ( phy , " reg " , NULL ) ;
2008-08-26 16:06:47 +04:00
if ( prop )
pdata . phy_addr = MV643XX_ETH_PHY_ADDR ( * prop ) ;
2007-05-12 04:56:24 +04:00
of_node_put ( phy ) ;
2008-04-08 02:11:27 +04:00
pdev = platform_device_alloc ( MV643XX_ETH_NAME , id ) ;
2007-05-12 04:56:24 +04:00
if ( ! pdev )
return - ENOMEM ;
2010-02-03 08:08:17 +03:00
pdev - > dev . coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
2007-05-12 04:56:24 +04:00
err = platform_device_add_resources ( pdev , r , 1 ) ;
if ( err )
goto error ;
err = platform_device_add_data ( pdev , & pdata , sizeof ( pdata ) ) ;
if ( err )
goto error ;
err = platform_device_add ( pdev ) ;
if ( err )
goto error ;
return 0 ;
error :
platform_device_put ( pdev ) ;
return err ;
}
2007-05-12 04:56:47 +04:00
/*
* Create mv64x60_i2c platform devices
*/
static int __init mv64x60_i2c_device_setup ( struct device_node * np , int id )
{
struct resource r [ 2 ] ;
struct platform_device * pdev ;
struct mv64xxx_i2c_pdata pdata ;
const unsigned int * prop ;
int err ;
memset ( r , 0 , sizeof ( r ) ) ;
err = of_address_to_resource ( np , 0 , & r [ 0 ] ) ;
if ( err )
return err ;
of_irq_to_resource ( np , 0 , & r [ 1 ] ) ;
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
2008-04-08 02:10:34 +04:00
pdata . freq_m = 8 ; /* default */
2007-05-12 04:56:47 +04:00
prop = of_get_property ( np , " freq_m " , NULL ) ;
2008-04-21 21:36:48 +04:00
if ( prop )
pdata . freq_m = * prop ;
2007-05-12 04:56:47 +04:00
2010-10-22 06:58:53 +04:00
pdata . freq_n = 3 ; /* default */
2007-05-12 04:56:47 +04:00
prop = of_get_property ( np , " freq_n " , NULL ) ;
2008-04-21 21:36:48 +04:00
if ( prop )
pdata . freq_n = * prop ;
2007-05-12 04:56:47 +04:00
2008-04-08 02:10:34 +04:00
pdata . timeout = 1000 ; /* default: 1 second */
2007-05-12 04:56:47 +04:00
pdev = platform_device_alloc ( MV64XXX_I2C_CTLR_NAME , id ) ;
if ( ! pdev )
return - ENOMEM ;
err = platform_device_add_resources ( pdev , r , 2 ) ;
if ( err )
goto error ;
err = platform_device_add_data ( pdev , & pdata , sizeof ( pdata ) ) ;
if ( err )
goto error ;
err = platform_device_add ( pdev ) ;
if ( err )
goto error ;
return 0 ;
error :
platform_device_put ( pdev ) ;
return err ;
}
2007-07-24 22:12:24 +04:00
/*
* Create mv64x60_wdt platform devices
*/
static int __init mv64x60_wdt_device_setup ( struct device_node * np , int id )
{
struct resource r ;
struct platform_device * pdev ;
struct mv64x60_wdt_pdata pdata ;
const unsigned int * prop ;
int err ;
err = of_address_to_resource ( np , 0 , & r ) ;
if ( err )
return err ;
memset ( & pdata , 0 , sizeof ( pdata ) ) ;
2008-04-08 02:10:34 +04:00
pdata . timeout = 10 ; /* Default: 10 seconds */
2007-07-24 22:12:24 +04:00
np = of_get_parent ( np ) ;
if ( ! np )
return - ENODEV ;
prop = of_get_property ( np , " clock-frequency " , NULL ) ;
of_node_put ( np ) ;
if ( ! prop )
return - ENODEV ;
pdata . bus_clk = * prop / 1000000 ; /* wdt driver wants freq in MHz */
pdev = platform_device_alloc ( MV64x60_WDT_NAME , id ) ;
if ( ! pdev )
return - ENOMEM ;
err = platform_device_add_resources ( pdev , & r , 1 ) ;
if ( err )
goto error ;
err = platform_device_add_data ( pdev , & pdata , sizeof ( pdata ) ) ;
if ( err )
goto error ;
err = platform_device_add ( pdev ) ;
if ( err )
goto error ;
return 0 ;
error :
platform_device_put ( pdev ) ;
return err ;
}
2007-05-12 04:55:53 +04:00
static int __init mv64x60_device_setup ( void )
{
2008-04-08 02:11:27 +04:00
struct device_node * np , * np2 ;
struct platform_device * pdev ;
int id , id2 ;
2007-05-12 04:55:53 +04:00
int err ;
2007-11-29 22:44:36 +03:00
id = 0 ;
2013-12-11 14:48:45 +04:00
for_each_compatible_node ( np , NULL , " marvell,mv64360-mpsc " ) {
2008-04-21 22:46:12 +04:00
err = mv64x60_mpsc_device_setup ( np , id + + ) ;
if ( err )
printk ( KERN_ERR " Failed to initialize MV64x60 "
" serial device %s: error %d. \n " ,
np - > full_name , err ) ;
}
2007-05-12 04:55:53 +04:00
2007-11-29 22:44:36 +03:00
id = 0 ;
2008-04-08 02:11:27 +04:00
id2 = 0 ;
for_each_compatible_node ( np , NULL , " marvell,mv64360-eth-group " ) {
pdev = mv64x60_eth_register_shared_pdev ( np , id + + ) ;
if ( IS_ERR ( pdev ) ) {
err = PTR_ERR ( pdev ) ;
2008-04-21 22:46:12 +04:00
printk ( KERN_ERR " Failed to initialize MV64x60 "
" network block %s: error %d. \n " ,
np - > full_name , err ) ;
continue ;
2008-04-08 02:11:27 +04:00
}
for_each_child_of_node ( np , np2 ) {
if ( ! of_device_is_compatible ( np2 ,
" marvell,mv64360-eth " ) )
continue ;
err = mv64x60_eth_device_setup ( np2 , id2 + + , pdev ) ;
2008-04-21 22:46:12 +04:00
if ( err )
printk ( KERN_ERR " Failed to initialize "
" MV64x60 network device %s: "
" error %d. \n " ,
np2 - > full_name , err ) ;
2008-04-08 02:11:27 +04:00
}
}
2007-05-12 04:56:24 +04:00
2007-11-29 22:44:36 +03:00
id = 0 ;
2008-04-21 22:46:12 +04:00
for_each_compatible_node ( np , " i2c " , " marvell,mv64360-i2c " ) {
err = mv64x60_i2c_device_setup ( np , id + + ) ;
if ( err )
printk ( KERN_ERR " Failed to initialize MV64x60 I2C "
" bus %s: error %d. \n " ,
np - > full_name , err ) ;
}
2007-05-12 04:56:47 +04:00
2007-07-24 22:12:24 +04:00
/* support up to one watchdog timer */
2008-04-08 02:09:03 +04:00
np = of_find_compatible_node ( np , NULL , " marvell,mv64360-wdt " ) ;
2007-07-24 22:12:24 +04:00
if ( np ) {
if ( ( err = mv64x60_wdt_device_setup ( np , id ) ) )
2008-04-21 22:46:12 +04:00
printk ( KERN_ERR " Failed to initialize MV64x60 "
" Watchdog %s: error %d. \n " ,
np - > full_name , err ) ;
2007-07-24 22:12:24 +04:00
of_node_put ( np ) ;
}
2008-05-01 04:40:44 +04:00
/* Now add every node that is on the device bus */
for_each_compatible_node ( np , NULL , " marvell,mv64360 " )
of_platform_bus_probe ( np , of_mv64x60_devices , NULL ) ;
2007-05-12 04:55:53 +04:00
return 0 ;
}
arch_initcall ( mv64x60_device_setup ) ;
2007-06-07 04:38:00 +04:00
static int __init mv64x60_add_mpsc_console ( void )
{
struct device_node * np = NULL ;
const char * prop ;
prop = of_get_property ( of_chosen , " linux,stdout-path " , NULL ) ;
if ( prop = = NULL )
goto not_mpsc ;
np = of_find_node_by_path ( prop ) ;
if ( ! np )
goto not_mpsc ;
2008-04-08 02:09:03 +04:00
if ( ! of_device_is_compatible ( np , " marvell,mv64360-mpsc " ) )
2007-06-07 04:38:00 +04:00
goto not_mpsc ;
2008-04-08 02:10:34 +04:00
prop = of_get_property ( np , " cell-index " , NULL ) ;
2007-06-07 04:38:00 +04:00
if ( ! prop )
goto not_mpsc ;
add_preferred_console ( " ttyMM " , * ( int * ) prop , NULL ) ;
not_mpsc :
return 0 ;
}
console_initcall ( mv64x60_add_mpsc_console ) ;