1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2011-2013 Freescale Semiconductor, Inc. 4 * Copyright 2011 Linaro Ltd. 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/irqchip.h> 9 #include <linux/of_platform.h> 10 #include <linux/pci.h> 11 #include <linux/phy.h> 12 #include <linux/regmap.h> 13 #include <linux/micrel_phy.h> 14 #include <linux/mfd/syscon.h> 15 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 16 #include <asm/mach/arch.h> 17 #include <asm/mach/map.h> 18 19 #include "common.h" 20 #include "cpuidle.h" 21 #include "hardware.h" 22 23 /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ 24 static int ksz9021rn_phy_fixup(struct phy_device *phydev) 25 { 26 if (IS_BUILTIN(CONFIG_PHYLIB)) { 27 /* min rx data delay */ 28 phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 29 0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW); 30 phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000); 31 32 /* max rx/tx clock delay, min rx/tx control delay */ 33 phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 34 0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW); 35 phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xf0f0); 36 phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL, 37 MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW); 38 } 39 40 return 0; 41 } 42 43 /* 44 * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High 45 * as they are used for slots1-7 PERST# 46 */ 47 static void ventana_pciesw_early_fixup(struct pci_dev *dev) 48 { 49 u32 dw; 50 51 if (!of_machine_is_compatible("gw,ventana")) 52 return; 53 54 if (dev->devfn != 0) 55 return; 56 57 pci_read_config_dword(dev, 0x62c, &dw); 58 dw |= 0xaaa8; // GPIO1-7 outputs 59 pci_write_config_dword(dev, 0x62c, dw); 60 61 pci_read_config_dword(dev, 0x644, &dw); 62 dw |= 0xfe; // GPIO1-7 output high 63 pci_write_config_dword(dev, 0x644, dw); 64 65 msleep(100); 66 } 67 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup); 68 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup); 69 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup); 70 71 static void __init imx6q_enet_phy_init(void) 72 { 73 if (IS_BUILTIN(CONFIG_PHYLIB)) { 74 phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, 75 ksz9021rn_phy_fixup); 76 } 77 } 78 79 static void __init imx6q_1588_init(void) 80 { 81 struct device_node *np; 82 struct clk *ptp_clk, *fec_enet_ref; 83 struct clk *enet_ref; 84 struct regmap *gpr; 85 u32 clksel; 86 87 np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec"); 88 if (!np) { 89 pr_warn("%s: failed to find fec node\n", __func__); 90 return; 91 } 92 93 /* 94 * If enet_clk_ref configured, we assume DT did it properly and . 95 * clk-imx6q.c will do needed configuration. 96 */ 97 fec_enet_ref = of_clk_get_by_name(np, "enet_clk_ref"); 98 if (!IS_ERR(fec_enet_ref)) 99 goto put_node; 100 101 ptp_clk = of_clk_get(np, 2); 102 if (IS_ERR(ptp_clk)) { 103 pr_warn("%s: failed to get ptp clock\n", __func__); 104 goto put_node; 105 } 106 107 enet_ref = clk_get_sys(NULL, "enet_ref"); 108 if (IS_ERR(enet_ref)) { 109 pr_warn("%s: failed to get enet clock\n", __func__); 110 goto put_ptp_clk; 111 } 112 113 /* 114 * If enet_ref from ANATOP/CCM is the PTP clock source, we need to 115 * set bit IOMUXC_GPR1[21]. Or the PTP clock must be from pad 116 * (external OSC), and we need to clear the bit. 117 */ 118 clksel = clk_is_match(ptp_clk, enet_ref) ? 119 IMX6Q_GPR1_ENET_CLK_SEL_ANATOP : 120 IMX6Q_GPR1_ENET_CLK_SEL_PAD; 121 gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); 122 if (!IS_ERR(gpr)) 123 regmap_update_bits(gpr, IOMUXC_GPR1, 124 IMX6Q_GPR1_ENET_CLK_SEL_MASK, 125 clksel); 126 else 127 pr_err("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); 128 129 clk_put(enet_ref); 130 put_ptp_clk: 131 clk_put(ptp_clk); 132 put_node: 133 of_node_put(np); 134 } 135 136 static void __init imx6q_axi_init(void) 137 { 138 struct regmap *gpr; 139 unsigned int mask; 140 141 gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); 142 if (!IS_ERR(gpr)) { 143 /* 144 * Enable the cacheable attribute of VPU and IPU 145 * AXI transactions. 146 */ 147 mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL | 148 IMX6Q_GPR4_VPU_RD_CACHE_SEL | 149 IMX6Q_GPR4_VPU_P_WR_CACHE_VAL | 150 IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK | 151 IMX6Q_GPR4_IPU_WR_CACHE_CTL | 152 IMX6Q_GPR4_IPU_RD_CACHE_CTL; 153 regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask); 154 155 /* Increase IPU read QoS priority */ 156 regmap_update_bits(gpr, IOMUXC_GPR6, 157 IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK | 158 IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK, 159 (0xf << 16) | (0x7 << 20)); 160 regmap_update_bits(gpr, IOMUXC_GPR7, 161 IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK | 162 IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK, 163 (0xf << 16) | (0x7 << 20)); 164 } else { 165 pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n"); 166 } 167 } 168 169 static void __init imx6q_init_machine(void) 170 { 171 if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) 172 /* 173 * SoCs that identify as i.MX6Q >= rev 2.0 are really i.MX6QP. 174 * Quirk: i.MX6QP revision = i.MX6Q revision - (1, 0), 175 * e.g. i.MX6QP rev 1.1 identifies as i.MX6Q rev 2.1. 176 */ 177 imx_print_silicon_rev("i.MX6QP", imx_get_soc_revision() - 0x10); 178 else 179 imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", 180 imx_get_soc_revision()); 181 182 imx6q_enet_phy_init(); 183 184 of_platform_default_populate(NULL, NULL, NULL); 185 186 imx_anatop_init(); 187 cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); 188 imx6q_1588_init(); 189 imx6q_axi_init(); 190 } 191 192 static void __init imx6q_init_late(void) 193 { 194 /* 195 * WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so 196 * there is no point to run cpuidle on them. 197 * 198 * It does work on imx6 Solo/DualLite starting from 1.1 199 */ 200 if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) || 201 (cpu_is_imx6dl() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_0)) 202 imx6q_cpuidle_init(); 203 204 if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) 205 platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); 206 } 207 208 static void __init imx6q_map_io(void) 209 { 210 debug_ll_io_init(); 211 imx_scu_map_io(); 212 } 213 214 static void __init imx6q_init_irq(void) 215 { 216 imx_gpc_check_dt(); 217 imx_init_revision_from_anatop(); 218 imx_init_l2cache(); 219 imx_src_init(); 220 irqchip_init(); 221 imx6_pm_ccm_init("fsl,imx6q-ccm"); 222 } 223 224 static const char * const imx6q_dt_compat[] __initconst = { 225 "fsl,imx6dl", 226 "fsl,imx6q", 227 "fsl,imx6qp", 228 NULL, 229 }; 230 231 DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") 232 .l2c_aux_val = 0, 233 .l2c_aux_mask = ~0, 234 .smp = smp_ops(imx_smp_ops), 235 .map_io = imx6q_map_io, 236 .init_irq = imx6q_init_irq, 237 .init_machine = imx6q_init_machine, 238 .init_late = imx6q_init_late, 239 .dt_compat = imx6q_dt_compat, 240 MACHINE_END 241
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.