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-02-07 07:17:47 +04:00
# include <linux/clocksource.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>
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>
2011-09-06 11:05:25 +04:00
# include <asm/hardware/cache-l2x0.h>
# 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-04-01 18:13:32 +04:00
static u32 chip_revision ;
2012-10-23 15:00:39 +04:00
2013-03-27 21:30:37 +04:00
int imx6q_revision ( void )
2012-10-23 15:00:39 +04:00
{
2013-04-01 18:13:32 +04:00
return chip_revision ;
}
2012-10-23 15:00:39 +04:00
2013-04-01 18:13:32 +04:00
static void __init imx6q_init_revision ( void )
{
u32 rev = imx_anatop_get_digprog ( ) ;
2012-10-23 15:00:39 +04:00
switch ( rev & 0xff ) {
case 0 :
2013-04-01 18:13:32 +04:00
chip_revision = IMX_CHIP_REVISION_1_0 ;
break ;
2012-10-23 15:00:39 +04:00
case 1 :
2013-04-01 18:13:32 +04:00
chip_revision = IMX_CHIP_REVISION_1_1 ;
break ;
2012-10-23 15:00:39 +04:00
case 2 :
2013-04-01 18:13:32 +04:00
chip_revision = IMX_CHIP_REVISION_1_2 ;
break ;
2012-10-23 15:00:39 +04:00
default :
2013-04-01 18:13:32 +04:00
chip_revision = IMX_CHIP_REVISION_UNKNOWN ;
2012-10-23 15:00:39 +04:00
}
2013-04-01 18:13:32 +04:00
mxc_set_cpu_type ( rev > > 16 & 0xff ) ;
2012-10-23 15:00:39 +04:00
}
2013-03-25 16:20:44 +04:00
static void imx6q_restart ( char 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 */
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-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 ) )
regmap_update_bits ( gpr , 0x4 , 1 < < 21 , 1 < < 21 ) ;
else
pr_err ( " failed to find fsl,imx6q-iomux-gpr regmap \n " ) ;
}
2012-07-12 06:25:24 +04:00
static void __init imx6q_usb_init ( void )
{
2013-03-21 03:39:42 +04:00
imx_anatop_usb_chrg_detect_disable ( ) ;
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 ) ;
2013-03-21 03:39:42 +04:00
imx_anatop_init ( ) ;
2011-09-06 11:05:25 +04:00
imx6q_pm_init ( ) ;
2012-07-12 06:25:24 +04:00
imx6q_usb_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 ) ;
}
static void __init imx6q_opp_init ( struct device * cpu_dev )
{
struct device_node * np ;
np = of_find_node_by_path ( " /cpus/cpu@0 " ) ;
if ( ! np ) {
pr_warn ( " failed to find cpu0 node \n " ) ;
return ;
}
cpu_dev - > of_node = np ;
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 .
*/
if ( imx6q_revision ( ) > IMX_CHIP_REVISION_1_1 )
imx6q_cpuidle_init ( ) ;
2013-01-08 10:25:14 +04:00
if ( IS_ENABLED ( CONFIG_ARM_IMX6Q_CPUFREQ ) ) {
imx6q_opp_init ( & imx6q_cpufreq_pdev . dev ) ;
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 ( ) ;
}
2013-04-26 12:13:56 +04:00
# ifdef CONFIG_CACHE_L2X0
static void __init imx6q_init_l2cache ( void )
{
void __iomem * l2x0_base ;
struct device_node * np ;
unsigned int val ;
np = of_find_compatible_node ( NULL , NULL , " arm,pl310-cache " ) ;
if ( ! np )
goto out ;
l2x0_base = of_iomap ( np , 0 ) ;
if ( ! l2x0_base ) {
of_node_put ( np ) ;
goto out ;
}
/* Configure the L2 PREFETCH and POWER registers */
val = readl_relaxed ( l2x0_base + L2X0_PREFETCH_CTRL ) ;
val | = 0x70800000 ;
writel_relaxed ( val , l2x0_base + L2X0_PREFETCH_CTRL ) ;
val = L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN ;
writel_relaxed ( val , l2x0_base + L2X0_POWER_CTRL ) ;
iounmap ( l2x0_base ) ;
of_node_put ( np ) ;
out :
l2x0_of_init ( 0 , ~ 0UL ) ;
}
# else
static inline void imx6q_init_l2cache ( void ) { }
# endif
2011-09-06 11:05:25 +04:00
static void __init imx6q_init_irq ( void )
{
2013-04-01 18:13:32 +04:00
imx6q_init_revision ( ) ;
2013-04-26 12:13:56 +04:00
imx6q_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 void __init imx6q_timer_init ( void )
{
mx6q_clocks_init ( ) ;
2013-02-07 07:17:47 +04:00
clocksource_of_init ( ) ;
2013-04-01 18:13:32 +04:00
imx_print_silicon_rev ( cpu_is_imx6dl ( ) ? " i.MX6DL " : " i.MX6Q " ,
imx6q_revision ( ) ) ;
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 ,
2012-11-08 23:40:59 +04:00
. init_time = imx6q_timer_init ,
2011-09-06 11:05:25 +04:00
. 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