code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2011-2013 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/clk.h>
#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/micrel_phy.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "cpuidle.h"
#include "hardware.h"

/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
static int ksz9021rn_phy_fixup(struct phy_device *phydev)
{
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
		/* min rx data delay */
		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
			0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW);
		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000);

		/* max rx/tx clock delay, min rx/tx control delay */
		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);
	}

	return 0;
}

/*
 * 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);

static void __init imx6q_enet_phy_init(void)
{
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
				ksz9021rn_phy_fixup);
	}
}

static void __init imx6q_1588_init(void)
{
	struct device_node *np;
	struct clk *ptp_clk;
	struct clk *enet_ref;
	struct regmap *gpr;
	u32 clksel;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-fec");
	if (!np) {
		pr_warn("%s: failed to find fec node\n", __func__);
		return;
	}

	ptp_clk = of_clk_get(np, 2);
	if (IS_ERR(ptp_clk)) {
		pr_warn("%s: failed to get ptp clock\n", __func__);
		goto put_node;
	}

	enet_ref = clk_get_sys(NULL, "enet_ref");
	if (IS_ERR(enet_ref)) {
		pr_warn("%s: failed to get enet clock\n", __func__);
		goto put_ptp_clk;
	}

	/*
	 * If enet_ref from ANATOP/CCM is the PTP clock source, we need to
	 * set bit IOMUXC_GPR1[21].  Or the PTP clock must be from pad
	 * (external OSC), and we need to clear the bit.
	 */
	clksel = clk_is_match(ptp_clk, enet_ref) ?
				IMX6Q_GPR1_ENET_CLK_SEL_ANATOP :
				IMX6Q_GPR1_ENET_CLK_SEL_PAD;
	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
	if (!IS_ERR(gpr))
		regmap_update_bits(gpr, IOMUXC_GPR1,
				IMX6Q_GPR1_ENET_CLK_SEL_MASK,
				clksel);
	else
		pr_err("failed to find fsl,imx6q-iomuxc-gpr regmap\n");

	clk_put(enet_ref);
put_ptp_clk:
	clk_put(ptp_clk);
put_node:
	of_node_put(np);
}

static void __init imx6q_axi_init(void)
{
	struct regmap *gpr;
	unsigned int mask;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
	if (!IS_ERR(gpr)) {
		/*
		 * Enable the cacheable attribute of VPU and IPU
		 * AXI transactions.
		 */
		mask = IMX6Q_GPR4_VPU_WR_CACHE_SEL |
			IMX6Q_GPR4_VPU_RD_CACHE_SEL |
			IMX6Q_GPR4_VPU_P_WR_CACHE_VAL |
			IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK |
			IMX6Q_GPR4_IPU_WR_CACHE_CTL |
			IMX6Q_GPR4_IPU_RD_CACHE_CTL;
		regmap_update_bits(gpr, IOMUXC_GPR4, mask, mask);

		/* Increase IPU read QoS priority */
		regmap_update_bits(gpr, IOMUXC_GPR6,
				IMX6Q_GPR6_IPU1_ID00_RD_QOS_MASK |
				IMX6Q_GPR6_IPU1_ID01_RD_QOS_MASK,
				(0xf << 16) | (0x7 << 20));
		regmap_update_bits(gpr, IOMUXC_GPR7,
				IMX6Q_GPR7_IPU2_ID00_RD_QOS_MASK |
				IMX6Q_GPR7_IPU2_ID01_RD_QOS_MASK,
				(0xf << 16) | (0x7 << 20));
	} else {
		pr_warn("failed to find fsl,imx6q-iomuxc-gpr regmap\n");
	}
}

static void __init imx6q_init_machine(void)
{
	if (cpu_is_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0)
		/*
		 * SoCs that identify as i.MX6Q >= rev 2.0 are really i.MX6QP.
		 * Quirk: i.MX6QP revision = i.MX6Q revision - (1, 0),
		 * e.g. i.MX6QP rev 1.1 identifies as i.MX6Q rev 2.1.
		 */
		imx_print_silicon_rev("i.MX6QP", imx_get_soc_revision() - 0x10);
	else
		imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
				imx_get_soc_revision());

	imx6q_enet_phy_init();

	of_platform_default_populate(NULL, NULL, NULL);

	imx_anatop_init();
	cpu_is_imx6q() ?  imx6q_pm_init() : imx6dl_pm_init();
	imx6q_1588_init();
	imx6q_axi_init();
}

static void __init imx6q_init_late(void)
{
	/*
	 * WAIT mode is broken on imx6 Dual/Quad revision 1.0 and 1.1 so
	 * there is no point to run cpuidle on them.
	 *
	 * It does work on imx6 Solo/DualLite starting from 1.1
	 */
	if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) ||
	    (cpu_is_imx6dl() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_0))
		imx6q_cpuidle_init();

	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
		platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}

static void __init imx6q_map_io(void)
{
	debug_ll_io_init();
	imx_scu_map_io();
}

static void __init imx6q_init_irq(void)
{
	imx_gpc_check_dt();
	imx_init_revision_from_anatop();
	imx_init_l2cache();
	imx_src_init();
	irqchip_init();
	imx6_pm_ccm_init("fsl,imx6q-ccm");
}

static const char * const imx6q_dt_compat[] __initconst = {
	"fsl,imx6dl",
	"fsl,imx6q",
	"fsl,imx6qp",
	NULL,
};

DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
	.l2c_aux_val 	= 0,
	.l2c_aux_mask	= ~0,
	.smp		= smp_ops(imx_smp_ops),
	.map_io		= imx6q_map_io,
	.init_irq	= imx6q_init_irq,
	.init_machine	= imx6q_init_machine,
	.init_late      = imx6q_init_late,
	.dt_compat	= imx6q_dt_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2013 Freescale Semiconductor, Inc.
 */

#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/regmap.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "cpuidle.h"
#include "hardware.h"

static void __init imx6sl_fec_init(void)
{
	struct regmap *gpr;

	/* set FEC clock from internal PLL clock source */
	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sl-iomuxc-gpr");
	if (!IS_ERR(gpr)) {
		regmap_update_bits(gpr, IOMUXC_GPR1,
			IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0);
		regmap_update_bits(gpr, IOMUXC_GPR1,
			IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0);
	} else {
		pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n");
	}
}

static void __init imx6sl_init_late(void)
{
	/* imx6sl reuses imx6q cpufreq driver */
	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
		platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);

	if (IS_ENABLED(CONFIG_SOC_IMX6SL) && cpu_is_imx6sl())
		imx6sl_cpuidle_init();
	else if (IS_ENABLED(CONFIG_SOC_IMX6SLL))
		imx6sx_cpuidle_init();
}

static void __init imx6sl_init_machine(void)
{
	of_platform_default_populate(NULL, NULL, NULL);

	if (cpu_is_imx6sl())
		imx6sl_fec_init();
	imx_anatop_init();
	imx6sl_pm_init();
}

static void __init imx6sl_init_irq(void)
{
	imx_gpc_check_dt();
	imx_init_revision_from_anatop();
	imx_init_l2cache();
	imx_src_init();
	irqchip_init();
	if (cpu_is_imx6sl())
		imx6_pm_ccm_init("fsl,imx6sl-ccm");
	else
		imx6_pm_ccm_init("fsl,imx6sll-ccm");
}

static const char * const imx6sl_dt_compat[] __initconst = {
	"fsl,imx6sl",
	"fsl,imx6sll",
	NULL,
};

DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)")
	.l2c_aux_val 	= 0,
	.l2c_aux_mask	= ~0,
	.init_irq	= imx6sl_init_irq,
	.init_machine	= imx6sl_init_machine,
	.init_late      = imx6sl_init_late,
	.dt_compat	= imx6sl_dt_compat,
MACHINE_END

repo_name: angery/linux


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2014 Freescale Semiconductor, Inc.
 */

#include <linux/irqchip.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "cpuidle.h"

static void __init imx6sx_enet_clk_sel(void)
{
	struct regmap *gpr;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr");
	if (!IS_ERR(gpr)) {
		regmap_update_bits(gpr, IOMUXC_GPR1,
				   IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0);
		regmap_update_bits(gpr, IOMUXC_GPR1,
				   IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0);
	} else {
		pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n");
	}
}

static inline void imx6sx_enet_init(void)
{
	imx6sx_enet_clk_sel();
}

static void __init imx6sx_init_machine(void)
{
	of_platform_default_populate(NULL, NULL, NULL);

	imx6sx_enet_init();
	imx_anatop_init();
	imx6sx_pm_init();
}

static void __init imx6sx_init_irq(void)
{
	imx_gpc_check_dt();
	imx_init_revision_from_anatop();
	imx_init_l2cache();
	imx_src_init();
	irqchip_init();
	imx6_pm_ccm_init("fsl,imx6sx-ccm");
}

static void __init imx6sx_init_late(void)
{
	imx6sx_cpuidle_init();

	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
		platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}

static const char * const imx6sx_dt_compat[] __initconst = {
	"fsl,imx6sx",
	NULL,
};

DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)")
	.l2c_aux_val 	= 0,
	.l2c_aux_mask	= ~0,
	.init_irq	= imx6sx_init_irq,
	.init_machine	= imx6sx_init_machine,
	.dt_compat	= imx6sx_dt_compat,
	.init_late	= imx6sx_init_late,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2015 Freescale Semiconductor, Inc.
 */
#include <linux/irqchip.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/micrel_phy.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"
#include "cpuidle.h"
#include "hardware.h"

static void __init imx6ul_enet_clk_init(void)
{
	struct regmap *gpr;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr");
	if (!IS_ERR(gpr))
		regmap_update_bits(gpr, IOMUXC_GPR1, IMX6UL_GPR1_ENET_CLK_DIR,
				   IMX6UL_GPR1_ENET_CLK_OUTPUT);
	else
		pr_err("failed to find fsl,imx6ul-iomux-gpr regmap\n");
}

static inline void imx6ul_enet_init(void)
{
	imx6ul_enet_clk_init();
}

static void __init imx6ul_init_machine(void)
{
	imx_print_silicon_rev(cpu_is_imx6ull() ? "i.MX6ULL" : "i.MX6UL",
		imx_get_soc_revision());

	of_platform_default_populate(NULL, NULL, NULL);
	imx6ul_enet_init();
	imx_anatop_init();
	imx6ul_pm_init();
}

static void __init imx6ul_init_irq(void)
{
	imx_init_revision_from_anatop();
	imx_src_init();
	irqchip_init();
	imx6_pm_ccm_init("fsl,imx6ul-ccm");
}

static void __init imx6ul_init_late(void)
{
	imx6sx_cpuidle_init();

	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
		platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}

static const char * const imx6ul_dt_compat[] __initconst = {
	"fsl,imx6ul",
	"fsl,imx6ull",
	NULL,
};

DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
	.init_irq	= imx6ul_init_irq,
	.init_machine	= imx6ul_init_machine,
	.init_late	= imx6ul_init_late,
	.dt_compat	= imx6ul_dt_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2018 Pengutronix, Oleksij Rempel <o.rempel@pengutronix.de>
 */

#include <linux/kernel.h>
#include <asm/v7m.h>
#include <asm/mach/arch.h>

static const char * const imx7d_cm4_dt_compat[] __initconst = {
	"fsl,imx7d-cm4",
	NULL,
};

DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual Cortex-M4 (Device Tree)")
	.dt_compat = imx7d_cm4_dt_compat,
	.restart = armv7m_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2015 Freescale Semiconductor, Inc.
 */
#include <linux/irqchip.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/regmap.h>

#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include "common.h"

static int bcm54220_phy_fixup(struct phy_device *dev)
{
	/* enable RXC skew select RGMII copper mode */
	phy_write(dev, 0x1e, 0x21);
	phy_write(dev, 0x1f, 0x7ea8);
	phy_write(dev, 0x1e, 0x2f);
	phy_write(dev, 0x1f, 0x71b7);

	return 0;
}

#define PHY_ID_BCM54220	0x600d8589

static void __init imx7d_enet_phy_init(void)
{
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
		phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff,
					   bcm54220_phy_fixup);
	}
}

static void __init imx7d_enet_clk_sel(void)
{
	struct regmap *gpr;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr");
	if (!IS_ERR(gpr)) {
		regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_TX_CLK_SEL_MASK, 0);
		regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_CLK_DIR_MASK, 0);
	} else {
		pr_err("failed to find fsl,imx7d-iomux-gpr regmap\n");
	}
}

static inline void imx7d_enet_init(void)
{
	imx7d_enet_phy_init();
	imx7d_enet_clk_sel();
}

static void __init imx7d_init_machine(void)
{
	imx_anatop_init();
	imx7d_enet_init();
}

static void __init imx7d_init_late(void)
{
	if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
		platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
}

static void __init imx7d_init_irq(void)
{
	imx_init_revision_from_anatop();
	imx7_src_init();
	irqchip_init();
}

static const char *const imx7d_dt_compat[] __initconst = {
	"fsl,imx7d",
	"fsl,imx7s",
	NULL,
};

DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)")
	.smp            = smp_ops(imx7_smp_ops),
	.init_irq	= imx7d_init_irq,
	.init_machine	= imx7d_init_machine,
	.init_late      = imx7d_init_late,
	.dt_compat	= imx7d_dt_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 * Copyright 2017-2018 NXP
 *   Author: Dong Aisheng <aisheng.dong@nxp.com>
 */

#include <linux/irqchip.h>
#include <linux/mfd/syscon.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <asm/mach/arch.h>

#include "common.h"
#include "cpuidle.h"
#include "hardware.h"

#define SIM_JTAG_ID_REG		0x8c

static void __init imx7ulp_set_revision(void)
{
	struct regmap *sim;
	u32 revision;

	sim = syscon_regmap_lookup_by_compatible("fsl,imx7ulp-sim");
	if (IS_ERR(sim)) {
		pr_warn("failed to find fsl,imx7ulp-sim regmap!\n");
		return;
	}

	if (regmap_read(sim, SIM_JTAG_ID_REG, &revision)) {
		pr_warn("failed to read sim regmap!\n");
		return;
	}

	/*
	 * bit[31:28] of JTAG_ID register defines revision as below from B0:
	 * 0001        B0
	 * 0010        B1
	 * 0011        B2
	 */
	switch (revision >> 28) {
	case 1:
		imx_set_soc_revision(IMX_CHIP_REVISION_2_0);
		break;
	case 2:
		imx_set_soc_revision(IMX_CHIP_REVISION_2_1);
		break;
	case 3:
		imx_set_soc_revision(IMX_CHIP_REVISION_2_2);
		break;
	default:
		imx_set_soc_revision(IMX_CHIP_REVISION_1_0);
		break;
	}
}

static void __init imx7ulp_init_machine(void)
{
	imx7ulp_pm_init();

	mxc_set_cpu_type(MXC_CPU_IMX7ULP);
	imx7ulp_set_revision();
	of_platform_default_populate(NULL, NULL, NULL);
}

static const char *const imx7ulp_dt_compat[] __initconst = {
	"fsl,imx7ulp",
	NULL,
};

static void __init imx7ulp_init_late(void)
{
	if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
		platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);

	imx7ulp_cpuidle_init();
}

DT_MACHINE_START(IMX7ulp, "Freescale i.MX7ULP (Device Tree)")
	.init_machine	= imx7ulp_init_machine,
	.dt_compat	= imx7ulp_dt_compat,
	.init_late	= imx7ulp_init_late,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019
 * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
 */

#include <linux/kernel.h>
#include <asm/mach/arch.h>
#include <asm/v7m.h>

static const char *const imxrt_compat[] __initconst = {
	"fsl,imxrt1050",
	NULL
};

DT_MACHINE_START(IMXRTDT, "IMXRT (Device Tree Support)")
	.dt_compat = imxrt_compat,
	.restart = armv7m_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2013-2014 Freescale Semiconductor, Inc.
 */

#include <asm/mach/arch.h>

#include "common.h"

static const char * const ls1021a_dt_compat[] __initconst = {
	"fsl,ls1021a",
	NULL,
};

DT_MACHINE_START(LS1021A, "Freescale LS1021A")
	.smp		= smp_ops(ls1021a_smp_ops),
	.dt_compat	= ls1021a_dt_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2012-2013 Freescale Semiconductor, Inc.
 */

#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/io.h>

#include <linux/irqchip.h>
#include <asm/mach/arch.h>
#include <asm/hardware/cache-l2x0.h>

#include "common.h"
#include "hardware.h"

#define MSCM_CPxCOUNT		0x00c
#define MSCM_CPxCFG1		0x014

static void __init vf610_detect_cpu(void)
{
	struct device_node *np;
	u32 cpxcount, cpxcfg1;
	unsigned int cpu_type;
	void __iomem *mscm;

	np = of_find_compatible_node(NULL, NULL, "fsl,vf610-mscm-cpucfg");
	if (WARN_ON(!np))
		return;

	mscm = of_iomap(np, 0);
	of_node_put(np);

	if (WARN_ON(!mscm))
		return;

	cpxcount = readl_relaxed(mscm + MSCM_CPxCOUNT);
	cpxcfg1  = readl_relaxed(mscm + MSCM_CPxCFG1);

	iounmap(mscm);

	cpu_type = cpxcount ? MXC_CPU_VF600 : MXC_CPU_VF500;

	if (cpxcfg1)
		cpu_type |= MXC_CPU_VFx10;

	mxc_set_cpu_type(cpu_type);
}

static void __init vf610_init_machine(void)
{
	vf610_detect_cpu();

	of_platform_default_populate(NULL, NULL, NULL);
}

static const char * const vf610_dt_compat[] __initconst = {
	"fsl,vf500",
	"fsl,vf510",
	"fsl,vf600",
	"fsl,vf610",
	"fsl,vf610m4",
	NULL,
};

DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF5xx/VF6xx (Device Tree)")
	.l2c_aux_val	= 0,
	.l2c_aux_mask	= ~0,
	.init_machine   = vf610_init_machine,
	.dt_compat	= vf610_dt_compat,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Copyright (C) 1999,2000 Arm Limited
 *  Copyright (C) 2000 Deep Blue Solutions Ltd
 *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
 *  Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 *    - add MX31 specific definitions
 */

#include <linux/mm.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of_address.h>

#include <asm/system_misc.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>

#include "common.h"
#include "crmregs-imx3.h"
#include "hardware.h"

void __iomem *mx3_ccm_base;

static void imx3_idle(void)
{
	unsigned long reg = 0;

	__asm__ __volatile__(
		/* disable I and D cache */
		"mrc p15, 0, %0, c1, c0, 0\n"
		"bic %0, %0, #0x00001000\n"
		"bic %0, %0, #0x00000004\n"
		"mcr p15, 0, %0, c1, c0, 0\n"
		/* invalidate I cache */
		"mov %0, #0\n"
		"mcr p15, 0, %0, c7, c5, 0\n"
		/* clear and invalidate D cache */
		"mov %0, #0\n"
		"mcr p15, 0, %0, c7, c14, 0\n"
		/* WFI */
		"mov %0, #0\n"
		"mcr p15, 0, %0, c7, c0, 4\n"
		"nop\n" "nop\n" "nop\n" "nop\n"
		"nop\n" "nop\n" "nop\n"
		/* enable I and D cache */
		"mrc p15, 0, %0, c1, c0, 0\n"
		"orr %0, %0, #0x00001000\n"
		"orr %0, %0, #0x00000004\n"
		"mcr p15, 0, %0, c1, c0, 0\n"
		: "=r" (reg));
}

static void __iomem *imx3_ioremap_caller(phys_addr_t phys_addr, size_t size,
					 unsigned int mtype, void *caller)
{
	if (mtype == MT_DEVICE) {
		/*
		 * Access all peripherals below 0x80000000 as nonshared device
		 * on mx3, but leave l2cc alone.  Otherwise cache corruptions
		 * can occur.
		 */
		if (phys_addr < 0x80000000 &&
				!addr_in_module(phys_addr, MX3x_L2CC))
			mtype = MT_DEVICE_NONSHARED;
	}

	return __arm_ioremap_caller(phys_addr, size, mtype, caller);
}

#ifdef CONFIG_SOC_IMX31
static struct map_desc mx31_io_desc[] __initdata = {
	imx_map_entry(MX31, X_MEMC, MT_DEVICE),
	imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED),
	imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED),
	imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED),
	imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED),
};

/*
 * This function initializes the memory map. It is called during the
 * system startup to create static physical to virtual memory mappings
 * for the IO modules.
 */
void __init mx31_map_io(void)
{
	iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc));
}

static void imx31_idle(void)
{
	int reg = imx_readl(mx3_ccm_base + MXC_CCM_CCMR);
	reg &= ~MXC_CCM_CCMR_LPM_MASK;
	imx_writel(reg, mx3_ccm_base + MXC_CCM_CCMR);

	imx3_idle();
}

void __init imx31_init_early(void)
{
	struct device_node *np;

	mxc_set_cpu_type(MXC_CPU_MX31);
	arch_ioremap_caller = imx3_ioremap_caller;
	arm_pm_idle = imx31_idle;
	np = of_find_compatible_node(NULL, NULL, "fsl,imx31-ccm");
	mx3_ccm_base = of_iomap(np, 0);
	BUG_ON(!mx3_ccm_base);
}
#endif /* ifdef CONFIG_SOC_IMX31 */

#ifdef CONFIG_SOC_IMX35
static struct map_desc mx35_io_desc[] __initdata = {
	imx_map_entry(MX35, X_MEMC, MT_DEVICE),
	imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED),
	imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED),
	imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED),
	imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED),
};

void __init mx35_map_io(void)
{
	iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc));
}

static void imx35_idle(void)
{
	int reg = imx_readl(mx3_ccm_base + MXC_CCM_CCMR);
	reg &= ~MXC_CCM_CCMR_LPM_MASK;
	reg |= MXC_CCM_CCMR_LPM_WAIT_MX35;
	imx_writel(reg, mx3_ccm_base + MXC_CCM_CCMR);

	imx3_idle();
}

void __init imx35_init_early(void)
{
	struct device_node *np;

	mxc_set_cpu_type(MXC_CPU_MX35);
	arm_pm_idle = imx35_idle;
	arch_ioremap_caller = imx3_ioremap_caller;
	np = of_find_compatible_node(NULL, NULL, "fsl,imx35-ccm");
	mx3_ccm_base = of_iomap(np, 0);
	BUG_ON(!mx3_ccm_base);
}
#endif /* ifdef CONFIG_SOC_IMX35 */


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2017 NXP
 * Copyright 2011,2016 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/clk.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/perf_event.h>
#include <linux/slab.h>

#include "common.h"

#define MMDC_MAPSR		0x404
#define BP_MMDC_MAPSR_PSD	0
#define BP_MMDC_MAPSR_PSS	4

#define MMDC_MDMISC		0x18
#define BM_MMDC_MDMISC_DDR_TYPE	0x18
#define BP_MMDC_MDMISC_DDR_TYPE	0x3

#define TOTAL_CYCLES		0x0
#define BUSY_CYCLES		0x1
#define READ_ACCESSES		0x2
#define WRITE_ACCESSES		0x3
#define READ_BYTES		0x4
#define WRITE_BYTES		0x5

/* Enables, resets, freezes, overflow profiling*/
#define DBG_DIS			0x0
#define DBG_EN			0x1
#define DBG_RST			0x2
#define PRF_FRZ			0x4
#define CYC_OVF			0x8
#define PROFILE_SEL		0x10

#define MMDC_MADPCR0	0x410
#define MMDC_MADPCR1	0x414
#define MMDC_MADPSR0	0x418
#define MMDC_MADPSR1	0x41C
#define MMDC_MADPSR2	0x420
#define MMDC_MADPSR3	0x424
#define MMDC_MADPSR4	0x428
#define MMDC_MADPSR5	0x42C

#define MMDC_NUM_COUNTERS	6

#define MMDC_FLAG_PROFILE_SEL	0x1
#define MMDC_PRF_AXI_ID_CLEAR	0x0

#define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu)

static int ddr_type;

struct fsl_mmdc_devtype_data {
	unsigned int flags;
};

static const struct fsl_mmdc_devtype_data imx6q_data = {
};

static const struct fsl_mmdc_devtype_data imx6qp_data = {
	.flags = MMDC_FLAG_PROFILE_SEL,
};

static const struct of_device_id imx_mmdc_dt_ids[] = {
	{ .compatible = "fsl,imx6q-mmdc", .data = (void *)&imx6q_data},
	{ .compatible = "fsl,imx6qp-mmdc", .data = (void *)&imx6qp_data},
	{ /* sentinel */ }
};

#ifdef CONFIG_PERF_EVENTS

static enum cpuhp_state cpuhp_mmdc_state;
static DEFINE_IDA(mmdc_ida);

PMU_EVENT_ATTR_STRING(total-cycles, mmdc_pmu_total_cycles, "event=0x00")
PMU_EVENT_ATTR_STRING(busy-cycles, mmdc_pmu_busy_cycles, "event=0x01")
PMU_EVENT_ATTR_STRING(read-accesses, mmdc_pmu_read_accesses, "event=0x02")
PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu_write_accesses, "event=0x03")
PMU_EVENT_ATTR_STRING(read-bytes, mmdc_pmu_read_bytes, "event=0x04")
PMU_EVENT_ATTR_STRING(read-bytes.unit, mmdc_pmu_read_bytes_unit, "MB");
PMU_EVENT_ATTR_STRING(read-bytes.scale, mmdc_pmu_read_bytes_scale, "0.000001");
PMU_EVENT_ATTR_STRING(write-bytes, mmdc_pmu_write_bytes, "event=0x05")
PMU_EVENT_ATTR_STRING(write-bytes.unit, mmdc_pmu_write_bytes_unit, "MB");
PMU_EVENT_ATTR_STRING(write-bytes.scale, mmdc_pmu_write_bytes_scale, "0.000001");

struct mmdc_pmu {
	struct pmu pmu;
	void __iomem *mmdc_base;
	cpumask_t cpu;
	struct hrtimer hrtimer;
	unsigned int active_events;
	struct device *dev;
	struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
	struct hlist_node node;
	struct fsl_mmdc_devtype_data *devtype_data;
	struct clk *mmdc_ipg_clk;
};

/*
 * Polling period is set to one second, overflow of total-cycles (the fastest
 * increasing counter) takes ten seconds so one second is safe
 */
static unsigned int mmdc_pmu_poll_period_us = 1000000;

module_param_named(pmu_pmu_poll_period_us, mmdc_pmu_poll_period_us, uint,
		S_IRUGO | S_IWUSR);

static ktime_t mmdc_pmu_timer_period(void)
{
	return ns_to_ktime((u64)mmdc_pmu_poll_period_us * 1000);
}

static ssize_t mmdc_pmu_cpumask_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct mmdc_pmu *pmu_mmdc = dev_get_drvdata(dev);

	return cpumap_print_to_pagebuf(true, buf, &pmu_mmdc->cpu);
}

static struct device_attribute mmdc_pmu_cpumask_attr =
	__ATTR(cpumask, S_IRUGO, mmdc_pmu_cpumask_show, NULL);

static struct attribute *mmdc_pmu_cpumask_attrs[] = {
	&mmdc_pmu_cpumask_attr.attr,
	NULL,
};

static struct attribute_group mmdc_pmu_cpumask_attr_group = {
	.attrs = mmdc_pmu_cpumask_attrs,
};

static struct attribute *mmdc_pmu_events_attrs[] = {
	&mmdc_pmu_total_cycles.attr.attr,
	&mmdc_pmu_busy_cycles.attr.attr,
	&mmdc_pmu_read_accesses.attr.attr,
	&mmdc_pmu_write_accesses.attr.attr,
	&mmdc_pmu_read_bytes.attr.attr,
	&mmdc_pmu_read_bytes_unit.attr.attr,
	&mmdc_pmu_read_bytes_scale.attr.attr,
	&mmdc_pmu_write_bytes.attr.attr,
	&mmdc_pmu_write_bytes_unit.attr.attr,
	&mmdc_pmu_write_bytes_scale.attr.attr,
	NULL,
};

static struct attribute_group mmdc_pmu_events_attr_group = {
	.name = "events",
	.attrs = mmdc_pmu_events_attrs,
};

PMU_FORMAT_ATTR(event, "config:0-63");
PMU_FORMAT_ATTR(axi_id, "config1:0-63");

static struct attribute *mmdc_pmu_format_attrs[] = {
	&format_attr_event.attr,
	&format_attr_axi_id.attr,
	NULL,
};

static struct attribute_group mmdc_pmu_format_attr_group = {
	.name = "format",
	.attrs = mmdc_pmu_format_attrs,
};

static const struct attribute_group *attr_groups[] = {
	&mmdc_pmu_events_attr_group,
	&mmdc_pmu_format_attr_group,
	&mmdc_pmu_cpumask_attr_group,
	NULL,
};

static u32 mmdc_pmu_read_counter(struct mmdc_pmu *pmu_mmdc, int cfg)
{
	void __iomem *mmdc_base, *reg;

	mmdc_base = pmu_mmdc->mmdc_base;

	switch (cfg) {
	case TOTAL_CYCLES:
		reg = mmdc_base + MMDC_MADPSR0;
		break;
	case BUSY_CYCLES:
		reg = mmdc_base + MMDC_MADPSR1;
		break;
	case READ_ACCESSES:
		reg = mmdc_base + MMDC_MADPSR2;
		break;
	case WRITE_ACCESSES:
		reg = mmdc_base + MMDC_MADPSR3;
		break;
	case READ_BYTES:
		reg = mmdc_base + MMDC_MADPSR4;
		break;
	case WRITE_BYTES:
		reg = mmdc_base + MMDC_MADPSR5;
		break;
	default:
		return WARN_ONCE(1,
			"invalid configuration %d for mmdc counter", cfg);
	}
	return readl(reg);
}

static int mmdc_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
{
	struct mmdc_pmu *pmu_mmdc = hlist_entry_safe(node, struct mmdc_pmu, node);
	int target;

	if (!cpumask_test_and_clear_cpu(cpu, &pmu_mmdc->cpu))
		return 0;

	target = cpumask_any_but(cpu_online_mask, cpu);
	if (target >= nr_cpu_ids)
		return 0;

	perf_pmu_migrate_context(&pmu_mmdc->pmu, cpu, target);
	cpumask_set_cpu(target, &pmu_mmdc->cpu);

	return 0;
}

static bool mmdc_pmu_group_event_is_valid(struct perf_event *event,
					  struct pmu *pmu,
					  unsigned long *used_counters)
{
	int cfg = event->attr.config;

	if (is_software_event(event))
		return true;

	if (event->pmu != pmu)
		return false;

	return !test_and_set_bit(cfg, used_counters);
}

/*
 * Each event has a single fixed-purpose counter, so we can only have a
 * single active event for each at any point in time. Here we just check
 * for duplicates, and rely on mmdc_pmu_event_init to verify that the HW
 * event numbers are valid.
 */
static bool mmdc_pmu_group_is_valid(struct perf_event *event)
{
	struct pmu *pmu = event->pmu;
	struct perf_event *leader = event->group_leader;
	struct perf_event *sibling;
	unsigned long counter_mask = 0;

	set_bit(leader->attr.config, &counter_mask);

	if (event != leader) {
		if (!mmdc_pmu_group_event_is_valid(event, pmu, &counter_mask))
			return false;
	}

	for_each_sibling_event(sibling, leader) {
		if (!mmdc_pmu_group_event_is_valid(sibling, pmu, &counter_mask))
			return false;
	}

	return true;
}

static int mmdc_pmu_event_init(struct perf_event *event)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	int cfg = event->attr.config;

	if (event->attr.type != event->pmu->type)
		return -ENOENT;

	if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
		return -EOPNOTSUPP;

	if (event->cpu < 0) {
		dev_warn(pmu_mmdc->dev, "Can't provide per-task data!\n");
		return -EOPNOTSUPP;
	}

	if (event->attr.sample_period)
		return -EINVAL;

	if (cfg < 0 || cfg >= MMDC_NUM_COUNTERS)
		return -EINVAL;

	if (!mmdc_pmu_group_is_valid(event))
		return -EINVAL;

	event->cpu = cpumask_first(&pmu_mmdc->cpu);
	return 0;
}

static void mmdc_pmu_event_update(struct perf_event *event)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
	u64 delta, prev_raw_count, new_raw_count;

	do {
		prev_raw_count = local64_read(&hwc->prev_count);
		new_raw_count = mmdc_pmu_read_counter(pmu_mmdc,
						      event->attr.config);
	} while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
		new_raw_count) != prev_raw_count);

	delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF;

	local64_add(delta, &event->count);
}

static void mmdc_pmu_event_start(struct perf_event *event, int flags)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;
	void __iomem *mmdc_base, *reg;
	u32 val;

	mmdc_base = pmu_mmdc->mmdc_base;
	reg = mmdc_base + MMDC_MADPCR0;

	/*
	 * hrtimer is required because mmdc does not provide an interrupt so
	 * polling is necessary
	 */
	hrtimer_start(&pmu_mmdc->hrtimer, mmdc_pmu_timer_period(),
			HRTIMER_MODE_REL_PINNED);

	local64_set(&hwc->prev_count, 0);

	writel(DBG_RST, reg);

	/*
	 * Write the AXI id parameter to MADPCR1.
	 */
	val = event->attr.config1;
	reg = mmdc_base + MMDC_MADPCR1;
	writel(val, reg);

	reg = mmdc_base + MMDC_MADPCR0;
	val = DBG_EN;
	if (pmu_mmdc->devtype_data->flags & MMDC_FLAG_PROFILE_SEL)
		val |= PROFILE_SEL;

	writel(val, reg);
}

static int mmdc_pmu_event_add(struct perf_event *event, int flags)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	struct hw_perf_event *hwc = &event->hw;

	int cfg = event->attr.config;

	if (flags & PERF_EF_START)
		mmdc_pmu_event_start(event, flags);

	if (pmu_mmdc->mmdc_events[cfg] != NULL)
		return -EAGAIN;

	pmu_mmdc->mmdc_events[cfg] = event;
	pmu_mmdc->active_events++;

	local64_set(&hwc->prev_count, mmdc_pmu_read_counter(pmu_mmdc, cfg));

	return 0;
}

static void mmdc_pmu_event_stop(struct perf_event *event, int flags)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	void __iomem *mmdc_base, *reg;

	mmdc_base = pmu_mmdc->mmdc_base;
	reg = mmdc_base + MMDC_MADPCR0;

	writel(PRF_FRZ, reg);

	reg = mmdc_base + MMDC_MADPCR1;
	writel(MMDC_PRF_AXI_ID_CLEAR, reg);

	mmdc_pmu_event_update(event);
}

static void mmdc_pmu_event_del(struct perf_event *event, int flags)
{
	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
	int cfg = event->attr.config;

	pmu_mmdc->mmdc_events[cfg] = NULL;
	pmu_mmdc->active_events--;

	if (pmu_mmdc->active_events == 0)
		hrtimer_cancel(&pmu_mmdc->hrtimer);

	mmdc_pmu_event_stop(event, PERF_EF_UPDATE);
}

static void mmdc_pmu_overflow_handler(struct mmdc_pmu *pmu_mmdc)
{
	int i;

	for (i = 0; i < MMDC_NUM_COUNTERS; i++) {
		struct perf_event *event = pmu_mmdc->mmdc_events[i];

		if (event)
			mmdc_pmu_event_update(event);
	}
}

static enum hrtimer_restart mmdc_pmu_timer_handler(struct hrtimer *hrtimer)
{
	struct mmdc_pmu *pmu_mmdc = container_of(hrtimer, struct mmdc_pmu,
			hrtimer);

	mmdc_pmu_overflow_handler(pmu_mmdc);
	hrtimer_forward_now(hrtimer, mmdc_pmu_timer_period());

	return HRTIMER_RESTART;
}

static int mmdc_pmu_init(struct mmdc_pmu *pmu_mmdc,
		void __iomem *mmdc_base, struct device *dev)
{
	int mmdc_num;

	*pmu_mmdc = (struct mmdc_pmu) {
		.pmu = (struct pmu) {
			.task_ctx_nr    = perf_invalid_context,
			.attr_groups    = attr_groups,
			.event_init     = mmdc_pmu_event_init,
			.add            = mmdc_pmu_event_add,
			.del            = mmdc_pmu_event_del,
			.start          = mmdc_pmu_event_start,
			.stop           = mmdc_pmu_event_stop,
			.read           = mmdc_pmu_event_update,
			.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
		},
		.mmdc_base = mmdc_base,
		.dev = dev,
		.active_events = 0,
	};

	mmdc_num = ida_simple_get(&mmdc_ida, 0, 0, GFP_KERNEL);

	return mmdc_num;
}

static int imx_mmdc_remove(struct platform_device *pdev)
{
	struct mmdc_pmu *pmu_mmdc = platform_get_drvdata(pdev);

	cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
	perf_pmu_unregister(&pmu_mmdc->pmu);
	iounmap(pmu_mmdc->mmdc_base);
	clk_disable_unprepare(pmu_mmdc->mmdc_ipg_clk);
	kfree(pmu_mmdc);
	return 0;
}

static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_base,
			      struct clk *mmdc_ipg_clk)
{
	struct mmdc_pmu *pmu_mmdc;
	char *name;
	int mmdc_num;
	int ret;
	const struct of_device_id *of_id =
		of_match_device(imx_mmdc_dt_ids, &pdev->dev);

	pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);
	if (!pmu_mmdc) {
		pr_err("failed to allocate PMU device!\n");
		return -ENOMEM;
	}

	/* The first instance registers the hotplug state */
	if (!cpuhp_mmdc_state) {
		ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
					      "perf/arm/mmdc:online", NULL,
					      mmdc_pmu_offline_cpu);
		if (ret < 0) {
			pr_err("cpuhp_setup_state_multi failed\n");
			goto pmu_free;
		}
		cpuhp_mmdc_state = ret;
	}

	mmdc_num = mmdc_pmu_init(pmu_mmdc, mmdc_base, &pdev->dev);
	pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk;
	if (mmdc_num == 0)
		name = "mmdc";
	else
		name = devm_kasprintf(&pdev->dev,
				GFP_KERNEL, "mmdc%d", mmdc_num);

	pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data;

	hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
			HRTIMER_MODE_REL);
	pmu_mmdc->hrtimer.function = mmdc_pmu_timer_handler;

	cpumask_set_cpu(raw_smp_processor_id(), &pmu_mmdc->cpu);

	/* Register the pmu instance for cpu hotplug */
	cpuhp_state_add_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);

	ret = perf_pmu_register(&(pmu_mmdc->pmu), name, -1);
	if (ret)
		goto pmu_register_err;

	platform_set_drvdata(pdev, pmu_mmdc);
	return 0;

pmu_register_err:
	pr_warn("MMDC Perf PMU failed (%d), disabled\n", ret);
	cpuhp_state_remove_instance_nocalls(cpuhp_mmdc_state, &pmu_mmdc->node);
	hrtimer_cancel(&pmu_mmdc->hrtimer);
pmu_free:
	kfree(pmu_mmdc);
	return ret;
}

#else
#define imx_mmdc_remove NULL
#define imx_mmdc_perf_init(pdev, mmdc_base, mmdc_ipg_clk) 0
#endif

static int imx_mmdc_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	void __iomem *mmdc_base, *reg;
	struct clk *mmdc_ipg_clk;
	u32 val;
	int err;

	/* the ipg clock is optional */
	mmdc_ipg_clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(mmdc_ipg_clk))
		mmdc_ipg_clk = NULL;

	err = clk_prepare_enable(mmdc_ipg_clk);
	if (err) {
		dev_err(&pdev->dev, "Unable to enable mmdc ipg clock.\n");
		return err;
	}

	mmdc_base = of_iomap(np, 0);
	WARN_ON(!mmdc_base);

	reg = mmdc_base + MMDC_MDMISC;
	/* Get ddr type */
	val = readl_relaxed(reg);
	ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >>
		 BP_MMDC_MDMISC_DDR_TYPE;

	reg = mmdc_base + MMDC_MAPSR;

	/* Enable automatic power saving */
	val = readl_relaxed(reg);
	val &= ~(1 << BP_MMDC_MAPSR_PSD);
	writel_relaxed(val, reg);

	err = imx_mmdc_perf_init(pdev, mmdc_base, mmdc_ipg_clk);
	if (err) {
		iounmap(mmdc_base);
		clk_disable_unprepare(mmdc_ipg_clk);
	}

	return err;
}

int imx_mmdc_get_ddr_type(void)
{
	return ddr_type;
}

static struct platform_driver imx_mmdc_driver = {
	.driver		= {
		.name	= "imx-mmdc",
		.of_match_table = imx_mmdc_dt_ids,
	},
	.probe		= imx_mmdc_probe,
	.remove		= imx_mmdc_remove,
};

static int __init imx_mmdc_init(void)
{
	return platform_driver_register(&imx_mmdc_driver);
}
postcore_initcall(imx_mmdc_init);


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
 *
 * This contains i.MX27-specific hardware definitions. For those
 * hardware pieces that are common between i.MX21 and i.MX27, have a
 * look at mx2x.h.
 */

#ifndef __MACH_MX27_H__
#define __MACH_MX27_H__

#define MX27_AIPI_BASE_ADDR		0x10000000
#define MX27_AIPI_SIZE			SZ_1M

#define MX27_SAHB1_BASE_ADDR		0x80000000
#define MX27_SAHB1_SIZE			SZ_1M

#define MX27_X_MEMC_BASE_ADDR		0xd8000000
#define MX27_X_MEMC_SIZE		SZ_1M

#define MX27_IO_P2V(x)			IMX_IO_P2V(x)

#endif /* ifndef __MACH_MX27_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
 *
 * This contains hardware definitions that are common between i.MX21 and
 * i.MX27.
 */

#ifndef __MACH_MX2x_H__
#define __MACH_MX2x_H__

/* The following addresses are common between i.MX21 and i.MX27 */

/* Register offsets */
#define MX2x_AIPI_BASE_ADDR		0x10000000
#define MX2x_AIPI_SIZE			SZ_1M
#define MX2x_DMA_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x01000)
#define MX2x_WDOG_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x02000)
#define MX2x_GPT1_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x03000)
#define MX2x_GPT2_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x04000)
#define MX2x_GPT3_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x05000)
#define MX2x_PWM_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x06000)
#define MX2x_RTC_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x07000)
#define MX2x_KPP_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x08000)
#define MX2x_OWIRE_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x09000)
#define MX2x_UART1_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0a000)
#define MX2x_UART2_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0b000)
#define MX2x_UART3_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0c000)
#define MX2x_UART4_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0d000)
#define MX2x_CSPI1_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0e000)
#define MX2x_CSPI2_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x0f000)
#define MX2x_SSI1_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x10000)
#define MX2x_SSI2_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x11000)
#define MX2x_I2C_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x12000)
#define MX2x_SDHC1_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x13000)
#define MX2x_SDHC2_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x14000)
#define MX2x_GPIO_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x15000)
#define MX2x_AUDMUX_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x16000)
#define MX2x_CSPI3_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x17000)
#define MX2x_LCDC_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x21000)
#define MX2x_SLCDC_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x22000)
#define MX2x_USBOTG_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x24000)
#define MX2x_EMMA_PP_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x26000)
#define MX2x_EMMA_PRP_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x26400)
#define MX2x_CCM_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x27000)
#define MX2x_SYSCTRL_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x27800)
#define MX2x_JAM_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x3e000)
#define MX2x_MAX_BASE_ADDR			(MX2x_AIPI_BASE_ADDR + 0x3f000)

#define MX2x_AVIC_BASE_ADDR		0x10040000

#define MX2x_SAHB1_BASE_ADDR		0x80000000
#define MX2x_SAHB1_SIZE			SZ_1M
#define MX2x_CSI_BASE_ADDR			(MX2x_SAHB1_BASE_ADDR + 0x0000)

/* fixed interrupt numbers */
#include <asm/irq.h>
#define MX2x_INT_CSPI3		(NR_IRQS_LEGACY + 6)
#define MX2x_INT_GPIO		(NR_IRQS_LEGACY + 8)
#define MX2x_INT_SDHC2		(NR_IRQS_LEGACY + 10)
#define MX2x_INT_SDHC1		(NR_IRQS_LEGACY + 11)
#define MX2x_INT_I2C		(NR_IRQS_LEGACY + 12)
#define MX2x_INT_SSI2		(NR_IRQS_LEGACY + 13)
#define MX2x_INT_SSI1		(NR_IRQS_LEGACY + 14)
#define MX2x_INT_CSPI2		(NR_IRQS_LEGACY + 15)
#define MX2x_INT_CSPI1		(NR_IRQS_LEGACY + 16)
#define MX2x_INT_UART4		(NR_IRQS_LEGACY + 17)
#define MX2x_INT_UART3		(NR_IRQS_LEGACY + 18)
#define MX2x_INT_UART2		(NR_IRQS_LEGACY + 19)
#define MX2x_INT_UART1		(NR_IRQS_LEGACY + 20)
#define MX2x_INT_KPP		(NR_IRQS_LEGACY + 21)
#define MX2x_INT_RTC		(NR_IRQS_LEGACY + 22)
#define MX2x_INT_PWM		(NR_IRQS_LEGACY + 23)
#define MX2x_INT_GPT3		(NR_IRQS_LEGACY + 24)
#define MX2x_INT_GPT2		(NR_IRQS_LEGACY + 25)
#define MX2x_INT_GPT1		(NR_IRQS_LEGACY + 26)
#define MX2x_INT_WDOG		(NR_IRQS_LEGACY + 27)
#define MX2x_INT_PCMCIA		(NR_IRQS_LEGACY + 28)
#define MX2x_INT_NANDFC		(NR_IRQS_LEGACY + 29)
#define MX2x_INT_CSI		(NR_IRQS_LEGACY + 31)
#define MX2x_INT_DMACH0		(NR_IRQS_LEGACY + 32)
#define MX2x_INT_DMACH1		(NR_IRQS_LEGACY + 33)
#define MX2x_INT_DMACH2		(NR_IRQS_LEGACY + 34)
#define MX2x_INT_DMACH3		(NR_IRQS_LEGACY + 35)
#define MX2x_INT_DMACH4		(NR_IRQS_LEGACY + 36)
#define MX2x_INT_DMACH5		(NR_IRQS_LEGACY + 37)
#define MX2x_INT_DMACH6		(NR_IRQS_LEGACY + 38)
#define MX2x_INT_DMACH7		(NR_IRQS_LEGACY + 39)
#define MX2x_INT_DMACH8		(NR_IRQS_LEGACY + 40)
#define MX2x_INT_DMACH9		(NR_IRQS_LEGACY + 41)
#define MX2x_INT_DMACH10	(NR_IRQS_LEGACY + 42)
#define MX2x_INT_DMACH11	(NR_IRQS_LEGACY + 43)
#define MX2x_INT_DMACH12	(NR_IRQS_LEGACY + 44)
#define MX2x_INT_DMACH13	(NR_IRQS_LEGACY + 45)
#define MX2x_INT_DMACH14	(NR_IRQS_LEGACY + 46)
#define MX2x_INT_DMACH15	(NR_IRQS_LEGACY + 47)
#define MX2x_INT_EMMAPRP	(NR_IRQS_LEGACY + 51)
#define MX2x_INT_EMMAPP		(NR_IRQS_LEGACY + 52)
#define MX2x_INT_SLCDC		(NR_IRQS_LEGACY + 60)
#define MX2x_INT_LCDC		(NR_IRQS_LEGACY + 61)

/* fixed DMA request numbers */
#define MX2x_DMA_REQ_CSPI3_RX	1
#define MX2x_DMA_REQ_CSPI3_TX	2
#define MX2x_DMA_REQ_EXT	3
#define MX2x_DMA_REQ_SDHC2	6
#define MX2x_DMA_REQ_SDHC1	7
#define MX2x_DMA_REQ_SSI2_RX0	8
#define MX2x_DMA_REQ_SSI2_TX0	9
#define MX2x_DMA_REQ_SSI2_RX1	10
#define MX2x_DMA_REQ_SSI2_TX1	11
#define MX2x_DMA_REQ_SSI1_RX0	12
#define MX2x_DMA_REQ_SSI1_TX0	13
#define MX2x_DMA_REQ_SSI1_RX1	14
#define MX2x_DMA_REQ_SSI1_TX1	15
#define MX2x_DMA_REQ_CSPI2_RX	16
#define MX2x_DMA_REQ_CSPI2_TX	17
#define MX2x_DMA_REQ_CSPI1_RX	18
#define MX2x_DMA_REQ_CSPI1_TX	19
#define MX2x_DMA_REQ_UART4_RX	20
#define MX2x_DMA_REQ_UART4_TX	21
#define MX2x_DMA_REQ_UART3_RX	22
#define MX2x_DMA_REQ_UART3_TX	23
#define MX2x_DMA_REQ_UART2_RX	24
#define MX2x_DMA_REQ_UART2_TX	25
#define MX2x_DMA_REQ_UART1_RX	26
#define MX2x_DMA_REQ_UART1_TX	27
#define MX2x_DMA_REQ_CSI_STAT	30
#define MX2x_DMA_REQ_CSI_RX	31

#endif /* ifndef __MACH_MX2x_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __MACH_MX31_H__
#define __MACH_MX31_H__

#define MX31_AIPS1_BASE_ADDR		0x43f00000
#define MX31_AIPS1_SIZE			SZ_1M
#define MX31_SPBA0_BASE_ADDR		0x50000000
#define MX31_SPBA0_SIZE			SZ_1M
#define MX31_AIPS2_BASE_ADDR		0x53f00000
#define MX31_AIPS2_SIZE			SZ_1M
#define MX31_AVIC_BASE_ADDR		0x68000000
#define MX31_AVIC_SIZE			SZ_1M
#define MX31_X_MEMC_BASE_ADDR		0xb8000000
#define MX31_X_MEMC_SIZE		SZ_64K

#define MX31_IO_P2V(x)			IMX_IO_P2V(x)

#endif /* ifndef __MACH_MX31_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __MACH_MX35_H__
#define __MACH_MX35_H__

#define MX35_AIPS1_BASE_ADDR		0x43f00000
#define MX35_AIPS1_SIZE			SZ_1M
#define MX35_SPBA0_BASE_ADDR		0x50000000
#define MX35_SPBA0_SIZE			SZ_1M
#define MX35_AIPS2_BASE_ADDR		0x53f00000
#define MX35_AIPS2_SIZE			SZ_1M
#define MX35_AVIC_BASE_ADDR		0x68000000
#define MX35_AVIC_SIZE			SZ_1M
#define MX35_X_MEMC_BASE_ADDR		0xb8000000
#define MX35_X_MEMC_SIZE		SZ_64K

#define MX35_IO_P2V(x)			IMX_IO_P2V(x)

#endif /* ifndef __MACH_MX35_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 */

#ifndef __MACH_MX3x_H__
#define __MACH_MX3x_H__

/*
 * MX31 memory map:
 *
 * Virt		Phys		Size	What
 * ---------------------------------------------------------------------------
 * FC000000	43F00000	1M	AIPS 1
 * FC100000	50000000	1M	SPBA
 * FC200000	53F00000	1M	AIPS 2
 * FC500000	60000000	128M	ROMPATCH
 * FC400000	68000000	128M	AVIC
 *         	70000000	256M	IPU (MAX M2)
 *         	80000000	256M	CSD0 SDRAM/DDR
 *         	90000000	256M	CSD1 SDRAM/DDR
 *         	A0000000	128M	CS0 Flash
 *         	A8000000	128M	CS1 Flash
 *         	B0000000	32M	CS2
 *         	B2000000	32M	CS3
 * F4000000	B4000000	32M	CS4
 *         	B6000000	32M	CS5
 * FC320000	B8000000	64K	NAND, SDRAM, WEIM, M3IF, EMI controllers
 *         	C0000000	64M	PCMCIA/CF
 */

/*
 * L2CC
 */
#define MX3x_L2CC_BASE_ADDR		0x30000000
#define MX3x_L2CC_SIZE			SZ_1M

/*
 * AIPS 1
 */
#define MX3x_AIPS1_BASE_ADDR		0x43f00000
#define MX3x_AIPS1_SIZE			SZ_1M
#define MX3x_MAX_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x04000)
#define MX3x_EVTMON_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x08000)
#define MX3x_CLKCTL_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x0c000)
#define MX3x_ETB_SLOT4_BASE_ADDR		(MX3x_AIPS1_BASE_ADDR + 0x10000)
#define MX3x_ETB_SLOT5_BASE_ADDR		(MX3x_AIPS1_BASE_ADDR + 0x14000)
#define MX3x_ECT_CTIO_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x18000)
#define MX3x_I2C_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x80000)
#define MX3x_I2C3_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x84000)
#define MX3x_UART1_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x90000)
#define MX3x_UART2_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x94000)
#define MX3x_I2C2_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x98000)
#define MX3x_OWIRE_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0x9c000)
#define MX3x_SSI1_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xa0000)
#define MX3x_CSPI1_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xa4000)
#define MX3x_KPP_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xa8000)
#define MX3x_IOMUXC_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xac000)
#define MX3x_ECT_IP1_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xb8000)
#define MX3x_ECT_IP2_BASE_ADDR			(MX3x_AIPS1_BASE_ADDR + 0xbc000)

/*
 * SPBA global module enabled #0
 */
#define MX3x_SPBA0_BASE_ADDR		0x50000000
#define MX3x_SPBA0_SIZE			SZ_1M
#define MX3x_UART3_BASE_ADDR			(MX3x_SPBA0_BASE_ADDR + 0x0c000)
#define MX3x_CSPI2_BASE_ADDR			(MX3x_SPBA0_BASE_ADDR + 0x10000)
#define MX3x_SSI2_BASE_ADDR			(MX3x_SPBA0_BASE_ADDR + 0x14000)
#define MX3x_ATA_DMA_BASE_ADDR			(MX3x_SPBA0_BASE_ADDR + 0x20000)
#define MX3x_MSHC1_BASE_ADDR			(MX3x_SPBA0_BASE_ADDR + 0x24000)
#define MX3x_SPBA_CTRL_BASE_ADDR		(MX3x_SPBA0_BASE_ADDR + 0x3c000)

/*
 * AIPS 2
 */
#define MX3x_AIPS2_BASE_ADDR		0x53f00000
#define MX3x_AIPS2_SIZE			SZ_1M
#define MX3x_CCM_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0x80000)
#define MX3x_GPT1_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0x90000)
#define MX3x_EPIT1_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0x94000)
#define MX3x_EPIT2_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0x98000)
#define MX3x_GPIO3_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xa4000)
#define MX3x_SCC_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xac000)
#define MX3x_RNGA_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xb0000)
#define MX3x_IPU_CTRL_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xc0000)
#define MX3x_AUDMUX_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xc4000)
#define MX3x_GPIO1_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xcc000)
#define MX3x_GPIO2_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xd0000)
#define MX3x_SDMA_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xd4000)
#define MX3x_RTC_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xd8000)
#define MX3x_WDOG_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xdc000)
#define MX3x_PWM_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xe0000)
#define MX3x_RTIC_BASE_ADDR			(MX3x_AIPS2_BASE_ADDR + 0xec000)

/*
 * ROMP and AVIC
 */
#define MX3x_ROMP_BASE_ADDR		0x60000000
#define MX3x_ROMP_SIZE			SZ_1M

#define MX3x_AVIC_BASE_ADDR		0x68000000
#define MX3x_AVIC_SIZE			SZ_1M

/*
 * Memory regions and CS
 */
#define MX3x_IPU_MEM_BASE_ADDR		0x70000000
#define MX3x_CSD0_BASE_ADDR		0x80000000
#define MX3x_CSD1_BASE_ADDR		0x90000000

#define MX3x_CS0_BASE_ADDR		0xa0000000
#define MX3x_CS1_BASE_ADDR		0xa8000000
#define MX3x_CS2_BASE_ADDR		0xb0000000
#define MX3x_CS3_BASE_ADDR		0xb2000000

#define MX3x_CS4_BASE_ADDR		0xb4000000
#define MX3x_CS4_BASE_ADDR_VIRT		0xf6000000
#define MX3x_CS4_SIZE			SZ_32M

#define MX3x_CS5_BASE_ADDR		0xb6000000
#define MX3x_CS5_BASE_ADDR_VIRT		0xf8000000
#define MX3x_CS5_SIZE			SZ_32M

/*
 * NAND, SDRAM, WEIM, M3IF, EMI controllers
 */
#define MX3x_X_MEMC_BASE_ADDR		0xb8000000
#define MX3x_X_MEMC_SIZE		SZ_64K
#define MX3x_ESDCTL_BASE_ADDR			(MX3x_X_MEMC_BASE_ADDR + 0x1000)
#define MX3x_WEIM_BASE_ADDR			(MX3x_X_MEMC_BASE_ADDR + 0x2000)
#define MX3x_M3IF_BASE_ADDR			(MX3x_X_MEMC_BASE_ADDR + 0x3000)
#define MX3x_EMI_CTL_BASE_ADDR			(MX3x_X_MEMC_BASE_ADDR + 0x4000)
#define MX3x_PCMCIA_CTL_BASE_ADDR		MX3x_EMI_CTL_BASE_ADDR

#define MX3x_PCMCIA_MEM_BASE_ADDR	0xbc000000

/*
 * Interrupt numbers
 */
#include <asm/irq.h>
#define MX3x_INT_I2C3		(NR_IRQS_LEGACY + 3)
#define MX3x_INT_I2C2		(NR_IRQS_LEGACY + 4)
#define MX3x_INT_RTIC		(NR_IRQS_LEGACY + 6)
#define MX3x_INT_I2C		(NR_IRQS_LEGACY + 10)
#define MX3x_INT_CSPI2		(NR_IRQS_LEGACY + 13)
#define MX3x_INT_CSPI1		(NR_IRQS_LEGACY + 14)
#define MX3x_INT_ATA		(NR_IRQS_LEGACY + 15)
#define MX3x_INT_UART3		(NR_IRQS_LEGACY + 18)
#define MX3x_INT_IIM		(NR_IRQS_LEGACY + 19)
#define MX3x_INT_RNGA		(NR_IRQS_LEGACY + 22)
#define MX3x_INT_EVTMON		(NR_IRQS_LEGACY + 23)
#define MX3x_INT_KPP		(NR_IRQS_LEGACY + 24)
#define MX3x_INT_RTC		(NR_IRQS_LEGACY + 25)
#define MX3x_INT_PWM		(NR_IRQS_LEGACY + 26)
#define MX3x_INT_EPIT2		(NR_IRQS_LEGACY + 27)
#define MX3x_INT_EPIT1		(NR_IRQS_LEGACY + 28)
#define MX3x_INT_GPT		(NR_IRQS_LEGACY + 29)
#define MX3x_INT_POWER_FAIL	(NR_IRQS_LEGACY + 30)
#define MX3x_INT_UART2		(NR_IRQS_LEGACY + 32)
#define MX3x_INT_NANDFC		(NR_IRQS_LEGACY + 33)
#define MX3x_INT_SDMA		(NR_IRQS_LEGACY + 34)
#define MX3x_INT_MSHC1		(NR_IRQS_LEGACY + 39)
#define MX3x_INT_IPU_ERR	(NR_IRQS_LEGACY + 41)
#define MX3x_INT_IPU_SYN	(NR_IRQS_LEGACY + 42)
#define MX3x_INT_UART1		(NR_IRQS_LEGACY + 45)
#define MX3x_INT_ECT		(NR_IRQS_LEGACY + 48)
#define MX3x_INT_SCC_SCM	(NR_IRQS_LEGACY + 49)
#define MX3x_INT_SCC_SMN	(NR_IRQS_LEGACY + 50)
#define MX3x_INT_GPIO2		(NR_IRQS_LEGACY + 51)
#define MX3x_INT_GPIO1		(NR_IRQS_LEGACY + 52)
#define MX3x_INT_WDOG		(NR_IRQS_LEGACY + 55)
#define MX3x_INT_GPIO3		(NR_IRQS_LEGACY + 56)
#define MX3x_INT_EXT_POWER	(NR_IRQS_LEGACY + 58)
#define MX3x_INT_EXT_TEMPER	(NR_IRQS_LEGACY + 59)
#define MX3x_INT_EXT_SENSOR60	(NR_IRQS_LEGACY + 60)
#define MX3x_INT_EXT_SENSOR61	(NR_IRQS_LEGACY + 61)
#define MX3x_INT_EXT_WDOG	(NR_IRQS_LEGACY + 62)
#define MX3x_INT_EXT_TV		(NR_IRQS_LEGACY + 63)

#define MX3x_PROD_SIGNATURE		0x1	/* For MX31 */

#endif /* ifndef __MACH_MX3x_H__ */


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2004-2007, 2010-2015 Freescale Semiconductor, Inc.
 * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
 */

#ifndef __ASM_ARCH_MXC_H__
#define __ASM_ARCH_MXC_H__

#include <linux/types.h>
#include <soc/imx/cpu.h>

#ifndef __ASM_ARCH_MXC_HARDWARE_H__
#error "Do not include directly."
#endif

#define IMX_DDR_TYPE_LPDDR2		1

#ifndef __ASSEMBLY__

#ifdef CONFIG_SOC_IMX6SL
static inline bool cpu_is_imx6sl(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6SL;
}
#else
static inline bool cpu_is_imx6sl(void)
{
	return false;
}
#endif

static inline bool cpu_is_imx6dl(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6DL;
}

static inline bool cpu_is_imx6sx(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6SX;
}

static inline bool cpu_is_imx6ul(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6UL;
}

static inline bool cpu_is_imx6ull(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6ULL;
}

static inline bool cpu_is_imx6ulz(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6ULZ;
}

static inline bool cpu_is_imx6sll(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6SLL;
}

static inline bool cpu_is_imx6q(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX6Q;
}

static inline bool cpu_is_imx7d(void)
{
	return __mxc_cpu_type == MXC_CPU_IMX7D;
}

struct cpu_op {
	u32 cpu_rate;
};

int tzic_enable_wake(void);

extern struct cpu_op *(*get_cpu_op)(int *op);
#endif

#define imx_readl	readl_relaxed
#define imx_readw	readw_relaxed
#define imx_writel	writel_relaxed
#define imx_writew	writew_relaxed

#endif /*  __ASM_ARCH_MXC_H__ */


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2011 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/smp.h>

#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/smp_scu.h>
#include <asm/mach/map.h>

#include "common.h"
#include "hardware.h"

u32 g_diag_reg;
static void __iomem *scu_base;

static struct map_desc scu_io_desc __initdata = {
	/* .virtual and .pfn are run-time assigned */
	.length		= SZ_4K,
	.type		= MT_DEVICE,
};

void __init imx_scu_map_io(void)
{
	unsigned long base;

	/* Get SCU base */
	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));

	scu_io_desc.virtual = IMX_IO_P2V(base);
	scu_io_desc.pfn = __phys_to_pfn(base);
	iotable_init(&scu_io_desc, 1);

	scu_base = IMX_IO_ADDRESS(base);
}

static int imx_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	imx_set_cpu_jump(cpu, v7_secondary_startup);
	imx_enable_cpu(cpu, true);
	return 0;
}

/*
 * Initialise the CPU possible map early - this describes the CPUs
 * which may be present or become present in the system.
 */
static void __init imx_smp_init_cpus(void)
{
	int i, ncores;

	ncores = scu_get_core_count(scu_base);

	for (i = ncores; i < NR_CPUS; i++)
		set_cpu_possible(i, false);
}

void imx_smp_prepare(void)
{
	scu_enable(scu_base);
}

static void __init imx_smp_prepare_cpus(unsigned int max_cpus)
{
	imx_smp_prepare();

	/*
	 * The diagnostic register holds the errata bits.  Mostly bootloader
	 * does not bring up secondary cores, so that when errata bits are set
	 * in bootloader, they are set only for boot cpu.  But on a SMP
	 * configuration, it should be equally done on every single core.
	 * Read the register from boot cpu here, and will replicate it into
	 * secondary cores when booting them.
	 */
	asm("mrc p15, 0, %0, c15, c0, 1" : "=r" (g_diag_reg) : : "cc");
	sync_cache_w(&g_diag_reg);
}

const struct smp_operations imx_smp_ops __initconst = {
	.smp_init_cpus		= imx_smp_init_cpus,
	.smp_prepare_cpus	= imx_smp_prepare_cpus,
	.smp_boot_secondary	= imx_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= imx_cpu_die,
	.cpu_kill		= imx_cpu_kill,
#endif
};

/*
 * Initialise the CPU possible map early - this describes the CPUs
 * which may be present or become present in the system.
 */
static void __init imx7_smp_init_cpus(void)
{
	struct device_node *np;
	int i, ncores = 0;

	/* The iMX7D SCU does not report core count, get it from DT */
	for_each_of_cpu_node(np)
		ncores++;

	for (i = ncores; i < NR_CPUS; i++)
		set_cpu_possible(i, false);
}

const struct smp_operations imx7_smp_ops __initconst = {
	.smp_init_cpus		= imx7_smp_init_cpus,
	.smp_boot_secondary	= imx_boot_secondary,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die		= imx_cpu_die,
	.cpu_kill		= imx_cpu_kill,
#endif
};

#define DCFG_CCSR_SCRATCHRW1	0x200

static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
	arch_send_wakeup_ipi_mask(cpumask_of(cpu));

	return 0;
}

static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
{
	struct device_node *np;
	void __iomem *dcfg_base;
	unsigned long paddr;

	np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
	dcfg_base = of_iomap(np, 0);
	of_node_put(np);
	BUG_ON(!dcfg_base);

	paddr = __pa_symbol(secondary_startup);
	writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);

	iounmap(dcfg_base);
}

const struct smp_operations ls1021a_smp_ops __initconst = {
	.smp_prepare_cpus	= ls1021a_smp_prepare_cpus,
	.smp_boot_secondary	= ls1021a_boot_secondary,
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2016 NXP Semiconductors
 */

#include <linux/kernel.h>
#include <linux/suspend.h>
#include <linux/io.h>

static int imx25_suspend_enter(suspend_state_t state)
{
	if (!IS_ENABLED(CONFIG_PM))
		return 0;

	switch (state) {
	case PM_SUSPEND_MEM:
		cpu_do_idle();
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static const struct platform_suspend_ops imx25_suspend_ops = {
	.enter = imx25_suspend_enter,
	.valid = suspend_valid_only_mem,
};

void __init imx25_pm_init(void)
{
	suspend_set_ops(&imx25_suspend_ops);
}


code:
/*
 * i.MX27 Power Management Routines
 *
 * Based on Freescale's BSP
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License.
 */

#include <linux/of_address.h>
#include <linux/kernel.h>
#include <linux/suspend.h>
#include <linux/io.h>

#include "common.h"
#include "hardware.h"

static int mx27_suspend_enter(suspend_state_t state)
{
	void __iomem *ccm_base;
	struct device_node *np;
	u32 cscr;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx27-ccm");
	ccm_base = of_iomap(np, 0);
	BUG_ON(!ccm_base);

	switch (state) {
	case PM_SUSPEND_MEM:
		/* Clear MPEN and SPEN to disable MPLL/SPLL */
		cscr = imx_readl(ccm_base);
		cscr &= 0xFFFFFFFC;
		imx_writel(cscr, ccm_base);
		/* Executes WFI */
		cpu_do_idle();
		break;

	default:
		return -EINVAL;
	}
	return 0;
}

static const struct platform_suspend_ops mx27_suspend_ops = {
	.enter = mx27_suspend_enter,
	.valid = suspend_valid_only_mem,
};

void __init imx27_pm_init(void)
{
	suspend_set_ops(&mx27_suspend_ops);
}


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
 */
#include <linux/suspend.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/export.h>

#include <linux/genalloc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>

#include <asm/cacheflush.h>
#include <asm/fncpy.h>
#include <asm/system_misc.h>
#include <asm/tlbflush.h>

#include "common.h"
#include "cpuidle.h"
#include "hardware.h"

#define MXC_CCM_CLPCR			0x54
#define MXC_CCM_CLPCR_LPM_OFFSET	0
#define MXC_CCM_CLPCR_LPM_MASK		0x3
#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET	9
#define MXC_CCM_CLPCR_VSTBY		(0x1 << 8)
#define MXC_CCM_CLPCR_SBYOS		(0x1 << 6)

#define MXC_CORTEXA8_PLAT_LPC		0xc
#define MXC_CORTEXA8_PLAT_LPC_DSM	(1 << 0)
#define MXC_CORTEXA8_PLAT_LPC_DBG_DSM	(1 << 1)

#define MXC_SRPG_NEON_SRPGCR		0x280
#define MXC_SRPG_ARM_SRPGCR		0x2a0
#define MXC_SRPG_EMPGC0_SRPGCR		0x2c0
#define MXC_SRPG_EMPGC1_SRPGCR		0x2d0

#define MXC_SRPGCR_PCR			1

/*
 * The WAIT_UNCLOCKED_POWER_OFF state only requires <= 500ns to exit.
 * This is also the lowest power state possible without affecting
 * non-cpu parts of the system.  For these reasons, imx5 should default
 * to always using this state for cpu idling.  The PM_SUSPEND_STANDBY also
 * uses this state and needs to take no action when registers remain configured
 * for this state.
 */
#define IMX5_DEFAULT_CPU_IDLE_STATE WAIT_UNCLOCKED_POWER_OFF

struct imx5_suspend_io_state {
	u32	offset;
	u32	clear;
	u32	set;
	u32	saved_value;
};

struct imx5_pm_data {
	phys_addr_t ccm_addr;
	phys_addr_t cortex_addr;
	phys_addr_t gpc_addr;
	phys_addr_t m4if_addr;
	phys_addr_t iomuxc_addr;
	void (*suspend_asm)(void __iomem *ocram_vbase);
	const u32 *suspend_asm_sz;
	const struct imx5_suspend_io_state *suspend_io_config;
	int suspend_io_count;
};

static const struct imx5_suspend_io_state imx53_suspend_io_config[] = {
#define MX53_DSE_HIGHZ_MASK (0x7 << 19)
	{.offset = 0x584, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM0 */
	{.offset = 0x594, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM1 */
	{.offset = 0x560, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM2 */
	{.offset = 0x554, .clear = MX53_DSE_HIGHZ_MASK}, /* DQM3 */
	{.offset = 0x574, .clear = MX53_DSE_HIGHZ_MASK}, /* CAS */
	{.offset = 0x588, .clear = MX53_DSE_HIGHZ_MASK}, /* RAS */
	{.offset = 0x578, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_0 */
	{.offset = 0x570, .clear = MX53_DSE_HIGHZ_MASK}, /* SDCLK_1 */

	{.offset = 0x580, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT0 */
	{.offset = 0x564, .clear = MX53_DSE_HIGHZ_MASK}, /* SDODT1 */
	{.offset = 0x57c, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS0 */
	{.offset = 0x590, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS1 */
	{.offset = 0x568, .clear = MX53_DSE_HIGHZ_MASK}, /* SDQS2 */
	{.offset = 0x558, .clear = MX53_DSE_HIGHZ_MASK}, /* SDSQ3 */
	{.offset = 0x6f0, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_ADDS */
	{.offset = 0x718, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_BODS */
	{.offset = 0x71c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B1DS */
	{.offset = 0x728, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B2DS */
	{.offset = 0x72c, .clear = MX53_DSE_HIGHZ_MASK}, /* GRP_B3DS */

	/* Controls the CKE signal which is required to leave self refresh */
	{.offset = 0x720, .clear = MX53_DSE_HIGHZ_MASK, .set = 1 << 19}, /* CTLDS */
};

static const struct imx5_pm_data imx51_pm_data __initconst = {
	.ccm_addr = 0x73fd4000,
	.cortex_addr = 0x83fa0000,
	.gpc_addr = 0x73fd8000,
};

static const struct imx5_pm_data imx53_pm_data __initconst = {
	.ccm_addr = 0x53fd4000,
	.cortex_addr = 0x63fa0000,
	.gpc_addr = 0x53fd8000,
	.m4if_addr = 0x63fd8000,
	.iomuxc_addr = 0x53fa8000,
	.suspend_asm = &imx53_suspend,
	.suspend_asm_sz = &imx53_suspend_sz,
	.suspend_io_config = imx53_suspend_io_config,
	.suspend_io_count = ARRAY_SIZE(imx53_suspend_io_config),
};

#define MX5_MAX_SUSPEND_IOSTATE ARRAY_SIZE(imx53_suspend_io_config)

/*
 * This structure is for passing necessary data for low level ocram
 * suspend code(arch/arm/mach-imx/suspend-imx53.S), if this struct
 * definition is changed, the offset definition in that file
 * must be also changed accordingly otherwise, the suspend to ocram
 * function will be broken!
 */
struct imx5_cpu_suspend_info {
	void __iomem	*m4if_base;
	void __iomem	*iomuxc_base;
	u32		io_count;
	struct imx5_suspend_io_state io_state[MX5_MAX_SUSPEND_IOSTATE];
} __aligned(8);

static void __iomem *ccm_base;
static void __iomem *cortex_base;
static void __iomem *gpc_base;
static void __iomem *suspend_ocram_base;
static void (*imx5_suspend_in_ocram_fn)(void __iomem *ocram_vbase);

/*
 * set cpu low power mode before WFI instruction. This function is called
 * mx5 because it can be used for mx51, and mx53.
 */
static void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
{
	u32 plat_lpc, arm_srpgcr, ccm_clpcr;
	u32 empgc0, empgc1;
	int stop_mode = 0;

	/* always allow platform to issue a deep sleep mode request */
	plat_lpc = imx_readl(cortex_base + MXC_CORTEXA8_PLAT_LPC) &
	    ~(MXC_CORTEXA8_PLAT_LPC_DSM);
	ccm_clpcr = imx_readl(ccm_base + MXC_CCM_CLPCR) &
		    ~(MXC_CCM_CLPCR_LPM_MASK);
	arm_srpgcr = imx_readl(gpc_base + MXC_SRPG_ARM_SRPGCR) &
		     ~(MXC_SRPGCR_PCR);
	empgc0 = imx_readl(gpc_base + MXC_SRPG_EMPGC0_SRPGCR) &
		 ~(MXC_SRPGCR_PCR);
	empgc1 = imx_readl(gpc_base + MXC_SRPG_EMPGC1_SRPGCR) &
		 ~(MXC_SRPGCR_PCR);

	switch (mode) {
	case WAIT_CLOCKED:
		break;
	case WAIT_UNCLOCKED:
		ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
		break;
	case WAIT_UNCLOCKED_POWER_OFF:
	case STOP_POWER_OFF:
		plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
			    | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
		if (mode == WAIT_UNCLOCKED_POWER_OFF) {
			ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
			stop_mode = 0;
		} else {
			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
			stop_mode = 1;
		}
		arm_srpgcr |= MXC_SRPGCR_PCR;
		break;
	case STOP_POWER_ON:
		ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
		break;
	default:
		printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
		return;
	}

	imx_writel(plat_lpc, cortex_base + MXC_CORTEXA8_PLAT_LPC);
	imx_writel(ccm_clpcr, ccm_base + MXC_CCM_CLPCR);
	imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_ARM_SRPGCR);
	imx_writel(arm_srpgcr, gpc_base + MXC_SRPG_NEON_SRPGCR);

	if (stop_mode) {
		empgc0 |= MXC_SRPGCR_PCR;
		empgc1 |= MXC_SRPGCR_PCR;

		imx_writel(empgc0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
		imx_writel(empgc1, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);
	}
}

static int mx5_suspend_enter(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_MEM:
		mx5_cpu_lp_set(STOP_POWER_OFF);
		break;
	case PM_SUSPEND_STANDBY:
		/* DEFAULT_IDLE_STATE already configured */
		break;
	default:
		return -EINVAL;
	}

	if (state == PM_SUSPEND_MEM) {
		local_flush_tlb_all();
		flush_cache_all();

		/*clear the EMPGC0/1 bits */
		imx_writel(0, gpc_base + MXC_SRPG_EMPGC0_SRPGCR);
		imx_writel(0, gpc_base + MXC_SRPG_EMPGC1_SRPGCR);

		if (imx5_suspend_in_ocram_fn)
			imx5_suspend_in_ocram_fn(suspend_ocram_base);
		else
			cpu_do_idle();

	} else {
		cpu_do_idle();
	}

	/* return registers to default idle state */
	mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
	return 0;
}

static int mx5_pm_valid(suspend_state_t state)
{
	return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
}

static const struct platform_suspend_ops mx5_suspend_ops = {
	.valid = mx5_pm_valid,
	.enter = mx5_suspend_enter,
};

static inline int imx5_cpu_do_idle(void)
{
	int ret = tzic_enable_wake();

	if (likely(!ret))
		cpu_do_idle();

	return ret;
}

static void imx5_pm_idle(void)
{
	imx5_cpu_do_idle();
}

static int __init imx_suspend_alloc_ocram(
				size_t size,
				void __iomem **virt_out,
				phys_addr_t *phys_out)
{
	struct device_node *node;
	struct platform_device *pdev;
	struct gen_pool *ocram_pool;
	unsigned long ocram_base;
	void __iomem *virt;
	phys_addr_t phys;
	int ret = 0;

	/* Copied from imx6: TODO factorize */
	node = of_find_compatible_node(NULL, NULL, "mmio-sram");
	if (!node) {
		pr_warn("%s: failed to find ocram node!\n", __func__);
		return -ENODEV;
	}

	pdev = of_find_device_by_node(node);
	if (!pdev) {
		pr_warn("%s: failed to find ocram device!\n", __func__);
		ret = -ENODEV;
		goto put_node;
	}

	ocram_pool = gen_pool_get(&pdev->dev, NULL);
	if (!ocram_pool) {
		pr_warn("%s: ocram pool unavailable!\n", __func__);
		ret = -ENODEV;
		goto put_device;
	}

	ocram_base = gen_pool_alloc(ocram_pool, size);
	if (!ocram_base) {
		pr_warn("%s: unable to alloc ocram!\n", __func__);
		ret = -ENOMEM;
		goto put_device;
	}

	phys = gen_pool_virt_to_phys(ocram_pool, ocram_base);
	virt = __arm_ioremap_exec(phys, size, false);
	if (phys_out)
		*phys_out = phys;
	if (virt_out)
		*virt_out = virt;

put_device:
	put_device(&pdev->dev);
put_node:
	of_node_put(node);

	return ret;
}

static int __init imx5_suspend_init(const struct imx5_pm_data *soc_data)
{
	struct imx5_cpu_suspend_info *suspend_info;
	int ret;
	/* Need this to avoid compile error due to const typeof in fncpy.h */
	void (*suspend_asm)(void __iomem *) = soc_data->suspend_asm;

	if (!suspend_asm)
		return 0;

	if (!soc_data->suspend_asm_sz || !*soc_data->suspend_asm_sz)
		return -EINVAL;

	ret = imx_suspend_alloc_ocram(
		*soc_data->suspend_asm_sz + sizeof(*suspend_info),
		&suspend_ocram_base, NULL);
	if (ret)
		return ret;

	suspend_info = suspend_ocram_base;

	suspend_info->io_count = soc_data->suspend_io_count;
	memcpy(suspend_info->io_state, soc_data->suspend_io_config,
	       sizeof(*suspend_info->io_state) * soc_data->suspend_io_count);

	suspend_info->m4if_base = ioremap(soc_data->m4if_addr, SZ_16K);
	if (!suspend_info->m4if_base) {
		ret = -ENOMEM;
		goto failed_map_m4if;
	}

	suspend_info->iomuxc_base = ioremap(soc_data->iomuxc_addr, SZ_16K);
	if (!suspend_info->iomuxc_base) {
		ret = -ENOMEM;
		goto failed_map_iomuxc;
	}

	imx5_suspend_in_ocram_fn = fncpy(
		suspend_ocram_base + sizeof(*suspend_info),
		suspend_asm,
		*soc_data->suspend_asm_sz);

	return 0;

failed_map_iomuxc:
	iounmap(suspend_info->m4if_base);

failed_map_m4if:
	return ret;
}

static int __init imx5_pm_common_init(const struct imx5_pm_data *data)
{
	int ret;
	struct clk *gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");

	if (IS_ERR(gpc_dvfs_clk))
		return PTR_ERR(gpc_dvfs_clk);

	ret = clk_prepare_enable(gpc_dvfs_clk);
	if (ret)
		return ret;

	arm_pm_idle = imx5_pm_idle;

	ccm_base = ioremap(data->ccm_addr, SZ_16K);
	cortex_base = ioremap(data->cortex_addr, SZ_16K);
	gpc_base = ioremap(data->gpc_addr, SZ_16K);
	WARN_ON(!ccm_base || !cortex_base || !gpc_base);

	/* Set the registers to the default cpu idle state. */
	mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);

	ret = imx5_cpuidle_init();
	if (ret)
		pr_warn("%s: cpuidle init failed %d\n", __func__, ret);

	ret = imx5_suspend_init(data);
	if (ret)
		pr_warn("%s: No DDR LPM support with suspend %d!\n",
			__func__, ret);

	suspend_set_ops(&mx5_suspend_ops);

	return 0;
}

void __init imx51_pm_init(void)
{
	if (IS_ENABLED(CONFIG_SOC_IMX51))
		imx5_pm_common_init(&imx51_pm_data);
}

void __init imx53_pm_init(void)
{
	if (IS_ENABLED(CONFIG_SOC_IMX53))
		imx5_pm_common_init(&imx53_pm_data);
}


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2011-2014 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/clk/imx.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/genalloc.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/suspend.h>
#include <asm/cacheflush.h>
#include <asm/fncpy.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/tlb.h>

#include "common.h"
#include "hardware.h"

#define CCR				0x0
#define BM_CCR_WB_COUNT			(0x7 << 16)
#define BM_CCR_RBC_BYPASS_COUNT		(0x3f << 21)
#define BM_CCR_RBC_EN			(0x1 << 27)

#define CLPCR				0x54
#define BP_CLPCR_LPM			0
#define BM_CLPCR_LPM			(0x3 << 0)
#define BM_CLPCR_BYPASS_PMIC_READY	(0x1 << 2)
#define BM_CLPCR_ARM_CLK_DIS_ON_LPM	(0x1 << 5)
#define BM_CLPCR_SBYOS			(0x1 << 6)
#define BM_CLPCR_DIS_REF_OSC		(0x1 << 7)
#define BM_CLPCR_VSTBY			(0x1 << 8)
#define BP_CLPCR_STBY_COUNT		9
#define BM_CLPCR_STBY_COUNT		(0x3 << 9)
#define BM_CLPCR_COSC_PWRDOWN		(0x1 << 11)
#define BM_CLPCR_WB_PER_AT_LPM		(0x1 << 16)
#define BM_CLPCR_WB_CORE_AT_LPM		(0x1 << 17)
#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS	(0x1 << 19)
#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS	(0x1 << 21)
#define BM_CLPCR_MASK_CORE0_WFI		(0x1 << 22)
#define BM_CLPCR_MASK_CORE1_WFI		(0x1 << 23)
#define BM_CLPCR_MASK_CORE2_WFI		(0x1 << 24)
#define BM_CLPCR_MASK_CORE3_WFI		(0x1 << 25)
#define BM_CLPCR_MASK_SCU_IDLE		(0x1 << 26)
#define BM_CLPCR_MASK_L2CC_IDLE		(0x1 << 27)

#define CGPR				0x64
#define BM_CGPR_INT_MEM_CLK_LPM		(0x1 << 17)

#define MX6Q_SUSPEND_OCRAM_SIZE		0x1000
#define MX6_MAX_MMDC_IO_NUM		33

static void __iomem *ccm_base;
static void __iomem *suspend_ocram_base;
static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase);

/*
 * suspend ocram space layout:
 * ======================== high address ======================
 *                              .
 *                              .
 *                              .
 *                              ^
 *                              ^
 *                              ^
 *                      imx6_suspend code
 *              PM_INFO structure(imx6_cpu_pm_info)
 * ======================== low address =======================
 */

struct imx6_pm_base {
	phys_addr_t pbase;
	void __iomem *vbase;
};

struct imx6_pm_socdata {
	u32 ddr_type;
	const char *mmdc_compat;
	const char *src_compat;
	const char *iomuxc_compat;
	const char *gpc_compat;
	const char *pl310_compat;
	const u32 mmdc_io_num;
	const u32 *mmdc_io_offset;
};

static const u32 imx6q_mmdc_io_offset[] __initconst = {
	0x5ac, 0x5b4, 0x528, 0x520, /* DQM0 ~ DQM3 */
	0x514, 0x510, 0x5bc, 0x5c4, /* DQM4 ~ DQM7 */
	0x56c, 0x578, 0x588, 0x594, /* CAS, RAS, SDCLK_0, SDCLK_1 */
	0x5a8, 0x5b0, 0x524, 0x51c, /* SDQS0 ~ SDQS3 */
	0x518, 0x50c, 0x5b8, 0x5c0, /* SDQS4 ~ SDQS7 */
	0x784, 0x788, 0x794, 0x79c, /* GPR_B0DS ~ GPR_B3DS */
	0x7a0, 0x7a4, 0x7a8, 0x748, /* GPR_B4DS ~ GPR_B7DS */
	0x59c, 0x5a0, 0x750, 0x774, /* SODT0, SODT1, MODE_CTL, MODE */
	0x74c,			    /* GPR_ADDS */
};

static const u32 imx6dl_mmdc_io_offset[] __initconst = {
	0x470, 0x474, 0x478, 0x47c, /* DQM0 ~ DQM3 */
	0x480, 0x484, 0x488, 0x48c, /* DQM4 ~ DQM7 */
	0x464, 0x490, 0x4ac, 0x4b0, /* CAS, RAS, SDCLK_0, SDCLK_1 */
	0x4bc, 0x4c0, 0x4c4, 0x4c8, /* DRAM_SDQS0 ~ DRAM_SDQS3 */
	0x4cc, 0x4d0, 0x4d4, 0x4d8, /* DRAM_SDQS4 ~ DRAM_SDQS7 */
	0x764, 0x770, 0x778, 0x77c, /* GPR_B0DS ~ GPR_B3DS */
	0x780, 0x784, 0x78c, 0x748, /* GPR_B4DS ~ GPR_B7DS */
	0x4b4, 0x4b8, 0x750, 0x760, /* SODT0, SODT1, MODE_CTL, MODE */
	0x74c,			    /* GPR_ADDS */
};

static const u32 imx6sl_mmdc_io_offset[] __initconst = {
	0x30c, 0x310, 0x314, 0x318, /* DQM0 ~ DQM3 */
	0x5c4, 0x5cc, 0x5d4, 0x5d8, /* GPR_B0DS ~ GPR_B3DS */
	0x300, 0x31c, 0x338, 0x5ac, /* CAS, RAS, SDCLK_0, GPR_ADDS */
	0x33c, 0x340, 0x5b0, 0x5c0, /* SODT0, SODT1, MODE_CTL, MODE */
	0x330, 0x334, 0x320,        /* SDCKE0, SDCKE1, RESET */
};

static const u32 imx6sll_mmdc_io_offset[] __initconst = {
	0x294, 0x298, 0x29c, 0x2a0, /* DQM0 ~ DQM3 */
	0x544, 0x54c, 0x554, 0x558, /* GPR_B0DS ~ GPR_B3DS */
	0x530, 0x540, 0x2ac, 0x52c, /* MODE_CTL, MODE, SDCLK_0, GPR_ADDDS */
	0x2a4, 0x2a8,		    /* SDCKE0, SDCKE1*/
};

static const u32 imx6sx_mmdc_io_offset[] __initconst = {
	0x2ec, 0x2f0, 0x2f4, 0x2f8, /* DQM0 ~ DQM3 */
	0x60c, 0x610, 0x61c, 0x620, /* GPR_B0DS ~ GPR_B3DS */
	0x300, 0x2fc, 0x32c, 0x5f4, /* CAS, RAS, SDCLK_0, GPR_ADDS */
	0x310, 0x314, 0x5f8, 0x608, /* SODT0, SODT1, MODE_CTL, MODE */
	0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */
};

static const u32 imx6ul_mmdc_io_offset[] __initconst = {
	0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */
	0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */
	0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */
	0x494, 0x4b0,	            /* MODE_CTL, MODE, */
};

static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6q-mmdc",
	.src_compat = "fsl,imx6q-src",
	.iomuxc_compat = "fsl,imx6q-iomuxc",
	.gpc_compat = "fsl,imx6q-gpc",
	.pl310_compat = "arm,pl310-cache",
	.mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
	.mmdc_io_offset = imx6q_mmdc_io_offset,
};

static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6q-mmdc",
	.src_compat = "fsl,imx6q-src",
	.iomuxc_compat = "fsl,imx6dl-iomuxc",
	.gpc_compat = "fsl,imx6q-gpc",
	.pl310_compat = "arm,pl310-cache",
	.mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
	.mmdc_io_offset = imx6dl_mmdc_io_offset,
};

static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6sl-mmdc",
	.src_compat = "fsl,imx6sl-src",
	.iomuxc_compat = "fsl,imx6sl-iomuxc",
	.gpc_compat = "fsl,imx6sl-gpc",
	.pl310_compat = "arm,pl310-cache",
	.mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
	.mmdc_io_offset = imx6sl_mmdc_io_offset,
};

static const struct imx6_pm_socdata imx6sll_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6sll-mmdc",
	.src_compat = "fsl,imx6sll-src",
	.iomuxc_compat = "fsl,imx6sll-iomuxc",
	.gpc_compat = "fsl,imx6sll-gpc",
	.pl310_compat = "arm,pl310-cache",
	.mmdc_io_num = ARRAY_SIZE(imx6sll_mmdc_io_offset),
	.mmdc_io_offset = imx6sll_mmdc_io_offset,
};

static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6sx-mmdc",
	.src_compat = "fsl,imx6sx-src",
	.iomuxc_compat = "fsl,imx6sx-iomuxc",
	.gpc_compat = "fsl,imx6sx-gpc",
	.pl310_compat = "arm,pl310-cache",
	.mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
	.mmdc_io_offset = imx6sx_mmdc_io_offset,
};

static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
	.mmdc_compat = "fsl,imx6ul-mmdc",
	.src_compat = "fsl,imx6ul-src",
	.iomuxc_compat = "fsl,imx6ul-iomuxc",
	.gpc_compat = "fsl,imx6ul-gpc",
	.pl310_compat = NULL,
	.mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
	.mmdc_io_offset = imx6ul_mmdc_io_offset,
};

/*
 * This structure is for passing necessary data for low level ocram
 * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct
 * definition is changed, the offset definition in
 * arch/arm/mach-imx/suspend-imx6.S must be also changed accordingly,
 * otherwise, the suspend to ocram function will be broken!
 */
struct imx6_cpu_pm_info {
	phys_addr_t pbase; /* The physical address of pm_info. */
	phys_addr_t resume_addr; /* The physical resume address for asm code */
	u32 ddr_type;
	u32 pm_info_size; /* Size of pm_info. */
	struct imx6_pm_base mmdc_base;
	struct imx6_pm_base src_base;
	struct imx6_pm_base iomuxc_base;
	struct imx6_pm_base ccm_base;
	struct imx6_pm_base gpc_base;
	struct imx6_pm_base l2_base;
	u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */
	u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */
} __aligned(8);

void imx6_set_int_mem_clk_lpm(bool enable)
{
	u32 val = readl_relaxed(ccm_base + CGPR);

	val &= ~BM_CGPR_INT_MEM_CLK_LPM;
	if (enable)
		val |= BM_CGPR_INT_MEM_CLK_LPM;
	writel_relaxed(val, ccm_base + CGPR);
}

void imx6_enable_rbc(bool enable)
{
	u32 val;

	/*
	 * need to mask all interrupts in GPC before
	 * operating RBC configurations
	 */
	imx_gpc_mask_all();

	/* configure RBC enable bit */
	val = readl_relaxed(ccm_base + CCR);
	val &= ~BM_CCR_RBC_EN;
	val |= enable ? BM_CCR_RBC_EN : 0;
	writel_relaxed(val, ccm_base + CCR);

	/* configure RBC count */
	val = readl_relaxed(ccm_base + CCR);
	val &= ~BM_CCR_RBC_BYPASS_COUNT;
	val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0;
	writel(val, ccm_base + CCR);

	/*
	 * need to delay at least 2 cycles of CKIL(32K)
	 * due to hardware design requirement, which is
	 * ~61us, here we use 65us for safe
	 */
	udelay(65);

	/* restore GPC interrupt mask settings */
	imx_gpc_restore_all();
}

static void imx6q_enable_wb(bool enable)
{
	u32 val;

	/* configure well bias enable bit */
	val = readl_relaxed(ccm_base + CLPCR);
	val &= ~BM_CLPCR_WB_PER_AT_LPM;
	val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0;
	writel_relaxed(val, ccm_base + CLPCR);

	/* configure well bias count */
	val = readl_relaxed(ccm_base + CCR);
	val &= ~BM_CCR_WB_COUNT;
	val |= enable ? BM_CCR_WB_COUNT : 0;
	writel_relaxed(val, ccm_base + CCR);
}

int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
{
	u32 val = readl_relaxed(ccm_base + CLPCR);

	val &= ~BM_CLPCR_LPM;
	switch (mode) {
	case WAIT_CLOCKED:
		break;
	case WAIT_UNCLOCKED:
		val |= 0x1 << BP_CLPCR_LPM;
		val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM;
		break;
	case STOP_POWER_ON:
		val |= 0x2 << BP_CLPCR_LPM;
		val &= ~BM_CLPCR_VSTBY;
		val &= ~BM_CLPCR_SBYOS;
		if (cpu_is_imx6sl())
			val |= BM_CLPCR_BYPASS_PMIC_READY;
		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() ||
		    cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz())
			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
		else
			val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
		break;
	case WAIT_UNCLOCKED_POWER_OFF:
		val |= 0x1 << BP_CLPCR_LPM;
		val &= ~BM_CLPCR_VSTBY;
		val &= ~BM_CLPCR_SBYOS;
		break;
	case STOP_POWER_OFF:
		val |= 0x2 << BP_CLPCR_LPM;
		val |= 0x3 << BP_CLPCR_STBY_COUNT;
		val |= BM_CLPCR_VSTBY;
		val |= BM_CLPCR_SBYOS;
		if (cpu_is_imx6sl() || cpu_is_imx6sx())
			val |= BM_CLPCR_BYPASS_PMIC_READY;
		if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul() ||
		    cpu_is_imx6ull() || cpu_is_imx6sll() || cpu_is_imx6ulz())
			val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
		else
			val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
		break;
	default:
		return -EINVAL;
	}

	/*
	 * ERR007265: CCM: When improper low-power sequence is used,
	 * the SoC enters low power mode before the ARM core executes WFI.
	 *
	 * Software workaround:
	 * 1) Software should trigger IRQ #32 (IOMUX) to be always pending
	 *    by setting IOMUX_GPR1_GINT.
	 * 2) Software should then unmask IRQ #32 in GPC before setting CCM
	 *    Low-Power mode.
	 * 3) Software should mask IRQ #32 right after CCM Low-Power mode
	 *    is set (set bits 0-1 of CCM_CLPCR).
	 *
	 * Note that IRQ #32 is GIC SPI #0.
	 */
	if (mode != WAIT_CLOCKED)
		imx_gpc_hwirq_unmask(0);
	writel_relaxed(val, ccm_base + CLPCR);
	if (mode != WAIT_CLOCKED)
		imx_gpc_hwirq_mask(0);

	return 0;
}

static int imx6q_suspend_finish(unsigned long val)
{
	if (!imx6_suspend_in_ocram_fn) {
		cpu_do_idle();
	} else {
		/*
		 * call low level suspend function in ocram,
		 * as we need to float DDR IO.
		 */
		local_flush_tlb_all();
		/* check if need to flush internal L2 cache */
		if (!((struct imx6_cpu_pm_info *)
			suspend_ocram_base)->l2_base.vbase)
			flush_cache_all();
		imx6_suspend_in_ocram_fn(suspend_ocram_base);
	}

	return 0;
}

static int imx6q_pm_enter(suspend_state_t state)
{
	switch (state) {
	case PM_SUSPEND_STANDBY:
		imx6_set_lpm(STOP_POWER_ON);
		imx6_set_int_mem_clk_lpm(true);
		imx_gpc_pre_suspend(false);
		if (cpu_is_imx6sl())
			imx6sl_set_wait_clk(true);
		/* Zzz ... */
		cpu_do_idle();
		if (cpu_is_imx6sl())
			imx6sl_set_wait_clk(false);
		imx_gpc_post_resume();
		imx6_set_lpm(WAIT_CLOCKED);
		break;
	case PM_SUSPEND_MEM:
		imx6_set_lpm(STOP_POWER_OFF);
		imx6_set_int_mem_clk_lpm(false);
		imx6q_enable_wb(true);
		/*
		 * For suspend into ocram, asm code already take care of
		 * RBC setting, so we do NOT need to do that here.
		 */
		if (!imx6_suspend_in_ocram_fn)
			imx6_enable_rbc(true);
		imx_gpc_pre_suspend(true);
		imx_anatop_pre_suspend();
		/* Zzz ... */
		cpu_suspend(0, imx6q_suspend_finish);
		if (cpu_is_imx6q() || cpu_is_imx6dl())
			imx_smp_prepare();
		imx_anatop_post_resume();
		imx_gpc_post_resume();
		imx6_enable_rbc(false);
		imx6q_enable_wb(false);
		imx6_set_int_mem_clk_lpm(true);
		imx6_set_lpm(WAIT_CLOCKED);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int imx6q_pm_valid(suspend_state_t state)
{
	return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM);
}

static const struct platform_suspend_ops imx6q_pm_ops = {
	.enter = imx6q_pm_enter,
	.valid = imx6q_pm_valid,
};

static int __init imx6_pm_get_base(struct imx6_pm_base *base,
				const char *compat)
{
	struct device_node *node;
	struct resource res;
	int ret = 0;

	node = of_find_compatible_node(NULL, NULL, compat);
	if (!node)
		return -ENODEV;

	ret = of_address_to_resource(node, 0, &res);
	if (ret)
		goto put_node;

	base->pbase = res.start;
	base->vbase = ioremap(res.start, resource_size(&res));
	if (!base->vbase)
		ret = -ENOMEM;

put_node:
	of_node_put(node);
	return ret;
}

static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
{
	phys_addr_t ocram_pbase;
	struct device_node *node;
	struct platform_device *pdev;
	struct imx6_cpu_pm_info *pm_info;
	struct gen_pool *ocram_pool;
	unsigned long ocram_base;
	int i, ret = 0;
	const u32 *mmdc_offset_array;

	suspend_set_ops(&imx6q_pm_ops);

	if (!socdata) {
		pr_warn("%s: invalid argument!\n", __func__);
		return -EINVAL;
	}

	node = of_find_compatible_node(NULL, NULL, "mmio-sram");
	if (!node) {
		pr_warn("%s: failed to find ocram node!\n", __func__);
		return -ENODEV;
	}

	pdev = of_find_device_by_node(node);
	if (!pdev) {
		pr_warn("%s: failed to find ocram device!\n", __func__);
		ret = -ENODEV;
		goto put_node;
	}

	ocram_pool = gen_pool_get(&pdev->dev, NULL);
	if (!ocram_pool) {
		pr_warn("%s: ocram pool unavailable!\n", __func__);
		ret = -ENODEV;
		goto put_device;
	}

	ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE);
	if (!ocram_base) {
		pr_warn("%s: unable to alloc ocram!\n", __func__);
		ret = -ENOMEM;
		goto put_device;
	}

	ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base);

	suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
		MX6Q_SUSPEND_OCRAM_SIZE, false);

	memset(suspend_ocram_base, 0, sizeof(*pm_info));
	pm_info = suspend_ocram_base;
	pm_info->pbase = ocram_pbase;
	pm_info->resume_addr = __pa_symbol(v7_cpu_resume);
	pm_info->pm_info_size = sizeof(*pm_info);

	/*
	 * ccm physical address is not used by asm code currently,
	 * so get ccm virtual address directly.
	 */
	pm_info->ccm_base.vbase = ccm_base;

	ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat);
	if (ret) {
		pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret);
		goto put_device;
	}

	ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat);
	if (ret) {
		pr_warn("%s: failed to get src base %d!\n", __func__, ret);
		goto src_map_failed;
	}

	ret = imx6_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat);
	if (ret) {
		pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret);
		goto iomuxc_map_failed;
	}

	ret = imx6_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat);
	if (ret) {
		pr_warn("%s: failed to get gpc base %d!\n", __func__, ret);
		goto gpc_map_failed;
	}

	if (socdata->pl310_compat) {
		ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat);
		if (ret) {
			pr_warn("%s: failed to get pl310-cache base %d!\n",
				__func__, ret);
			goto pl310_cache_map_failed;
		}
	}

	pm_info->ddr_type = imx_mmdc_get_ddr_type();
	pm_info->mmdc_io_num = socdata->mmdc_io_num;
	mmdc_offset_array = socdata->mmdc_io_offset;

	for (i = 0; i < pm_info->mmdc_io_num; i++) {
		pm_info->mmdc_io_val[i][0] =
			mmdc_offset_array[i];
		pm_info->mmdc_io_val[i][1] =
			readl_relaxed(pm_info->iomuxc_base.vbase +
			mmdc_offset_array[i]);
	}

	imx6_suspend_in_ocram_fn = fncpy(
		suspend_ocram_base + sizeof(*pm_info),
		&imx6_suspend,
		MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info));

	__arm_iomem_set_ro(suspend_ocram_base, MX6Q_SUSPEND_OCRAM_SIZE);

	goto put_device;

pl310_cache_map_failed:
	iounmap(pm_info->gpc_base.vbase);
gpc_map_failed:
	iounmap(pm_info->iomuxc_base.vbase);
iomuxc_map_failed:
	iounmap(pm_info->src_base.vbase);
src_map_failed:
	iounmap(pm_info->mmdc_base.vbase);
put_device:
	put_device(&pdev->dev);
put_node:
	of_node_put(node);

	return ret;
}

static void __init imx6_pm_common_init(const struct imx6_pm_socdata
					*socdata)
{
	struct regmap *gpr;
	int ret;

	WARN_ON(!ccm_base);

	if (IS_ENABLED(CONFIG_SUSPEND)) {
		ret = imx6q_suspend_init(socdata);
		if (ret)
			pr_warn("%s: No DDR LPM support with suspend %d!\n",
				__func__, ret);
	}

	/*
	 * This is for SW workaround step #1 of ERR007265, see comments
	 * in imx6_set_lpm for details of this errata.
	 * Force IOMUXC irq pending, so that the interrupt to GPC can be
	 * used to deassert dsm_request signal when the signal gets
	 * asserted unexpectedly.
	 */
	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
	if (!IS_ERR(gpr))
		regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT,
				   IMX6Q_GPR1_GINT);
}

static void imx6_pm_stby_poweroff(void)
{
	gic_cpu_if_down(0);
	imx6_set_lpm(STOP_POWER_OFF);
	imx6q_suspend_finish(0);

	mdelay(1000);

	pr_emerg("Unable to poweroff system\n");
}

static int imx6_pm_stby_poweroff_probe(void)
{
	if (pm_power_off) {
		pr_warn("%s: pm_power_off already claimed  %p %ps!\n",
			__func__, pm_power_off, pm_power_off);
		return -EBUSY;
	}

	pm_power_off = imx6_pm_stby_poweroff;
	return 0;
}

void __init imx6_pm_ccm_init(const char *ccm_compat)
{
	struct device_node *np;
	u32 val;

	np = of_find_compatible_node(NULL, NULL, ccm_compat);
	ccm_base = of_iomap(np, 0);
	BUG_ON(!ccm_base);

	/*
	 * Initialize CCM_CLPCR_LPM into RUN mode to avoid ARM core
	 * clock being shut down unexpectedly by WAIT mode.
	 */
	val = readl_relaxed(ccm_base + CLPCR);
	val &= ~BM_CLPCR_LPM;
	writel_relaxed(val, ccm_base + CLPCR);

	if (of_property_read_bool(np, "fsl,pmic-stby-poweroff"))
		imx6_pm_stby_poweroff_probe();

	of_node_put(np);
}

void __init imx6q_pm_init(void)
{
	imx6_pm_common_init(&imx6q_pm_data);
}

void __init imx6dl_pm_init(void)
{
	imx6_pm_common_init(&imx6dl_pm_data);
}

void __init imx6sl_pm_init(void)
{
	struct regmap *gpr;

	if (cpu_is_imx6sl()) {
		imx6_pm_common_init(&imx6sl_pm_data);
	} else {
		imx6_pm_common_init(&imx6sll_pm_data);
		gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
		if (!IS_ERR(gpr))
			regmap_update_bits(gpr, IOMUXC_GPR5,
				IMX6SLL_GPR5_AFCG_X_BYPASS_MASK, 0);
	}
}

void __init imx6sx_pm_init(void)
{
	imx6_pm_common_init(&imx6sx_pm_data);
}

void __init imx6ul_pm_init(void)
{
	imx6_pm_common_init(&imx6ul_pm_data);
}


code:
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2016 Freescale Semiconductor, Inc.
 * Copyright 2017-2018 NXP
 *   Author: Dong Aisheng <aisheng.dong@nxp.com>
 */

#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>

#include "common.h"

#define SMC_PMCTRL		0x10
#define BP_PMCTRL_PSTOPO        16
#define PSTOPO_PSTOP3		0x3
#define PSTOPO_PSTOP2		0x2
#define PSTOPO_PSTOP1		0x1
#define BP_PMCTRL_RUNM		8
#define RUNM_RUN		0
#define BP_PMCTRL_STOPM		0
#define STOPM_STOP		0

#define BM_PMCTRL_PSTOPO	(3 << BP_PMCTRL_PSTOPO)
#define BM_PMCTRL_RUNM		(3 << BP_PMCTRL_RUNM)
#define BM_PMCTRL_STOPM		(7 << BP_PMCTRL_STOPM)

static void __iomem *smc1_base;

int imx7ulp_set_lpm(enum ulp_cpu_pwr_mode mode)
{
	u32 val = readl_relaxed(smc1_base + SMC_PMCTRL);

	/* clear all */
	val &= ~(BM_PMCTRL_RUNM | BM_PMCTRL_STOPM | BM_PMCTRL_PSTOPO);

	switch (mode) {
	case ULP_PM_RUN:
		/* system/bus clock enabled */
		val |= PSTOPO_PSTOP3 << BP_PMCTRL_PSTOPO;
		break;
	case ULP_PM_WAIT:
		/* system clock disabled, bus clock enabled */
		val |= PSTOPO_PSTOP2 << BP_PMCTRL_PSTOPO;
		break;
	case ULP_PM_STOP:
		/* system/bus clock disabled */
		val |= PSTOPO_PSTOP1 << BP_PMCTRL_PSTOPO;
		break;
	default:
		return -EINVAL;
	}

	writel_relaxed(val, smc1_base + SMC_PMCTRL);

	return 0;
}

void __init imx7ulp_pm_init(void)
{
	struct device_node *np;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
	smc1_base = of_iomap(np, 0);
	of_node_put(np);
	WARN_ON(!smc1_base);

	imx7ulp_set_lpm(ULP_PM_RUN);
}


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2014 Freescale Semiconductor, Inc.
 */

#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hardware/cache-l2x0.h>
#include "hardware.h"

.arch armv7-a

/*
 * The following code must assume it is running from physical address
 * where absolute virtual addresses to the data section have to be
 * turned into relative ones.
 */

ENTRY(v7_cpu_resume)
	bl	v7_invalidate_l1
#ifdef CONFIG_CACHE_L2X0
	bl	l2c310_early_resume
#endif
	b	cpu_resume
ENDPROC(v7_cpu_resume)


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright 2011 Freescale Semiconductor, Inc.
 * Copyright 2011 Linaro Ltd.
 */

#include <linux/init.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>
#include "common.h"
#include "hardware.h"

#define SRC_SCR				0x000
#define SRC_GPR1_V1			0x020
#define SRC_GPR1_V2			0x074
#define SRC_GPR1(gpr_v2)		((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1)
#define BP_SRC_SCR_WARM_RESET_ENABLE	0
#define BP_SRC_SCR_SW_GPU_RST		1
#define BP_SRC_SCR_SW_VPU_RST		2
#define BP_SRC_SCR_SW_IPU1_RST		3
#define BP_SRC_SCR_SW_OPEN_VG_RST	4
#define BP_SRC_SCR_SW_IPU2_RST		12
#define BP_SRC_SCR_CORE1_RST		14
#define BP_SRC_SCR_CORE1_ENABLE		22
/* below is for i.MX7D */
#define SRC_A7RCR1			0x008
#define BP_SRC_A7RCR1_A7_CORE1_ENABLE	1
#define GPC_CPU_PGC_SW_PUP_REQ		0xf0
#define GPC_CPU_PGC_SW_PDN_REQ		0xfc
#define GPC_PGC_C1			0x840
#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7	0x2

static void __iomem *src_base;
static DEFINE_SPINLOCK(scr_lock);
static bool gpr_v2;
static void __iomem *gpc_base;

static const int sw_reset_bits[5] = {
	BP_SRC_SCR_SW_GPU_RST,
	BP_SRC_SCR_SW_VPU_RST,
	BP_SRC_SCR_SW_IPU1_RST,
	BP_SRC_SCR_SW_OPEN_VG_RST,
	BP_SRC_SCR_SW_IPU2_RST
};

static int imx_src_reset_module(struct reset_controller_dev *rcdev,
		unsigned long sw_reset_idx)
{
	unsigned long timeout;
	unsigned long flags;
	int bit;
	u32 val;

	if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
		return -EINVAL;

	bit = 1 << sw_reset_bits[sw_reset_idx];

	spin_lock_irqsave(&scr_lock, flags);
	val = readl_relaxed(src_base + SRC_SCR);
	val |= bit;
	writel_relaxed(val, src_base + SRC_SCR);
	spin_unlock_irqrestore(&scr_lock, flags);

	timeout = jiffies + msecs_to_jiffies(1000);
	while (readl(src_base + SRC_SCR) & bit) {
		if (time_after(jiffies, timeout))
			return -ETIME;
		cpu_relax();
	}

	return 0;
}

static const struct reset_control_ops imx_src_ops = {
	.reset = imx_src_reset_module,
};

static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset)
{
	writel_relaxed(enable, gpc_base + offset);
}

/*
 * The motivation for bringing up the second i.MX7D core inside the kernel
 * is that legacy vendor bootloaders usually do not implement PSCI support.
 * This is a significant blocker for systems in the field that are running old
 * bootloader versions to upgrade to a modern mainline kernel version, as only
 * one CPU of the i.MX7D would be brought up.
 * Bring up the second i.MX7D core inside the kernel to make the migration
 * path to mainline kernel easier for the existing iMX7D users.
 */
void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn)
{
	u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ;
	u32 val, pup;
	int ret;

	imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1);
	val = readl_relaxed(gpc_base + reg);
	val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
	writel_relaxed(val, gpc_base + reg);

	ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup,
				!(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7),
				5, 1000000);
	if (ret < 0) {
		pr_err("i.MX7D: CORE1_A7 power up timeout\n");
		val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7;
		writel_relaxed(val, gpc_base + reg);
	}

	imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1);
}

void imx_enable_cpu(int cpu, bool enable)
{
	u32 mask, val;

	cpu = cpu_logical_map(cpu);
	spin_lock(&scr_lock);
	if (gpr_v2) {
		if (enable)
			imx_gpcv2_set_core1_pdn_pup_by_software(false);

		mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1);
		val = readl_relaxed(src_base + SRC_A7RCR1);
		val = enable ? val | mask : val & ~mask;
		writel_relaxed(val, src_base + SRC_A7RCR1);
	} else {
		mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
		val = readl_relaxed(src_base + SRC_SCR);
		val = enable ? val | mask : val & ~mask;
		val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1);
		writel_relaxed(val, src_base + SRC_SCR);
	}
	spin_unlock(&scr_lock);
}

void imx_set_cpu_jump(int cpu, void *jump_addr)
{
	cpu = cpu_logical_map(cpu);
	writel_relaxed(__pa_symbol(jump_addr),
		       src_base + SRC_GPR1(gpr_v2) + cpu * 8);
}

u32 imx_get_cpu_arg(int cpu)
{
	cpu = cpu_logical_map(cpu);
	return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
}

void imx_set_cpu_arg(int cpu, u32 arg)
{
	cpu = cpu_logical_map(cpu);
	writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4);
}

void __init imx_src_init(void)
{
	struct device_node *np;
	u32 val;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src");
	if (!np)
		return;
	src_base = of_iomap(np, 0);
	WARN_ON(!src_base);

	/*
	 * force warm reset sources to generate cold reset
	 * for a more reliable restart
	 */
	spin_lock(&scr_lock);
	val = readl_relaxed(src_base + SRC_SCR);
	val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
	writel_relaxed(val, src_base + SRC_SCR);
	spin_unlock(&scr_lock);
}

void __init imx7_src_init(void)
{
	struct device_node *np;

	gpr_v2 = true;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src");
	if (!np)
		return;

	src_base = of_iomap(np, 0);
	if (!src_base)
		return;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc");
	if (!np)
		return;

	gpc_base = of_iomap(np, 0);
	if (!gpc_base)
		return;
}

static const struct of_device_id imx_src_dt_ids[] = {
	{ .compatible = "fsl,imx51-src" },
	{ /* sentinel */ }
};

static int imx_src_probe(struct platform_device *pdev)
{
	struct reset_controller_dev *rcdev;

	rcdev = devm_kzalloc(&pdev->dev, sizeof(*rcdev), GFP_KERNEL);
	if (!rcdev)
		return -ENOMEM;

	rcdev->ops = &imx_src_ops;
	rcdev->dev = &pdev->dev;
	rcdev->of_node = pdev->dev.of_node;
	rcdev->nr_resets = ARRAY_SIZE(sw_reset_bits);

	return devm_reset_controller_register(&pdev->dev, rcdev);
}

static struct platform_driver imx_src_driver = {
	.driver = {
		.name = "imx-src",
		.of_match_table = imx_src_dt_ids,
	},
	.probe = imx_src_probe,
};
builtin_platform_driver(imx_src_driver);


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Exported ksyms for the SSI FIQ handler
 *
 * Copyright (C) 2009, Sascha Hauer <s.hauer@pengutronix.de>
 */

#include <linux/module.h>

#include <linux/platform_data/asoc-imx-ssi.h>

EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
EXPORT_SYMBOL(imx_ssi_fiq_start);
EXPORT_SYMBOL(imx_ssi_fiq_end);
EXPORT_SYMBOL(imx_ssi_fiq_base);


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
 */

#include <linux/linkage.h>
#include <asm/assembler.h>

/*
 * r8  = bit 0-15: tx offset, bit 16-31: tx buffer size
 * r9  = bit 0-15: rx offset, bit 16-31: rx buffer size
 */

#define SSI_STX0	0x00
#define SSI_SRX0	0x08
#define SSI_SISR	0x14
#define SSI_SIER	0x18
#define SSI_SACNT	0x38

#define SSI_SACNT_AC97EN	(1 << 0)

#define SSI_SIER_TFE0_EN	(1 << 0)
#define SSI_SISR_TFE0		(1 << 0)
#define SSI_SISR_RFF0		(1 << 2)
#define SSI_SIER_RFF0_EN	(1 << 2)

		.text
		.global	imx_ssi_fiq_start
		.global	imx_ssi_fiq_end
		.global imx_ssi_fiq_base
		.global imx_ssi_fiq_rx_buffer
		.global imx_ssi_fiq_tx_buffer

/*
 * imx_ssi_fiq_start is _intentionally_ not marked as a function symbol
 * using ENDPROC().  imx_ssi_fiq_start and imx_ssi_fiq_end are used to
 * mark the function body so that it can be copied to the FIQ vector in
 * the vectors page.  imx_ssi_fiq_start should only be called as the result
 * of an FIQ: calling it directly will not work.
 */
imx_ssi_fiq_start:
		ldr r12, .L_imx_ssi_fiq_base

		/* TX */
		ldr r13, .L_imx_ssi_fiq_tx_buffer

		/* shall we send? */
		ldr r11, [r12, #SSI_SIER]
		tst r11, #SSI_SIER_TFE0_EN
		beq 1f

		/* TX FIFO empty? */
		ldr r11, [r12, #SSI_SISR]
		tst r11, #SSI_SISR_TFE0
		beq 1f

		mov r10, #0x10000
		sub r10, #1
		and r10, r10, r8	/* r10: current buffer offset */

		add r13, r13, r10

		ldrh r11, [r13]
		strh r11, [r12, #SSI_STX0]

		ldrh r11, [r13, #2]
		strh r11, [r12, #SSI_STX0]

		ldrh r11, [r13, #4]
		strh r11, [r12, #SSI_STX0]

		ldrh r11, [r13, #6]
		strh r11, [r12, #SSI_STX0]

		add r10, #8
		lsr r11, r8, #16	/* r11: buffer size */
		cmp r10, r11
		lslgt r8, r11, #16
		addle r8, #8
1:
		/* RX */

		/* shall we receive? */
		ldr r11, [r12, #SSI_SIER]
		tst r11, #SSI_SIER_RFF0_EN
		beq 1f

		/* RX FIFO full? */
		ldr r11, [r12, #SSI_SISR]
		tst r11, #SSI_SISR_RFF0
		beq 1f

		ldr r13, .L_imx_ssi_fiq_rx_buffer

		mov r10, #0x10000
		sub r10, #1
		and r10, r10, r9	/* r10: current buffer offset */

		add r13, r13, r10

		ldr r11, [r12, #SSI_SACNT]
		tst r11, #SSI_SACNT_AC97EN

		ldr r11, [r12, #SSI_SRX0]
		strh r11, [r13]

		ldr r11, [r12, #SSI_SRX0]
		strh r11, [r13, #2]

		/* dummy read to skip slot 12 */
		ldrne r11, [r12, #SSI_SRX0]

		ldr r11, [r12, #SSI_SRX0]
		strh r11, [r13, #4]

		ldr r11, [r12, #SSI_SRX0]
		strh r11, [r13, #6]

		/* dummy read to skip slot 12 */
		ldrne r11, [r12, #SSI_SRX0]

		add r10, #8
		lsr r11, r9, #16	/* r11: buffer size */
		cmp r10, r11
		lslgt r9, r11, #16
		addle r9, #8

1:
		@ return from FIQ
		subs	pc, lr, #4

		.align
.L_imx_ssi_fiq_base:
imx_ssi_fiq_base:
		.word 0x0
.L_imx_ssi_fiq_rx_buffer:
imx_ssi_fiq_rx_buffer:
		.word 0x0
.L_imx_ssi_fiq_tx_buffer:
imx_ssi_fiq_tx_buffer:
		.word 0x0
.L_imx_ssi_fiq_end:
imx_ssi_fiq_end: