2012-03-31 21:26:57 +08:00
/*
* Copyright 2012 Freescale Semiconductor , Inc .
* Copyright 2012 Linaro Ltd .
*
* The code contained herein is licensed under the GNU General Public
* License . You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations :
*
* http : //www.opensource.org/licenses/gpl-license.html
* http : //www.gnu.org/copyleft/gpl.html
*/
# include <linux/clk.h>
# include <linux/clkdev.h>
2013-03-25 14:53:08 +08:00
# include <linux/clocksource.h>
2012-08-06 22:00:45 +08:00
# include <linux/can/platform/flexcan.h>
2012-07-13 14:15:34 +08:00
# include <linux/delay.h>
2012-03-31 21:26:57 +08:00
# include <linux/err.h>
2012-07-13 14:15:34 +08:00
# include <linux/gpio.h>
2012-03-31 21:26:57 +08:00
# include <linux/init.h>
2013-03-25 21:34:51 +08:00
# include <linux/irqchip.h>
# include <linux/irqchip/mxs.h>
2012-07-07 23:12:03 +08:00
# include <linux/micrel_phy.h>
2012-06-25 21:21:46 +08:00
# include <linux/mxsfb.h>
2012-03-31 21:26:57 +08:00
# include <linux/of_platform.h>
2012-07-07 23:12:03 +08:00
# include <linux/phy.h>
2012-07-13 14:15:34 +08:00
# include <linux/pinctrl/consumer.h>
2012-03-31 21:26:57 +08:00
# include <asm/mach/arch.h>
# include <asm/mach/time.h>
# include <mach/common.h>
2012-08-01 11:20:16 +08:00
# include <mach/digctl.h>
2012-07-13 14:15:34 +08:00
# include <mach/mxs.h>
2012-03-31 21:26:57 +08:00
2012-06-25 21:21:46 +08:00
static struct fb_videomode mx23evk_video_modes [ ] = {
{
. name = " Samsung-LMS430HF02 " ,
. refresh = 60 ,
. xres = 480 ,
. yres = 272 ,
. pixclock = 108096 , /* picosecond (9.2 MHz) */
. left_margin = 15 ,
. right_margin = 8 ,
. upper_margin = 12 ,
. lower_margin = 4 ,
. hsync_len = 1 ,
. vsync_len = 1 ,
} ,
} ;
static struct fb_videomode mx28evk_video_modes [ ] = {
{
. name = " Seiko-43WVF1G " ,
. refresh = 60 ,
. xres = 800 ,
. yres = 480 ,
. pixclock = 29851 , /* picosecond (33.5 MHz) */
. left_margin = 89 ,
. right_margin = 164 ,
. upper_margin = 23 ,
. lower_margin = 10 ,
. hsync_len = 10 ,
. vsync_len = 10 ,
} ,
} ;
2012-07-07 21:21:38 +08:00
static struct fb_videomode m28evk_video_modes [ ] = {
{
. name = " Ampire AM-800480R2TMQW-T01H " ,
. refresh = 60 ,
. xres = 800 ,
. yres = 480 ,
. pixclock = 30066 , /* picosecond (33.26 MHz) */
. left_margin = 0 ,
. right_margin = 256 ,
. upper_margin = 0 ,
. lower_margin = 45 ,
. hsync_len = 1 ,
. vsync_len = 1 ,
} ,
} ;
2012-07-10 10:08:08 +03:00
static struct fb_videomode apx4devkit_video_modes [ ] = {
{
. name = " HannStar PJ70112A " ,
. refresh = 60 ,
. xres = 800 ,
. yres = 480 ,
. pixclock = 33333 , /* picosecond (30.00 MHz) */
. left_margin = 88 ,
. right_margin = 40 ,
. upper_margin = 32 ,
. lower_margin = 13 ,
. hsync_len = 48 ,
. vsync_len = 3 ,
2013-03-18 19:24:02 +01:00
. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
2012-07-10 10:08:08 +03:00
} ,
} ;
2012-11-02 19:01:48 +01:00
static struct fb_videomode apf28dev_video_modes [ ] = {
{
. name = " LW700 " ,
. refresh = 60 ,
. xres = 800 ,
. yres = 480 ,
. pixclock = 30303 , /* picosecond */
. left_margin = 96 ,
. right_margin = 96 , /* at least 3 & 1 */
. upper_margin = 0x14 ,
. lower_margin = 0x15 ,
. hsync_len = 64 ,
. vsync_len = 4 ,
2013-03-18 19:24:02 +01:00
. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
2012-11-02 19:01:48 +01:00
} ,
} ;
2013-01-25 09:54:07 +01:00
static struct fb_videomode cfa10049_video_modes [ ] = {
{
. name = " Himax HX8357-B " ,
. refresh = 60 ,
. xres = 320 ,
. yres = 480 ,
. pixclock = 108506 , /* picosecond (9.216 MHz) */
. left_margin = 2 ,
. right_margin = 2 ,
. upper_margin = 2 ,
. lower_margin = 2 ,
. hsync_len = 15 ,
. vsync_len = 15 ,
} ,
} ;
2012-06-25 21:21:46 +08:00
static struct mxsfb_platform_data mxsfb_pdata __initdata ;
2012-08-06 22:00:45 +08:00
/*
* MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers
*/
# define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13)
static int flexcan0_en , flexcan1_en ;
static void mx28evk_flexcan_switch ( void )
{
if ( flexcan0_en | | flexcan1_en )
gpio_set_value ( MX28EVK_FLEXCAN_SWITCH , 1 ) ;
else
gpio_set_value ( MX28EVK_FLEXCAN_SWITCH , 0 ) ;
}
static void mx28evk_flexcan0_switch ( int enable )
{
flexcan0_en = enable ;
mx28evk_flexcan_switch ( ) ;
}
static void mx28evk_flexcan1_switch ( int enable )
{
flexcan1_en = enable ;
mx28evk_flexcan_switch ( ) ;
}
static struct flexcan_platform_data flexcan_pdata [ 2 ] ;
2012-06-25 21:21:46 +08:00
static struct of_dev_auxdata mxs_auxdata_lookup [ ] __initdata = {
OF_DEV_AUXDATA ( " fsl,imx23-lcdif " , 0x80030000 , NULL , & mxsfb_pdata ) ,
OF_DEV_AUXDATA ( " fsl,imx28-lcdif " , 0x80030000 , NULL , & mxsfb_pdata ) ,
2012-08-06 22:00:45 +08:00
OF_DEV_AUXDATA ( " fsl,imx28-flexcan " , 0x80032000 , NULL , & flexcan_pdata [ 0 ] ) ,
OF_DEV_AUXDATA ( " fsl,imx28-flexcan " , 0x80034000 , NULL , & flexcan_pdata [ 1 ] ) ,
2012-06-25 21:21:46 +08:00
{ /* sentinel */ }
} ;
2012-05-04 21:33:42 +08:00
static void __init imx23_timer_init ( void )
{
mx23_clocks_init ( ) ;
2013-03-25 14:53:08 +08:00
clocksource_of_init ( ) ;
2012-05-04 21:33:42 +08:00
}
2012-03-31 21:26:57 +08:00
static void __init imx28_timer_init ( void )
{
mx28_clocks_init ( ) ;
2013-03-25 14:53:08 +08:00
clocksource_of_init ( ) ;
2012-03-31 21:26:57 +08:00
}
2012-06-19 22:38:14 +08:00
enum mac_oui {
OUI_FSL ,
OUI_DENX ,
2012-10-07 10:36:28 +08:00
OUI_CRYSTALFONTZ ,
2012-06-19 22:38:14 +08:00
} ;
static void __init update_fec_mac_prop ( enum mac_oui oui )
{
struct device_node * np , * from = NULL ;
2012-07-13 14:13:55 +08:00
struct property * newmac ;
2012-06-19 22:38:14 +08:00
const u32 * ocotp = mxs_get_ocotp ( ) ;
u8 * macaddr ;
u32 val ;
int i ;
for ( i = 0 ; i < 2 ; i + + ) {
np = of_find_compatible_node ( from , NULL , " fsl,imx28-fec " ) ;
if ( ! np )
return ;
2012-09-25 13:32:18 +02:00
2012-06-19 22:38:14 +08:00
from = np ;
2012-09-25 13:32:18 +02:00
if ( of_get_property ( np , " local-mac-address " , NULL ) )
continue ;
2012-06-19 22:38:14 +08:00
newmac = kzalloc ( sizeof ( * newmac ) + 6 , GFP_KERNEL ) ;
if ( ! newmac )
return ;
newmac - > value = newmac + 1 ;
newmac - > length = 6 ;
newmac - > name = kstrdup ( " local-mac-address " , GFP_KERNEL ) ;
if ( ! newmac - > name ) {
kfree ( newmac ) ;
return ;
}
/*
* OCOTP only stores the last 4 octets for each mac address ,
* so hard - code OUI here .
*/
macaddr = newmac - > value ;
switch ( oui ) {
case OUI_FSL :
macaddr [ 0 ] = 0x00 ;
macaddr [ 1 ] = 0x04 ;
macaddr [ 2 ] = 0x9f ;
break ;
case OUI_DENX :
macaddr [ 0 ] = 0xc0 ;
macaddr [ 1 ] = 0xe5 ;
macaddr [ 2 ] = 0x4e ;
break ;
2012-10-07 10:36:28 +08:00
case OUI_CRYSTALFONTZ :
macaddr [ 0 ] = 0x58 ;
macaddr [ 1 ] = 0xb9 ;
macaddr [ 2 ] = 0xe1 ;
break ;
2012-06-19 22:38:14 +08:00
}
val = ocotp [ i ] ;
macaddr [ 3 ] = ( val > > 16 ) & 0xff ;
macaddr [ 4 ] = ( val > > 8 ) & 0xff ;
macaddr [ 5 ] = ( val > > 0 ) & 0xff ;
2012-10-02 16:58:46 +00:00
of_update_property ( np , newmac ) ;
2012-06-19 22:38:14 +08:00
}
}
2012-06-25 21:21:46 +08:00
static void __init imx23_evk_init ( void )
{
mxsfb_pdata . mode_list = mx23evk_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( mx23evk_video_modes ) ;
mxsfb_pdata . default_bpp = 32 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_24BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
MXSFB_SYNC_DOTCLK_FAILING_ACT ;
2012-06-25 21:21:46 +08:00
}
2012-07-07 21:21:38 +08:00
static inline void enable_clk_enet_out ( void )
2012-03-31 21:26:57 +08:00
{
2012-07-07 21:21:38 +08:00
struct clk * clk = clk_get_sys ( " enet_out " , NULL ) ;
2012-03-31 21:26:57 +08:00
if ( ! IS_ERR ( clk ) )
clk_prepare_enable ( clk ) ;
2012-07-07 21:21:38 +08:00
}
2012-06-19 22:38:14 +08:00
2012-07-07 21:21:38 +08:00
static void __init imx28_evk_init ( void )
{
enable_clk_enet_out ( ) ;
2012-06-19 22:38:14 +08:00
update_fec_mac_prop ( OUI_FSL ) ;
2012-06-25 21:21:46 +08:00
mxsfb_pdata . mode_list = mx28evk_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( mx28evk_video_modes ) ;
mxsfb_pdata . default_bpp = 32 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_24BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
MXSFB_SYNC_DOTCLK_FAILING_ACT ;
2012-08-01 11:20:16 +08:00
mxs_saif_clkmux_select ( MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0 ) ;
2012-03-31 21:26:57 +08:00
}
2012-08-06 22:00:45 +08:00
static void __init imx28_evk_post_init ( void )
2012-07-07 21:21:38 +08:00
{
2012-08-06 22:00:45 +08:00
if ( ! gpio_request_one ( MX28EVK_FLEXCAN_SWITCH , GPIOF_DIR_OUT ,
" flexcan-switch " ) ) {
flexcan_pdata [ 0 ] . transceiver_switch = mx28evk_flexcan0_switch ;
flexcan_pdata [ 1 ] . transceiver_switch = mx28evk_flexcan1_switch ;
}
}
2012-07-07 21:21:38 +08:00
static void __init m28evk_init ( void )
{
mxsfb_pdata . mode_list = m28evk_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( m28evk_video_modes ) ;
mxsfb_pdata . default_bpp = 16 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_18BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT ;
2012-07-07 21:21:38 +08:00
}
2012-11-18 22:08:29 +01:00
static void __init sc_sps1_init ( void )
{
enable_clk_enet_out ( ) ;
}
2012-07-07 23:12:03 +08:00
static int apx4devkit_phy_fixup ( struct phy_device * phy )
{
phy - > dev_flags | = MICREL_PHY_50MHZ_CLK ;
return 0 ;
}
static void __init apx4devkit_init ( void )
{
enable_clk_enet_out ( ) ;
if ( IS_BUILTIN ( CONFIG_PHYLIB ) )
2012-09-23 16:58:50 +00:00
phy_register_fixup_for_uid ( PHY_ID_KSZ8051 , MICREL_PHY_ID_MASK ,
2012-07-07 23:12:03 +08:00
apx4devkit_phy_fixup ) ;
2012-07-10 10:08:08 +03:00
mxsfb_pdata . mode_list = apx4devkit_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( apx4devkit_video_modes ) ;
mxsfb_pdata . default_bpp = 32 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_24BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
MXSFB_SYNC_DOTCLK_FAILING_ACT ;
2012-07-07 23:12:03 +08:00
}
2012-07-13 14:15:34 +08:00
# define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0)
# define ENET0_MDIO__GPIO_4_1 MXS_GPIO_NR(4, 1)
# define ENET0_RX_EN__GPIO_4_2 MXS_GPIO_NR(4, 2)
# define ENET0_RXD0__GPIO_4_3 MXS_GPIO_NR(4, 3)
# define ENET0_RXD1__GPIO_4_4 MXS_GPIO_NR(4, 4)
# define ENET0_TX_EN__GPIO_4_6 MXS_GPIO_NR(4, 6)
# define ENET0_TXD0__GPIO_4_7 MXS_GPIO_NR(4, 7)
# define ENET0_TXD1__GPIO_4_8 MXS_GPIO_NR(4, 8)
# define ENET_CLK__GPIO_4_16 MXS_GPIO_NR(4, 16)
# define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29)
# define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13)
# define TX28_FEC_nINT MXS_GPIO_NR(4, 5)
static const struct gpio tx28_gpios [ ] __initconst = {
{ ENET0_MDC__GPIO_4_0 , GPIOF_OUT_INIT_LOW , " GPIO_4_0 " } ,
{ ENET0_MDIO__GPIO_4_1 , GPIOF_OUT_INIT_LOW , " GPIO_4_1 " } ,
{ ENET0_RX_EN__GPIO_4_2 , GPIOF_OUT_INIT_LOW , " GPIO_4_2 " } ,
{ ENET0_RXD0__GPIO_4_3 , GPIOF_OUT_INIT_LOW , " GPIO_4_3 " } ,
{ ENET0_RXD1__GPIO_4_4 , GPIOF_OUT_INIT_LOW , " GPIO_4_4 " } ,
{ ENET0_TX_EN__GPIO_4_6 , GPIOF_OUT_INIT_LOW , " GPIO_4_6 " } ,
{ ENET0_TXD0__GPIO_4_7 , GPIOF_OUT_INIT_LOW , " GPIO_4_7 " } ,
{ ENET0_TXD1__GPIO_4_8 , GPIOF_OUT_INIT_LOW , " GPIO_4_8 " } ,
{ ENET_CLK__GPIO_4_16 , GPIOF_OUT_INIT_LOW , " GPIO_4_16 " } ,
{ TX28_FEC_PHY_POWER , GPIOF_OUT_INIT_LOW , " fec-phy-power " } ,
{ TX28_FEC_PHY_RESET , GPIOF_OUT_INIT_LOW , " fec-phy-reset " } ,
{ TX28_FEC_nINT , GPIOF_DIR_IN , " fec-int " } ,
} ;
static void __init tx28_post_init ( void )
{
struct device_node * np ;
struct platform_device * pdev ;
struct pinctrl * pctl ;
int ret ;
enable_clk_enet_out ( ) ;
np = of_find_compatible_node ( NULL , NULL , " fsl,imx28-fec " ) ;
pdev = of_find_device_by_node ( np ) ;
if ( ! pdev ) {
pr_err ( " %s: failed to find fec device \n " , __func__ ) ;
return ;
}
pctl = pinctrl_get_select ( & pdev - > dev , " gpio_mode " ) ;
if ( IS_ERR ( pctl ) ) {
pr_err ( " %s: failed to get pinctrl state \n " , __func__ ) ;
return ;
}
ret = gpio_request_array ( tx28_gpios , ARRAY_SIZE ( tx28_gpios ) ) ;
if ( ret ) {
pr_err ( " %s: failed to request gpios: %d \n " , __func__ , ret ) ;
return ;
}
/* Power up fec phy */
gpio_set_value ( TX28_FEC_PHY_POWER , 1 ) ;
msleep ( 26 ) ; /* 25ms according to data sheet */
/* Mode strap pins */
gpio_set_value ( ENET0_RX_EN__GPIO_4_2 , 1 ) ;
gpio_set_value ( ENET0_RXD0__GPIO_4_3 , 1 ) ;
gpio_set_value ( ENET0_RXD1__GPIO_4_4 , 1 ) ;
udelay ( 100 ) ; /* minimum assertion time for nRST */
/* Deasserting FEC PHY RESET */
gpio_set_value ( TX28_FEC_PHY_RESET , 1 ) ;
pinctrl_put ( pctl ) ;
}
2012-10-07 10:36:28 +08:00
static void __init cfa10049_init ( void )
{
enable_clk_enet_out ( ) ;
update_fec_mac_prop ( OUI_CRYSTALFONTZ ) ;
2013-03-05 16:13:35 +01:00
mxsfb_pdata . mode_list = cfa10049_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( cfa10049_video_modes ) ;
mxsfb_pdata . default_bpp = 32 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_18BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT ;
2012-10-07 10:36:28 +08:00
}
2013-01-26 13:40:37 +08:00
static void __init cfa10037_init ( void )
{
enable_clk_enet_out ( ) ;
update_fec_mac_prop ( OUI_CRYSTALFONTZ ) ;
}
2012-10-18 11:50:26 +02:00
static void __init apf28_init ( void )
{
enable_clk_enet_out ( ) ;
2012-11-02 19:01:48 +01:00
mxsfb_pdata . mode_list = apf28dev_video_modes ;
mxsfb_pdata . mode_count = ARRAY_SIZE ( apf28dev_video_modes ) ;
mxsfb_pdata . default_bpp = 16 ;
mxsfb_pdata . ld_intf_width = STMLCDIF_16BIT ;
2013-03-18 19:24:02 +01:00
mxsfb_pdata . sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
MXSFB_SYNC_DOTCLK_FAILING_ACT ;
2012-10-18 11:50:26 +02:00
}
2012-03-31 21:26:57 +08:00
static void __init mxs_machine_init ( void )
{
if ( of_machine_is_compatible ( " fsl,imx28-evk " ) )
imx28_evk_init ( ) ;
2012-06-25 21:21:46 +08:00
else if ( of_machine_is_compatible ( " fsl,imx23-evk " ) )
imx23_evk_init ( ) ;
2012-07-07 21:21:38 +08:00
else if ( of_machine_is_compatible ( " denx,m28evk " ) )
m28evk_init ( ) ;
2012-07-07 23:12:03 +08:00
else if ( of_machine_is_compatible ( " bluegiga,apx4devkit " ) )
apx4devkit_init ( ) ;
2013-01-26 13:40:37 +08:00
else if ( of_machine_is_compatible ( " crystalfontz,cfa10037 " ) )
cfa10037_init ( ) ;
2012-10-07 10:36:28 +08:00
else if ( of_machine_is_compatible ( " crystalfontz,cfa10049 " ) )
cfa10049_init ( ) ;
2012-10-18 11:50:26 +02:00
else if ( of_machine_is_compatible ( " armadeus,imx28-apf28 " ) )
apf28_init ( ) ;
2012-11-18 22:08:29 +01:00
else if ( of_machine_is_compatible ( " schulercontrol,imx28-sps1 " ) )
sc_sps1_init ( ) ;
2012-03-31 21:26:57 +08:00
of_platform_populate ( NULL , of_default_bus_match_table ,
2012-06-25 21:21:46 +08:00
mxs_auxdata_lookup , NULL ) ;
2012-07-13 14:15:34 +08:00
if ( of_machine_is_compatible ( " karo,tx28 " ) )
tx28_post_init ( ) ;
2012-08-06 22:00:45 +08:00
if ( of_machine_is_compatible ( " fsl,imx28-evk " ) )
imx28_evk_post_init ( ) ;
2012-03-31 21:26:57 +08:00
}
2012-05-04 21:33:42 +08:00
static const char * imx23_dt_compat [ ] __initdata = {
" fsl,imx23 " ,
NULL ,
} ;
2012-03-31 21:26:57 +08:00
static const char * imx28_dt_compat [ ] __initdata = {
" fsl,imx28 " ,
NULL ,
} ;
2012-05-04 21:33:42 +08:00
DT_MACHINE_START ( IMX23 , " Freescale i.MX23 (Device Tree) " )
. map_io = mx23_map_io ,
2013-03-25 21:34:51 +08:00
. init_irq = irqchip_init ,
2012-08-20 10:14:56 +08:00
. handle_irq = icoll_handle_irq ,
2012-11-08 12:40:59 -07:00
. init_time = imx23_timer_init ,
2012-05-04 21:33:42 +08:00
. init_machine = mxs_machine_init ,
. dt_compat = imx23_dt_compat ,
. restart = mxs_restart ,
MACHINE_END
2012-03-31 21:26:57 +08:00
DT_MACHINE_START ( IMX28 , " Freescale i.MX28 (Device Tree) " )
. map_io = mx28_map_io ,
2013-03-25 21:34:51 +08:00
. init_irq = irqchip_init ,
2012-08-20 10:14:56 +08:00
. handle_irq = icoll_handle_irq ,
2012-11-08 12:40:59 -07:00
. init_time = imx28_timer_init ,
2012-03-31 21:26:57 +08:00
. init_machine = mxs_machine_init ,
. dt_compat = imx28_dt_compat ,
. restart = mxs_restart ,
MACHINE_END