2011-09-06 11:05:25 +04:00
/*
* Copyright 2011 Freescale Semiconductor , Inc .
* Copyright 2011 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
*/
2012-04-24 10:19:13 +04:00
# include <linux/clk.h>
# include <linux/clkdev.h>
2012-05-22 02:50:30 +04:00
# include <linux/cpuidle.h>
2011-12-09 03:51:26 +04:00
# include <linux/delay.h>
2012-05-22 02:50:30 +04:00
# include <linux/export.h>
2011-09-06 11:05:25 +04:00
# include <linux/init.h>
2011-12-09 03:51:26 +04:00
# include <linux/io.h>
2011-09-06 11:05:25 +04:00
# include <linux/irq.h>
# include <linux/of.h>
2011-12-09 03:51:26 +04:00
# include <linux/of_address.h>
2011-09-06 11:05:25 +04:00
# include <linux/of_irq.h>
# include <linux/of_platform.h>
2011-12-14 05:26:47 +04:00
# include <linux/phy.h>
2012-09-05 06:57:15 +04:00
# include <linux/regmap.h>
2011-12-14 05:26:47 +04:00
# include <linux/micrel_phy.h>
2012-09-05 06:57:15 +04:00
# include <linux/mfd/syscon.h>
2012-05-22 02:50:30 +04:00
# include <asm/cpuidle.h>
2012-01-10 23:44:19 +04:00
# include <asm/smp_twd.h>
2011-09-06 11:05:25 +04:00
# include <asm/hardware/cache-l2x0.h>
# include <asm/hardware/gic.h>
# include <asm/mach/arch.h>
# include <asm/mach/time.h>
2012-03-28 21:30:01 +04:00
# include <asm/system_misc.h>
2011-09-06 11:05:25 +04:00
2012-09-13 17:01:00 +04:00
# include "common.h"
2012-09-13 17:12:50 +04:00
# include "cpuidle.h"
2012-09-14 10:14:45 +04:00
# include "hardware.h"
2012-05-22 02:50:30 +04:00
2011-12-09 03:51:26 +04:00
void imx6q_restart ( char mode , const char * cmd )
{
struct device_node * np ;
void __iomem * wdog_base ;
np = of_find_compatible_node ( NULL , NULL , " fsl,imx6q-wdt " ) ;
wdog_base = of_iomap ( np , 0 ) ;
if ( ! wdog_base )
goto soft ;
imx_src_prepare_restart ( ) ;
/* enable wdog */
writew_relaxed ( 1 < < 2 , wdog_base ) ;
/* write twice to ensure the request will not get ignored */
writew_relaxed ( 1 < < 2 , wdog_base ) ;
/* wait for reset to assert ... */
mdelay ( 500 ) ;
pr_err ( " Watchdog reset failed to assert reset \n " ) ;
/* delay to allow the serial port to show the message */
mdelay ( 50 ) ;
soft :
/* we'll take a jump through zero as a poor second */
soft_restart ( 0 ) ;
}
2011-12-14 05:26:47 +04:00
/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
static int ksz9021rn_phy_fixup ( struct phy_device * phydev )
{
2012-08-16 11:42:50 +04:00
if ( IS_BUILTIN ( CONFIG_PHYLIB ) ) {
2012-05-08 17:39:33 +04:00
/* min rx data delay */
phy_write ( phydev , 0x0b , 0x8105 ) ;
phy_write ( phydev , 0x0c , 0x0000 ) ;
2011-12-14 05:26:47 +04:00
2012-05-08 17:39:33 +04:00
/* max rx/tx clock delay, min rx/tx control delay */
phy_write ( phydev , 0x0b , 0x8104 ) ;
phy_write ( phydev , 0x0c , 0xf0f0 ) ;
phy_write ( phydev , 0x0b , 0x104 ) ;
}
2011-12-14 05:26:47 +04:00
return 0 ;
}
2012-04-24 10:19:13 +04:00
static void __init imx6q_sabrelite_cko1_setup ( void )
{
struct clk * cko1_sel , * ahb , * cko1 ;
unsigned long rate ;
cko1_sel = clk_get_sys ( NULL , " cko1_sel " ) ;
ahb = clk_get_sys ( NULL , " ahb " ) ;
cko1 = clk_get_sys ( NULL , " cko1 " ) ;
if ( IS_ERR ( cko1_sel ) | | IS_ERR ( ahb ) | | IS_ERR ( cko1 ) ) {
pr_err ( " cko1 setup failed! \n " ) ;
goto put_clk ;
}
clk_set_parent ( cko1_sel , ahb ) ;
rate = clk_round_rate ( cko1 , 16000000 ) ;
clk_set_rate ( cko1 , rate ) ;
put_clk :
if ( ! IS_ERR ( cko1_sel ) )
clk_put ( cko1_sel ) ;
if ( ! IS_ERR ( ahb ) )
clk_put ( ahb ) ;
if ( ! IS_ERR ( cko1 ) )
clk_put ( cko1 ) ;
}
2012-04-27 11:02:59 +04:00
static void __init imx6q_sabrelite_init ( void )
{
2012-08-16 11:42:50 +04:00
if ( IS_BUILTIN ( CONFIG_PHYLIB ) )
2012-05-08 17:39:33 +04:00
phy_register_fixup_for_uid ( PHY_ID_KSZ9021 , MICREL_PHY_ID_MASK ,
2012-04-27 11:02:59 +04:00
ksz9021rn_phy_fixup ) ;
2012-04-24 10:19:13 +04:00
imx6q_sabrelite_cko1_setup ( ) ;
2012-04-27 11:02:59 +04:00
}
2012-07-12 06:25:24 +04:00
static void __init imx6q_usb_init ( void )
{
2012-09-05 06:57:15 +04:00
struct regmap * anatop ;
2012-07-12 06:25:24 +04:00
# define HW_ANADIG_USB1_CHRG_DETECT 0x000001b0
# define HW_ANADIG_USB2_CHRG_DETECT 0x00000210
# define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x00100000
# define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x00080000
2012-09-05 06:57:15 +04:00
anatop = syscon_regmap_lookup_by_compatible ( " fsl,imx6q-anatop " ) ;
if ( ! IS_ERR ( anatop ) ) {
/*
* The external charger detector needs to be disabled ,
* or the signal at DP will be poor
*/
regmap_write ( anatop , HW_ANADIG_USB1_CHRG_DETECT ,
BM_ANADIG_USB_CHRG_DETECT_EN_B
| BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B ) ;
regmap_write ( anatop , HW_ANADIG_USB2_CHRG_DETECT ,
BM_ANADIG_USB_CHRG_DETECT_EN_B |
BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B ) ;
} else {
pr_warn ( " failed to find fsl,imx6q-anatop regmap \n " ) ;
}
2012-07-12 06:25:24 +04:00
}
2011-09-06 11:05:25 +04:00
static void __init imx6q_init_machine ( void )
{
2011-12-14 05:26:47 +04:00
if ( of_machine_is_compatible ( " fsl,imx6q-sabrelite " ) )
2012-04-27 11:02:59 +04:00
imx6q_sabrelite_init ( ) ;
2011-12-14 05:26:47 +04:00
2011-09-06 11:05:25 +04:00
of_platform_populate ( NULL , of_default_bus_match_table , NULL , NULL ) ;
imx6q_pm_init ( ) ;
2012-07-12 06:25:24 +04:00
imx6q_usb_init ( ) ;
2011-09-06 11:05:25 +04:00
}
2012-05-22 02:50:30 +04:00
static struct cpuidle_driver imx6q_cpuidle_driver = {
. name = " imx6q_cpuidle " ,
. owner = THIS_MODULE ,
. en_core_tk_irqen = 1 ,
. states [ 0 ] = ARM_CPUIDLE_WFI_STATE ,
. state_count = 1 ,
} ;
static void __init imx6q_init_late ( void )
{
imx_cpuidle_init ( & imx6q_cpuidle_driver ) ;
}
2011-09-06 11:05:25 +04:00
static void __init imx6q_map_io ( void )
{
imx_lluart_map_io ( ) ;
imx_scu_map_io ( ) ;
2011-11-17 14:54:29 +04:00
imx6q_clock_map_io ( ) ;
2011-09-06 11:05:25 +04:00
}
static const struct of_device_id imx6q_irq_match [ ] __initconst = {
{ . compatible = " arm,cortex-a9-gic " , . data = gic_of_init , } ,
{ /* sentinel */ }
} ;
static void __init imx6q_init_irq ( void )
{
l2x0_of_init ( 0 , ~ 0UL ) ;
imx_src_init ( ) ;
imx_gpc_init ( ) ;
of_irq_init ( imx6q_irq_match ) ;
}
static void __init imx6q_timer_init ( void )
{
mx6q_clocks_init ( ) ;
2012-01-10 23:44:19 +04:00
twd_local_timer_of_register ( ) ;
2011-09-06 11:05:25 +04:00
}
static struct sys_timer imx6q_timer = {
. init = imx6q_timer_init ,
} ;
static const char * imx6q_dt_compat [ ] __initdata = {
2012-02-17 15:07:00 +04:00
" fsl,imx6q " ,
2011-09-06 11:05:25 +04:00
NULL ,
} ;
DT_MACHINE_START ( IMX6Q , " Freescale i.MX6 Quad (Device Tree) " )
2011-09-08 16:15:22 +04:00
. smp = smp_ops ( imx_smp_ops ) ,
2011-09-06 11:05:25 +04:00
. map_io = imx6q_map_io ,
. init_irq = imx6q_init_irq ,
. handle_irq = imx6q_handle_irq ,
. timer = & imx6q_timer ,
. init_machine = imx6q_init_machine ,
2012-05-22 02:50:30 +04:00
. init_late = imx6q_init_late ,
2011-09-06 11:05:25 +04:00
. dt_compat = imx6q_dt_compat ,
2011-12-09 03:51:26 +04:00
. restart = imx6q_restart ,
2011-09-06 11:05:25 +04:00
MACHINE_END