162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2011-2013 Freescale Semiconductor, Inc. 462306a36Sopenharmony_ci * Copyright 2011 Linaro Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/irqchip.h> 962306a36Sopenharmony_ci#include <linux/of_platform.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/phy.h> 1262306a36Sopenharmony_ci#include <linux/regmap.h> 1362306a36Sopenharmony_ci#include <linux/micrel_phy.h> 1462306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1562306a36Sopenharmony_ci#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 1662306a36Sopenharmony_ci#include <asm/mach/arch.h> 1762306a36Sopenharmony_ci#include <asm/mach/map.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "common.h" 2062306a36Sopenharmony_ci#include "cpuidle.h" 2162306a36Sopenharmony_ci#include "hardware.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ 2462306a36Sopenharmony_cistatic int ksz9021rn_phy_fixup(struct phy_device *phydev) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci if (IS_BUILTIN(CONFIG_PHYLIB)) { 2762306a36Sopenharmony_ci /* min rx data delay */ 2862306a36Sopenharmony_ci phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 2962306a36Sopenharmony_ci 0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW); 3062306a36Sopenharmony_ci phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* max rx/tx clock delay, min rx/tx control delay */ 3362306a36Sopenharmony_ci phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 3462306a36Sopenharmony_ci 0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW); 3562306a36Sopenharmony_ci phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xf0f0); 3662306a36Sopenharmony_ci phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 3762306a36Sopenharmony_ci MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW); 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High 4562306a36Sopenharmony_ci * as they are used for slots1-7 PERST# 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic void ventana_pciesw_early_fixup(struct pci_dev *dev) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci u32 dw; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (!of_machine_is_compatible("gw,ventana")) 5262306a36Sopenharmony_ci return; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (dev->devfn != 0) 5562306a36Sopenharmony_ci return; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci pci_read_config_dword(dev, 0x62c, &dw); 5862306a36Sopenharmony_ci dw |= 0xaaa8; // GPIO1-7 outputs 5962306a36Sopenharmony_ci pci_write_config_dword(dev, 0x62c, dw); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci pci_read_config_dword(dev, 0x644, &dw); 6262306a36Sopenharmony_ci dw |= 0xfe; // GPIO1-7 output high 6362306a36Sopenharmony_ci pci_write_config_dword(dev, 0x644, dw); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci msleep(100); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup); 6862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup); 6962306a36Sopenharmony_ciDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void __init imx6q_enet_phy_init(void) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (IS_BUILTIN(CONFIG_PHYLIB)) { 7462306a36Sopenharmony_ci phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, 7562306a36Sopenharmony_ci ksz9021rn_phy_fixup); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void __init imx6q_1588_init(void) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct device_node *np; 8262306a36Sopenharmony_ci struct clk *ptp_clk, *fec_enet_ref; 8362306a36Sopenharmony_ci struct clk *enet_ref; 8462306a36Sopenharmony_ci struct regmap *gpr; 8562306a36Sopenharmony_ci u32 clksel; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec"); 8862306a36Sopenharmony_ci if (!np) { 8962306a36Sopenharmony_ci pr_warn("%s: failed to find fec node\n", __func__); 9062306a36Sopenharmony_ci return; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * If enet_clk_ref configured, we assume DT did it properly and . 9562306a36Sopenharmony_ci * clk-imx6q.c will do needed configuration. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci fec_enet_ref = of_clk_get_by_name(np, "enet_clk_ref"); 9862306a36Sopenharmony_ci if (!IS_ERR(fec_enet_ref)) 9962306a36Sopenharmony_ci goto put_node; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ptp_clk = of_clk_get(np, 2); 10262306a36Sopenharmony_ci if (IS_ERR(ptp_clk)) { 10362306a36Sopenharmony_ci pr_warn("%s: failed to get ptp clock\n", __func__); 10462306a36Sopenharmony_ci goto put_node; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci enet_ref = clk_get_sys(NULL, "enet_ref"); 10862306a36Sopenharmony_ci if (IS_ERR(enet_ref)) { 10962306a36Sopenharmony_ci pr_warn("%s: failed to get enet clock\n", __func__); 11062306a36Sopenharmony_ci goto put_ptp_clk; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * If enet_ref from ANATOP/CCM is the PTP clock source, we need to 11562306a36Sopenharmony_ci * set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad 11662306a36Sopenharmony_ci * (external OSC), and we need to clear the bit. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci clksel = clk_is_match(ptp_clk, enet_ref) ? 11962306a36Sopenharmony_ci IMX6Q_GPR1_ENET_CLK_SEL_ANATOP : 12062306a36Sopenharmony_ci IMX6Q_GPR1_ENET_CLK_SEL_PAD; 12162306a36Sopenharmony_ci gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); 12262306a36Sopenharmony_ci if (!IS_ERR(gpr)) 12362306a36Sopenharmony_ci regmap_update_bits(gpr, IOMUXC_GPR1, 12462306a36Sopenharmony_ci IMX6Q_GPR1_ENET_CLK_SEL_MASK, 12562306a36Sopenharmony_ci clksel); 12662306a36Sopenharmony_ci else 12762306a36Sopenharmony_ci pr_err("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci clk_put(enet_ref); 13062306a36Sopenharmony_ciput_ptp_clk: 13162306a36Sopenharmony_ci clk_put(ptp_clk); 13262306a36Sopenharmony_ciput_node: 13362306a36Sopenharmony_ci of_node_put(np); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void __init imx6q_axi_init(void) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct regmap *gpr; 13962306a36Sopenharmony_ci unsigned int mask; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); 14262306a36Sopenharmony_ci if (!IS_ERR(gpr)) { 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * Enable the cacheable attribute of VPU and IPU 14562306a36Sopenharmony_ci * AXI transactions. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL | 14862306a36Sopenharmony_ci IMX6Q_GPR4_VPU_RD_CACHE_SEL | 14962306a36Sopenharmony_ci IMX6Q_GPR4_VPU_P_WR_CACHE_VAL | 15062306a36Sopenharmony_ci IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK | 15162306a36Sopenharmony_ci IMX6Q_GPR4_IPU_WR_CACHE_CTL | 15262306a36Sopenharmony_ci IMX6Q_GPR4_IPU_RD_CACHE_CTL; 15362306a36Sopenharmony_ci regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Increase IPU read QoS priority */ 15662306a36Sopenharmony_ci regmap_update_bits(gpr, IOMUXC_GPR6, 15762306a36Sopenharmony_ci IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK | 15862306a36Sopenharmony_ci IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK, 15962306a36Sopenharmony_ci (0xf << 16) | (0x7 << 20)); 16062306a36Sopenharmony_ci regmap_update_bits(gpr, IOMUXC_GPR7, 16162306a36Sopenharmony_ci IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK | 16262306a36Sopenharmony_ci IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK, 16362306a36Sopenharmony_ci (0xf << 16) | (0x7 << 20)); 16462306a36Sopenharmony_ci } else { 16562306a36Sopenharmony_ci pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void __init imx6q_init_machine(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * SoCs that identify as i.MX6Q >= rev 2.0 are really i.MX6QP. 17462306a36Sopenharmony_ci * Quirk: i.MX6QP revision = i.MX6Q revision - (1, 0), 17562306a36Sopenharmony_ci * e.g. i.MX6QP rev 1.1 identifies as i.MX6Q rev 2.1. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci imx_print_silicon_rev("i.MX6QP", imx_get_soc_revision() - 0x10); 17862306a36Sopenharmony_ci else 17962306a36Sopenharmony_ci imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", 18062306a36Sopenharmony_ci imx_get_soc_revision()); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci imx6q_enet_phy_init(); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci of_platform_default_populate(NULL, NULL, NULL); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci imx_anatop_init(); 18762306a36Sopenharmony_ci cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); 18862306a36Sopenharmony_ci imx6q_1588_init(); 18962306a36Sopenharmony_ci imx6q_axi_init(); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic void __init imx6q_init_late(void) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci /* 19562306a36Sopenharmony_ci * WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so 19662306a36Sopenharmony_ci * there is no point to run cpuidle on them. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * It does work on imx6 Solo/DualLite starting from 1.1 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) || 20162306a36Sopenharmony_ci (cpu_is_imx6dl() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_0)) 20262306a36Sopenharmony_ci imx6q_cpuidle_init(); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) 20562306a36Sopenharmony_ci platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void __init imx6q_map_io(void) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci debug_ll_io_init(); 21162306a36Sopenharmony_ci imx_scu_map_io(); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void __init imx6q_init_irq(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci imx_gpc_check_dt(); 21762306a36Sopenharmony_ci imx_init_revision_from_anatop(); 21862306a36Sopenharmony_ci imx_init_l2cache(); 21962306a36Sopenharmony_ci imx_src_init(); 22062306a36Sopenharmony_ci irqchip_init(); 22162306a36Sopenharmony_ci imx6_pm_ccm_init("fsl,imx6q-ccm"); 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic const char * const imx6q_dt_compat[] __initconst = { 22562306a36Sopenharmony_ci "fsl,imx6dl", 22662306a36Sopenharmony_ci "fsl,imx6q", 22762306a36Sopenharmony_ci "fsl,imx6qp", 22862306a36Sopenharmony_ci NULL, 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciDT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") 23262306a36Sopenharmony_ci .l2c_aux_val = 0, 23362306a36Sopenharmony_ci .l2c_aux_mask = ~0, 23462306a36Sopenharmony_ci .smp = smp_ops(imx_smp_ops), 23562306a36Sopenharmony_ci .map_io = imx6q_map_io, 23662306a36Sopenharmony_ci .init_irq = imx6q_init_irq, 23762306a36Sopenharmony_ci .init_machine = imx6q_init_machine, 23862306a36Sopenharmony_ci .init_late = imx6q_init_late, 23962306a36Sopenharmony_ci .dt_compat = imx6q_dt_compat, 24062306a36Sopenharmony_ciMACHINE_END 241