linux/arch/arm/mach-imx/mach-imx6q.c
<<
>>
Prefs
   1/*
   2 * Copyright 2011-2013 Freescale Semiconductor, Inc.
   3 * Copyright 2011 Linaro Ltd.
   4 *
   5 * The code contained herein is licensed under the GNU General Public
   6 * License. You may obtain a copy of the GNU General Public License
   7 * Version 2 or later at the following locations:
   8 *
   9 * http://www.opensource.org/licenses/gpl-license.html
  10 * http://www.gnu.org/copyleft/gpl.html
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/clkdev.h>
  15#include <linux/cpu.h>
  16#include <linux/delay.h>
  17#include <linux/export.h>
  18#include <linux/init.h>
  19#include <linux/io.h>
  20#include <linux/irq.h>
  21#include <linux/irqchip.h>
  22#include <linux/of.h>
  23#include <linux/of_address.h>
  24#include <linux/of_irq.h>
  25#include <linux/of_platform.h>
  26#include <linux/pm_opp.h>
  27#include <linux/pci.h>
  28#include <linux/phy.h>
  29#include <linux/reboot.h>
  30#include <linux/regmap.h>
  31#include <linux/micrel_phy.h>
  32#include <linux/mfd/syscon.h>
  33#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
  34#include <asm/mach/arch.h>
  35#include <asm/mach/map.h>
  36#include <asm/system_misc.h>
  37
  38#include "common.h"
  39#include "cpuidle.h"
  40#include "hardware.h"
  41
  42/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
  43static int ksz9021rn_phy_fixup(struct phy_device *phydev)
  44{
  45        if (IS_BUILTIN(CONFIG_PHYLIB)) {
  46                /* min rx data delay */
  47                phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
  48                        0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW);
  49                phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000);
  50
  51                /* max rx/tx clock delay, min rx/tx control delay */
  52                phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
  53                        0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
  54                phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xf0f0);
  55                phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
  56                        MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
  57        }
  58
  59        return 0;
  60}
  61
  62static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val)
  63{
  64        phy_write(dev, 0x0d, device);
  65        phy_write(dev, 0x0e, reg);
  66        phy_write(dev, 0x0d, (1 << 14) | device);
  67        phy_write(dev, 0x0e, val);
  68}
  69
  70static int ksz9031rn_phy_fixup(struct phy_device *dev)
  71{
  72        /*
  73         * min rx data delay, max rx/tx clock delay,
  74         * min rx/tx control delay
  75         */
  76        mmd_write_reg(dev, 2, 4, 0);
  77        mmd_write_reg(dev, 2, 5, 0);
  78        mmd_write_reg(dev, 2, 8, 0x003ff);
  79
  80        return 0;
  81}
  82
  83/*
  84 * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High
  85 * as they are used for slots1-7 PERST#
  86 */
  87static void ventana_pciesw_early_fixup(struct pci_dev *dev)
  88{
  89        u32 dw;
  90
  91        if (!of_machine_is_compatible("gw,ventana"))
  92                return;
  93
  94        if (dev->devfn != 0)
  95                return;
  96
  97        pci_read_config_dword(dev, 0x62c, &dw);
  98        dw |= 0xaaa8; // GPIO1-7 outputs
  99        pci_write_config_dword(dev, 0x62c, dw);
 100
 101        pci_read_config_dword(dev, 0x644, &dw);
 102        dw |= 0xfe;   // GPIO1-7 output high
 103        pci_write_config_dword(dev, 0x644, dw);
 104
 105        msleep(100);
 106}
 107DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup);
 108DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup);
 109DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup);
 110
 111static int ar8031_phy_fixup(struct phy_device *dev)
 112{
 113        u16 val;
 114
 115        /* To enable AR8031 output a 125MHz clk from CLK_25M */
 116        phy_write(dev, 0xd, 0x7);
 117        phy_write(dev, 0xe, 0x8016);
 118        phy_write(dev, 0xd, 0x4007);
 119
 120        val = phy_read(dev, 0xe);
 121        val &= 0xffe3;
 122        val |= 0x18;
 123        phy_write(dev, 0xe, val);
 124
 125        /* introduce tx clock delay */
 126        phy_write(dev, 0x1d, 0x5);
 127        val = phy_read(dev, 0x1e);
 128        val |= 0x0100;
 129        phy_write(dev, 0x1e, val);
 130
 131        return 0;
 132}
 133
 134#define PHY_ID_AR8031   0x004dd074
 135
 136static int ar8035_phy_fixup(struct phy_device *dev)
 137{
 138        u16 val;
 139
 140        /* Ar803x phy SmartEEE feature cause link status generates glitch,
 141         * which cause ethernet link down/up issue, so disable SmartEEE
 142         */
 143        phy_write(dev, 0xd, 0x3);
 144        phy_write(dev, 0xe, 0x805d);
 145        phy_write(dev, 0xd, 0x4003);
 146
 147        val = phy_read(dev, 0xe);
 148        phy_write(dev, 0xe, val & ~(1 << 8));
 149
 150        /*
 151         * Enable 125MHz clock from CLK_25M on the AR8031.  This
 152         * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad.
 153         * Also, introduce a tx clock delay.
 154         *
 155         * This is the same as is the AR8031 fixup.
 156         */
 157        ar8031_phy_fixup(dev);
 158
 159        /*check phy power*/
 160        val = phy_read(dev, 0x0);
 161        if (val & BMCR_PDOWN)
 162                phy_write(dev, 0x0, val & ~BMCR_PDOWN);
 163
 164        return 0;
 165}
 166
 167#define PHY_ID_AR8035 0x004dd072
 168
 169static void __init imx6q_enet_phy_init(void)
 170{
 171        if (IS_BUILTIN(CONFIG_PHYLIB)) {
 172                phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
 173                                ksz9021rn_phy_fixup);
 174                phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
 175                                ksz9031rn_phy_fixup);
 176                phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef,
 177                                ar8031_phy_fixup);
 178                phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,
 179                                ar8035_phy_fixup);
 180        }
 181}
 182
 183static void __init imx6q_1588_init(void)
 184{
 185        struct device_node *np;
 186        struct clk *ptp_clk;
 187        struct clk *enet_ref;
 188        struct regmap *gpr;
 189        u32 clksel;
 190
 191        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec");
 192        if (!np) {
 193                pr_warn("%s: failed to find fec node\n", __func__);
 194                return;
 195        }
 196
 197        ptp_clk = of_clk_get(np, 2);
 198        if (IS_ERR(ptp_clk)) {
 199                pr_warn("%s: failed to get ptp clock\n", __func__);
 200                goto put_node;
 201        }
 202
 203        enet_ref = clk_get_sys(NULL, "enet_ref");
 204        if (IS_ERR(enet_ref)) {
 205                pr_warn("%s: failed to get enet clock\n", __func__);
 206                goto put_ptp_clk;
 207        }
 208
 209        /*
 210         * If enet_ref from ANATOP/CCM is the PTP clock source, we need to
 211         * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
 212         * (external OSC), and we need to clear the bit.
 213         */
 214        clksel = clk_is_match(ptp_clk, enet_ref) ?
 215                                IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
 216                                IMX6Q_GPR1_ENET_CLK_SEL_PAD;
 217        gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
 218        if (!IS_ERR(gpr))
 219                regmap_update_bits(gpr, IOMUXC_GPR1,
 220                                IMX6Q_GPR1_ENET_CLK_SEL_MASK,
 221                                clksel);
 222        else
 223                pr_err("failed to find fsl,imx6q-iomuxc-gpr regmap\n");
 224
 225        clk_put(enet_ref);
 226put_ptp_clk:
 227        clk_put(ptp_clk);
 228put_node:
 229        of_node_put(np);
 230}
 231
 232static void __init imx6q_axi_init(void)
 233{
 234        struct regmap *gpr;
 235        unsigned int mask;
 236
 237        gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
 238        if (!IS_ERR(gpr)) {
 239                /*
 240                 * Enable the cacheable attribute of VPU and IPU
 241                 * AXI transactions.
 242                 */
 243                mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL |
 244                        IMX6Q_GPR4_VPU_RD_CACHE_SEL |
 245                        IMX6Q_GPR4_VPU_P_WR_CACHE_VAL |
 246                        IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK |
 247                        IMX6Q_GPR4_IPU_WR_CACHE_CTL |
 248                        IMX6Q_GPR4_IPU_RD_CACHE_CTL;
 249                regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask);
 250
 251                /* Increase IPU read QoS priority */
 252                regmap_update_bits(gpr, IOMUXC_GPR6,
 253                                IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK |
 254                                IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK,
 255                                (0xf << 16) | (0x7 << 20));
 256                regmap_update_bits(gpr, IOMUXC_GPR7,
 257                                IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK |
 258                                IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK,
 259                                (0xf << 16) | (0x7 << 20));
 260        } else {
 261                pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n");
 262        }
 263}
 264
 265static void __init imx6q_init_machine(void)
 266{
 267        struct device *parent;
 268
 269        if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_2_0)
 270                imx_print_silicon_rev("i.MX6QP", IMX_CHIP_REVISION_1_0);
 271        else
 272                imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
 273                                imx_get_soc_revision());
 274
 275        parent = imx_soc_device_init();
 276        if (parent == NULL)
 277                pr_warn("failed to initialize soc device\n");
 278
 279        imx6q_enet_phy_init();
 280
 281        of_platform_default_populate(NULL, NULL, parent);
 282
 283        imx_anatop_init();
 284        cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
 285        imx6q_1588_init();
 286        imx6q_axi_init();
 287}
 288
 289static void __init imx6q_init_late(void)
 290{
 291        /*
 292         * WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so
 293         * there is no point to run cpuidle on them.
 294         *
 295         * It does work on imx6 Solo/DualLite starting from 1.1
 296         */
 297        if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) ||
 298            (cpu_is_imx6dl() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_0))
 299                imx6q_cpuidle_init();
 300
 301        if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
 302                platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
 303}
 304
 305static void __init imx6q_map_io(void)
 306{
 307        debug_ll_io_init();
 308        imx_scu_map_io();
 309}
 310
 311static void __init imx6q_init_irq(void)
 312{
 313        imx_gpc_check_dt();
 314        imx_init_revision_from_anatop();
 315        imx_init_l2cache();
 316        imx_src_init();
 317        irqchip_init();
 318        imx6_pm_ccm_init("fsl,imx6q-ccm");
 319}
 320
 321static const char * const imx6q_dt_compat[] __initconst = {
 322        "fsl,imx6dl",
 323        "fsl,imx6q",
 324        "fsl,imx6qp",
 325        NULL,
 326};
 327
 328DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
 329        .l2c_aux_val    = 0,
 330        .l2c_aux_mask   = ~0,
 331        .smp            = smp_ops(imx_smp_ops),
 332        .map_io         = imx6q_map_io,
 333        .init_irq       = imx6q_init_irq,
 334        .init_machine   = imx6q_init_machine,
 335        .init_late      = imx6q_init_late,
 336        .dt_compat      = imx6q_dt_compat,
 337MACHINE_END
 338