2011-09-06 11:05:25 +04:00
/*
2013-03-21 03:39:42 +04:00
* Copyright 2011 - 2013 Freescale Semiconductor , Inc .
2011-09-06 11:05:25 +04:00
* 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>
2013-01-08 10:25:14 +04:00
# include <linux/cpu.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>
2012-11-06 02:18:28 +04:00
# include <linux/irqchip.h>
2011-09-06 11:05:25 +04:00
# 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>
2013-01-08 10:25:14 +04:00
# include <linux/opp.h>
2011-12-14 05:26:47 +04:00
# include <linux/phy.h>
2013-07-09 03:01:40 +04:00
# include <linux/reboot.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>
2013-06-26 17:08:49 +04:00
# include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
2011-09-06 11:05:25 +04:00
# include <asm/mach/arch.h>
2013-01-17 12:37:42 +04:00
# include <asm/mach/map.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
2013-07-09 03:01:40 +04:00
static void imx6q_restart ( enum reboot_mode mode , const char * cmd )
2011-12-09 03:51:26 +04:00
{
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 */
2013-08-13 18:59:00 +04:00
phy_write ( phydev , MICREL_KSZ9021_EXTREG_CTRL ,
0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW ) ;
phy_write ( phydev , MICREL_KSZ9021_EXTREG_DATA_WRITE , 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 */
2013-08-13 18:59:00 +04:00
phy_write ( phydev , MICREL_KSZ9021_EXTREG_CTRL ,
0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW ) ;
phy_write ( phydev , MICREL_KSZ9021_EXTREG_DATA_WRITE , 0xf0f0 ) ;
phy_write ( phydev , MICREL_KSZ9021_EXTREG_CTRL ,
MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW ) ;
2012-05-08 17:39:33 +04:00
}
2011-12-14 05:26:47 +04:00
return 0 ;
}
2013-06-20 19:34:33 +04:00
static void mmd_write_reg ( struct phy_device * dev , int device , int reg , int val )
2012-04-24 10:19:13 +04:00
{
2013-06-20 19:34:33 +04:00
phy_write ( dev , 0x0d , device ) ;
phy_write ( dev , 0x0e , reg ) ;
phy_write ( dev , 0x0d , ( 1 < < 14 ) | device ) ;
phy_write ( dev , 0x0e , val ) ;
2012-04-24 10:19:13 +04:00
}
2013-06-20 19:34:33 +04:00
static int ksz9031rn_phy_fixup ( struct phy_device * dev )
2012-04-27 11:02:59 +04:00
{
2013-06-20 19:34:33 +04:00
/*
* min rx data delay , max rx / tx clock delay ,
* min rx / tx control delay
*/
mmd_write_reg ( dev , 2 , 4 , 0 ) ;
mmd_write_reg ( dev , 2 , 5 , 0 ) ;
mmd_write_reg ( dev , 2 , 8 , 0x003ff ) ;
return 0 ;
2012-04-27 11:02:59 +04:00
}
2013-06-20 19:34:32 +04:00
static int ar8031_phy_fixup ( struct phy_device * dev )
2013-06-13 15:50:56 +04:00
{
2013-06-20 19:34:32 +04:00
u16 val ;
/* To enable AR8031 output a 125MHz clk from CLK_25M */
phy_write ( dev , 0xd , 0x7 ) ;
phy_write ( dev , 0xe , 0x8016 ) ;
phy_write ( dev , 0xd , 0x4007 ) ;
val = phy_read ( dev , 0xe ) ;
val & = 0xffe3 ;
val | = 0x18 ;
phy_write ( dev , 0xe , val ) ;
/* introduce tx clock delay */
phy_write ( dev , 0x1d , 0x5 ) ;
val = phy_read ( dev , 0x1e ) ;
val | = 0x0100 ;
phy_write ( dev , 0x1e , val ) ;
return 0 ;
2013-06-13 15:50:56 +04:00
}
2013-06-20 19:34:32 +04:00
# define PHY_ID_AR8031 0x004dd074
2013-06-20 19:34:31 +04:00
static void __init imx6q_enet_phy_init ( void )
2013-06-13 15:50:56 +04:00
{
2013-06-20 19:34:31 +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 ) ;
2013-06-20 19:34:33 +04:00
phy_register_fixup_for_uid ( PHY_ID_KSZ9031 , MICREL_PHY_ID_MASK ,
ksz9031rn_phy_fixup ) ;
2013-06-20 19:34:32 +04:00
phy_register_fixup_for_uid ( PHY_ID_AR8031 , 0xffffffff ,
ar8031_phy_fixup ) ;
2013-06-20 19:34:31 +04:00
}
2013-06-13 15:50:56 +04:00
}
2012-10-30 22:25:22 +04:00
static void __init imx6q_1588_init ( void )
{
struct regmap * gpr ;
gpr = syscon_regmap_lookup_by_compatible ( " fsl,imx6q-iomuxc-gpr " ) ;
if ( ! IS_ERR ( gpr ) )
2013-06-26 17:08:49 +04:00
regmap_update_bits ( gpr , IOMUXC_GPR1 ,
IMX6Q_GPR1_ENET_CLK_SEL_MASK ,
IMX6Q_GPR1_ENET_CLK_SEL_ANATOP ) ;
2012-10-30 22:25:22 +04:00
else
pr_err ( " failed to find fsl,imx6q-iomux-gpr 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 )
{
2013-08-13 12:59:28 +04:00
struct device * parent ;
2013-08-27 16:50:00 +04:00
imx_print_silicon_rev ( cpu_is_imx6dl ( ) ? " i.MX6DL " : " i.MX6Q " ,
2013-08-13 10:10:29 +04:00
imx_get_soc_revision ( ) ) ;
2013-08-27 16:50:00 +04:00
2013-08-13 12:59:28 +04:00
parent = imx_soc_device_init ( ) ;
if ( parent = = NULL )
pr_warn ( " failed to initialize soc device \n " ) ;
2013-06-20 19:34:31 +04:00
imx6q_enet_phy_init ( ) ;
2011-12-14 05:26:47 +04:00
2013-08-13 12:59:28 +04:00
of_platform_populate ( NULL , of_default_bus_match_table , NULL , parent ) ;
2011-09-06 11:05:25 +04:00
2013-03-21 03:39:42 +04:00
imx_anatop_init ( ) ;
2011-09-06 11:05:25 +04:00
imx6q_pm_init ( ) ;
2012-10-30 22:25:22 +04:00
imx6q_1588_init ( ) ;
2011-09-06 11:05:25 +04:00
}
2013-01-08 10:25:14 +04:00
# define OCOTP_CFG3 0x440
# define OCOTP_CFG3_SPEED_SHIFT 16
# define OCOTP_CFG3_SPEED_1P2GHZ 0x3
static void __init imx6q_opp_check_1p2ghz ( struct device * cpu_dev )
{
struct device_node * np ;
void __iomem * base ;
u32 val ;
np = of_find_compatible_node ( NULL , NULL , " fsl,imx6q-ocotp " ) ;
if ( ! np ) {
pr_warn ( " failed to find ocotp node \n " ) ;
return ;
}
base = of_iomap ( np , 0 ) ;
if ( ! base ) {
pr_warn ( " failed to map ocotp \n " ) ;
goto put_node ;
}
val = readl_relaxed ( base + OCOTP_CFG3 ) ;
val > > = OCOTP_CFG3_SPEED_SHIFT ;
if ( ( val & 0x3 ) ! = OCOTP_CFG3_SPEED_1P2GHZ )
if ( opp_disable ( cpu_dev , 1200000000 ) )
pr_warn ( " failed to disable 1.2 GHz OPP \n " ) ;
put_node :
of_node_put ( np ) ;
}
2013-09-10 21:59:47 +04:00
static void __init imx6q_opp_init ( void )
2013-01-08 10:25:14 +04:00
{
struct device_node * np ;
2013-09-10 21:59:47 +04:00
struct device * cpu_dev = get_cpu_device ( 0 ) ;
2013-01-08 10:25:14 +04:00
2013-09-10 21:59:47 +04:00
if ( ! cpu_dev ) {
pr_warn ( " failed to get cpu0 device \n " ) ;
return ;
}
2013-06-17 17:58:48 +04:00
np = of_node_get ( cpu_dev - > of_node ) ;
2013-01-08 10:25:14 +04:00
if ( ! np ) {
pr_warn ( " failed to find cpu0 node \n " ) ;
return ;
}
if ( of_init_opp_table ( cpu_dev ) ) {
pr_warn ( " failed to init OPP table \n " ) ;
goto put_node ;
}
imx6q_opp_check_1p2ghz ( cpu_dev ) ;
put_node :
of_node_put ( np ) ;
}
2013-03-25 16:20:44 +04:00
static struct platform_device imx6q_cpufreq_pdev = {
2013-01-08 10:25:14 +04:00
. name = " imx6q-cpufreq " ,
} ;
2012-05-22 02:50:30 +04:00
static void __init imx6q_init_late ( void )
{
2012-12-04 18:55:15 +04:00
/*
* WAIT mode is broken on TO 1.0 and 1.1 , so there is no point
* to run cpuidle on them .
*/
2013-08-13 10:10:29 +04:00
if ( imx_get_soc_revision ( ) > IMX_CHIP_REVISION_1_1 )
2012-12-04 18:55:15 +04:00
imx6q_cpuidle_init ( ) ;
2013-01-08 10:25:14 +04:00
if ( IS_ENABLED ( CONFIG_ARM_IMX6Q_CPUFREQ ) ) {
2013-09-10 21:59:47 +04:00
imx6q_opp_init ( ) ;
2013-01-08 10:25:14 +04:00
platform_device_register ( & imx6q_cpufreq_pdev ) ;
}
2012-05-22 02:50:30 +04:00
}
2011-09-06 11:05:25 +04:00
static void __init imx6q_map_io ( void )
{
2013-01-17 12:37:42 +04:00
debug_ll_io_init ( ) ;
2011-09-06 11:05:25 +04:00
imx_scu_map_io ( ) ;
}
static void __init imx6q_init_irq ( void )
{
2013-08-13 10:59:43 +04:00
imx_init_revision_from_anatop ( ) ;
2013-07-08 17:45:20 +04:00
imx_init_l2cache ( ) ;
2011-09-06 11:05:25 +04:00
imx_src_init ( ) ;
imx_gpc_init ( ) ;
2012-11-06 02:18:28 +04:00
irqchip_init ( ) ;
2011-09-06 11:05:25 +04:00
}
static const char * imx6q_dt_compat [ ] __initdata = {
2013-04-01 18:13:32 +04:00
" fsl,imx6dl " ,
2012-02-17 15:07:00 +04:00
" fsl,imx6q " ,
2011-09-06 11:05:25 +04:00
NULL ,
} ;
2013-04-01 18:13:32 +04:00
DT_MACHINE_START ( IMX6Q , " Freescale i.MX6 Quad/DualLite (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 ,
. 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