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>
2013-10-23 08:51:28 +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-09-20 01:03:52 +04:00
# include <linux/pm_opp.h>
2013-10-23 08:51:28 +04:00
# include <linux/pci.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
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-10-23 08:51:28 +04:00
/*
* fixup for PLX PEX8909 bridge to configure GPIO1 - 7 as output High
* as they are used for slots1 - 7 PERST #
*/
static void ventana_pciesw_early_fixup ( struct pci_dev * dev )
{
u32 dw ;
if ( ! of_machine_is_compatible ( " gw,ventana " ) )
return ;
if ( dev - > devfn ! = 0 )
return ;
pci_read_config_dword ( dev , 0x62c , & dw ) ;
dw | = 0xaaa8 ; // GPIO1-7 outputs
pci_write_config_dword ( dev , 0x62c , dw ) ;
pci_read_config_dword ( dev , 0x644 , & dw ) ;
dw | = 0xfe ; // GPIO1-7 output high
pci_write_config_dword ( dev , 0x644 , dw ) ;
msleep ( 100 ) ;
}
DECLARE_PCI_FIXUP_EARLY ( PCI_VENDOR_ID_PLX , 0x8609 , ventana_pciesw_early_fixup ) ;
DECLARE_PCI_FIXUP_EARLY ( PCI_VENDOR_ID_PLX , 0x8606 , ventana_pciesw_early_fixup ) ;
DECLARE_PCI_FIXUP_EARLY ( PCI_VENDOR_ID_PLX , 0x8604 , ventana_pciesw_early_fixup ) ;
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-09-27 23:07:26 +04:00
static int ar8035_phy_fixup ( struct phy_device * dev )
{
u16 val ;
/* Ar803x phy SmartEEE feature cause link status generates glitch,
* which cause ethernet link down / up issue , so disable SmartEEE
*/
phy_write ( dev , 0xd , 0x3 ) ;
phy_write ( dev , 0xe , 0x805d ) ;
phy_write ( dev , 0xd , 0x4003 ) ;
val = phy_read ( dev , 0xe ) ;
phy_write ( dev , 0xe , val & ~ ( 1 < < 8 ) ) ;
/*
* Enable 125 MHz clock from CLK_25M on the AR8031 . This
* is fed in to the IMX6 on the ENET_REF_CLK ( V22 ) pad .
* Also , introduce a tx clock delay .
*
* This is the same as is the AR8031 fixup .
*/
ar8031_phy_fixup ( dev ) ;
/*check phy power*/
val = phy_read ( dev , 0x0 ) ;
if ( val & BMCR_PDOWN )
phy_write ( dev , 0x0 , val & ~ BMCR_PDOWN ) ;
return 0 ;
}
# define PHY_ID_AR8035 0x004dd072
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-09-27 23:07:26 +04:00
phy_register_fixup_for_uid ( PHY_ID_AR8035 , 0xffffffef ,
ar8035_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-10-06 12:47:46 +04:00
mxc_arch_reset_init_dt ( ) ;
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 ( ) ;
2014-01-17 07:39:05 +04:00
cpu_is_imx6q ( ) ? imx6q_pm_init ( ) : imx6dl_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 )
2013-09-20 01:03:50 +04:00
if ( dev_pm_opp_disable ( cpu_dev , 1200000000 ) )
2013-01-08 10:25:14 +04:00
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
}
2013-12-09 10:04:35 +04:00
static const char * imx6q_dt_compat [ ] __initconst = {
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 ,
2013-10-06 12:47:46 +04:00
. restart = mxc_restart ,
2011-09-06 11:05:25 +04:00
MACHINE_END