code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * OMAP44xx PRM instance offset macros
 *
 * Copyright (C) 2009-2011 Texas Instruments, Inc.
 * Copyright (C) 2009-2010 Nokia Corporation
 *
 * Paul Walmsley (paul@pwsan.com)
 * Rajendra Nayak (rnayak@ti.com)
 * Benoit Cousson (b-cousson@ti.com)
 *
 * This file is automatically generated from the OMAP hardware databases.
 * We respectfully ask that any modifications to this file be coordinated
 * with the public linux-omap@vger.kernel.org mailing list and the
 * authors above to ensure that the autogeneration scripts are kept
 * up-to-date with the file contents.
 *
 * XXX This file needs to be updated to align on one of "OMAP4", "OMAP44XX",
 *     or "OMAP4430".
 */

#ifndef __ARCH_ARM_MACH_OMAP2_PRM44XX_H
#define __ARCH_ARM_MACH_OMAP2_PRM44XX_H

#include "prm44xx_54xx.h"
#include "prm.h"

#define OMAP4430_PRM_BASE		0x4a306000

#define OMAP44XX_PRM_REGADDR(inst, reg)				\
	OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE + (inst) + (reg))

/* PRM instances */
#define OMAP4430_PRM_OCP_SOCKET_INST	0x0000
#define OMAP4430_PRM_CKGEN_INST		0x0100
#define OMAP4430_PRM_MPU_INST		0x0300
#define OMAP4430_PRM_TESLA_INST		0x0400
#define OMAP4430_PRM_ABE_INST		0x0500
#define OMAP4430_PRM_ALWAYS_ON_INST	0x0600
#define OMAP4430_PRM_CORE_INST		0x0700
#define OMAP4430_PRM_IVAHD_INST		0x0f00
#define OMAP4430_PRM_CAM_INST		0x1000
#define OMAP4430_PRM_DSS_INST		0x1100
#define OMAP4430_PRM_GFX_INST		0x1200
#define OMAP4430_PRM_L3INIT_INST	0x1300
#define OMAP4430_PRM_L4PER_INST		0x1400
#define OMAP4430_PRM_CEFUSE_INST	0x1600
#define OMAP4430_PRM_WKUP_INST		0x1700
#define OMAP4430_PRM_WKUP_CM_INST	0x1800
#define OMAP4430_PRM_EMU_INST		0x1900
#define OMAP4430_PRM_EMU_CM_INST	0x1a00
#define OMAP4430_PRM_DEVICE_INST	0x1b00

/* PRM clockdomain register offsets (from instance start) */
#define OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS	0x0000
#define OMAP4430_PRM_EMU_CM_EMU_CDOFFS		0x0000

/* OMAP4 specific register offsets */
#define OMAP4_RM_RSTST					0x0004
#define OMAP4_PM_PWSTCTRL				0x0000
#define OMAP4_PM_PWSTST					0x0004

/* PRM.OCP_SOCKET_PRM register offsets */
#define OMAP4_REVISION_PRM_OFFSET			0x0000
#define OMAP4_PRM_IRQSTATUS_MPU_OFFSET			0x0010
#define OMAP4430_PRM_IRQSTATUS_MPU			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_INST, 0x0010)
#define OMAP4_PRM_IRQSTATUS_MPU_2_OFFSET		0x0014
#define OMAP4_PRM_IRQENABLE_MPU_OFFSET			0x0018
#define OMAP4430_PRM_IRQENABLE_MPU			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_INST, 0x0018)

/* PRM.MPU_PRM register offsets */
#define OMAP4_RM_MPU_MPU_CONTEXT_OFFSET			0x0024

/* PRM.DEVICE_PRM register offsets */
#define OMAP4_PRM_RSTCTRL_OFFSET			0x0000
#define OMAP4_PRM_VOLTCTRL_OFFSET			0x0010
#define OMAP4_PRM_IO_PMCTRL_OFFSET			0x0020
#define OMAP4_PRM_VOLTSETUP_CORE_OFF_OFFSET		0x0028
#define OMAP4_PRM_VOLTSETUP_MPU_OFF_OFFSET		0x002c
#define OMAP4_PRM_VOLTSETUP_IVA_OFF_OFFSET		0x0030
#define OMAP4_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET	0x0034
#define OMAP4_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET	0x0038
#define OMAP4_PRM_VOLTSETUP_IVA_RET_SLEEP_OFFSET	0x003c
#define OMAP4_PRM_VP_CORE_CONFIG_OFFSET			0x0040
#define OMAP4_PRM_VP_CORE_STATUS_OFFSET			0x0044
#define OMAP4_PRM_VP_CORE_VLIMITTO_OFFSET		0x0048
#define OMAP4_PRM_VP_CORE_VOLTAGE_OFFSET		0x004c
#define OMAP4_PRM_VP_CORE_VSTEPMAX_OFFSET		0x0050
#define OMAP4_PRM_VP_CORE_VSTEPMIN_OFFSET		0x0054
#define OMAP4_PRM_VP_MPU_CONFIG_OFFSET			0x0058
#define OMAP4_PRM_VP_MPU_STATUS_OFFSET			0x005c
#define OMAP4_PRM_VP_MPU_VLIMITTO_OFFSET		0x0060
#define OMAP4_PRM_VP_MPU_VOLTAGE_OFFSET			0x0064
#define OMAP4_PRM_VP_MPU_VSTEPMAX_OFFSET		0x0068
#define OMAP4_PRM_VP_MPU_VSTEPMIN_OFFSET		0x006c
#define OMAP4_PRM_VP_IVA_CONFIG_OFFSET			0x0070
#define OMAP4_PRM_VP_IVA_STATUS_OFFSET			0x0074
#define OMAP4_PRM_VP_IVA_VLIMITTO_OFFSET		0x0078
#define OMAP4_PRM_VP_IVA_VOLTAGE_OFFSET			0x007c
#define OMAP4_PRM_VP_IVA_VSTEPMAX_OFFSET		0x0080
#define OMAP4_PRM_VP_IVA_VSTEPMIN_OFFSET		0x0084
#define OMAP4_PRM_VC_SMPS_SA_OFFSET			0x0088
#define OMAP4_PRM_VC_VAL_SMPS_RA_VOL_OFFSET		0x008c
#define OMAP4_PRM_VC_VAL_SMPS_RA_CMD_OFFSET		0x0090
#define OMAP4_PRM_VC_VAL_CMD_VDD_CORE_L_OFFSET		0x0094
#define OMAP4_PRM_VC_VAL_CMD_VDD_MPU_L_OFFSET		0x0098
#define OMAP4_PRM_VC_VAL_CMD_VDD_IVA_L_OFFSET		0x009c
#define OMAP4_PRM_VC_VAL_BYPASS_OFFSET			0x00a0
#define OMAP4_PRM_VC_CFG_CHANNEL_OFFSET			0x00a4
#define OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET		0x00a8
#define OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET			0x00ac

#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * OMAP44xx and 54xx PRM common functions
 *
 * Copyright (C) 2009-2013 Texas Instruments, Inc.
 * Copyright (C) 2009-2010 Nokia Corporation
 *
 * Paul Walmsley (paul@pwsan.com)
 * Rajendra Nayak (rnayak@ti.com)
 * Benoit Cousson (b-cousson@ti.com)
 *
 * This file is automatically generated from the OMAP hardware databases.
 * We respectfully ask that any modifications to this file be coordinated
 * with the public linux-omap@vger.kernel.org mailing list and the
 * authors above to ensure that the autogeneration scripts are kept
 * up-to-date with the file contents.
 */

#ifndef __ARCH_ARM_MACH_OMAP2_PRM44XX_54XX_H
#define __ARCH_ARM_MACH_OMAP2_PRM44XX_54XX_H

#include "prcm-common.h"

/* Function prototypes */
#ifndef __ASSEMBLER__

/*
 * OMAP4/OMAP5 access functions for voltage controller (VC) and
 * voltage proccessor (VP) in the PRM.
 */
extern u32 omap4_prm_vcvp_read(u8 offset);
extern void omap4_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);

int __init omap44xx_prm_init(const struct omap_prcm_init_data *data);

#endif

#endif

repo_name: angery/linux


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * OMAP54xx PRM instance offset macros
 *
 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com
 *
 * Paul Walmsley (paul@pwsan.com)
 * Rajendra Nayak (rnayak@ti.com)
 * Benoit Cousson (b-cousson@ti.com)
 *
 * This file is automatically generated from the OMAP hardware databases.
 * We respectfully ask that any modifications to this file be coordinated
 * with the public linux-omap@vger.kernel.org mailing list and the
 * authors above to ensure that the autogeneration scripts are kept
 * up-to-date with the file contents.
 */

#ifndef __ARCH_ARM_MACH_OMAP2_PRM54XX_H
#define __ARCH_ARM_MACH_OMAP2_PRM54XX_H

#include "prm44xx_54xx.h"
#include "prm.h"

#define OMAP54XX_PRM_BASE		0x4ae06000

#define OMAP54XX_PRM_REGADDR(inst, reg)				\
	OMAP2_L4_IO_ADDRESS(OMAP54XX_PRM_BASE + (inst) + (reg))

/* PRM instances */
#define OMAP54XX_PRM_OCP_SOCKET_INST	0x0000
#define OMAP54XX_PRM_CKGEN_INST		0x0100
#define OMAP54XX_PRM_MPU_INST		0x0300
#define OMAP54XX_PRM_DSP_INST		0x0400
#define OMAP54XX_PRM_ABE_INST		0x0500
#define OMAP54XX_PRM_COREAON_INST	0x0600
#define OMAP54XX_PRM_CORE_INST		0x0700
#define OMAP54XX_PRM_IVA_INST		0x1200
#define OMAP54XX_PRM_CAM_INST		0x1300
#define OMAP54XX_PRM_DSS_INST		0x1400
#define OMAP54XX_PRM_GPU_INST		0x1500
#define OMAP54XX_PRM_L3INIT_INST	0x1600
#define OMAP54XX_PRM_CUSTEFUSE_INST	0x1700
#define OMAP54XX_PRM_WKUPAON_INST	0x1800
#define OMAP54XX_PRM_WKUPAON_CM_INST	0x1900
#define OMAP54XX_PRM_EMU_INST		0x1a00
#define OMAP54XX_PRM_EMU_CM_INST	0x1b00
#define OMAP54XX_PRM_DEVICE_INST	0x1c00

/* PRM clockdomain register offsets (from instance start) */
#define OMAP54XX_PRM_WKUPAON_CM_WKUPAON_CDOFFS	0x0000
#define OMAP54XX_PRM_EMU_CM_EMU_CDOFFS		0x0000

/* PRM.DEVICE_PRM register offsets */
#define OMAP54XX_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET		0x0034
#define OMAP54XX_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET		0x0038
#define OMAP54XX_PRM_VOLTSETUP_MM_RET_SLEEP_OFFSET		0x003c

#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * DRA7xx PRM instance offset macros
 *
 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com
 *
 * Generated by code originally written by:
 * Paul Walmsley (paul@pwsan.com)
 * Rajendra Nayak (rnayak@ti.com)
 * Benoit Cousson (b-cousson@ti.com)
 *
 * This file is automatically generated from the OMAP hardware databases.
 * We respectfully ask that any modifications to this file be coordinated
 * with the public linux-omap@vger.kernel.org mailing list and the
 * authors above to ensure that the autogeneration scripts are kept
 * up-to-date with the file contents.
 */

#ifndef __ARCH_ARM_MACH_OMAP2_PRM7XX_H
#define __ARCH_ARM_MACH_OMAP2_PRM7XX_H

#include "prcm-common.h"
#include "prm44xx_54xx.h"
#include "prm.h"

#define DRA7XX_PRM_BASE		0x4ae06000

#define DRA7XX_PRM_REGADDR(inst, reg)				\
	OMAP2_L4_IO_ADDRESS(DRA7XX_PRM_BASE + (inst) + (reg))

/* PRM instances */
#define DRA7XX_PRM_OCP_SOCKET_INST	0x0000
#define DRA7XX_PRM_CKGEN_INST		0x0100
#define DRA7XX_PRM_MPU_INST		0x0300
#define DRA7XX_PRM_DSP1_INST		0x0400
#define DRA7XX_PRM_IPU_INST		0x0500
#define DRA7XX_PRM_COREAON_INST		0x0628
#define DRA7XX_PRM_CORE_INST		0x0700
#define DRA7XX_PRM_IVA_INST		0x0f00
#define DRA7XX_PRM_CAM_INST		0x1000
#define DRA7XX_PRM_DSS_INST		0x1100
#define DRA7XX_PRM_GPU_INST		0x1200
#define DRA7XX_PRM_L3INIT_INST		0x1300
#define DRA7XX_PRM_L4PER_INST		0x1400
#define DRA7XX_PRM_CUSTEFUSE_INST	0x1600
#define DRA7XX_PRM_WKUPAON_INST		0x1724
#define DRA7XX_PRM_WKUPAON_CM_INST	0x1800
#define DRA7XX_PRM_EMU_INST		0x1900
#define DRA7XX_PRM_EMU_CM_INST		0x1a00
#define DRA7XX_PRM_DSP2_INST		0x1b00
#define DRA7XX_PRM_EVE1_INST		0x1b40
#define DRA7XX_PRM_EVE2_INST		0x1b80
#define DRA7XX_PRM_EVE3_INST		0x1bc0
#define DRA7XX_PRM_EVE4_INST		0x1c00
#define DRA7XX_PRM_RTC_INST		0x1c60
#define DRA7XX_PRM_VPE_INST		0x1c80
#define DRA7XX_PRM_DEVICE_INST		0x1d00

/* PRM clockdomain register offsets (from instance start) */
#define DRA7XX_PRM_WKUPAON_CM_WKUPAON_CDOFFS	0x0000
#define DRA7XX_PRM_EMU_CM_EMU_CDOFFS		0x0000

/* PRM.CKGEN_PRM register offsets */
#define DRA7XX_CM_CLKSEL_SYS					DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0010)

#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP2+ common Power & Reset Management (PRM) IP block functions
 *
 * Copyright (C) 2011 Texas Instruments, Inc.
 * Tero Kristo <t-kristo@ti.com>
 *
 * For historical purposes, the API used to configure the PRM
 * interrupt handler refers to it as the "PRCM interrupt."  The
 * underlying registers are located in the PRM on OMAP3/4.
 *
 * XXX This code should eventually be moved to a PRM driver.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>

#include "soc.h"
#include "prm2xxx_3xxx.h"
#include "prm2xxx.h"
#include "prm3xxx.h"
#include "prm33xx.h"
#include "prm44xx.h"
#include "prm54xx.h"
#include "prm7xx.h"
#include "prcm43xx.h"
#include "common.h"
#include "clock.h"
#include "cm.h"
#include "control.h"

/*
 * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
 * XXX this is technically not needed, since
 * omap_prcm_register_chain_handler() could allocate this based on the
 * actual amount of memory needed for the SoC
 */
#define OMAP_PRCM_MAX_NR_PENDING_REG		2

/*
 * prcm_irq_chips: an array of all of the "generic IRQ chips" in use
 * by the PRCM interrupt handler code.  There will be one 'chip' per
 * PRM_{IRQSTATUS,IRQENABLE}_MPU register pair.  (So OMAP3 will have
 * one "chip" and OMAP4 will have two.)
 */
static struct irq_chip_generic **prcm_irq_chips;

/*
 * prcm_irq_setup: the PRCM IRQ parameters for the hardware the code
 * is currently running on.  Defined and passed by initialization code
 * that calls omap_prcm_register_chain_handler().
 */
static struct omap_prcm_irq_setup *prcm_irq_setup;

/* prm_base: base virtual address of the PRM IP block */
struct omap_domain_base prm_base;

u16 prm_features;

/*
 * prm_ll_data: function pointers to SoC-specific implementations of
 * common PRM functions
 */
static struct prm_ll_data null_prm_ll_data;
static struct prm_ll_data *prm_ll_data = &null_prm_ll_data;

/* Private functions */

/*
 * Move priority events from events to priority_events array
 */
static void omap_prcm_events_filter_priority(unsigned long *events,
	unsigned long *priority_events)
{
	int i;

	for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
		priority_events[i] =
			events[i] & prcm_irq_setup->priority_mask[i];
		events[i] ^= priority_events[i];
	}
}

/*
 * PRCM Interrupt Handler
 *
 * This is a common handler for the OMAP PRCM interrupts. Pending
 * interrupts are detected by a call to prcm_pending_events and
 * dispatched accordingly. Clearing of the wakeup events should be
 * done by the SoC specific individual handlers.
 */
static void omap_prcm_irq_handler(struct irq_desc *desc)
{
	unsigned long pending[OMAP_PRCM_MAX_NR_PENDING_REG];
	unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned int virtirq;
	int nr_irq = prcm_irq_setup->nr_regs * 32;

	/*
	 * If we are suspended, mask all interrupts from PRCM level,
	 * this does not ack them, and they will be pending until we
	 * re-enable the interrupts, at which point the
	 * omap_prcm_irq_handler will be executed again.  The
	 * _save_and_clear_irqen() function must ensure that the PRM
	 * write to disable all IRQs has reached the PRM before
	 * returning, or spurious PRCM interrupts may occur during
	 * suspend.
	 */
	if (prcm_irq_setup->suspended) {
		prcm_irq_setup->save_and_clear_irqen(prcm_irq_setup->saved_mask);
		prcm_irq_setup->suspend_save_flag = true;
	}

	/*
	 * Loop until all pending irqs are handled, since
	 * generic_handle_irq() can cause new irqs to come
	 */
	while (!prcm_irq_setup->suspended) {
		prcm_irq_setup->read_pending_irqs(pending);

		/* No bit set, then all IRQs are handled */
		if (find_first_bit(pending, nr_irq) >= nr_irq)
			break;

		omap_prcm_events_filter_priority(pending, priority_pending);

		/*
		 * Loop on all currently pending irqs so that new irqs
		 * cannot starve previously pending irqs
		 */

		/* Serve priority events first */
		for_each_set_bit(virtirq, priority_pending, nr_irq)
			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);

		/* Serve normal events next */
		for_each_set_bit(virtirq, pending, nr_irq)
			generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
	}
	if (chip->irq_ack)
		chip->irq_ack(&desc->irq_data);
	if (chip->irq_eoi)
		chip->irq_eoi(&desc->irq_data);
	chip->irq_unmask(&desc->irq_data);

	prcm_irq_setup->ocp_barrier(); /* avoid spurious IRQs */
}

/* Public functions */

/**
 * omap_prcm_event_to_irq - given a PRCM event name, returns the
 * corresponding IRQ on which the handler should be registered
 * @name: name of the PRCM interrupt bit to look up - see struct omap_prcm_irq
 *
 * Returns the Linux internal IRQ ID corresponding to @name upon success,
 * or -ENOENT upon failure.
 */
int omap_prcm_event_to_irq(const char *name)
{
	int i;

	if (!prcm_irq_setup || !name)
		return -ENOENT;

	for (i = 0; i < prcm_irq_setup->nr_irqs; i++)
		if (!strcmp(prcm_irq_setup->irqs[i].name, name))
			return prcm_irq_setup->base_irq +
				prcm_irq_setup->irqs[i].offset;

	return -ENOENT;
}

/**
 * omap_prcm_irq_cleanup - reverses memory allocated and other steps
 * done by omap_prcm_register_chain_handler()
 *
 * No return value.
 */
void omap_prcm_irq_cleanup(void)
{
	unsigned int irq;
	int i;

	if (!prcm_irq_setup) {
		pr_err("PRCM: IRQ handler not initialized; cannot cleanup\n");
		return;
	}

	if (prcm_irq_chips) {
		for (i = 0; i < prcm_irq_setup->nr_regs; i++) {
			if (prcm_irq_chips[i])
				irq_remove_generic_chip(prcm_irq_chips[i],
					0xffffffff, 0, 0);
			prcm_irq_chips[i] = NULL;
		}
		kfree(prcm_irq_chips);
		prcm_irq_chips = NULL;
	}

	kfree(prcm_irq_setup->saved_mask);
	prcm_irq_setup->saved_mask = NULL;

	kfree(prcm_irq_setup->priority_mask);
	prcm_irq_setup->priority_mask = NULL;

	irq = prcm_irq_setup->irq;
	irq_set_chained_handler(irq, NULL);

	if (prcm_irq_setup->base_irq > 0)
		irq_free_descs(prcm_irq_setup->base_irq,
			prcm_irq_setup->nr_regs * 32);
	prcm_irq_setup->base_irq = 0;
}

void omap_prcm_irq_prepare(void)
{
	prcm_irq_setup->suspended = true;
}

void omap_prcm_irq_complete(void)
{
	prcm_irq_setup->suspended = false;

	/* If we have not saved the masks, do not attempt to restore */
	if (!prcm_irq_setup->suspend_save_flag)
		return;

	prcm_irq_setup->suspend_save_flag = false;

	/*
	 * Re-enable all masked PRCM irq sources, this causes the PRCM
	 * interrupt to fire immediately if the events were masked
	 * previously in the chain handler
	 */
	prcm_irq_setup->restore_irqen(prcm_irq_setup->saved_mask);
}

/**
 * omap_prcm_register_chain_handler - initializes the prcm chained interrupt
 * handler based on provided parameters
 * @irq_setup: hardware data about the underlying PRM/PRCM
 *
 * Set up the PRCM chained interrupt handler on the PRCM IRQ.  Sets up
 * one generic IRQ chip per PRM interrupt status/enable register pair.
 * Returns 0 upon success, -EINVAL if called twice or if invalid
 * arguments are passed, or -ENOMEM on any other error.
 */
int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
{
	int nr_regs;
	u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
	int offset, i, irq;
	struct irq_chip_generic *gc;
	struct irq_chip_type *ct;

	if (!irq_setup)
		return -EINVAL;

	nr_regs = irq_setup->nr_regs;

	if (prcm_irq_setup) {
		pr_err("PRCM: already initialized; won't reinitialize\n");
		return -EINVAL;
	}

	if (nr_regs > OMAP_PRCM_MAX_NR_PENDING_REG) {
		pr_err("PRCM: nr_regs too large\n");
		return -EINVAL;
	}

	prcm_irq_setup = irq_setup;

	prcm_irq_chips = kcalloc(nr_regs, sizeof(void *), GFP_KERNEL);
	prcm_irq_setup->saved_mask = kcalloc(nr_regs, sizeof(u32),
					     GFP_KERNEL);
	prcm_irq_setup->priority_mask = kcalloc(nr_regs, sizeof(u32),
						GFP_KERNEL);

	if (!prcm_irq_chips || !prcm_irq_setup->saved_mask ||
	    !prcm_irq_setup->priority_mask)
		goto err;

	memset(mask, 0, sizeof(mask));

	for (i = 0; i < irq_setup->nr_irqs; i++) {
		offset = irq_setup->irqs[i].offset;
		mask[offset >> 5] |= 1 << (offset & 0x1f);
		if (irq_setup->irqs[i].priority)
			irq_setup->priority_mask[offset >> 5] |=
				1 << (offset & 0x1f);
	}

	irq = irq_setup->irq;
	irq_set_chained_handler(irq, omap_prcm_irq_handler);

	irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32,
		0);

	if (irq_setup->base_irq < 0) {
		pr_err("PRCM: failed to allocate irq descs: %d\n",
			irq_setup->base_irq);
		goto err;
	}

	for (i = 0; i < irq_setup->nr_regs; i++) {
		gc = irq_alloc_generic_chip("PRCM", 1,
			irq_setup->base_irq + i * 32, prm_base.va,
			handle_level_irq);

		if (!gc) {
			pr_err("PRCM: failed to allocate generic chip\n");
			goto err;
		}
		ct = gc->chip_types;
		ct->chip.irq_ack = irq_gc_ack_set_bit;
		ct->chip.irq_mask = irq_gc_mask_clr_bit;
		ct->chip.irq_unmask = irq_gc_mask_set_bit;

		ct->regs.ack = irq_setup->ack + i * 4;
		ct->regs.mask = irq_setup->mask + i * 4;

		irq_setup_generic_chip(gc, mask[i], 0, IRQ_NOREQUEST, 0);
		prcm_irq_chips[i] = gc;
	}

	irq = omap_prcm_event_to_irq("io");
	omap_pcs_legacy_init(irq, irq_setup->reconfigure_io_chain);

	return 0;

err:
	omap_prcm_irq_cleanup();
	return -ENOMEM;
}

/**
 * omap2_set_globals_prm - set the PRM base address (for early use)
 * @prm: PRM base virtual address
 *
 * XXX Will be replaced when the PRM/CM drivers are completed.
 */
void __init omap2_set_globals_prm(void __iomem *prm)
{
	prm_base.va = prm;
}

/**
 * prm_read_reset_sources - return the sources of the SoC's last reset
 *
 * Return a u32 bitmask representing the reset sources that caused the
 * SoC to reset.  The low-level per-SoC functions called by this
 * function remap the SoC-specific reset source bits into an
 * OMAP-common set of reset source bits, defined in
 * arch/arm/mach-omap2/prm.h.  Returns the standardized reset source
 * u32 bitmask from the hardware upon success, or returns (1 <<
 * OMAP_UNKNOWN_RST_SRC_ID_SHIFT) if no low-level read_reset_sources()
 * function was registered.
 */
u32 prm_read_reset_sources(void)
{
	u32 ret = 1 << OMAP_UNKNOWN_RST_SRC_ID_SHIFT;

	if (prm_ll_data->read_reset_sources)
		ret = prm_ll_data->read_reset_sources();
	else
		WARN_ONCE(1, "prm: %s: no mapping function defined for reset sources\n", __func__);

	return ret;
}

/**
 * prm_was_any_context_lost_old - was device context lost? (old API)
 * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
 * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
 * @idx: CONTEXT register offset
 *
 * Return 1 if any bits were set in the *_CONTEXT_* register
 * identified by (@part, @inst, @idx), which means that some context
 * was lost for that module; otherwise, return 0.  XXX Deprecated;
 * callers need to use a less-SoC-dependent way to identify hardware
 * IP blocks.
 */
bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx)
{
	bool ret = true;

	if (prm_ll_data->was_any_context_lost_old)
		ret = prm_ll_data->was_any_context_lost_old(part, inst, idx);
	else
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);

	return ret;
}

/**
 * prm_clear_context_lost_flags_old - clear context loss flags (old API)
 * @part: PRM partition ID (e.g., OMAP4430_PRM_PARTITION)
 * @inst: PRM instance offset (e.g., OMAP4430_PRM_MPU_INST)
 * @idx: CONTEXT register offset
 *
 * Clear hardware context loss bits for the module identified by
 * (@part, @inst, @idx).  No return value.  XXX Deprecated; callers
 * need to use a less-SoC-dependent way to identify hardware IP
 * blocks.
 */
void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx)
{
	if (prm_ll_data->clear_context_loss_flags_old)
		prm_ll_data->clear_context_loss_flags_old(part, inst, idx);
	else
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
}

/**
 * omap_prm_assert_hardreset - assert hardreset for an IP block
 * @shift: register bit shift corresponding to the reset line
 * @part: PRM partition
 * @prm_mod: PRM submodule base or instance offset
 * @offset: register offset
 *
 * Asserts a hardware reset line for an IP block.
 */
int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
	if (!prm_ll_data->assert_hardreset) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return -EINVAL;
	}

	return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset);
}

/**
 * omap_prm_deassert_hardreset - deassert hardreset for an IP block
 * @shift: register bit shift corresponding to the reset line
 * @st_shift: reset status bit shift corresponding to the reset line
 * @part: PRM partition
 * @prm_mod: PRM submodule base or instance offset
 * @offset: register offset
 * @st_offset: status register offset
 *
 * Deasserts a hardware reset line for an IP block.
 */
int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
				u16 offset, u16 st_offset)
{
	if (!prm_ll_data->deassert_hardreset) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return -EINVAL;
	}

	return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod,
					       offset, st_offset);
}

/**
 * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block
 * @shift: register bit shift corresponding to the reset line
 * @part: PRM partition
 * @prm_mod: PRM submodule base or instance offset
 * @offset: register offset
 *
 * Checks if a hardware reset line for an IP block is enabled or not.
 */
int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
	if (!prm_ll_data->is_hardreset_asserted) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return -EINVAL;
	}

	return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset);
}

/**
 * omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
 *
 * Clear any previously-latched I/O wakeup events and ensure that the
 * I/O wakeup gates are aligned with the current mux settings.
 * Calls SoC specific I/O chain reconfigure function if available,
 * otherwise does nothing.
 */
void omap_prm_reconfigure_io_chain(void)
{
	if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain)
		return;

	prcm_irq_setup->reconfigure_io_chain();
}

/**
 * omap_prm_reset_system - trigger global SW reset
 *
 * Triggers SoC specific global warm reset to reboot the device.
 */
void omap_prm_reset_system(void)
{
	if (!prm_ll_data->reset_system) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return;
	}

	prm_ll_data->reset_system();

	while (1) {
		cpu_relax();
		wfe();
	}
}

/**
 * omap_prm_clear_mod_irqs - clear wake-up events from PRCM interrupt
 * @module: PRM module to clear wakeups from
 * @regs: register to clear
 * @wkst_mask: wkst bits to clear
 *
 * Clears any wakeup events for the module and register set defined.
 * Uses SoC specific implementation to do the actual wakeup status
 * clearing.
 */
int omap_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
{
	if (!prm_ll_data->clear_mod_irqs) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return -EINVAL;
	}

	return prm_ll_data->clear_mod_irqs(module, regs, wkst_mask);
}

/**
 * omap_prm_vp_check_txdone - check voltage processor TX done status
 *
 * Checks if voltage processor transmission has been completed.
 * Returns non-zero if a transmission has completed, 0 otherwise.
 */
u32 omap_prm_vp_check_txdone(u8 vp_id)
{
	if (!prm_ll_data->vp_check_txdone) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return 0;
	}

	return prm_ll_data->vp_check_txdone(vp_id);
}

/**
 * omap_prm_vp_clear_txdone - clears voltage processor TX done status
 *
 * Clears the status bit for completed voltage processor transmission
 * returned by prm_vp_check_txdone.
 */
void omap_prm_vp_clear_txdone(u8 vp_id)
{
	if (!prm_ll_data->vp_clear_txdone) {
		WARN_ONCE(1, "prm: %s: no mapping function defined\n",
			  __func__);
		return;
	}

	prm_ll_data->vp_clear_txdone(vp_id);
}

/**
 * prm_register - register per-SoC low-level data with the PRM
 * @pld: low-level per-SoC OMAP PRM data & function pointers to register
 *
 * Register per-SoC low-level OMAP PRM data and function pointers with
 * the OMAP PRM common interface.  The caller must keep the data
 * pointed to by @pld valid until it calls prm_unregister() and
 * it returns successfully.  Returns 0 upon success, -EINVAL if @pld
 * is NULL, or -EEXIST if prm_register() has already been called
 * without an intervening prm_unregister().
 */
int prm_register(struct prm_ll_data *pld)
{
	if (!pld)
		return -EINVAL;

	if (prm_ll_data != &null_prm_ll_data)
		return -EEXIST;

	prm_ll_data = pld;

	return 0;
}

/**
 * prm_unregister - unregister per-SoC low-level data & function pointers
 * @pld: low-level per-SoC OMAP PRM data & function pointers to unregister
 *
 * Unregister per-SoC low-level OMAP PRM data and function pointers
 * that were previously registered with prm_register().  The
 * caller may not destroy any of the data pointed to by @pld until
 * this function returns successfully.  Returns 0 upon success, or
 * -EINVAL if @pld is NULL or if @pld does not match the struct
 * prm_ll_data * previously registered by prm_register().
 */
int prm_unregister(struct prm_ll_data *pld)
{
	if (!pld || prm_ll_data != pld)
		return -EINVAL;

	prm_ll_data = &null_prm_ll_data;

	return 0;
}

#ifdef CONFIG_ARCH_OMAP2
static struct omap_prcm_init_data omap2_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap2xxx_prm_init,
};
#endif

#ifdef CONFIG_ARCH_OMAP3
static struct omap_prcm_init_data omap3_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap3xxx_prm_init,

	/*
	 * IVA2 offset is a negative value, must offset the prm_base
	 * address by this to get it to positive
	 */
	.offset = -OMAP3430_IVA2_MOD,
};
#endif

#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_TI81XX)
static struct omap_prcm_init_data am3_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = am33xx_prm_init,
};
#endif

#ifdef CONFIG_SOC_TI81XX
static struct omap_prcm_init_data dm814_pllss_data __initdata = {
	.index = TI_CLKM_PLLSS,
	.init = am33xx_prm_init,
};
#endif

#ifdef CONFIG_ARCH_OMAP4
static struct omap_prcm_init_data omap4_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap44xx_prm_init,
	.device_inst_offset = OMAP4430_PRM_DEVICE_INST,
	.flags = PRM_HAS_IO_WAKEUP | PRM_HAS_VOLTAGE,
};
#endif

#ifdef CONFIG_SOC_OMAP5
static struct omap_prcm_init_data omap5_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap44xx_prm_init,
	.device_inst_offset = OMAP54XX_PRM_DEVICE_INST,
	.flags = PRM_HAS_IO_WAKEUP | PRM_HAS_VOLTAGE,
};
#endif

#ifdef CONFIG_SOC_DRA7XX
static struct omap_prcm_init_data dra7_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap44xx_prm_init,
	.device_inst_offset = DRA7XX_PRM_DEVICE_INST,
	.flags = PRM_HAS_IO_WAKEUP,
};
#endif

#ifdef CONFIG_SOC_AM43XX
static struct omap_prcm_init_data am4_prm_data __initdata = {
	.index = TI_CLKM_PRM,
	.init = omap44xx_prm_init,
	.device_inst_offset = AM43XX_PRM_DEVICE_INST,
	.flags = PRM_HAS_IO_WAKEUP,
};
#endif

#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
static struct omap_prcm_init_data scrm_data __initdata = {
	.index = TI_CLKM_SCRM,
};
#endif

static const struct of_device_id omap_prcm_dt_match_table[] __initconst = {
#ifdef CONFIG_SOC_AM33XX
	{ .compatible = "ti,am3-prcm", .data = &am3_prm_data },
#endif
#ifdef CONFIG_SOC_AM43XX
	{ .compatible = "ti,am4-prcm", .data = &am4_prm_data },
#endif
#ifdef CONFIG_SOC_TI81XX
	{ .compatible = "ti,dm814-prcm", .data = &am3_prm_data },
	{ .compatible = "ti,dm814-pllss", .data = &dm814_pllss_data },
	{ .compatible = "ti,dm816-prcm", .data = &am3_prm_data },
#endif
#ifdef CONFIG_ARCH_OMAP2
	{ .compatible = "ti,omap2-prcm", .data = &omap2_prm_data },
#endif
#ifdef CONFIG_ARCH_OMAP3
	{ .compatible = "ti,omap3-prm", .data = &omap3_prm_data },
#endif
#ifdef CONFIG_ARCH_OMAP4
	{ .compatible = "ti,omap4-prm", .data = &omap4_prm_data },
	{ .compatible = "ti,omap4-scrm", .data = &scrm_data },
#endif
#ifdef CONFIG_SOC_OMAP5
	{ .compatible = "ti,omap5-prm", .data = &omap5_prm_data },
	{ .compatible = "ti,omap5-scrm", .data = &scrm_data },
#endif
#ifdef CONFIG_SOC_DRA7XX
	{ .compatible = "ti,dra7-prm", .data = &dra7_prm_data },
#endif
	{ }
};

/**
 * omap2_prm_base_init - initialize iomappings for the PRM driver
 *
 * Detects and initializes the iomappings for the PRM driver, based
 * on the DT data. Returns 0 in success, negative error value
 * otherwise.
 */
int __init omap2_prm_base_init(void)
{
	struct device_node *np;
	const struct of_device_id *match;
	struct omap_prcm_init_data *data;
	struct resource res;
	int ret;

	for_each_matching_node_and_match(np, omap_prcm_dt_match_table, &match) {
		data = (struct omap_prcm_init_data *)match->data;

		ret = of_address_to_resource(np, 0, &res);
		if (ret) {
			of_node_put(np);
			return ret;
		}

		data->mem = ioremap(res.start, resource_size(&res));

		if (data->index == TI_CLKM_PRM) {
			prm_base.va = data->mem + data->offset;
			prm_base.pa = res.start + data->offset;
		}

		data->np = np;

		if (data->init)
			data->init(data);
	}

	return 0;
}

int __init omap2_prcm_base_init(void)
{
	int ret;

	ret = omap2_prm_base_init();
	if (ret)
		return ret;

	return omap2_cm_base_init();
}

/**
 * omap_prcm_init - low level init for the PRCM drivers
 *
 * Initializes the low level clock infrastructure for PRCM drivers.
 * Returns 0 in success, negative error value in failure.
 */
int __init omap_prcm_init(void)
{
	struct device_node *np;
	const struct of_device_id *match;
	const struct omap_prcm_init_data *data;
	int ret;

	for_each_matching_node_and_match(np, omap_prcm_dt_match_table, &match) {
		data = match->data;

		ret = omap2_clk_provider_init(np, data->index, NULL, data->mem);
		if (ret) {
			of_node_put(np);
			return ret;
		}
	}

	omap_cm_init();

	return 0;
}

static int __init prm_late_init(void)
{
	if (prm_ll_data->late_init)
		return prm_ll_data->late_init();
	return 0;
}
subsys_initcall(prm_late_init);


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP4 PRM instance functions
 *
 * Copyright (C) 2009 Nokia Corporation
 * Copyright (C) 2011 Texas Instruments, Inc.
 * Paul Walmsley
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>

#include "iomap.h"
#include "common.h"
#include "prcm-common.h"
#include "prm44xx.h"
#include "prm54xx.h"
#include "prm7xx.h"
#include "prminst44xx.h"
#include "prm-regbits-44xx.h"
#include "prcm44xx.h"
#include "prcm43xx.h"
#include "prcm_mpu44xx.h"
#include "soc.h"

static struct omap_domain_base _prm_bases[OMAP4_MAX_PRCM_PARTITIONS];

static s32 prm_dev_inst = PRM_INSTANCE_UNKNOWN;

/**
 * omap_prm_base_init - Populates the prm partitions
 *
 * Populates the base addresses of the _prm_bases
 * array used for read/write of prm module registers.
 */
void omap_prm_base_init(void)
{
	memcpy(&_prm_bases[OMAP4430_PRM_PARTITION], &prm_base,
	       sizeof(prm_base));
	memcpy(&_prm_bases[OMAP4430_PRCM_MPU_PARTITION], &prcm_mpu_base,
	       sizeof(prcm_mpu_base));
}

s32 omap4_prmst_get_prm_dev_inst(void)
{
	return prm_dev_inst;
}

void omap4_prminst_set_prm_dev_inst(s32 dev_inst)
{
	prm_dev_inst = dev_inst;
}

/* Read a register in a PRM instance */
u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx)
{
	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
	       part == OMAP4430_INVALID_PRCM_PARTITION ||
	       !_prm_bases[part].va);
	return readl_relaxed(_prm_bases[part].va + inst + idx);
}

/* Write into a register in a PRM instance */
void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx)
{
	BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
	       part == OMAP4430_INVALID_PRCM_PARTITION ||
	       !_prm_bases[part].va);
	writel_relaxed(val, _prm_bases[part].va + inst + idx);
}

/* Read-modify-write a register in PRM. Caller must lock */
u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, s16 inst,
				    u16 idx)
{
	u32 v;

	v = omap4_prminst_read_inst_reg(part, inst, idx);
	v &= ~mask;
	v |= bits;
	omap4_prminst_write_inst_reg(v, part, inst, idx);

	return v;
}

/**
 * omap4_prminst_is_hardreset_asserted - read the HW reset line state of
 * submodules contained in the hwmod module
 * @rstctrl_reg: RM_RSTCTRL register address for this module
 * @shift: register bit shift corresponding to the reset line to check
 *
 * Returns 1 if the (sub)module hardreset line is currently asserted,
 * 0 if the (sub)module hardreset line is not currently asserted, or
 * -EINVAL upon parameter error.
 */
int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
					u16 rstctrl_offs)
{
	u32 v;

	v = omap4_prminst_read_inst_reg(part, inst, rstctrl_offs);
	v &= 1 << shift;
	v >>= shift;

	return v;
}

/**
 * omap4_prminst_assert_hardreset - assert the HW reset line of a submodule
 * @rstctrl_reg: RM_RSTCTRL register address for this module
 * @shift: register bit shift corresponding to the reset line to assert
 *
 * Some IPs like dsp, ipu or iva contain processors that require an HW
 * reset line to be asserted / deasserted in order to fully enable the
 * IP.  These modules may have multiple hard-reset lines that reset
 * different 'submodules' inside the IP block.  This function will
 * place the submodule into reset.  Returns 0 upon success or -EINVAL
 * upon an argument error.
 */
int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
				   u16 rstctrl_offs)
{
	u32 mask = 1 << shift;

	omap4_prminst_rmw_inst_reg_bits(mask, mask, part, inst, rstctrl_offs);

	return 0;
}

/**
 * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and
 * wait
 * @shift: register bit shift corresponding to the reset line to deassert
 * @st_shift: status bit offset corresponding to the reset line
 * @part: PRM partition
 * @inst: PRM instance offset
 * @rstctrl_offs: reset register offset
 * @rstst_offs: reset status register offset
 *
 * Some IPs like dsp, ipu or iva contain processors that require an HW
 * reset line to be asserted / deasserted in order to fully enable the
 * IP.  These modules may have multiple hard-reset lines that reset
 * different 'submodules' inside the IP block.  This function will
 * take the submodule out of reset and wait until the PRCM indicates
 * that the reset has completed before returning.  Returns 0 upon success or
 * -EINVAL upon an argument error, -EEXIST if the submodule was already out
 * of reset, or -EBUSY if the submodule did not exit reset promptly.
 */
int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst,
				     u16 rstctrl_offs, u16 rstst_offs)
{
	int c;
	u32 mask = 1 << shift;
	u32 st_mask = 1 << st_shift;

	/* Check the current status to avoid de-asserting the line twice */
	if (omap4_prminst_is_hardreset_asserted(shift, part, inst,
						rstctrl_offs) == 0)
		return -EEXIST;

	/* Clear the reset status by writing 1 to the status bit */
	omap4_prminst_rmw_inst_reg_bits(0xffffffff, st_mask, part, inst,
					rstst_offs);
	/* de-assert the reset control line */
	omap4_prminst_rmw_inst_reg_bits(mask, 0, part, inst, rstctrl_offs);
	/* wait the status to be set */
	omap_test_timeout(omap4_prminst_is_hardreset_asserted(st_shift, part,
							      inst, rstst_offs),
			  MAX_MODULE_HARDRESET_WAIT, c);

	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
}

void omap4_prminst_global_warm_sw_reset(void)
{
	u32 v;
	s32 inst = omap4_prmst_get_prm_dev_inst();

	if (inst == PRM_INSTANCE_UNKNOWN)
		return;

	v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, inst,
					OMAP4_PRM_RSTCTRL_OFFSET);
	v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
	omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
				 inst, OMAP4_PRM_RSTCTRL_OFFSET);

	/* OCP barrier */
	v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
				    inst, OMAP4_PRM_RSTCTRL_OFFSET);
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * OMAP4 Power/Reset Management (PRM) function prototypes
 *
 * Copyright (C) 2010 Nokia Corporation
 * Copyright (C) 2011 Texas Instruments, Inc.
 * Paul Walmsley
 */
#ifndef __ARCH_ASM_MACH_OMAP2_PRMINST44XX_H
#define __ARCH_ASM_MACH_OMAP2_PRMINST44XX_H

#define PRM_INSTANCE_UNKNOWN	-1
extern s32 omap4_prmst_get_prm_dev_inst(void);
void omap4_prminst_set_prm_dev_inst(s32 dev_inst);

/*
 * In an ideal world, we would not export these low-level functions,
 * but this will probably take some time to fix properly
 */
extern u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx);
extern void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx);
extern u32 omap4_prminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part,
					   s16 inst, u16 idx);

extern void omap4_prminst_global_warm_sw_reset(void);

extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
					       u16 rstctrl_offs);
extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
					  u16 rstctrl_offs);
int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
				     s16 inst, u16 rstctrl_offs,
				     u16 rstst_offs);

extern void omap_prm_base_init(void);

#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * OMAP44xx SCRM registers and bitfields
 *
 * Copyright (C) 2010 Texas Instruments, Inc.
 *
 * Benoit Cousson (b-cousson@ti.com)
 *
 * This file is automatically generated from the OMAP hardware databases.
 * We respectfully ask that any modifications to this file be coordinated
 * with the public linux-omap@vger.kernel.org mailing list and the
 * authors above to ensure that the autogeneration scripts are kept
 * up-to-date with the file contents.
 */

#ifndef __ARCH_ARM_MACH_OMAP2_SCRM_44XX_H
#define __ARCH_ARM_MACH_OMAP2_SCRM_44XX_H

#define OMAP4_SCRM_BASE				0x4a30a000

#define OMAP44XX_SCRM_REGADDR(reg)	\
		OMAP2_L4_IO_ADDRESS(OMAP4_SCRM_BASE + (reg))

/* Registers offset */
#define OMAP4_SCRM_CLKSETUPTIME			OMAP44XX_SCRM_REGADDR(0x0100)

/* CLKSETUPTIME */
#define OMAP4_DOWNTIME_SHIFT			16
#define OMAP4_DOWNTIME_MASK			(0x3f << 16)
#define OMAP4_SETUPTIME_SHIFT			0
#define OMAP4_SETUPTIME_MASK			(0xfff << 0)

#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * SMS/SDRC (SDRAM controller) common code for OMAP2/3
 *
 * Copyright (C) 2005, 2008 Texas Instruments Inc.
 * Copyright (C) 2005, 2008 Nokia Corporation
 *
 * Tony Lindgren <tony@atomide.com>
 * Paul Walmsley
 * Richard Woodruff <r-woodruff2@ti.com>
 */
#undef DEBUG

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>

#include "common.h"
#include "clock.h"
#include "sdrc.h"

static struct omap_sdrc_params *sdrc_init_params_cs0, *sdrc_init_params_cs1;

void __iomem *omap2_sdrc_base;
void __iomem *omap2_sms_base;

struct omap2_sms_regs {
	u32	sms_sysconfig;
};

static struct omap2_sms_regs sms_context;

/* SDRC_POWER register bits */
#define SDRC_POWER_EXTCLKDIS_SHIFT		3
#define SDRC_POWER_PWDENA_SHIFT			2
#define SDRC_POWER_PAGEPOLICY_SHIFT		0

/**
 * omap2_sms_save_context - Save SMS registers
 *
 * Save SMS registers that need to be restored after off mode.
 */
void omap2_sms_save_context(void)
{
	sms_context.sms_sysconfig = sms_read_reg(SMS_SYSCONFIG);
}

/**
 * omap2_sms_restore_context - Restore SMS registers
 *
 * Restore SMS registers that need to be Restored after off mode.
 */
void omap2_sms_restore_context(void)
{
	sms_write_reg(sms_context.sms_sysconfig, SMS_SYSCONFIG);
}

/**
 * omap2_sdrc_get_params - return SDRC register values for a given clock rate
 * @r: SDRC clock rate (in Hz)
 * @sdrc_cs0: chip select 0 ram timings **
 * @sdrc_cs1: chip select 1 ram timings **
 *
 * Return pre-calculated values for the SDRC_ACTIM_CTRLA,
 *  SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL and SDRC_MR registers in sdrc_cs[01]
 *  structs,for a given SDRC clock rate 'r'.
 * These parameters control various timing delays in the SDRAM controller
 *  that are expressed in terms of the number of SDRC clock cycles to
 *  wait; hence the clock rate dependency.
 *
 * Supports 2 different timing parameters for both chip selects.
 *
 * Note 1: the sdrc_init_params_cs[01] must be sorted rate descending.
 * Note 2: If sdrc_init_params_cs_1 is not NULL it must be of same size
 *  as sdrc_init_params_cs_0.
 *
 * Fills in the struct omap_sdrc_params * for each chip select.
 * Returns 0 upon success or -1 upon failure.
 */
int omap2_sdrc_get_params(unsigned long r,
			  struct omap_sdrc_params **sdrc_cs0,
			  struct omap_sdrc_params **sdrc_cs1)
{
	struct omap_sdrc_params *sp0, *sp1;

	if (!sdrc_init_params_cs0)
		return -1;

	sp0 = sdrc_init_params_cs0;
	sp1 = sdrc_init_params_cs1;

	while (sp0->rate && sp0->rate != r) {
		sp0++;
		if (sdrc_init_params_cs1)
			sp1++;
	}

	if (!sp0->rate)
		return -1;

	*sdrc_cs0 = sp0;
	*sdrc_cs1 = sp1;
	return 0;
}

void __init omap2_set_globals_sdrc(void __iomem *sdrc, void __iomem *sms)
{
	omap2_sdrc_base = sdrc;
	omap2_sms_base = sms;
}

/**
 * omap2_sdrc_init - initialize SMS, SDRC devices on boot
 * @sdrc_cs[01]: pointers to a null-terminated list of struct omap_sdrc_params
 *  Support for 2 chip selects timings
 *
 * Turn on smart idle modes for SDRAM scheduler and controller.
 * Program a known-good configuration for the SDRC to deal with buggy
 * bootloaders.
 */
void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
			    struct omap_sdrc_params *sdrc_cs1)
{
	u32 l;

	l = sms_read_reg(SMS_SYSCONFIG);
	l &= ~(0x3 << 3);
	l |= (0x2 << 3);
	sms_write_reg(l, SMS_SYSCONFIG);

	l = sdrc_read_reg(SDRC_SYSCONFIG);
	l &= ~(0x3 << 3);
	l |= (0x2 << 3);
	sdrc_write_reg(l, SDRC_SYSCONFIG);

	sdrc_init_params_cs0 = sdrc_cs0;
	sdrc_init_params_cs1 = sdrc_cs1;

	/* XXX Enable SRFRONIDLEREQ here also? */
	/*
	 * PWDENA should not be set due to 34xx erratum 1.150 - PWDENA
	 * can cause random memory corruption
	 */
	l = (1 << SDRC_POWER_EXTCLKDIS_SHIFT) |
		(1 << SDRC_POWER_PAGEPOLICY_SHIFT);
	sdrc_write_reg(l, SDRC_POWER);
	omap2_sms_save_context();
}


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

/*
 * OMAP2/3 SDRC/SMS macros and prototypes
 *
 * Copyright (C) 2007-2008, 2012 Texas Instruments, Inc.
 * Copyright (C) 2007-2008 Nokia Corporation
 *
 * Paul Walmsley
 * Tony Lindgren
 * Richard Woodruff
 */
#undef DEBUG

#ifndef __ASSEMBLER__

#include <linux/io.h>

extern void __iomem *omap2_sdrc_base;
extern void __iomem *omap2_sms_base;

#define OMAP_SDRC_REGADDR(reg)			(omap2_sdrc_base + (reg))
#define OMAP_SMS_REGADDR(reg)			(omap2_sms_base + (reg))

/* SDRC global register get/set */

static inline void sdrc_write_reg(u32 val, u16 reg)
{
	writel_relaxed(val, OMAP_SDRC_REGADDR(reg));
}

static inline u32 sdrc_read_reg(u16 reg)
{
	return readl_relaxed(OMAP_SDRC_REGADDR(reg));
}

/* SMS global register get/set */

static inline void sms_write_reg(u32 val, u16 reg)
{
	writel_relaxed(val, OMAP_SMS_REGADDR(reg));
}

static inline u32 sms_read_reg(u16 reg)
{
	return readl_relaxed(OMAP_SMS_REGADDR(reg));
}

extern void omap2_set_globals_sdrc(void __iomem *sdrc, void __iomem *sms);

/**
 * struct omap_sdrc_params - SDRC parameters for a given SDRC clock rate
 * @rate: SDRC clock rate (in Hz)
 * @actim_ctrla: Value to program to SDRC_ACTIM_CTRLA for this rate
 * @actim_ctrlb: Value to program to SDRC_ACTIM_CTRLB for this rate
 * @rfr_ctrl: Value to program to SDRC_RFR_CTRL for this rate
 * @mr: Value to program to SDRC_MR for this rate
 *
 * This structure holds a pre-computed set of register values for the
 * SDRC for a given SDRC clock rate and SDRAM chip.  These are
 * intended to be pre-computed and specified in an array in the board-*.c
 * files.  The structure is keyed off the 'rate' field.
 */
struct omap_sdrc_params {
	unsigned long rate;
	u32 actim_ctrla;
	u32 actim_ctrlb;
	u32 rfr_ctrl;
	u32 mr;
};

#ifdef CONFIG_SOC_HAS_OMAP2_SDRC
void omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
			    struct omap_sdrc_params *sdrc_cs1);
#else
static inline void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
					  struct omap_sdrc_params *sdrc_cs1) {};
#endif

int omap2_sdrc_get_params(unsigned long r,
			  struct omap_sdrc_params **sdrc_cs0,
			  struct omap_sdrc_params **sdrc_cs1);
void omap2_sms_save_context(void);
void omap2_sms_restore_context(void);

struct memory_timings {
	u32 m_type;		/* ddr = 1, sdr = 0 */
	u32 dll_mode;		/* use lock mode = 1, unlock mode = 0 */
	u32 slow_dll_ctrl;	/* unlock mode, dll value for slow speed */
	u32 fast_dll_ctrl;	/* unlock mode, dll value for fast speed */
	u32 base_cs;		/* base chip select to use for calculations */
};

extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
struct omap_sdrc_params *rx51_get_sdram_timings(void);

u32 omap2xxx_sdrc_dll_is_unlocked(void);
u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);

#else
#define OMAP242X_SDRC_REGADDR(reg)					\
			OMAP2_L3_IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
#define OMAP243X_SDRC_REGADDR(reg)					\
			OMAP2_L3_IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
#define OMAP34XX_SDRC_REGADDR(reg)					\
			OMAP2_L3_IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))

#endif	/* __ASSEMBLER__ */

/* Minimum frequency that the SDRC DLL can lock at */
#define MIN_SDRC_DLL_LOCK_FREQ		83000000

/* Scale factor for fixed-point arith in omap3_core_dpll_m2_set_rate() */
#define SDRC_MPURATE_SCALE		8

/* 2^SDRC_MPURATE_BASE_SHIFT: MPU MHz that SDRC_MPURATE_LOOPS is defined for */
#define SDRC_MPURATE_BASE_SHIFT		9

/*
 * SDRC_MPURATE_LOOPS: Number of MPU loops to execute at
 * 2^MPURATE_BASE_SHIFT MHz for SDRC to stabilize
 */
#define SDRC_MPURATE_LOOPS		96

/* SDRC register offsets - read/write with sdrc_{read,write}_reg() */

#define SDRC_SYSCONFIG		0x010
#define SDRC_CS_CFG		0x040
#define SDRC_SHARING		0x044
#define SDRC_ERR_TYPE		0x04C
#define SDRC_DLLA_CTRL		0x060
#define SDRC_DLLA_STATUS	0x064
#define SDRC_DLLB_CTRL		0x068
#define SDRC_DLLB_STATUS	0x06C
#define SDRC_POWER		0x070
#define SDRC_MCFG_0		0x080
#define SDRC_MR_0		0x084
#define SDRC_EMR2_0		0x08c
#define SDRC_ACTIM_CTRL_A_0	0x09c
#define SDRC_ACTIM_CTRL_B_0	0x0a0
#define SDRC_RFR_CTRL_0		0x0a4
#define SDRC_MANUAL_0		0x0a8
#define SDRC_MCFG_1		0x0B0
#define SDRC_MR_1		0x0B4
#define SDRC_EMR2_1		0x0BC
#define SDRC_ACTIM_CTRL_A_1	0x0C4
#define SDRC_ACTIM_CTRL_B_1	0x0C8
#define SDRC_RFR_CTRL_1		0x0D4
#define SDRC_MANUAL_1		0x0D8

#define SDRC_POWER_AUTOCOUNT_SHIFT	8
#define SDRC_POWER_AUTOCOUNT_MASK	(0xffff << SDRC_POWER_AUTOCOUNT_SHIFT)
#define SDRC_POWER_CLKCTRL_SHIFT	4
#define SDRC_POWER_CLKCTRL_MASK		(0x3 << SDRC_POWER_CLKCTRL_SHIFT)
#define SDRC_SELF_REFRESH_ON_AUTOCOUNT	(0x2 << SDRC_POWER_CLKCTRL_SHIFT)

/*
 * These values represent the number of memory clock cycles between
 * autorefresh initiation.  They assume 1 refresh per 64 ms (JEDEC), 8192
 * rows per device, and include a subtraction of a 50 cycle window in the
 * event that the autorefresh command is delayed due to other SDRC activity.
 * The '| 1' sets the ARE field to send one autorefresh when the autorefresh
 * counter reaches 0.
 *
 * These represent optimal values for common parts, it won't work for all.
 * As long as you scale down, most parameters are still work, they just
 * become sub-optimal. The RFR value goes in the opposite direction. If you
 * don't adjust it down as your clock period increases the refresh interval
 * will not be met. Setting all parameters for complete worst case may work,
 * but may cut memory performance by 2x. Due to errata the DLLs need to be
 * unlocked and their value needs run time calibration. A dynamic call is
 * need for that as no single right value exists across production samples.
 *
 * Only the FULL speed values are given. Current code is such that rate
 * changes must be made at DPLLoutx2. The actual value adjustment for low
 * frequency operation will be handled by omap_set_performance()
 *
 * By having the boot loader boot up in the fastest L4 speed available likely
 * will result in something which you can switch between.
 */
#define SDRC_RFR_CTRL_165MHz	(0x00044c00 | 1)
#define SDRC_RFR_CTRL_133MHz	(0x0003de00 | 1)
#define SDRC_RFR_CTRL_100MHz	(0x0002da01 | 1)
#define SDRC_RFR_CTRL_110MHz	(0x0002da01 | 1) /* Need to calc */
#define SDRC_RFR_CTRL_BYPASS	(0x00005000 | 1) /* Need to calc */

/*
 * SMS register access
 */

#define OMAP242X_SMS_REGADDR(reg)					\
		(void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP2420_SMS_BASE + reg)
#define OMAP243X_SMS_REGADDR(reg)					\
		(void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP243X_SMS_BASE + reg)
#define OMAP343X_SMS_REGADDR(reg)					\
		(void __iomem *)OMAP2_L3_IO_ADDRESS(OMAP343X_SMS_BASE + reg)

/* SMS register offsets - read/write with sms_{read,write}_reg() */

#define SMS_SYSCONFIG			0x010
/* REVISIT: fill in other SMS registers here */

#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/mach-omap2/sdrc2xxx.c
 *
 * SDRAM timing related functions for OMAP2xxx
 *
 * Copyright (C) 2005, 2008 Texas Instruments Inc.
 * Copyright (C) 2005, 2008 Nokia Corporation
 *
 * Tony Lindgren <tony@atomide.com>
 * Paul Walmsley
 * Richard Woodruff <r-woodruff2@ti.com>
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>

#include "soc.h"
#include "iomap.h"
#include "common.h"
#include "prm2xxx.h"
#include "clock.h"
#include "sdrc.h"
#include "sram.h"

/* Memory timing, DLL mode flags */
#define M_DDR		1
#define M_LOCK_CTRL	(1 << 2)
#define M_UNLOCK	0
#define M_LOCK		1

static struct memory_timings mem_timings;
static u32 curr_perf_level = CORE_CLK_SRC_DPLL_X2;

static u32 omap2xxx_sdrc_get_slow_dll_ctrl(void)
{
	return mem_timings.slow_dll_ctrl;
}

static u32 omap2xxx_sdrc_get_fast_dll_ctrl(void)
{
	return mem_timings.fast_dll_ctrl;
}

static u32 omap2xxx_sdrc_get_type(void)
{
	return mem_timings.m_type;
}

/*
 * Check the DLL lock state, and return tue if running in unlock mode.
 * This is needed to compensate for the shifted DLL value in unlock mode.
 */
u32 omap2xxx_sdrc_dll_is_unlocked(void)
{
	/* dlla and dllb are a set */
	u32 dll_state = sdrc_read_reg(SDRC_DLLA_CTRL);

	if ((dll_state & (1 << 2)) == (1 << 2))
		return 1;
	else
		return 0;
}

/*
 * 'level' is the value to store to CM_CLKSEL2_PLL.CORE_CLK_SRC.
 * Practical values are CORE_CLK_SRC_DPLL (for CORE_CLK = DPLL_CLK) or
 * CORE_CLK_SRC_DPLL_X2 (for CORE_CLK = * DPLL_CLK * 2)
 *
 * Used by the clock framework during CORE DPLL changes
 */
u32 omap2xxx_sdrc_reprogram(u32 level, u32 force)
{
	u32 dll_ctrl, m_type;
	u32 prev = curr_perf_level;
	unsigned long flags;

	if ((curr_perf_level == level) && !force)
		return prev;

	if (level == CORE_CLK_SRC_DPLL)
		dll_ctrl = omap2xxx_sdrc_get_slow_dll_ctrl();
	else if (level == CORE_CLK_SRC_DPLL_X2)
		dll_ctrl = omap2xxx_sdrc_get_fast_dll_ctrl();
	else
		return prev;

	m_type = omap2xxx_sdrc_get_type();

	local_irq_save(flags);
	/*
	 * XXX These calls should be abstracted out through a
	 * prm2xxx.c function
	 */
	if (cpu_is_omap2420())
		writel_relaxed(0xffff, OMAP2420_PRCM_VOLTSETUP);
	else
		writel_relaxed(0xffff, OMAP2430_PRCM_VOLTSETUP);
	omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
	curr_perf_level = level;
	local_irq_restore(flags);

	return prev;
}

/* Used by the clock framework during CORE DPLL changes */
void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode)
{
	unsigned long dll_cnt;
	u32 fast_dll = 0;

	/* DDR = 1, SDR = 0 */
	mem_timings.m_type = !((sdrc_read_reg(SDRC_MR_0) & 0x3) == 0x1);

	/* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
	 * In the case of 2422, its ok to use CS1 instead of CS0.
	 */
	if (cpu_is_omap2422())
		mem_timings.base_cs = 1;
	else
		mem_timings.base_cs = 0;

	if (mem_timings.m_type != M_DDR)
		return;

	/* With DDR we need to determine the low frequency DLL value */
	if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL))
		mem_timings.dll_mode = M_UNLOCK;
	else
		mem_timings.dll_mode = M_LOCK;

	if (mem_timings.base_cs == 0) {
		fast_dll = sdrc_read_reg(SDRC_DLLA_CTRL);
		dll_cnt = sdrc_read_reg(SDRC_DLLA_STATUS) & 0xff00;
	} else {
		fast_dll = sdrc_read_reg(SDRC_DLLB_CTRL);
		dll_cnt = sdrc_read_reg(SDRC_DLLB_STATUS) & 0xff00;
	}
	if (force_lock_to_unlock_mode) {
		fast_dll &= ~0xff00;
		fast_dll |= dll_cnt;		/* Current lock mode */
	}
	/* set fast timings with DLL filter disabled */
	mem_timings.fast_dll_ctrl = (fast_dll | (3 << 8));

	/* No disruptions, DDR will be offline & C-ABI not followed */
	omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl,
			    mem_timings.fast_dll_ctrl,
			    mem_timings.base_cs,
			    force_lock_to_unlock_mode);
	mem_timings.slow_dll_ctrl &= 0xff00;	/* Keep lock value */

	/* Turn status into unlock ctrl */
	mem_timings.slow_dll_ctrl |=
		((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2));

	/* 90 degree phase for anything below 133MHz + disable DLL filter */
	mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8));
}


code:
/*
 * Copyright (C) 2009 Texas Instruments
 * Added OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */

/* OMAP2 serial ports */
#define OMAP2_UART1_BASE	0x4806a000
#define OMAP2_UART2_BASE	0x4806c000
#define OMAP2_UART3_BASE	0x4806e000

/* OMAP3 serial ports */
#define OMAP3_UART1_BASE	OMAP2_UART1_BASE
#define OMAP3_UART2_BASE	OMAP2_UART2_BASE
#define OMAP3_UART3_BASE	0x49020000
#define OMAP3_UART4_BASE	0x49042000	/* Only on 36xx */
#define OMAP3_UART4_AM35XX_BASE	0x4809E000	/* Only on AM35xx */

/* OMAP4 serial ports */
#define OMAP4_UART1_BASE	OMAP2_UART1_BASE
#define OMAP4_UART2_BASE	OMAP2_UART2_BASE
#define OMAP4_UART3_BASE	0x48020000
#define OMAP4_UART4_BASE	0x4806e000

/* TI81XX serial ports */
#define TI81XX_UART1_BASE	0x48020000
#define TI81XX_UART2_BASE	0x48022000
#define TI81XX_UART3_BASE	0x48024000

/* AM3505/3517 UART4 */
#define AM35XX_UART4_BASE	0x4809E000	/* Only on AM3505/3517 */

/* AM33XX serial port */
#define AM33XX_UART1_BASE	0x44E09000

/* OMAP5 serial ports */
#define OMAP5_UART1_BASE	OMAP2_UART1_BASE
#define OMAP5_UART2_BASE	OMAP2_UART2_BASE
#define OMAP5_UART3_BASE	OMAP4_UART3_BASE
#define OMAP5_UART4_BASE	OMAP4_UART4_BASE
#define OMAP5_UART5_BASE	0x48066000
#define OMAP5_UART6_BASE	0x48068000

/* External port on Zoom2/3 */
#define ZOOM_UART_BASE		0x10000000
#define ZOOM_UART_VIRT		0xfa400000

#define OMAP_PORT_SHIFT		2
#define ZOOM_PORT_SHIFT		1

#define OMAP24XX_BASE_BAUD	(48000000/16)

#ifndef __ASSEMBLER__

struct omap_board_data;
struct omap_uart_port_info;

extern void omap_serial_init(void);
extern void omap_serial_board_init(struct omap_uart_port_info *platform_data);
extern void omap_serial_init_port(struct omap_board_data *bdata,
		struct omap_uart_port_info *platform_data);
#endif


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * linux/arch/arm/mach-omap2/sleep.S
 *
 * (C) Copyright 2004
 * Texas Instruments, <www.ti.com>
 * Richard Woodruff <r-woodruff2@ti.com>
 *
 * (C) Copyright 2006 Nokia Corporation
 * Fixed idle loop sleep
 * Igor Stoppa <igor.stoppa@nokia.com>
 */

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

#include "omap24xx.h"
#include "sdrc.h"

/* First address of reserved address space?  apparently valid for OMAP2 & 3 */
#define A_SDRC0_V		(0xC0000000)

	.text

/*
 * omap24xx_cpu_suspend() - Forces OMAP into deep sleep state by completing
 * SDRC shutdown then ARM shutdown.  Upon wake MPU is back on so just restore
 * SDRC.
 *
 * Input:
 * R0 :	DLL ctrl value pre-Sleep
 * R1 : SDRC_DLLA_CTRL
 * R2 : SDRC_POWER
 *
 * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
 * when we get called, but the DLL probably isn't.  We will wait a bit more in
 * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
 * if in unlocked mode.
 *
 * For less than 242x-ES2.2 upon wake from a sleep mode where the external
 * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
 * clock can pass into the PRCM can cause problems at DSP and IVA.
 * To work around this the code will switch to the 32kHz source prior to sleep.
 * Post sleep we will shift back to using the DPLL.  Apparently,
 * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
 * 3x12MHz + 3x32kHz clocks for a full switch.
 *
 * The DLL load value is not kept in RETENTION or OFF.	It needs to be restored
 * at wake
 */
	.align	3
ENTRY(omap24xx_cpu_suspend)
	stmfd	sp!, {r0 - r12, lr}	@ save registers on stack
	mov	r3, #0x0		@ clear for mcr call
	mcr	p15, 0, r3, c7, c10, 4	@ memory barrier, hope SDR/DDR finished
	nop
	nop
	ldr	r4, [r2]		@ read SDRC_POWER
	orr	r4, r4, #0x40		@ enable self refresh on idle req
	mov	r5, #0x2000		@ set delay (DPLL relock + DLL relock)
	str	r4, [r2]		@ make it so
	nop
	mcr	p15, 0, r3, c7, c0, 4	@ wait for interrupt
	nop
loop:
	subs	r5, r5, #0x1		@ awake, wait just a bit
	bne	loop

	/* The DPLL has to be on before we take the DDR out of self refresh */
	bic	r4, r4, #0x40		@ now clear self refresh bit.
	str	r4, [r2]		@ write to SDRC_POWER
	ldr	r4, A_SDRC0		@ make a clock happen
	ldr	r4, [r4]		@ read A_SDRC0
	nop				@ start auto refresh only after clk ok
	movs	r0, r0			@ see if DDR or SDR
	strne	r0, [r1]		@ rewrite DLLA to force DLL reload
	addne	r1, r1, #0x8		@ move to DLLB
	strne	r0, [r1]		@ rewrite DLLB to force DLL reload

	mov	r5, #0x1000
loop2:
	subs	r5, r5, #0x1
	bne	loop2
	/* resume*/
	ldmfd	sp!, {r0 - r12, pc}	@ restore regs and return

A_SDRC0:
	.word A_SDRC0_V

ENTRY(omap24xx_cpu_suspend_sz)
	.word	. - omap24xx_cpu_suspend


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Low level suspend code for AM33XX SoCs
 *
 * Copyright (C) 2012-2018 Texas Instruments Incorporated - https://www.ti.com/
 *	Dave Gerlach, Vaibhav Bedia
 */

#include <linux/linkage.h>
#include <linux/platform_data/pm33xx.h>
#include <linux/ti-emif-sram.h>
#include <asm/assembler.h>
#include <asm/memory.h>

#include "iomap.h"
#include "cm33xx.h"
#include "pm-asm-offsets.h"

#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED			0x00030000
#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE			0x0003
#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE			0x0002

/* replicated define because linux/bitops.h cannot be included in assembly */
#define BIT(nr)			(1 << (nr))

	.arm
	.arch armv7-a
	.align 3

ENTRY(am33xx_do_wfi)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack

	/* Save wfi_flags arg to data space */
	mov	r4, r0
	adr	r3, am33xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	str	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

	/* Only flush cache is we know we are losing MPU context */
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_flush

	/*
	 * Flush all data from the L1 and L2 data cache before disabling
	 * SCTLR.C bit.
	 */
	ldr	r1, kernel_flush
	blx	r1

	/*
	 * Clear the SCTLR.C bit to prevent further data cache
	 * allocation. Clearing SCTLR.C would make all the data accesses
	 * strongly ordered and would not hit the cache.
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #(1 << 2)	@ Disable the C bit
	mcr	p15, 0, r0, c1, c0, 0
	isb

	/*
	 * Invalidate L1 and L2 data cache.
	 */
	ldr	r1, kernel_flush
	blx	r1

	adr	r3, am33xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	ldr	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

cache_skip_flush:
	/* Check if we want self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_enter_sr

	adr	r9, am33xx_emif_sram_table

	ldr	r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
	blx	r3

emif_skip_enter_sr:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SAVE_EMIF
	beq	emif_skip_save

	ldr	r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
	blx	r3

emif_skip_save:
	/* Only can disable EMIF if we have entered self refresh */
	tst     r4, #WFI_FLAG_SELF_REFRESH
	beq     emif_skip_disable

	/* Disable EMIF */
	ldr     r1, virt_emif_clkctrl
	ldr     r2, [r1]
	bic     r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
	str     r2, [r1]

	ldr	r1, virt_emif_clkctrl
wait_emif_disable:
	ldr	r2, [r1]
	mov	r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED
	cmp	r2, r3
	bne	wait_emif_disable

emif_skip_disable:
	tst	r4, #WFI_FLAG_WAKE_M3
	beq	wkup_m3_skip

	/*
	 * For the MPU WFI to be registered as an interrupt
	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
	 * to DISABLED
	 */
	ldr	r1, virt_mpu_clkctrl
	ldr	r2, [r1]
	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
	str	r2, [r1]

wkup_m3_skip:
	/*
	 * Execute an ISB instruction to ensure that all of the
	 * CP15 register changes have been committed.
	 */
	isb

	/*
	 * Execute a barrier instruction to ensure that all cache,
	 * TLB and branch predictor maintenance operations issued
	 * have completed.
	 */
	dsb
	dmb

	/*
	 * Execute a WFI instruction and wait until the
	 * STANDBYWFI output is asserted to indicate that the
	 * CPU is in idle and low power state. CPU can specualatively
	 * prefetch the instructions so add NOPs after WFI. Thirteen
	 * NOPs as per Cortex-A8 pipeline.
	 */
	wfi

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	/* We come here in case of an abort due to a late interrupt */

	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
	ldr	r1, virt_mpu_clkctrl
	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r2, [r1]

	/* Re-enable EMIF */
	ldr	r1, virt_emif_clkctrl
	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r2, [r1]
wait_emif_enable:
	ldr	r3, [r1]
	cmp	r2, r3
	bne	wait_emif_enable

	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_exit_sr_abt

	adr	r9, am33xx_emif_sram_table
	ldr	r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
	blx	r1

emif_skip_exit_sr_abt:
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_restore

	/*
	 * Set SCTLR.C bit to allow data cache allocation
	 */
	mrc	p15, 0, r0, c1, c0, 0
	orr	r0, r0, #(1 << 2)	@ Enable the C bit
	mcr	p15, 0, r0, c1, c0, 0
	isb

cache_skip_restore:
	/* Let the suspend code know about the abort */
	mov	r0, #1
	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
ENDPROC(am33xx_do_wfi)

	.align
ENTRY(am33xx_resume_offset)
	.word . - am33xx_do_wfi

ENTRY(am33xx_resume_from_deep_sleep)
	/* Re-enable EMIF */
	ldr	r0, phys_emif_clkctrl
	mov	r1, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r1, [r0]
wait_emif_enable1:
	ldr	r2, [r0]
	cmp	r1, r2
	bne	wait_emif_enable1

	adr	r9, am33xx_emif_sram_table

	ldr	r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET]
	blx	r1

	ldr	r1, [r9, #EMIF_PM_EXIT_SR_OFFSET]
	blx	r1

resume_to_ddr:
	/* We are back. Branch to the common CPU resume routine */
	mov	r0, #0
	ldr	pc, resume_addr
ENDPROC(am33xx_resume_from_deep_sleep)

/*
 * Local variables
 */
	.align
kernel_flush:
	.word   v7_flush_dcache_all
virt_mpu_clkctrl:
	.word	AM33XX_CM_MPU_MPU_CLKCTRL
virt_emif_clkctrl:
	.word	AM33XX_CM_PER_EMIF_CLKCTRL
phys_emif_clkctrl:
	.word	(AM33XX_CM_BASE + AM33XX_CM_PER_MOD + \
		AM33XX_CM_PER_EMIF_CLKCTRL_OFFSET)

.align 3
/* DDR related defines */
am33xx_emif_sram_table:
	.space EMIF_PM_FUNCTIONS_SIZE

ENTRY(am33xx_pm_sram)
	.word am33xx_do_wfi
	.word am33xx_do_wfi_sz
	.word am33xx_resume_offset
	.word am33xx_emif_sram_table
	.word am33xx_pm_ro_sram_data

resume_addr:
.word  cpu_resume - PAGE_OFFSET + 0x80000000

.align 3
ENTRY(am33xx_pm_ro_sram_data)
	.space AMX3_PM_RO_SRAM_DATA_SIZE

ENTRY(am33xx_do_wfi_sz)
	.word	. - am33xx_do_wfi


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * (C) Copyright 2007
 * Texas Instruments
 * Karthik Dasu <karthik-dp@ti.com>
 *
 * (C) Copyright 2004
 * Texas Instruments, <www.ti.com>
 * Richard Woodruff <r-woodruff2@ti.com>
 */
#include <linux/linkage.h>

#include <asm/assembler.h>

#include "omap34xx.h"
#include "iomap.h"
#include "cm3xxx.h"
#include "prm3xxx.h"
#include "sdrc.h"
#include "sram.h"
#include "control.h"

/*
 * Registers access definitions
 */
#define SDRC_SCRATCHPAD_SEM_OFFS	0xc
#define SDRC_SCRATCHPAD_SEM_V	OMAP343X_SCRATCHPAD_REGADDR\
					(SDRC_SCRATCHPAD_SEM_OFFS)
#define PM_PREPWSTST_CORE_P	OMAP3430_PRM_BASE + CORE_MOD +\
					OMAP3430_PM_PREPWSTST
#define PM_PWSTCTRL_MPU_P	OMAP3430_PRM_BASE + MPU_MOD + OMAP2_PM_PWSTCTRL
#define CM_IDLEST1_CORE_V	OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1)
#define CM_IDLEST_CKGEN_V	OMAP34XX_CM_REGADDR(PLL_MOD, CM_IDLEST)
#define SRAM_BASE_P		OMAP3_SRAM_PA
#define CONTROL_STAT		OMAP343X_CTRL_BASE + OMAP343X_CONTROL_STATUS
#define CONTROL_MEM_RTA_CTRL	(OMAP343X_CTRL_BASE +\
					OMAP36XX_CONTROL_MEM_RTA_CTRL)

/* Move this as correct place is available */
#define SCRATCHPAD_MEM_OFFS	0x310
#define SCRATCHPAD_BASE_P	(OMAP343X_CTRL_BASE +\
					OMAP343X_CONTROL_MEM_WKUP +\
					SCRATCHPAD_MEM_OFFS)
#define SDRC_POWER_V		OMAP34XX_SDRC_REGADDR(SDRC_POWER)
#define SDRC_SYSCONFIG_P	(OMAP343X_SDRC_BASE + SDRC_SYSCONFIG)
#define SDRC_MR_0_P		(OMAP343X_SDRC_BASE + SDRC_MR_0)
#define SDRC_EMR2_0_P		(OMAP343X_SDRC_BASE + SDRC_EMR2_0)
#define SDRC_MANUAL_0_P		(OMAP343X_SDRC_BASE + SDRC_MANUAL_0)
#define SDRC_MR_1_P		(OMAP343X_SDRC_BASE + SDRC_MR_1)
#define SDRC_EMR2_1_P		(OMAP343X_SDRC_BASE + SDRC_EMR2_1)
#define SDRC_MANUAL_1_P		(OMAP343X_SDRC_BASE + SDRC_MANUAL_1)
#define SDRC_DLLA_STATUS_V	OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
#define SDRC_DLLA_CTRL_V	OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)

/*
 * This file needs be built unconditionally as ARM to interoperate correctly
 * with non-Thumb-2-capable firmware.
 */
	.arm

/*
 * API functions
 */

	.text
/*
 * L2 cache needs to be toggled for stable OFF mode functionality on 3630.
 * This function sets up a flag that will allow for this toggling to take
 * place on 3630. Hopefully some version in the future may not need this.
 */
ENTRY(enable_omap3630_toggle_l2_on_restore)
	stmfd	sp!, {lr}	@ save registers on stack
	/* Setup so that we will disable and enable l2 */
	mov	r1, #0x1
	adr	r3, l2dis_3630_offset
	ldr	r2, [r3]		@ value for offset
	str	r1, [r2, r3]		@ write to l2dis_3630
	ldmfd	sp!, {pc}	@ restore regs and return
ENDPROC(enable_omap3630_toggle_l2_on_restore)

/*
 * Function to call rom code to save secure ram context.
 *
 * r0 = physical address of the parameters
 */
	.arch armv7-a
	.arch_extension sec
ENTRY(save_secure_ram_context)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack
	mov	r3, r0			@ physical address of parameters
	mov	r0, #25			@ set service ID for PPA
	mov	r12, r0			@ copy secure service ID in r12
	mov	r1, #0			@ set task id for ROM code in r1
	mov	r2, #4			@ set some flags in r2, r6
	mov	r6, #0xff
	dsb				@ data write barrier
	dmb				@ data memory barrier
	smc	#1			@ call SMI monitor (smi #1)
	nop
	nop
	nop
	nop
	ldmfd	sp!, {r4 - r11, pc}
ENDPROC(save_secure_ram_context)

/*
 * ======================
 * == Idle entry point ==
 * ======================
 */

/*
 * Forces OMAP into idle state
 *
 * omap34xx_cpu_suspend() - This bit of code saves the CPU context if needed
 * and executes the WFI instruction. Calling WFI effectively changes the
 * power domains states to the desired target power states.
 *
 *
 * Notes:
 * - only the minimum set of functions gets copied to internal SRAM at boot
 *   and after wake-up from OFF mode, cf. omap_push_sram_idle. The function
 *   pointers in SDRAM or SRAM are called depending on the desired low power
 *   target state.
 * - when the OMAP wakes up it continues at different execution points
 *   depending on the low power mode (non-OFF vs OFF modes),
 *   cf. 'Resume path for xxx mode' comments.
 */
	.align	3
ENTRY(omap34xx_cpu_suspend)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack

	/*
	 * r0 contains information about saving context:
	 *   0 - No context lost
	 *   1 - Only L1 and logic lost
	 *   2 - Only L2 lost (Even L1 is retained we clean it along with L2)
	 *   3 - Both L1 and L2 lost and logic lost
	 */

	/*
	 * For OFF mode: save context and jump to WFI in SDRAM (omap3_do_wfi)
	 * For non-OFF modes: jump to the WFI code in SRAM (omap3_do_wfi_sram)
	 */
	ldr	r4, omap3_do_wfi_sram_addr
	ldr	r5, [r4]
	cmp	r0, #0x0		@ If no context save required,
	bxeq	r5			@  jump to the WFI code in SRAM

	/* Otherwise fall through to the save context code */
save_context_wfi:
	/*
	 * jump out to kernel flush routine
	 *  - reuse that code is better
	 *  - it executes in a cached space so is faster than refetch per-block
	 *  - should be faster and will change with kernel
	 *  - 'might' have to copy address, load and jump to it
	 * Flush all data from the L1 data cache before disabling
	 * SCTLR.C bit.
	 */
	ldr	r1, kernel_flush
	mov	lr, pc
	bx	r1

	/*
	 * Clear the SCTLR.C bit to prevent further data cache
	 * allocation. Clearing SCTLR.C would make all the data accesses
	 * strongly ordered and would not hit the cache.
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #(1 << 2)	@ Disable the C bit
	mcr	p15, 0, r0, c1, c0, 0
	isb

	/*
	 * Invalidate L1 data cache. Even though only invalidate is
	 * necessary exported flush API is used here. Doing clean
	 * on already clean cache would be almost NOP.
	 */
	ldr	r1, kernel_flush
	blx	r1
	b	omap3_do_wfi
ENDPROC(omap34xx_cpu_suspend)
omap3_do_wfi_sram_addr:
	.word omap3_do_wfi_sram
kernel_flush:
	.word v7_flush_dcache_all

/* ===================================
 * == WFI instruction => Enter idle ==
 * ===================================
 */

/*
 * Do WFI instruction
 * Includes the resume path for non-OFF modes
 *
 * This code gets copied to internal SRAM and is accessible
 * from both SDRAM and SRAM:
 * - executed from SRAM for non-off modes (omap3_do_wfi_sram),
 * - executed from SDRAM for OFF mode (omap3_do_wfi).
 */
	.align	3
ENTRY(omap3_do_wfi)
	ldr	r4, sdrc_power		@ read the SDRC_POWER register
	ldr	r5, [r4]		@ read the contents of SDRC_POWER
	orr	r5, r5, #0x40		@ enable self refresh on idle req
	str	r5, [r4]		@ write back to SDRC_POWER register

	/* Data memory barrier and Data sync barrier */
	dsb
	dmb

/*
 * ===================================
 * == WFI instruction => Enter idle ==
 * ===================================
 */
	wfi				@ wait for interrupt

/*
 * ===================================
 * == Resume path for non-OFF modes ==
 * ===================================
 */
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

/*
 * This function implements the erratum ID i581 WA:
 *  SDRC state restore before accessing the SDRAM
 *
 * Only used at return from non-OFF mode. For OFF
 * mode the ROM code configures the SDRC and
 * the DPLL before calling the restore code directly
 * from DDR.
 */

/* Make sure SDRC accesses are ok */
wait_sdrc_ok:

/* DPLL3 must be locked before accessing the SDRC. Maybe the HW ensures this */
	ldr	r4, cm_idlest_ckgen
wait_dpll3_lock:
	ldr	r5, [r4]
	tst	r5, #1
	beq	wait_dpll3_lock

	ldr	r4, cm_idlest1_core
wait_sdrc_ready:
	ldr	r5, [r4]
	tst	r5, #0x2
	bne	wait_sdrc_ready
	/* allow DLL powerdown upon hw idle req */
	ldr	r4, sdrc_power
	ldr	r5, [r4]
	bic	r5, r5, #0x40
	str	r5, [r4]

is_dll_in_lock_mode:
	/* Is dll in lock mode? */
	ldr	r4, sdrc_dlla_ctrl
	ldr	r5, [r4]
	tst	r5, #0x4
	bne	exit_nonoff_modes	@ Return if locked
	/* wait till dll locks */
wait_dll_lock_timed:
	ldr	r4, sdrc_dlla_status
	/* Wait 20uS for lock */
	mov	r6, #8
wait_dll_lock:
	subs	r6, r6, #0x1
	beq	kick_dll
	ldr	r5, [r4]
	and	r5, r5, #0x4
	cmp	r5, #0x4
	bne	wait_dll_lock
	b	exit_nonoff_modes	@ Return when locked

	/* disable/reenable DLL if not locked */
kick_dll:
	ldr	r4, sdrc_dlla_ctrl
	ldr	r5, [r4]
	mov	r6, r5
	bic	r6, #(1<<3)		@ disable dll
	str	r6, [r4]
	dsb
	orr	r6, r6, #(1<<3)		@ enable dll
	str	r6, [r4]
	dsb
	b	wait_dll_lock_timed

exit_nonoff_modes:
	/* Re-enable C-bit if needed */
	mrc	p15, 0, r0, c1, c0, 0
	tst	r0, #(1 << 2)		@ Check C bit enabled?
	orreq	r0, r0, #(1 << 2)	@ Enable the C bit if cleared
	mcreq	p15, 0, r0, c1, c0, 0
	isb

/*
 * ===================================
 * == Exit point from non-OFF modes ==
 * ===================================
 */
	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
ENDPROC(omap3_do_wfi)
sdrc_power:
	.word	SDRC_POWER_V
cm_idlest1_core:
	.word	CM_IDLEST1_CORE_V
cm_idlest_ckgen:
	.word	CM_IDLEST_CKGEN_V
sdrc_dlla_status:
	.word	SDRC_DLLA_STATUS_V
sdrc_dlla_ctrl:
	.word	SDRC_DLLA_CTRL_V
ENTRY(omap3_do_wfi_sz)
	.word	. - omap3_do_wfi

/*
 * ==============================
 * == Resume path for OFF mode ==
 * ==============================
 */

/*
 * The restore_* functions are called by the ROM code
 *  when back from WFI in OFF mode.
 * Cf. the get_*restore_pointer functions.
 *
 *  restore_es3: applies to 34xx >= ES3.0
 *  restore_3630: applies to 36xx
 *  restore: common code for 3xxx
 *
 * Note: when back from CORE and MPU OFF mode we are running
 *  from SDRAM, without MMU, without the caches and prediction.
 *  Also the SRAM content has been cleared.
 */
ENTRY(omap3_restore_es3)
	ldr	r5, pm_prepwstst_core_p
	ldr	r4, [r5]
	and	r4, r4, #0x3
	cmp	r4, #0x0	@ Check if previous power state of CORE is OFF
	bne	omap3_restore	@ Fall through to OMAP3 common code
	adr	r0, es3_sdrc_fix
	ldr	r1, sram_base
	ldr	r2, es3_sdrc_fix_sz
	mov	r2, r2, ror #2
copy_to_sram:
	ldmia	r0!, {r3}	@ val = *src
	stmia	r1!, {r3}	@ *dst = val
	subs	r2, r2, #0x1	@ num_words--
	bne	copy_to_sram
	ldr	r1, sram_base
	blx	r1
	b	omap3_restore	@ Fall through to OMAP3 common code
ENDPROC(omap3_restore_es3)

ENTRY(omap3_restore_3630)
	ldr	r1, pm_prepwstst_core_p
	ldr	r2, [r1]
	and	r2, r2, #0x3
	cmp	r2, #0x0	@ Check if previous power state of CORE is OFF
	bne	omap3_restore	@ Fall through to OMAP3 common code
	/* Disable RTA before giving control */
	ldr	r1, control_mem_rta
	mov	r2, #OMAP36XX_RTA_DISABLE
	str	r2, [r1]
ENDPROC(omap3_restore_3630)

	/* Fall through to common code for the remaining logic */

ENTRY(omap3_restore)
	/*
	 * Read the pwstctrl register to check the reason for mpu reset.
	 * This tells us what was lost.
	 */
	ldr	r1, pm_pwstctrl_mpu
	ldr	r2, [r1]
	and	r2, r2, #0x3
	cmp	r2, #0x0	@ Check if target power state was OFF or RET
	bne	logic_l1_restore

	adr	r1, l2dis_3630_offset	@ address for offset
	ldr	r0, [r1]		@ value for offset
	ldr	r0, [r1, r0]		@ value at l2dis_3630
	cmp	r0, #0x1	@ should we disable L2 on 3630?
	bne	skipl2dis
	mrc	p15, 0, r0, c1, c0, 1
	bic	r0, r0, #2	@ disable L2 cache
	mcr	p15, 0, r0, c1, c0, 1
skipl2dis:
	ldr	r0, control_stat
	ldr	r1, [r0]
	and	r1, #0x700
	cmp	r1, #0x300
	beq	l2_inv_gp
	adr	r0, l2_inv_api_params_offset
	ldr	r3, [r0]
	add	r3, r3, r0		@ r3 points to dummy parameters
	mov	r0, #40			@ set service ID for PPA
	mov	r12, r0			@ copy secure Service ID in r12
	mov	r1, #0			@ set task id for ROM code in r1
	mov	r2, #4			@ set some flags in r2, r6
	mov	r6, #0xff
	dsb				@ data write barrier
	dmb				@ data memory barrier
	smc	#1			@ call SMI monitor (smi #1)
	/* Write to Aux control register to set some bits */
	mov	r0, #42			@ set service ID for PPA
	mov	r12, r0			@ copy secure Service ID in r12
	mov	r1, #0			@ set task id for ROM code in r1
	mov	r2, #4			@ set some flags in r2, r6
	mov	r6, #0xff
	ldr	r4, scratchpad_base
	ldr	r3, [r4, #0xBC]		@ r3 points to parameters
	dsb				@ data write barrier
	dmb				@ data memory barrier
	smc	#1			@ call SMI monitor (smi #1)

#ifdef CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE
	/* Restore L2 aux control register */
					@ set service ID for PPA
	mov	r0, #CONFIG_OMAP3_L2_AUX_SECURE_SERVICE_SET_ID
	mov	r12, r0			@ copy service ID in r12
	mov	r1, #0			@ set task ID for ROM code in r1
	mov	r2, #4			@ set some flags in r2, r6
	mov	r6, #0xff
	ldr	r4, scratchpad_base
	ldr	r3, [r4, #0xBC]
	adds	r3, r3, #8		@ r3 points to parameters
	dsb				@ data write barrier
	dmb				@ data memory barrier
	smc	#1			@ call SMI monitor (smi #1)
#endif
	b	logic_l1_restore

	.align
l2_inv_api_params_offset:
	.long	l2_inv_api_params - .
l2_inv_gp:
	/* Execute smi to invalidate L2 cache */
	mov r12, #0x1			@ set up to invalidate L2
	smc	#0			@ Call SMI monitor (smieq)
	/* Write to Aux control register to set some bits */
	ldr	r4, scratchpad_base
	ldr	r3, [r4,#0xBC]
	ldr	r0, [r3,#4]
	mov	r12, #0x3
	smc	#0			@ Call SMI monitor (smieq)
	ldr	r4, scratchpad_base
	ldr	r3, [r4,#0xBC]
	ldr	r0, [r3,#12]
	mov	r12, #0x2
	smc	#0			@ Call SMI monitor (smieq)
logic_l1_restore:
	adr	r0, l2dis_3630_offset	@ adress for offset
	ldr	r1, [r0]		@ value for offset
	ldr	r1, [r0, r1]		@ value at l2dis_3630
	cmp	r1, #0x1		@ Test if L2 re-enable needed on 3630
	bne	skipl2reen
	mrc	p15, 0, r1, c1, c0, 1
	orr	r1, r1, #2		@ re-enable L2 cache
	mcr	p15, 0, r1, c1, c0, 1
skipl2reen:

	/* Now branch to the common CPU resume function */
	b	cpu_resume
ENDPROC(omap3_restore)

	.ltorg

/*
 * Local variables
 */
pm_prepwstst_core_p:
	.word	PM_PREPWSTST_CORE_P
pm_pwstctrl_mpu:
	.word	PM_PWSTCTRL_MPU_P
scratchpad_base:
	.word	SCRATCHPAD_BASE_P
sram_base:
	.word	SRAM_BASE_P + 0x8000
control_stat:
	.word	CONTROL_STAT
control_mem_rta:
	.word	CONTROL_MEM_RTA_CTRL
l2dis_3630_offset:
	.long	l2dis_3630 - .

	.data
	.align	2
l2dis_3630:
	.word	0

	.data
	.align	2
l2_inv_api_params:
	.word	0x1, 0x00

/*
 * Internal functions
 */

/*
 * This function implements the erratum ID i443 WA, applies to 34xx >= ES3.0
 * Copied to and run from SRAM in order to reconfigure the SDRC parameters.
 */
	.text
	.align	3
ENTRY(es3_sdrc_fix)
	ldr	r4, sdrc_syscfg		@ get config addr
	ldr	r5, [r4]		@ get value
	tst	r5, #0x100		@ is part access blocked
	it	eq
	biceq	r5, r5, #0x100		@ clear bit if set
	str	r5, [r4]		@ write back change
	ldr	r4, sdrc_mr_0		@ get config addr
	ldr	r5, [r4]		@ get value
	str	r5, [r4]		@ write back change
	ldr	r4, sdrc_emr2_0		@ get config addr
	ldr	r5, [r4]		@ get value
	str	r5, [r4]		@ write back change
	ldr	r4, sdrc_manual_0	@ get config addr
	mov	r5, #0x2		@ autorefresh command
	str	r5, [r4]		@ kick off refreshes
	ldr	r4, sdrc_mr_1		@ get config addr
	ldr	r5, [r4]		@ get value
	str	r5, [r4]		@ write back change
	ldr	r4, sdrc_emr2_1		@ get config addr
	ldr	r5, [r4]		@ get value
	str	r5, [r4]		@ write back change
	ldr	r4, sdrc_manual_1	@ get config addr
	mov	r5, #0x2		@ autorefresh command
	str	r5, [r4]		@ kick off refreshes
	bx	lr

/*
 * Local variables
 */
	.align
sdrc_syscfg:
	.word	SDRC_SYSCONFIG_P
sdrc_mr_0:
	.word	SDRC_MR_0_P
sdrc_emr2_0:
	.word	SDRC_EMR2_0_P
sdrc_manual_0:
	.word	SDRC_MANUAL_0_P
sdrc_mr_1:
	.word	SDRC_MR_1_P
sdrc_emr2_1:
	.word	SDRC_EMR2_1_P
sdrc_manual_1:
	.word	SDRC_MANUAL_1_P
ENDPROC(es3_sdrc_fix)
ENTRY(es3_sdrc_fix_sz)
	.word	. - es3_sdrc_fix


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Low level suspend code for AM43XX SoCs
 *
 * Copyright (C) 2013-2018 Texas Instruments Incorporated - https://www.ti.com/
 *	Dave Gerlach, Vaibhav Bedia
 */

#include <linux/linkage.h>
#include <linux/ti-emif-sram.h>
#include <linux/platform_data/pm33xx.h>
#include <asm/assembler.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/memory.h>

#include "cm33xx.h"
#include "common.h"
#include "iomap.h"
#include "omap-secure.h"
#include "omap44xx.h"
#include "pm-asm-offsets.h"
#include "prm33xx.h"
#include "prcm43xx.h"

/* replicated define because linux/bitops.h cannot be included in assembly */
#define BIT(nr)			(1 << (nr))

#define AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED		0x00030000
#define AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE		0x0003
#define AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE		0x0002

#define AM43XX_EMIF_POWEROFF_ENABLE			0x1
#define AM43XX_EMIF_POWEROFF_DISABLE			0x0

#define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP		0x1
#define AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO		0x3

#define AM43XX_CM_BASE					0x44DF0000

#define AM43XX_CM_REGADDR(inst, reg)                           \
       AM33XX_L4_WK_IO_ADDRESS(AM43XX_CM_BASE + (inst) + (reg))

#define AM43XX_CM_MPU_CLKSTCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \
					AM43XX_CM_MPU_MPU_CDOFFS)
#define AM43XX_CM_MPU_MPU_CLKCTRL AM43XX_CM_REGADDR(AM43XX_CM_MPU_INST, \
					AM43XX_CM_MPU_MPU_CLKCTRL_OFFSET)
#define AM43XX_CM_PER_EMIF_CLKCTRL  AM43XX_CM_REGADDR(AM43XX_CM_PER_INST, \
					AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET)
#define AM43XX_PRM_EMIF_CTRL_OFFSET			0x0030

#define RTC_SECONDS_REG					0x0
#define RTC_PMIC_REG					0x98
#define RTC_PMIC_POWER_EN				BIT(16)
#define RTC_PMIC_EXT_WAKEUP_STS				BIT(12)
#define RTC_PMIC_EXT_WAKEUP_POL				BIT(4)
#define RTC_PMIC_EXT_WAKEUP_EN				BIT(0)

	.arm
	.arch armv7-a
	.arch_extension sec
	.align 3

ENTRY(am43xx_do_wfi)
	stmfd	sp!, {r4 - r11, lr}	@ save registers on stack

	/* Save wfi_flags arg to data space */
	mov	r4, r0
	adr	r3, am43xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	str	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

#ifdef CONFIG_CACHE_L2X0
	/* Retrieve l2 cache virt address BEFORE we shut off EMIF */
	ldr	r1, get_l2cache_base
	blx	r1
	mov	r8, r0
#endif

	/* Only flush cache is we know we are losing MPU context */
	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_flush

	/*
	 * Flush all data from the L1 and L2 data cache before disabling
	 * SCTLR.C bit.
	 */
	ldr	r1, kernel_flush
	blx	r1

	/*
	 * Clear the SCTLR.C bit to prevent further data cache
	 * allocation. Clearing SCTLR.C would make all the data accesses
	 * strongly ordered and would not hit the cache.
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #(1 << 2)	@ Disable the C bit
	mcr	p15, 0, r0, c1, c0, 0
	isb
	dsb

	/*
	 * Invalidate L1 and L2 data cache.
	 */
	ldr	r1, kernel_flush
	blx	r1

#ifdef CONFIG_CACHE_L2X0
	/*
	 * Clean and invalidate the L2 cache.
	 */
#ifdef CONFIG_PL310_ERRATA_727915
	mov	r0, #0x03
	mov	r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
	dsb
	smc	#0
	dsb
#endif
	mov	r0, r8
	adr	r4, am43xx_pm_ro_sram_data
	ldr	r3, [r4, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]

	mov	r2, r0
	ldr	r0, [r2, #L2X0_AUX_CTRL]
	str	r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET]
	ldr	r0, [r2, #L310_PREFETCH_CTRL]
	str	r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET]

	ldr	r0, l2_val
	str	r0, [r2, #L2X0_CLEAN_INV_WAY]
wait:
	ldr	r0, [r2, #L2X0_CLEAN_INV_WAY]
	ldr	r1, l2_val
	ands	r0, r0, r1
	bne	wait
#ifdef CONFIG_PL310_ERRATA_727915
	mov	r0, #0x00
	mov	r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
	dsb
	smc	#0
	dsb
#endif
l2x_sync:
	mov	r0, r8
	mov	r2, r0
	mov	r0, #0x0
	str	r0, [r2, #L2X0_CACHE_SYNC]
sync:
	ldr	r0, [r2, #L2X0_CACHE_SYNC]
	ands	r0, r0, #0x1
	bne	sync
#endif

	/* Restore wfi_flags */
	adr	r3, am43xx_pm_ro_sram_data
	ldr	r2, [r3, #AMX3_PM_RO_SRAM_DATA_VIRT_OFFSET]
	ldr	r4, [r2, #AMX3_PM_WFI_FLAGS_OFFSET]

cache_skip_flush:
	/*
	 * If we are trying to enter RTC+DDR mode we must perform
	 * a read from the rtc address space to ensure translation
	 * presence in the TLB to avoid page table walk after DDR
	 * is unavailable.
	 */
	tst	r4, #WFI_FLAG_RTC_ONLY
	beq	skip_rtc_va_refresh

	adr	r3, am43xx_pm_ro_sram_data
	ldr	r1, [r3, #AMX3_PM_RTC_BASE_VIRT_OFFSET]
	ldr	r0, [r1]

skip_rtc_va_refresh:
	/* Check if we want self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_enter_sr

	adr     r9, am43xx_emif_sram_table

	ldr     r3, [r9, #EMIF_PM_ENTER_SR_OFFSET]
	blx     r3

emif_skip_enter_sr:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SAVE_EMIF
	beq	emif_skip_save

	ldr     r3, [r9, #EMIF_PM_SAVE_CONTEXT_OFFSET]
	blx	r3

emif_skip_save:
	/* Only can disable EMIF if we have entered self refresh */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_disable

	/* Disable EMIF */
	ldr	r1, am43xx_virt_emif_clkctrl
	ldr	r2, [r1]
	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
	str	r2, [r1]

wait_emif_disable:
	ldr	r2, [r1]
	mov	r3, #AM33XX_CM_CLKCTRL_MODULESTATE_DISABLED
	cmp	r2, r3
	bne	wait_emif_disable

emif_skip_disable:
	tst	r4, #WFI_FLAG_RTC_ONLY
	beq	skip_rtc_only

	adr	r3, am43xx_pm_ro_sram_data
	ldr	r1, [r3, #AMX3_PM_RTC_BASE_VIRT_OFFSET]

	ldr	r0, [r1, #RTC_PMIC_REG]
	orr	r0, r0, #RTC_PMIC_POWER_EN
	orr	r0, r0, #RTC_PMIC_EXT_WAKEUP_STS
	orr	r0, r0, #RTC_PMIC_EXT_WAKEUP_EN
	orr	r0, r0, #RTC_PMIC_EXT_WAKEUP_POL
	str	r0, [r1, #RTC_PMIC_REG]
	ldr	r0, [r1, #RTC_PMIC_REG]
	/* Wait for 2 seconds to lose power */
	mov	r3, #2
	ldr	r2, [r1, #RTC_SECONDS_REG]
rtc_loop:
	ldr	r0, [r1, #RTC_SECONDS_REG]
	cmp	r0, r2
	beq	rtc_loop
	mov	r2, r0
	subs	r3, r3, #1
	bne	rtc_loop

	b	re_enable_emif

skip_rtc_only:

	tst	r4, #WFI_FLAG_WAKE_M3
	beq	wkup_m3_skip

	/*
	 * For the MPU WFI to be registered as an interrupt
	 * to WKUP_M3, MPU_CLKCTRL.MODULEMODE needs to be set
	 * to DISABLED
	 */
	ldr	r1, am43xx_virt_mpu_clkctrl
	ldr	r2, [r1]
	bic	r2, r2, #AM33XX_CM_CLKCTRL_MODULEMODE_DISABLE
	str	r2, [r1]

	/*
	 * Put MPU CLKDM to SW_SLEEP
	 */
	ldr	r1, am43xx_virt_mpu_clkstctrl
	mov	r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_SW_SLEEP
	str	r2, [r1]

wkup_m3_skip:
	/*
	 * Execute a barrier instruction to ensure that all cache,
	 * TLB and branch predictor maintenance operations issued
	 * have completed.
	 */
	dsb
	dmb

	/*
	 * Execute a WFI instruction and wait until the
	 * STANDBYWFI output is asserted to indicate that the
	 * CPU is in idle and low power state. CPU can specualatively
	 * prefetch the instructions so add NOPs after WFI. Sixteen
	 * NOPs as per Cortex-A9 pipeline.
	 */
	wfi

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

	/* We come here in case of an abort due to a late interrupt */
	ldr	r1, am43xx_virt_mpu_clkstctrl
	mov	r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO
	str	r2, [r1]

	/* Set MPU_CLKCTRL.MODULEMODE back to ENABLE */
	ldr	r1, am43xx_virt_mpu_clkctrl
	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r2, [r1]

re_enable_emif:
	/* Re-enable EMIF */
	ldr	r1, am43xx_virt_emif_clkctrl
	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r2, [r1]
wait_emif_enable:
	ldr	r3, [r1]
	cmp	r2, r3
	bne	wait_emif_enable

	tst	r4, #WFI_FLAG_FLUSH_CACHE
	beq	cache_skip_restore

	/*
	 * Set SCTLR.C bit to allow data cache allocation
	 */
	mrc	p15, 0, r0, c1, c0, 0
	orr	r0, r0, #(1 << 2)	@ Enable the C bit
	mcr	p15, 0, r0, c1, c0, 0
	isb

cache_skip_restore:
	/* Only necessary if PER is losing context */
	tst	r4, #WFI_FLAG_SELF_REFRESH
	beq	emif_skip_exit_sr_abt

	adr	r9, am43xx_emif_sram_table
	ldr	r1, [r9, #EMIF_PM_ABORT_SR_OFFSET]
	blx	r1

emif_skip_exit_sr_abt:
	/* Let the suspend code know about the abort */
	mov	r0, #1
	ldmfd	sp!, {r4 - r11, pc}	@ restore regs and return
ENDPROC(am43xx_do_wfi)

	.align
ENTRY(am43xx_resume_offset)
	.word . - am43xx_do_wfi

ENTRY(am43xx_resume_from_deep_sleep)
	/* Set MPU CLKSTCTRL to HW AUTO so that CPUidle works properly */
	ldr	r1, am43xx_virt_mpu_clkstctrl
	mov	r2, #AM43XX_CM_CLKSTCTRL_CLKTRCTRL_HW_AUTO
	str	r2, [r1]

	/* For AM43xx, use EMIF power down until context is restored */
	ldr	r2, am43xx_phys_emif_poweroff
	mov	r1, #AM43XX_EMIF_POWEROFF_ENABLE
	str	r1, [r2, #0x0]

	/* Re-enable EMIF */
	ldr	r1, am43xx_phys_emif_clkctrl
	mov	r2, #AM33XX_CM_CLKCTRL_MODULEMODE_ENABLE
	str	r2, [r1]
wait_emif_enable1:
	ldr	r3, [r1]
	cmp	r2, r3
	bne	wait_emif_enable1

	adr     r9, am43xx_emif_sram_table

	ldr     r1, [r9, #EMIF_PM_RESTORE_CONTEXT_OFFSET]
	blx     r1

	ldr     r1, [r9, #EMIF_PM_EXIT_SR_OFFSET]
	blx     r1

	ldr     r2, am43xx_phys_emif_poweroff
	mov     r1, #AM43XX_EMIF_POWEROFF_DISABLE
	str     r1, [r2, #0x0]

	ldr     r1, [r9, #EMIF_PM_RUN_HW_LEVELING]
	blx     r1

#ifdef CONFIG_CACHE_L2X0
	ldr	r2, l2_cache_base
	ldr	r0, [r2, #L2X0_CTRL]
	and	r0, #0x0f
	cmp	r0, #1
	beq	skip_l2en			@ Skip if already enabled

	adr	r4, am43xx_pm_ro_sram_data
	ldr	r3, [r4, #AMX3_PM_RO_SRAM_DATA_PHYS_OFFSET]
	ldr     r0, [r3, #AMX3_PM_L2_PREFETCH_CTRL_VAL_OFFSET]

	ldr	r12, l2_smc1
	dsb
	smc	#0
	dsb
set_aux_ctrl:
	ldr     r0, [r3, #AMX3_PM_L2_AUX_CTRL_VAL_OFFSET]
	ldr	r12, l2_smc2
	dsb
	smc	#0
	dsb

	/* L2 invalidate on resume */
	ldr	r0, l2_val
	ldr	r2, l2_cache_base
	str	r0, [r2, #L2X0_INV_WAY]
wait2:
	ldr	r0, [r2, #L2X0_INV_WAY]
	ldr	r1, l2_val
	ands	r0, r0, r1
	bne	wait2
#ifdef CONFIG_PL310_ERRATA_727915
	mov	r0, #0x00
	mov	r12, #OMAP4_MON_L2X0_DBG_CTRL_INDEX
	dsb
	smc	#0
	dsb
#endif
l2x_sync2:
	ldr	r2, l2_cache_base
	mov	r0, #0x0
	str	r0, [r2, #L2X0_CACHE_SYNC]
sync2:
	ldr	r0, [r2, #L2X0_CACHE_SYNC]
	ands	r0, r0, #0x1
	bne	sync2

	mov	r0, #0x1
	ldr	r12, l2_smc3
	dsb
	smc	#0
	dsb
#endif
skip_l2en:
	/* We are back. Branch to the common CPU resume routine */
	mov	r0, #0
	ldr	pc, resume_addr
ENDPROC(am43xx_resume_from_deep_sleep)

/*
 * Local variables
 */
	.align
kernel_flush:
	.word   v7_flush_dcache_all
ddr_start:
	.word	PAGE_OFFSET

am43xx_phys_emif_poweroff:
	.word   (AM43XX_CM_BASE + AM43XX_PRM_DEVICE_INST + \
		 AM43XX_PRM_EMIF_CTRL_OFFSET)
am43xx_virt_mpu_clkstctrl:
	.word	(AM43XX_CM_MPU_CLKSTCTRL)
am43xx_virt_mpu_clkctrl:
	.word	(AM43XX_CM_MPU_MPU_CLKCTRL)
am43xx_virt_emif_clkctrl:
	.word	(AM43XX_CM_PER_EMIF_CLKCTRL)
am43xx_phys_emif_clkctrl:
	.word	(AM43XX_CM_BASE + AM43XX_CM_PER_INST + \
		 AM43XX_CM_PER_EMIF_CLKCTRL_OFFSET)

#ifdef CONFIG_CACHE_L2X0
/* L2 cache related defines for AM437x */
get_l2cache_base:
	.word	omap4_get_l2cache_base
l2_cache_base:
	.word	OMAP44XX_L2CACHE_BASE
l2_smc1:
	.word	OMAP4_MON_L2X0_PREFETCH_INDEX
l2_smc2:
	.word	OMAP4_MON_L2X0_AUXCTRL_INDEX
l2_smc3:
	.word	OMAP4_MON_L2X0_CTRL_INDEX
l2_val:
	.word	0xffff
#endif

.align 3
/* DDR related defines */
ENTRY(am43xx_emif_sram_table)
	.space EMIF_PM_FUNCTIONS_SIZE

ENTRY(am43xx_pm_sram)
	.word am43xx_do_wfi
	.word am43xx_do_wfi_sz
	.word am43xx_resume_offset
	.word am43xx_emif_sram_table
	.word am43xx_pm_ro_sram_data

resume_addr:
	.word   cpu_resume - PAGE_OFFSET + 0x80000000
.align 3

ENTRY(am43xx_pm_ro_sram_data)
	.space AMX3_PM_RO_SRAM_DATA_SIZE

ENTRY(am43xx_do_wfi_sz)
	.word	. - am43xx_do_wfi