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