code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/plat-omap/dma.c
 *
 * Copyright (C) 2003 - 2008 Nokia Corporation
 * Author: Juha Yrjölä <juha.yrjola@nokia.com>
 * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
 * Graphics DMA and LCD DMA graphics tranformations
 * by Imre Deak <imre.deak@nokia.com>
 * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
 * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
 * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
 *
 * Copyright (C) 2009 Texas Instruments
 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
 *
 * Support functions for the OMAP internal DMA channels.
 *
 * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
 * Converted DMA library into DMA platform driver.
 *	- G, Manjunath Kondaiah <manjugk@ti.com>
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/delay.h>

#include <linux/omap-dma.h>

#include <linux/soc/ti/omap1-io.h>
#include <linux/soc/ti/omap1-soc.h>

#include "tc.h"

/*
 * MAX_LOGICAL_DMA_CH_COUNT: the maximum number of logical DMA
 * channels that an instance of the SDMA IP block can support.  Used
 * to size arrays.  (The actual maximum on a particular SoC may be less
 * than this -- for example, OMAP1 SDMA instances only support 17 logical
 * DMA channels.)
 */
#define MAX_LOGICAL_DMA_CH_COUNT		32

#undef DEBUG

#define OMAP_DMA_ACTIVE			0x01

#define OMAP_FUNC_MUX_ARM_BASE		(0xfffe1000 + 0xec)

static struct omap_system_dma_plat_info *p;
static struct omap_dma_dev_attr *d;
static int enable_1510_mode;
static u32 errata;

struct dma_link_info {
	int *linked_dmach_q;
	int no_of_lchs_linked;

	int q_count;
	int q_tail;
	int q_head;

	int chain_state;
	int chain_mode;

};

static int dma_lch_count;
static int dma_chan_count;
static int omap_dma_reserve_channels;

static DEFINE_SPINLOCK(dma_chan_lock);
static struct omap_dma_lch *dma_chan;

static inline void omap_disable_channel_irq(int lch)
{
	/* disable channel interrupts */
	p->dma_write(0, CICR, lch);
	/* Clear CSR */
	p->dma_read(CSR, lch);
}

static inline void set_gdma_dev(int req, int dev)
{
	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
	int shift = ((req - 1) % 5) * 6;
	u32 l;

	l = omap_readl(reg);
	l &= ~(0x3f << shift);
	l |= (dev - 1) << shift;
	omap_writel(l, reg);
}

#if IS_ENABLED(CONFIG_FB_OMAP)
void omap_set_dma_priority(int lch, int dst_port, int priority)
{
	unsigned long reg;
	u32 l;

	if (dma_omap1()) {
		switch (dst_port) {
		case OMAP_DMA_PORT_OCP_T1:	/* FFFECC00 */
			reg = OMAP_TC_OCPT1_PRIOR;
			break;
		case OMAP_DMA_PORT_OCP_T2:	/* FFFECCD0 */
			reg = OMAP_TC_OCPT2_PRIOR;
			break;
		case OMAP_DMA_PORT_EMIFF:	/* FFFECC08 */
			reg = OMAP_TC_EMIFF_PRIOR;
			break;
		case OMAP_DMA_PORT_EMIFS:	/* FFFECC04 */
			reg = OMAP_TC_EMIFS_PRIOR;
			break;
		default:
			BUG();
			return;
		}
		l = omap_readl(reg);
		l &= ~(0xf << 8);
		l |= (priority & 0xf) << 8;
		omap_writel(l, reg);
	}
}
EXPORT_SYMBOL(omap_set_dma_priority);
#endif

#if IS_ENABLED(CONFIG_USB_OMAP)
#ifdef CONFIG_ARCH_OMAP15XX
/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
static int omap_dma_in_1510_mode(void)
{
	return enable_1510_mode;
}
#else
#define omap_dma_in_1510_mode()		0
#endif

void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
				  int frame_count, int sync_mode,
				  int dma_trigger, int src_or_dst_synch)
{
	u32 l;
	u16 ccr;

	l = p->dma_read(CSDP, lch);
	l &= ~0x03;
	l |= data_type;
	p->dma_write(l, CSDP, lch);

	ccr = p->dma_read(CCR, lch);
	ccr &= ~(1 << 5);
	if (sync_mode == OMAP_DMA_SYNC_FRAME)
		ccr |= 1 << 5;
	p->dma_write(ccr, CCR, lch);

	ccr = p->dma_read(CCR2, lch);
	ccr &= ~(1 << 2);
	if (sync_mode == OMAP_DMA_SYNC_BLOCK)
		ccr |= 1 << 2;
	p->dma_write(ccr, CCR2, lch);
	p->dma_write(elem_count, CEN, lch);
	p->dma_write(frame_count, CFN, lch);
}
EXPORT_SYMBOL(omap_set_dma_transfer_params);

void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
{
	if (!dma_omap15xx()) {
		u32 l;

		l = p->dma_read(LCH_CTRL, lch);
		l &= ~0x7;
		l |= mode;
		p->dma_write(l, LCH_CTRL, lch);
	}
}
EXPORT_SYMBOL(omap_set_dma_channel_mode);

/* Note that src_port is only for omap1 */
void omap_set_dma_src_params(int lch, int src_port, int src_amode,
			     unsigned long src_start,
			     int src_ei, int src_fi)
{
	u32 l;
	u16 w;

	w = p->dma_read(CSDP, lch);
	w &= ~(0x1f << 2);
	w |= src_port << 2;
	p->dma_write(w, CSDP, lch);

	l = p->dma_read(CCR, lch);
	l &= ~(0x03 << 12);
	l |= src_amode << 12;
	p->dma_write(l, CCR, lch);

	p->dma_write(src_start, CSSA, lch);

	p->dma_write(src_ei, CSEI, lch);
	p->dma_write(src_fi, CSFI, lch);
}
EXPORT_SYMBOL(omap_set_dma_src_params);

void omap_set_dma_src_data_pack(int lch, int enable)
{
	u32 l;

	l = p->dma_read(CSDP, lch);
	l &= ~(1 << 6);
	if (enable)
		l |= (1 << 6);
	p->dma_write(l, CSDP, lch);
}
EXPORT_SYMBOL(omap_set_dma_src_data_pack);

void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
{
	unsigned int burst = 0;
	u32 l;

	l = p->dma_read(CSDP, lch);
	l &= ~(0x03 << 7);

	switch (burst_mode) {
	case OMAP_DMA_DATA_BURST_DIS:
		break;
	case OMAP_DMA_DATA_BURST_4:
		burst = 0x2;
		break;
	case OMAP_DMA_DATA_BURST_8:
		/*
		 * not supported by current hardware on OMAP1
		 * w |= (0x03 << 7);
		 */
		fallthrough;
	case OMAP_DMA_DATA_BURST_16:
		/* OMAP1 don't support burst 16 */
		fallthrough;
	default:
		BUG();
	}

	l |= (burst << 7);
	p->dma_write(l, CSDP, lch);
}
EXPORT_SYMBOL(omap_set_dma_src_burst_mode);

/* Note that dest_port is only for OMAP1 */
void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
			      unsigned long dest_start,
			      int dst_ei, int dst_fi)
{
	u32 l;

	l = p->dma_read(CSDP, lch);
	l &= ~(0x1f << 9);
	l |= dest_port << 9;
	p->dma_write(l, CSDP, lch);

	l = p->dma_read(CCR, lch);
	l &= ~(0x03 << 14);
	l |= dest_amode << 14;
	p->dma_write(l, CCR, lch);

	p->dma_write(dest_start, CDSA, lch);

	p->dma_write(dst_ei, CDEI, lch);
	p->dma_write(dst_fi, CDFI, lch);
}
EXPORT_SYMBOL(omap_set_dma_dest_params);

void omap_set_dma_dest_data_pack(int lch, int enable)
{
	u32 l;

	l = p->dma_read(CSDP, lch);
	l &= ~(1 << 13);
	if (enable)
		l |= 1 << 13;
	p->dma_write(l, CSDP, lch);
}
EXPORT_SYMBOL(omap_set_dma_dest_data_pack);

void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
{
	unsigned int burst = 0;
	u32 l;

	l = p->dma_read(CSDP, lch);
	l &= ~(0x03 << 14);

	switch (burst_mode) {
	case OMAP_DMA_DATA_BURST_DIS:
		break;
	case OMAP_DMA_DATA_BURST_4:
		burst = 0x2;
		break;
	case OMAP_DMA_DATA_BURST_8:
		burst = 0x3;
		break;
	case OMAP_DMA_DATA_BURST_16:
		/* OMAP1 don't support burst 16 */
		fallthrough;
	default:
		printk(KERN_ERR "Invalid DMA burst mode\n");
		BUG();
		return;
	}
	l |= (burst << 14);
	p->dma_write(l, CSDP, lch);
}
EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);

static inline void omap_enable_channel_irq(int lch)
{
	/* Clear CSR */
	p->dma_read(CSR, lch);

	/* Enable some nice interrupts. */
	p->dma_write(dma_chan[lch].enabled_irqs, CICR, lch);
}

void omap_disable_dma_irq(int lch, u16 bits)
{
	dma_chan[lch].enabled_irqs &= ~bits;
}
EXPORT_SYMBOL(omap_disable_dma_irq);

static inline void enable_lnk(int lch)
{
	u32 l;

	l = p->dma_read(CLNK_CTRL, lch);

	l &= ~(1 << 14);

	/* Set the ENABLE_LNK bits */
	if (dma_chan[lch].next_lch != -1)
		l = dma_chan[lch].next_lch | (1 << 15);

	p->dma_write(l, CLNK_CTRL, lch);
}

static inline void disable_lnk(int lch)
{
	u32 l;

	l = p->dma_read(CLNK_CTRL, lch);

	/* Disable interrupts */
	omap_disable_channel_irq(lch);

	/* Set the STOP_LNK bit */
	l |= 1 << 14;

	p->dma_write(l, CLNK_CTRL, lch);
	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
}
#endif

int omap_request_dma(int dev_id, const char *dev_name,
		     void (*callback)(int lch, u16 ch_status, void *data),
		     void *data, int *dma_ch_out)
{
	int ch, free_ch = -1;
	unsigned long flags;
	struct omap_dma_lch *chan;

	WARN(strcmp(dev_name, "DMA engine"), "Using deprecated platform DMA API - please update to DMA engine");

	spin_lock_irqsave(&dma_chan_lock, flags);
	for (ch = 0; ch < dma_chan_count; ch++) {
		if (free_ch == -1 && dma_chan[ch].dev_id == -1) {
			free_ch = ch;
			/* Exit after first free channel found */
			break;
		}
	}
	if (free_ch == -1) {
		spin_unlock_irqrestore(&dma_chan_lock, flags);
		return -EBUSY;
	}
	chan = dma_chan + free_ch;
	chan->dev_id = dev_id;

	if (p->clear_lch_regs)
		p->clear_lch_regs(free_ch);

	spin_unlock_irqrestore(&dma_chan_lock, flags);

	chan->dev_name = dev_name;
	chan->callback = callback;
	chan->data = data;
	chan->flags = 0;

	chan->enabled_irqs = OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;

	chan->enabled_irqs |= OMAP1_DMA_TOUT_IRQ;

	if (dma_omap16xx()) {
		/* If the sync device is set, configure it dynamically. */
		if (dev_id != 0) {
			set_gdma_dev(free_ch + 1, dev_id);
			dev_id = free_ch + 1;
		}
		/*
		 * Disable the 1510 compatibility mode and set the sync device
		 * id.
		 */
		p->dma_write(dev_id | (1 << 10), CCR, free_ch);
	} else {
		p->dma_write(dev_id, CCR, free_ch);
	}

	*dma_ch_out = free_ch;

	return 0;
}
EXPORT_SYMBOL(omap_request_dma);

void omap_free_dma(int lch)
{
	unsigned long flags;

	if (dma_chan[lch].dev_id == -1) {
		pr_err("omap_dma: trying to free unallocated DMA channel %d\n",
		       lch);
		return;
	}

	/* Disable all DMA interrupts for the channel. */
	omap_disable_channel_irq(lch);

	/* Make sure the DMA transfer is stopped. */
	p->dma_write(0, CCR, lch);

	spin_lock_irqsave(&dma_chan_lock, flags);
	dma_chan[lch].dev_id = -1;
	dma_chan[lch].next_lch = -1;
	dma_chan[lch].callback = NULL;
	spin_unlock_irqrestore(&dma_chan_lock, flags);
}
EXPORT_SYMBOL(omap_free_dma);

/*
 * Clears any DMA state so the DMA engine is ready to restart with new buffers
 * through omap_start_dma(). Any buffers in flight are discarded.
 */
static void omap_clear_dma(int lch)
{
	unsigned long flags;

	local_irq_save(flags);
	p->clear_dma(lch);
	local_irq_restore(flags);
}

#if IS_ENABLED(CONFIG_USB_OMAP)
void omap_start_dma(int lch)
{
	u32 l;

	/*
	 * The CPC/CDAC register needs to be initialized to zero
	 * before starting dma transfer.
	 */
	if (dma_omap15xx())
		p->dma_write(0, CPC, lch);
	else
		p->dma_write(0, CDAC, lch);

	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
		int next_lch, cur_lch;
		char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];

		/* Set the link register of the first channel */
		enable_lnk(lch);

		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
		dma_chan_link_map[lch] = 1;

		cur_lch = dma_chan[lch].next_lch;
		do {
			next_lch = dma_chan[cur_lch].next_lch;

			/* The loop case: we've been here already */
			if (dma_chan_link_map[cur_lch])
				break;
			/* Mark the current channel */
			dma_chan_link_map[cur_lch] = 1;

			enable_lnk(cur_lch);
			omap_enable_channel_irq(cur_lch);

			cur_lch = next_lch;
		} while (next_lch != -1);
	} else if (IS_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS))
		p->dma_write(lch, CLNK_CTRL, lch);

	omap_enable_channel_irq(lch);

	l = p->dma_read(CCR, lch);

	if (IS_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING))
			l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
	l |= OMAP_DMA_CCR_EN;

	/*
	 * As dma_write() uses IO accessors which are weakly ordered, there
	 * is no guarantee that data in coherent DMA memory will be visible
	 * to the DMA device.  Add a memory barrier here to ensure that any
	 * such data is visible prior to enabling DMA.
	 */
	mb();
	p->dma_write(l, CCR, lch);

	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
}
EXPORT_SYMBOL(omap_start_dma);

void omap_stop_dma(int lch)
{
	u32 l;

	/* Disable all interrupts on the channel */
	omap_disable_channel_irq(lch);

	l = p->dma_read(CCR, lch);
	if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
			(l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
		int i = 0;
		u32 sys_cf;

		/* Configure No-Standby */
		l = p->dma_read(OCP_SYSCONFIG, lch);
		sys_cf = l;
		l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
		l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
		p->dma_write(l , OCP_SYSCONFIG, 0);

		l = p->dma_read(CCR, lch);
		l &= ~OMAP_DMA_CCR_EN;
		p->dma_write(l, CCR, lch);

		/* Wait for sDMA FIFO drain */
		l = p->dma_read(CCR, lch);
		while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
					OMAP_DMA_CCR_WR_ACTIVE))) {
			udelay(5);
			i++;
			l = p->dma_read(CCR, lch);
		}
		if (i >= 100)
			pr_err("DMA drain did not complete on lch %d\n", lch);
		/* Restore OCP_SYSCONFIG */
		p->dma_write(sys_cf, OCP_SYSCONFIG, lch);
	} else {
		l &= ~OMAP_DMA_CCR_EN;
		p->dma_write(l, CCR, lch);
	}

	/*
	 * Ensure that data transferred by DMA is visible to any access
	 * after DMA has been disabled.  This is important for coherent
	 * DMA regions.
	 */
	mb();

	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
		int next_lch, cur_lch = lch;
		char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];

		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
		do {
			/* The loop case: we've been here already */
			if (dma_chan_link_map[cur_lch])
				break;
			/* Mark the current channel */
			dma_chan_link_map[cur_lch] = 1;

			disable_lnk(cur_lch);

			next_lch = dma_chan[cur_lch].next_lch;
			cur_lch = next_lch;
		} while (next_lch != -1);
	}

	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
}
EXPORT_SYMBOL(omap_stop_dma);

/*
 * Allows changing the DMA callback function or data. This may be needed if
 * the driver shares a single DMA channel for multiple dma triggers.
 */
/*
 * Returns current physical source address for the given DMA channel.
 * If the channel is running the caller must disable interrupts prior calling
 * this function and process the returned value before re-enabling interrupt to
 * prevent races with the interrupt handler. Note that in continuous mode there
 * is a chance for CSSA_L register overflow between the two reads resulting
 * in incorrect return value.
 */
dma_addr_t omap_get_dma_src_pos(int lch)
{
	dma_addr_t offset = 0;

	if (dma_omap15xx())
		offset = p->dma_read(CPC, lch);
	else
		offset = p->dma_read(CSAC, lch);

	if (IS_DMA_ERRATA(DMA_ERRATA_3_3) && offset == 0)
		offset = p->dma_read(CSAC, lch);

	if (!dma_omap15xx()) {
		/*
		 * CDAC == 0 indicates that the DMA transfer on the channel has
		 * not been started (no data has been transferred so far).
		 * Return the programmed source start address in this case.
		 */
		if (likely(p->dma_read(CDAC, lch)))
			offset = p->dma_read(CSAC, lch);
		else
			offset = p->dma_read(CSSA, lch);
	}

	offset |= (p->dma_read(CSSA, lch) & 0xFFFF0000);

	return offset;
}
EXPORT_SYMBOL(omap_get_dma_src_pos);

/*
 * Returns current physical destination address for the given DMA channel.
 * If the channel is running the caller must disable interrupts prior calling
 * this function and process the returned value before re-enabling interrupt to
 * prevent races with the interrupt handler. Note that in continuous mode there
 * is a chance for CDSA_L register overflow between the two reads resulting
 * in incorrect return value.
 */
dma_addr_t omap_get_dma_dst_pos(int lch)
{
	dma_addr_t offset = 0;

	if (dma_omap15xx())
		offset = p->dma_read(CPC, lch);
	else
		offset = p->dma_read(CDAC, lch);

	/*
	 * omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
	 * read before the DMA controller finished disabling the channel.
	 */
	if (!dma_omap15xx() && offset == 0) {
		offset = p->dma_read(CDAC, lch);
		/*
		 * CDAC == 0 indicates that the DMA transfer on the channel has
		 * not been started (no data has been transferred so far).
		 * Return the programmed destination start address in this case.
		 */
		if (unlikely(!offset))
			offset = p->dma_read(CDSA, lch);
	}

	offset |= (p->dma_read(CDSA, lch) & 0xFFFF0000);

	return offset;
}
EXPORT_SYMBOL(omap_get_dma_dst_pos);

int omap_get_dma_active_status(int lch)
{
	return (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) != 0;
}
EXPORT_SYMBOL(omap_get_dma_active_status);
#endif

int omap_dma_running(void)
{
	int lch;

	if (omap_lcd_dma_running())
		return 1;

	for (lch = 0; lch < dma_chan_count; lch++)
		if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN)
			return 1;

	return 0;
}

/*----------------------------------------------------------------------------*/

static int omap1_dma_handle_ch(int ch)
{
	u32 csr;

	if (enable_1510_mode && ch >= 6) {
		csr = dma_chan[ch].saved_csr;
		dma_chan[ch].saved_csr = 0;
	} else
		csr = p->dma_read(CSR, ch);
	if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) {
		dma_chan[ch + 6].saved_csr = csr >> 7;
		csr &= 0x7f;
	}
	if ((csr & 0x3f) == 0)
		return 0;
	if (unlikely(dma_chan[ch].dev_id == -1)) {
		pr_warn("Spurious interrupt from DMA channel %d (CSR %04x)\n",
			ch, csr);
		return 0;
	}
	if (unlikely(csr & OMAP1_DMA_TOUT_IRQ))
		pr_warn("DMA timeout with device %d\n", dma_chan[ch].dev_id);
	if (unlikely(csr & OMAP_DMA_DROP_IRQ))
		pr_warn("DMA synchronization event drop occurred with device %d\n",
			dma_chan[ch].dev_id);
	if (likely(csr & OMAP_DMA_BLOCK_IRQ))
		dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
	if (likely(dma_chan[ch].callback != NULL))
		dma_chan[ch].callback(ch, csr, dma_chan[ch].data);

	return 1;
}

static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
{
	int ch = ((int) dev_id) - 1;
	int handled = 0;

	for (;;) {
		int handled_now = 0;

		handled_now += omap1_dma_handle_ch(ch);
		if (enable_1510_mode && dma_chan[ch + 6].saved_csr)
			handled_now += omap1_dma_handle_ch(ch + 6);
		if (!handled_now)
			break;
		handled += handled_now;
	}

	return handled ? IRQ_HANDLED : IRQ_NONE;
}

struct omap_system_dma_plat_info *omap_get_plat_info(void)
{
	return p;
}
EXPORT_SYMBOL_GPL(omap_get_plat_info);

static int omap_system_dma_probe(struct platform_device *pdev)
{
	int ch, ret = 0;
	int dma_irq;
	char irq_name[4];

	p = pdev->dev.platform_data;
	if (!p) {
		dev_err(&pdev->dev,
			"%s: System DMA initialized without platform data\n",
			__func__);
		return -EINVAL;
	}

	d			= p->dma_attr;
	errata			= p->errata;

	if ((d->dev_caps & RESERVE_CHANNEL) && omap_dma_reserve_channels
			&& (omap_dma_reserve_channels < d->lch_count))
		d->lch_count	= omap_dma_reserve_channels;

	dma_lch_count		= d->lch_count;
	dma_chan_count		= dma_lch_count;
	enable_1510_mode	= d->dev_caps & ENABLE_1510_MODE;

	dma_chan = devm_kcalloc(&pdev->dev, dma_lch_count,
				sizeof(*dma_chan), GFP_KERNEL);
	if (!dma_chan)
		return -ENOMEM;

	for (ch = 0; ch < dma_chan_count; ch++) {
		omap_clear_dma(ch);

		dma_chan[ch].dev_id = -1;
		dma_chan[ch].next_lch = -1;

		if (ch >= 6 && enable_1510_mode)
			continue;

		/*
		 * request_irq() doesn't like dev_id (ie. ch) being
		 * zero, so we have to kludge around this.
		 */
		sprintf(&irq_name[0], "%d", ch);
		dma_irq = platform_get_irq_byname(pdev, irq_name);

		if (dma_irq < 0) {
			ret = dma_irq;
			goto exit_dma_irq_fail;
		}

		/* INT_DMA_LCD is handled in lcd_dma.c */
		if (dma_irq == INT_DMA_LCD)
			continue;

		ret = request_irq(dma_irq,
				omap1_dma_irq_handler, 0, "DMA",
				(void *) (ch + 1));
		if (ret != 0)
			goto exit_dma_irq_fail;
	}

	/* reserve dma channels 0 and 1 in high security devices on 34xx */
	if (d->dev_caps & HS_CHANNELS_RESERVED) {
		pr_info("Reserving DMA channels 0 and 1 for HS ROM code\n");
		dma_chan[0].dev_id = 0;
		dma_chan[1].dev_id = 1;
	}
	p->show_dma_caps();
	return 0;

exit_dma_irq_fail:
	return ret;
}

static int omap_system_dma_remove(struct platform_device *pdev)
{
	int dma_irq, irq_rel = 0;

	for ( ; irq_rel < dma_chan_count; irq_rel++) {
		dma_irq = platform_get_irq(pdev, irq_rel);
		free_irq(dma_irq, (void *)(irq_rel + 1));
	}

	return 0;
}

static struct platform_driver omap_system_dma_driver = {
	.probe		= omap_system_dma_probe,
	.remove		= omap_system_dma_remove,
	.driver		= {
		.name	= "omap_dma_system"
	},
};

static int __init omap_system_dma_init(void)
{
	return platform_driver_register(&omap_system_dma_driver);
}
arch_initcall(omap_system_dma_init);

static void __exit omap_system_dma_exit(void)
{
	platform_driver_unregister(&omap_system_dma_driver);
}

MODULE_DESCRIPTION("OMAP SYSTEM DMA DRIVER");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Texas Instruments Inc");

/*
 * Reserve the omap SDMA channels using cmdline bootarg
 * "omap_dma_reserve_ch=". The valid range is 1 to 32
 */
static int __init omap_dma_cmdline_reserve_ch(char *str)
{
	if (get_option(&str, &omap_dma_reserve_channels) != 1)
		omap_dma_reserve_channels = 0;
	return 1;
}

__setup("omap_dma_reserve_ch=", omap_dma_cmdline_reserve_ch);


code:
/*
 * Hardware definitions for TI OMAP1510 processor.
 *
 * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef __ASM_ARCH_OMAP15XX_H
#define __ASM_ARCH_OMAP15XX_H

/*
 * ----------------------------------------------------------------------------
 * Base addresses
 * ----------------------------------------------------------------------------
 */

/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */

#define OMAP1510_DSP_BASE	0xE0000000
#define OMAP1510_DSP_SIZE	0x28000
#define OMAP1510_DSP_START	0xE0000000

#define OMAP1510_DSPREG_BASE	0xE1000000
#define OMAP1510_DSPREG_SIZE	SZ_128K
#define OMAP1510_DSPREG_START	0xE1000000

#define OMAP1510_DSP_MMU_BASE	(0xfffed200)

/*
 * ---------------------------------------------------------------------------
 *  OMAP-1510 FPGA
 * ---------------------------------------------------------------------------
 */
#define OMAP1510_FPGA_BASE		0xE8000000		/* VA */
#define OMAP1510_FPGA_SIZE		SZ_4K
#define OMAP1510_FPGA_START		0x08000000		/* PA */

/* Revision */
#define OMAP1510_FPGA_REV_LOW			IOMEM(OMAP1510_FPGA_BASE + 0x0)
#define OMAP1510_FPGA_REV_HIGH			IOMEM(OMAP1510_FPGA_BASE + 0x1)
#define OMAP1510_FPGA_LCD_PANEL_CONTROL		IOMEM(OMAP1510_FPGA_BASE + 0x2)
#define OMAP1510_FPGA_LED_DIGIT			IOMEM(OMAP1510_FPGA_BASE + 0x3)
#define INNOVATOR_FPGA_HID_SPI			IOMEM(OMAP1510_FPGA_BASE + 0x4)
#define OMAP1510_FPGA_POWER			IOMEM(OMAP1510_FPGA_BASE + 0x5)

/* Interrupt status */
#define OMAP1510_FPGA_ISR_LO			IOMEM(OMAP1510_FPGA_BASE + 0x6)
#define OMAP1510_FPGA_ISR_HI			IOMEM(OMAP1510_FPGA_BASE + 0x7)

/* Interrupt mask */
#define OMAP1510_FPGA_IMR_LO			IOMEM(OMAP1510_FPGA_BASE + 0x8)
#define OMAP1510_FPGA_IMR_HI			IOMEM(OMAP1510_FPGA_BASE + 0x9)

/* Reset registers */
#define OMAP1510_FPGA_HOST_RESET		IOMEM(OMAP1510_FPGA_BASE + 0xa)
#define OMAP1510_FPGA_RST			IOMEM(OMAP1510_FPGA_BASE + 0xb)

#define OMAP1510_FPGA_AUDIO			IOMEM(OMAP1510_FPGA_BASE + 0xc)
#define OMAP1510_FPGA_DIP			IOMEM(OMAP1510_FPGA_BASE + 0xe)
#define OMAP1510_FPGA_FPGA_IO			IOMEM(OMAP1510_FPGA_BASE + 0xf)
#define OMAP1510_FPGA_UART1			IOMEM(OMAP1510_FPGA_BASE + 0x14)
#define OMAP1510_FPGA_UART2			IOMEM(OMAP1510_FPGA_BASE + 0x15)
#define OMAP1510_FPGA_OMAP1510_STATUS		IOMEM(OMAP1510_FPGA_BASE + 0x16)
#define OMAP1510_FPGA_BOARD_REV			IOMEM(OMAP1510_FPGA_BASE + 0x18)
#define INNOVATOR_FPGA_CAM_USB_CONTROL		IOMEM(OMAP1510_FPGA_BASE + 0x20c)
#define OMAP1510P1_PPT_DATA			IOMEM(OMAP1510_FPGA_BASE + 0x100)
#define OMAP1510P1_PPT_STATUS			IOMEM(OMAP1510_FPGA_BASE + 0x101)
#define OMAP1510P1_PPT_CONTROL			IOMEM(OMAP1510_FPGA_BASE + 0x102)

#define OMAP1510_FPGA_TOUCHSCREEN		IOMEM(OMAP1510_FPGA_BASE + 0x204)

#define INNOVATOR_FPGA_INFO			IOMEM(OMAP1510_FPGA_BASE + 0x205)
#define INNOVATOR_FPGA_LCD_BRIGHT_LO		IOMEM(OMAP1510_FPGA_BASE + 0x206)
#define INNOVATOR_FPGA_LCD_BRIGHT_HI		IOMEM(OMAP1510_FPGA_BASE + 0x207)
#define INNOVATOR_FPGA_LED_GRN_LO		IOMEM(OMAP1510_FPGA_BASE + 0x208)
#define INNOVATOR_FPGA_LED_GRN_HI		IOMEM(OMAP1510_FPGA_BASE + 0x209)
#define INNOVATOR_FPGA_LED_RED_LO		IOMEM(OMAP1510_FPGA_BASE + 0x20a)
#define INNOVATOR_FPGA_LED_RED_HI		IOMEM(OMAP1510_FPGA_BASE + 0x20b)
#define INNOVATOR_FPGA_EXP_CONTROL		IOMEM(OMAP1510_FPGA_BASE + 0x20d)
#define INNOVATOR_FPGA_ISR2			IOMEM(OMAP1510_FPGA_BASE + 0x20e)
#define INNOVATOR_FPGA_IMR2			IOMEM(OMAP1510_FPGA_BASE + 0x210)

#define OMAP1510_FPGA_ETHR_START		(OMAP1510_FPGA_START + 0x300)

/*
 * Power up Giga UART driver, turn on HID clock.
 * Turn off BT power, since we're not using it and it
 * draws power.
 */
#define OMAP1510_FPGA_RESET_VALUE		0x42

#define OMAP1510_FPGA_PCR_IF_PD0		(1 << 7)
#define OMAP1510_FPGA_PCR_COM2_EN		(1 << 6)
#define OMAP1510_FPGA_PCR_COM1_EN		(1 << 5)
#define OMAP1510_FPGA_PCR_EXP_PD0		(1 << 4)
#define OMAP1510_FPGA_PCR_EXP_PD1		(1 << 3)
#define OMAP1510_FPGA_PCR_48MHZ_CLK		(1 << 2)
#define OMAP1510_FPGA_PCR_4MHZ_CLK		(1 << 1)
#define OMAP1510_FPGA_PCR_RSRVD_BIT0		(1 << 0)

/*
 * Innovator/OMAP1510 FPGA HID register bit definitions
 */
#define OMAP1510_FPGA_HID_SCLK	(1<<0)	/* output */
#define OMAP1510_FPGA_HID_MOSI	(1<<1)	/* output */
#define OMAP1510_FPGA_HID_nSS	(1<<2)	/* output 0/1 chip idle/select */
#define OMAP1510_FPGA_HID_nHSUS	(1<<3)	/* output 0/1 host active/suspended */
#define OMAP1510_FPGA_HID_MISO	(1<<4)	/* input */
#define OMAP1510_FPGA_HID_ATN	(1<<5)	/* input  0/1 chip idle/ATN */
#define OMAP1510_FPGA_HID_rsrvd	(1<<6)
#define OMAP1510_FPGA_HID_RESETn (1<<7)	/* output - 0/1 USAR reset/run */

/* The FPGA IRQ is cascaded through GPIO_13 */
#define OMAP1510_INT_FPGA		(IH_GPIO_BASE + 13)

/* IRQ Numbers for interrupts muxed through the FPGA */
#define OMAP1510_INT_FPGA_ATN		(OMAP_FPGA_IRQ_BASE + 0)
#define OMAP1510_INT_FPGA_ACK		(OMAP_FPGA_IRQ_BASE + 1)
#define OMAP1510_INT_FPGA2		(OMAP_FPGA_IRQ_BASE + 2)
#define OMAP1510_INT_FPGA3		(OMAP_FPGA_IRQ_BASE + 3)
#define OMAP1510_INT_FPGA4		(OMAP_FPGA_IRQ_BASE + 4)
#define OMAP1510_INT_FPGA5		(OMAP_FPGA_IRQ_BASE + 5)
#define OMAP1510_INT_FPGA6		(OMAP_FPGA_IRQ_BASE + 6)
#define OMAP1510_INT_FPGA7		(OMAP_FPGA_IRQ_BASE + 7)
#define OMAP1510_INT_FPGA8		(OMAP_FPGA_IRQ_BASE + 8)
#define OMAP1510_INT_FPGA9		(OMAP_FPGA_IRQ_BASE + 9)
#define OMAP1510_INT_FPGA10		(OMAP_FPGA_IRQ_BASE + 10)
#define OMAP1510_INT_FPGA11		(OMAP_FPGA_IRQ_BASE + 11)
#define OMAP1510_INT_FPGA12		(OMAP_FPGA_IRQ_BASE + 12)
#define OMAP1510_INT_ETHER		(OMAP_FPGA_IRQ_BASE + 13)
#define OMAP1510_INT_FPGAUART1		(OMAP_FPGA_IRQ_BASE + 14)
#define OMAP1510_INT_FPGAUART2		(OMAP_FPGA_IRQ_BASE + 15)
#define OMAP1510_INT_FPGA_TS		(OMAP_FPGA_IRQ_BASE + 16)
#define OMAP1510_INT_FPGA17		(OMAP_FPGA_IRQ_BASE + 17)
#define OMAP1510_INT_FPGA_CAM		(OMAP_FPGA_IRQ_BASE + 18)
#define OMAP1510_INT_FPGA_RTC_A		(OMAP_FPGA_IRQ_BASE + 19)
#define OMAP1510_INT_FPGA_RTC_B		(OMAP_FPGA_IRQ_BASE + 20)
#define OMAP1510_INT_FPGA_CD		(OMAP_FPGA_IRQ_BASE + 21)
#define OMAP1510_INT_FPGA22		(OMAP_FPGA_IRQ_BASE + 22)
#define OMAP1510_INT_FPGA23		(OMAP_FPGA_IRQ_BASE + 23)

#endif /*  __ASM_ARCH_OMAP15XX_H */

repo_name: angery/linux


code:
/*
 * Hardware definitions for TI OMAP1610/5912/1710 processors.
 *
 * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef __ASM_ARCH_OMAP16XX_H
#define __ASM_ARCH_OMAP16XX_H

/*
 * ----------------------------------------------------------------------------
 * Base addresses
 * ----------------------------------------------------------------------------
 */

/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */

#define OMAP16XX_DSP_BASE	0xE0000000
#define OMAP16XX_DSP_SIZE	0x28000
#define OMAP16XX_DSP_START	0xE0000000

#define OMAP16XX_DSPREG_BASE	0xE1000000
#define OMAP16XX_DSPREG_SIZE	SZ_128K
#define OMAP16XX_DSPREG_START	0xE1000000

#define OMAP16XX_SEC_BASE	0xFFFE4000
#define OMAP16XX_SEC_DES	(OMAP16XX_SEC_BASE + 0x0000)
#define OMAP16XX_SEC_SHA1MD5	(OMAP16XX_SEC_BASE + 0x0800)
#define OMAP16XX_SEC_RNG	(OMAP16XX_SEC_BASE + 0x1000)

/*
 * ---------------------------------------------------------------------------
 * Interrupts
 * ---------------------------------------------------------------------------
 */
#define OMAP_IH2_0_BASE		(0xfffe0000)
#define OMAP_IH2_1_BASE		(0xfffe0100)
#define OMAP_IH2_2_BASE		(0xfffe0200)
#define OMAP_IH2_3_BASE		(0xfffe0300)

#define OMAP_IH2_0_ITR		(OMAP_IH2_0_BASE + 0x00)
#define OMAP_IH2_0_MIR		(OMAP_IH2_0_BASE + 0x04)
#define OMAP_IH2_0_SIR_IRQ	(OMAP_IH2_0_BASE + 0x10)
#define OMAP_IH2_0_SIR_FIQ	(OMAP_IH2_0_BASE + 0x14)
#define OMAP_IH2_0_CONTROL	(OMAP_IH2_0_BASE + 0x18)
#define OMAP_IH2_0_ILR0		(OMAP_IH2_0_BASE + 0x1c)
#define OMAP_IH2_0_ISR		(OMAP_IH2_0_BASE + 0x9c)

#define OMAP_IH2_1_ITR		(OMAP_IH2_1_BASE + 0x00)
#define OMAP_IH2_1_MIR		(OMAP_IH2_1_BASE + 0x04)
#define OMAP_IH2_1_SIR_IRQ	(OMAP_IH2_1_BASE + 0x10)
#define OMAP_IH2_1_SIR_FIQ	(OMAP_IH2_1_BASE + 0x14)
#define OMAP_IH2_1_CONTROL	(OMAP_IH2_1_BASE + 0x18)
#define OMAP_IH2_1_ILR1		(OMAP_IH2_1_BASE + 0x1c)
#define OMAP_IH2_1_ISR		(OMAP_IH2_1_BASE + 0x9c)

#define OMAP_IH2_2_ITR		(OMAP_IH2_2_BASE + 0x00)
#define OMAP_IH2_2_MIR		(OMAP_IH2_2_BASE + 0x04)
#define OMAP_IH2_2_SIR_IRQ	(OMAP_IH2_2_BASE + 0x10)
#define OMAP_IH2_2_SIR_FIQ	(OMAP_IH2_2_BASE + 0x14)
#define OMAP_IH2_2_CONTROL	(OMAP_IH2_2_BASE + 0x18)
#define OMAP_IH2_2_ILR2		(OMAP_IH2_2_BASE + 0x1c)
#define OMAP_IH2_2_ISR		(OMAP_IH2_2_BASE + 0x9c)

#define OMAP_IH2_3_ITR		(OMAP_IH2_3_BASE + 0x00)
#define OMAP_IH2_3_MIR		(OMAP_IH2_3_BASE + 0x04)
#define OMAP_IH2_3_SIR_IRQ	(OMAP_IH2_3_BASE + 0x10)
#define OMAP_IH2_3_SIR_FIQ	(OMAP_IH2_3_BASE + 0x14)
#define OMAP_IH2_3_CONTROL	(OMAP_IH2_3_BASE + 0x18)
#define OMAP_IH2_3_ILR3		(OMAP_IH2_3_BASE + 0x1c)
#define OMAP_IH2_3_ISR		(OMAP_IH2_3_BASE + 0x9c)

/*
 * ----------------------------------------------------------------------------
 * Clocks
 * ----------------------------------------------------------------------------
 */
#define OMAP16XX_ARM_IDLECT3	(CLKGEN_REG_BASE + 0x24)

/*
 * ----------------------------------------------------------------------------
 * Pin configuration registers
 * ----------------------------------------------------------------------------
 */
#define OMAP16XX_CONF_VOLTAGE_VDDSHV6	(1 << 8)
#define OMAP16XX_CONF_VOLTAGE_VDDSHV7	(1 << 9)
#define OMAP16XX_CONF_VOLTAGE_VDDSHV8	(1 << 10)
#define OMAP16XX_CONF_VOLTAGE_VDDSHV9	(1 << 11)
#define OMAP16XX_SUBLVDS_CONF_VALID	(1 << 13)

/*
 * ----------------------------------------------------------------------------
 * System control registers
 * ----------------------------------------------------------------------------
 */
#define OMAP1610_RESET_CONTROL  0xfffe1140

/*
 * ---------------------------------------------------------------------------
 * TIPB bus interface
 * ---------------------------------------------------------------------------
 */
#define TIPB_SWITCH_BASE		 (0xfffbc800)
#define OMAP16XX_MMCSD2_SSW_MPU_CONF	(TIPB_SWITCH_BASE + 0x160)

/* UART3 Registers Mapping through MPU bus */
#define UART3_RHR               (OMAP1_UART3_BASE + 0)
#define UART3_THR               (OMAP1_UART3_BASE + 0)
#define UART3_DLL               (OMAP1_UART3_BASE + 0)
#define UART3_IER               (OMAP1_UART3_BASE + 4)
#define UART3_DLH               (OMAP1_UART3_BASE + 4)
#define UART3_IIR               (OMAP1_UART3_BASE + 8)
#define UART3_FCR               (OMAP1_UART3_BASE + 8)
#define UART3_EFR               (OMAP1_UART3_BASE + 8)
#define UART3_LCR               (OMAP1_UART3_BASE + 0x0C)
#define UART3_MCR               (OMAP1_UART3_BASE + 0x10)
#define UART3_XON1_ADDR1        (OMAP1_UART3_BASE + 0x10)
#define UART3_XON2_ADDR2        (OMAP1_UART3_BASE + 0x14)
#define UART3_LSR               (OMAP1_UART3_BASE + 0x14)
#define UART3_TCR               (OMAP1_UART3_BASE + 0x18)
#define UART3_MSR               (OMAP1_UART3_BASE + 0x18)
#define UART3_XOFF1             (OMAP1_UART3_BASE + 0x18)
#define UART3_XOFF2             (OMAP1_UART3_BASE + 0x1C)
#define UART3_SPR               (OMAP1_UART3_BASE + 0x1C)
#define UART3_TLR               (OMAP1_UART3_BASE + 0x1C)
#define UART3_MDR1              (OMAP1_UART3_BASE + 0x20)
#define UART3_MDR2              (OMAP1_UART3_BASE + 0x24)
#define UART3_SFLSR             (OMAP1_UART3_BASE + 0x28)
#define UART3_TXFLL             (OMAP1_UART3_BASE + 0x28)
#define UART3_RESUME            (OMAP1_UART3_BASE + 0x2C)
#define UART3_TXFLH             (OMAP1_UART3_BASE + 0x2C)
#define UART3_SFREGL            (OMAP1_UART3_BASE + 0x30)
#define UART3_RXFLL             (OMAP1_UART3_BASE + 0x30)
#define UART3_SFREGH            (OMAP1_UART3_BASE + 0x34)
#define UART3_RXFLH             (OMAP1_UART3_BASE + 0x34)
#define UART3_BLR               (OMAP1_UART3_BASE + 0x38)
#define UART3_ACREG             (OMAP1_UART3_BASE + 0x3C)
#define UART3_DIV16             (OMAP1_UART3_BASE + 0x3C)
#define UART3_SCR               (OMAP1_UART3_BASE + 0x40)
#define UART3_SSR               (OMAP1_UART3_BASE + 0x44)
#define UART3_EBLR              (OMAP1_UART3_BASE + 0x48)
#define UART3_OSC_12M_SEL       (OMAP1_UART3_BASE + 0x4C)
#define UART3_MVR               (OMAP1_UART3_BASE + 0x50)

/*
 * ---------------------------------------------------------------------------
 * Watchdog timer
 * ---------------------------------------------------------------------------
 */

/* 32-bit Watchdog timer in OMAP 16XX */
#define OMAP_16XX_WATCHDOG_BASE        (0xfffeb000)
#define OMAP_16XX_WIDR         (OMAP_16XX_WATCHDOG_BASE + 0x00)
#define OMAP_16XX_WD_SYSCONFIG (OMAP_16XX_WATCHDOG_BASE + 0x10)
#define OMAP_16XX_WD_SYSSTATUS (OMAP_16XX_WATCHDOG_BASE + 0x14)
#define OMAP_16XX_WCLR         (OMAP_16XX_WATCHDOG_BASE + 0x24)
#define OMAP_16XX_WCRR         (OMAP_16XX_WATCHDOG_BASE + 0x28)
#define OMAP_16XX_WLDR         (OMAP_16XX_WATCHDOG_BASE + 0x2c)
#define OMAP_16XX_WTGR         (OMAP_16XX_WATCHDOG_BASE + 0x30)
#define OMAP_16XX_WWPS         (OMAP_16XX_WATCHDOG_BASE + 0x34)
#define OMAP_16XX_WSPR         (OMAP_16XX_WATCHDOG_BASE + 0x48)

#define WCLR_PRE_SHIFT         5
#define WCLR_PTV_SHIFT         2

#define WWPS_W_PEND_WSPR       (1 << 4)
#define WWPS_W_PEND_WTGR       (1 << 3)
#define WWPS_W_PEND_WLDR       (1 << 2)
#define WWPS_W_PEND_WCRR       (1 << 1)
#define WWPS_W_PEND_WCLR       (1 << 0)

#define WSPR_ENABLE_0          (0x0000bbbb)
#define WSPR_ENABLE_1          (0x00004444)
#define WSPR_DISABLE_0         (0x0000aaaa)
#define WSPR_DISABLE_1         (0x00005555)

#define OMAP16XX_DSP_MMU_BASE	(0xfffed200)
#define OMAP16XX_MAILBOX_BASE	(0xfffcf000)

#endif /*  __ASM_ARCH_OMAP16XX_H */


code:
/*
 * Hardware definitions for TI OMAP7XX processor.
 *
 * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.com>
 * Adapted for omap850 by Zebediah C. McClure <zmc@lurian.net>
 * Adapted for omap7xx by Alistair Buxton <a.j.buxton@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the  GNU General Public License along
 * with this program; if not, write  to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef __ASM_ARCH_OMAP7XX_H
#define __ASM_ARCH_OMAP7XX_H

/*
 * ----------------------------------------------------------------------------
 * Base addresses
 * ----------------------------------------------------------------------------
 */

/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */

#define OMAP7XX_DSP_BASE	0xE0000000
#define OMAP7XX_DSP_SIZE	0x50000
#define OMAP7XX_DSP_START	0xE0000000

#define OMAP7XX_DSPREG_BASE	0xE1000000
#define OMAP7XX_DSPREG_SIZE	SZ_128K
#define OMAP7XX_DSPREG_START	0xE1000000

#define OMAP7XX_SPI1_BASE	0xfffc0800
#define OMAP7XX_SPI2_BASE	0xfffc1000

/*
 * ----------------------------------------------------------------------------
 * OMAP7XX specific configuration registers
 * ----------------------------------------------------------------------------
 */
#define OMAP7XX_CONFIG_BASE	0xfffe1000
#define OMAP7XX_IO_CONF_0	0xfffe1070
#define OMAP7XX_IO_CONF_1	0xfffe1074
#define OMAP7XX_IO_CONF_2	0xfffe1078
#define OMAP7XX_IO_CONF_3	0xfffe107c
#define OMAP7XX_IO_CONF_4	0xfffe1080
#define OMAP7XX_IO_CONF_5	0xfffe1084
#define OMAP7XX_IO_CONF_6	0xfffe1088
#define OMAP7XX_IO_CONF_7	0xfffe108c
#define OMAP7XX_IO_CONF_8	0xfffe1090
#define OMAP7XX_IO_CONF_9	0xfffe1094
#define OMAP7XX_IO_CONF_10	0xfffe1098
#define OMAP7XX_IO_CONF_11	0xfffe109c
#define OMAP7XX_IO_CONF_12	0xfffe10a0
#define OMAP7XX_IO_CONF_13	0xfffe10a4

#define OMAP7XX_MODE_1		0xfffe1010
#define OMAP7XX_MODE_2		0xfffe1014

/* CSMI specials: in terms of base + offset */
#define OMAP7XX_MODE2_OFFSET	0x14

/*
 * ----------------------------------------------------------------------------
 * OMAP7XX traffic controller configuration registers
 * ----------------------------------------------------------------------------
 */
#define OMAP7XX_FLASH_CFG_0	0xfffecc10
#define OMAP7XX_FLASH_ACFG_0	0xfffecc50
#define OMAP7XX_FLASH_CFG_1	0xfffecc14
#define OMAP7XX_FLASH_ACFG_1	0xfffecc54

/*
 * ----------------------------------------------------------------------------
 * OMAP7XX DSP control registers
 * ----------------------------------------------------------------------------
 */
#define OMAP7XX_ICR_BASE	0xfffbb800
#define OMAP7XX_DSP_M_CTL	0xfffbb804
#define OMAP7XX_DSP_MMU_BASE	0xfffed200

/*
 * ----------------------------------------------------------------------------
 * OMAP7XX PCC_UPLD configuration registers
 * ----------------------------------------------------------------------------
 */
#define OMAP7XX_PCC_UPLD_CTRL_BASE	(0xfffe0900)
#define OMAP7XX_PCC_UPLD_CTRL		(OMAP7XX_PCC_UPLD_CTRL_BASE + 0x00)

#endif /*  __ASM_ARCH_OMAP7XX_H */


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mach-omap1/opp.h
 *
 *  Copyright (C) 2004 - 2005 Nokia corporation
 *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
 */

#ifndef __ARCH_ARM_MACH_OMAP1_OPP_H
#define __ARCH_ARM_MACH_OMAP1_OPP_H

#include <linux/types.h>

struct mpu_rate {
	unsigned long		rate;
	unsigned long		xtal;
	unsigned long		pll_rate;
	__u16			ckctl_val;
	__u16			dpllctl_val;
	u32			flags;
};

extern struct mpu_rate omap1_rate_table[];

#endif


code:
/*
 * linux/arch/arm/mach-omap1/pm.c
 *
 * OMAP Power Management Routines
 *
 * Original code for the SA11x0:
 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
 *
 * Modified for the PXA250 by Nicolas Pitre:
 * Copyright (c) 2002 Monta Vista Software, Inc.
 *
 * Modified for the OMAP1510 by David Singleton:
 * Copyright (c) 2002 Monta Vista Software, Inc.
 *
 * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/suspend.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/atomic.h>
#include <linux/cpu.h>

#include <asm/fncpy.h>
#include <asm/system_misc.h>
#include <asm/irq.h>
#include <asm/mach/time.h>
#include <asm/mach/irq.h>

#include <linux/soc/ti/omap1-io.h>
#include "tc.h"
#include <linux/omap-dma.h>
#include <clocksource/timer-ti-dm.h>

#include "hardware.h"
#include "mux.h"
#include "irqs.h"
#include "iomap.h"
#include "clock.h"
#include "pm.h"
#include "soc.h"
#include "sram.h"

static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
static unsigned int mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_SIZE];
static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];

static unsigned short enable_dyn_sleep;

static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
			 char *buf)
{
	return sprintf(buf, "%hu\n", enable_dyn_sleep);
}

static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
			  const char * buf, size_t n)
{
	unsigned short value;
	if (sscanf(buf, "%hu", &value) != 1 ||
	    (value != 0 && value != 1) ||
	    (value != 0 && !IS_ENABLED(CONFIG_OMAP_32K_TIMER))) {
		pr_err("idle_sleep_store: Invalid value\n");
		return -EINVAL;
	}
	enable_dyn_sleep = value;
	return n;
}

static struct kobj_attribute sleep_while_idle_attr =
	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);

static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;

/*
 * Let's power down on idle, but only if we are really
 * idle, because once we start down the path of
 * going idle we continue to do idle even if we get
 * a clock tick interrupt . .
 */
void omap1_pm_idle(void)
{
	extern __u32 arm_idlect1_mask;
	__u32 use_idlect1 = arm_idlect1_mask;

	local_fiq_disable();

#if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
	use_idlect1 = use_idlect1 & ~(1 << 9);
#endif

#ifdef CONFIG_OMAP_DM_TIMER
	use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
#endif

	if (omap_dma_running())
		use_idlect1 &= ~(1 << 6);

	/*
	 * We should be able to remove the do_sleep variable and multiple
	 * tests above as soon as drivers, timer and DMA code have been fixed.
	 * Even the sleep block count should become obsolete.
	 */
	if ((use_idlect1 != ~0) || !enable_dyn_sleep) {

		__u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
		if (cpu_is_omap15xx())
			use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
		else
			use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
		omap_writel(use_idlect1, ARM_IDLECT1);
		__asm__ volatile ("mcr	p15, 0, r0, c7, c0, 4");
		omap_writel(saved_idlect1, ARM_IDLECT1);

		local_fiq_enable();
		return;
	}
	omap_sram_suspend(omap_readl(ARM_IDLECT1),
			  omap_readl(ARM_IDLECT2));

	local_fiq_enable();
}

/*
 * Configuration of the wakeup event is board specific. For the
 * moment we put it into this helper function. Later it may move
 * to board specific files.
 */
static void omap_pm_wakeup_setup(void)
{
	u32 level1_wake = 0;
	u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);

	/*
	 * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
	 * and the L2 wakeup interrupts: keypad and UART2. Note that the
	 * drivers must still separately call omap_set_gpio_wakeup() to
	 * wake up to a GPIO interrupt.
	 */
	if (cpu_is_omap7xx())
		level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) |
			OMAP_IRQ_BIT(INT_7XX_IH2_IRQ);
	else if (cpu_is_omap15xx())
		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
			OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
	else if (cpu_is_omap16xx())
		level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
			OMAP_IRQ_BIT(INT_1610_IH2_IRQ);

	omap_writel(~level1_wake, OMAP_IH1_MIR);

	if (cpu_is_omap7xx()) {
		omap_writel(~level2_wake, OMAP_IH2_0_MIR);
		omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) |
				OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)),
				OMAP_IH2_1_MIR);
	} else if (cpu_is_omap15xx()) {
		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
		omap_writel(~level2_wake,  OMAP_IH2_MIR);
	} else if (cpu_is_omap16xx()) {
		level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
		omap_writel(~level2_wake, OMAP_IH2_0_MIR);

		/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
		omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
			    OMAP_IH2_1_MIR);
		omap_writel(~0x0, OMAP_IH2_2_MIR);
		omap_writel(~0x0, OMAP_IH2_3_MIR);
	}

	/*  New IRQ agreement, recalculate in cascade order */
	omap_writel(1, OMAP_IH2_CONTROL);
	omap_writel(1, OMAP_IH1_CONTROL);
}

#define EN_DSPCK	13	/* ARM_CKCTL */
#define EN_APICK	6	/* ARM_IDLECT2 */
#define DSP_EN		1	/* ARM_RSTCT1 */

void omap1_pm_suspend(void)
{
	unsigned long arg0 = 0, arg1 = 0;

	printk(KERN_INFO "PM: OMAP%x is trying to enter deep sleep...\n",
		omap_rev());

	omap_serial_wake_trigger(1);

	if (!cpu_is_omap15xx())
		omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);

	/*
	 * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
	 */

	local_irq_disable();
	local_fiq_disable();

	/*
	 * Step 2: save registers
	 *
	 * The omap is a strange/beautiful device. The caches, memory
	 * and register state are preserved across power saves.
	 * We have to save and restore very little register state to
	 * idle the omap.
         *
	 * Save interrupt, MPUI, ARM and UPLD control registers.
	 */

	if (cpu_is_omap7xx()) {
		MPUI7XX_SAVE(OMAP_IH1_MIR);
		MPUI7XX_SAVE(OMAP_IH2_0_MIR);
		MPUI7XX_SAVE(OMAP_IH2_1_MIR);
		MPUI7XX_SAVE(MPUI_CTRL);
		MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
		MPUI7XX_SAVE(EMIFS_CONFIG);
		MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);

	} else if (cpu_is_omap15xx()) {
		MPUI1510_SAVE(OMAP_IH1_MIR);
		MPUI1510_SAVE(OMAP_IH2_MIR);
		MPUI1510_SAVE(MPUI_CTRL);
		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
		MPUI1510_SAVE(EMIFS_CONFIG);
		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
	} else if (cpu_is_omap16xx()) {
		MPUI1610_SAVE(OMAP_IH1_MIR);
		MPUI1610_SAVE(OMAP_IH2_0_MIR);
		MPUI1610_SAVE(OMAP_IH2_1_MIR);
		MPUI1610_SAVE(OMAP_IH2_2_MIR);
		MPUI1610_SAVE(OMAP_IH2_3_MIR);
		MPUI1610_SAVE(MPUI_CTRL);
		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
		MPUI1610_SAVE(EMIFS_CONFIG);
		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
	}

	ARM_SAVE(ARM_CKCTL);
	ARM_SAVE(ARM_IDLECT1);
	ARM_SAVE(ARM_IDLECT2);
	if (!(cpu_is_omap15xx()))
		ARM_SAVE(ARM_IDLECT3);
	ARM_SAVE(ARM_EWUPCT);
	ARM_SAVE(ARM_RSTCT1);
	ARM_SAVE(ARM_RSTCT2);
	ARM_SAVE(ARM_SYSST);
	ULPD_SAVE(ULPD_CLOCK_CTRL);
	ULPD_SAVE(ULPD_STATUS_REQ);

	/* (Step 3 removed - we now allow deep sleep by default) */

	/*
	 * Step 4: OMAP DSP Shutdown
	 */

	/* stop DSP */
	omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);

		/* shut down dsp_ck */
	if (!cpu_is_omap7xx())
		omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);

	/* temporarily enabling api_ck to access DSP registers */
	omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);

	/* save DSP registers */
	DSP_SAVE(DSP_IDLECT2);

	/* Stop all DSP domain clocks */
	__raw_writew(0, DSP_IDLECT2);

	/*
	 * Step 5: Wakeup Event Setup
	 */

	omap_pm_wakeup_setup();

	/*
	 * Step 6: ARM and Traffic controller shutdown
	 */

	/* disable ARM watchdog */
	omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
	omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);

	/*
	 * Step 6b: ARM and Traffic controller shutdown
	 *
	 * Step 6 continues here. Prepare jump to power management
	 * assembly code in internal SRAM.
	 *
	 * Since the omap_cpu_suspend routine has been copied to
	 * SRAM, we'll do an indirect procedure call to it and pass the
	 * contents of arm_idlect1 and arm_idlect2 so it can restore
	 * them when it wakes up and it will return.
	 */

	arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
	arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];

	/*
	 * Step 6c: ARM and Traffic controller shutdown
	 *
	 * Jump to assembly code. The processor will stay there
	 * until wake up.
	 */
	omap_sram_suspend(arg0, arg1);

	/*
	 * If we are here, processor is woken up!
	 */

	/*
	 * Restore DSP clocks
	 */

	/* again temporarily enabling api_ck to access DSP registers */
	omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);

	/* Restore DSP domain clocks */
	DSP_RESTORE(DSP_IDLECT2);

	/*
	 * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
	 */

	if (!(cpu_is_omap15xx()))
		ARM_RESTORE(ARM_IDLECT3);
	ARM_RESTORE(ARM_CKCTL);
	ARM_RESTORE(ARM_EWUPCT);
	ARM_RESTORE(ARM_RSTCT1);
	ARM_RESTORE(ARM_RSTCT2);
	ARM_RESTORE(ARM_SYSST);
	ULPD_RESTORE(ULPD_CLOCK_CTRL);
	ULPD_RESTORE(ULPD_STATUS_REQ);

	if (cpu_is_omap7xx()) {
		MPUI7XX_RESTORE(EMIFS_CONFIG);
		MPUI7XX_RESTORE(EMIFF_SDRAM_CONFIG);
		MPUI7XX_RESTORE(OMAP_IH1_MIR);
		MPUI7XX_RESTORE(OMAP_IH2_0_MIR);
		MPUI7XX_RESTORE(OMAP_IH2_1_MIR);
	} else if (cpu_is_omap15xx()) {
		MPUI1510_RESTORE(MPUI_CTRL);
		MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
		MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
		MPUI1510_RESTORE(EMIFS_CONFIG);
		MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
		MPUI1510_RESTORE(OMAP_IH1_MIR);
		MPUI1510_RESTORE(OMAP_IH2_MIR);
	} else if (cpu_is_omap16xx()) {
		MPUI1610_RESTORE(MPUI_CTRL);
		MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
		MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
		MPUI1610_RESTORE(EMIFS_CONFIG);
		MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);

		MPUI1610_RESTORE(OMAP_IH1_MIR);
		MPUI1610_RESTORE(OMAP_IH2_0_MIR);
		MPUI1610_RESTORE(OMAP_IH2_1_MIR);
		MPUI1610_RESTORE(OMAP_IH2_2_MIR);
		MPUI1610_RESTORE(OMAP_IH2_3_MIR);
	}

	if (!cpu_is_omap15xx())
		omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);

	/*
	 * Re-enable interrupts
	 */

	local_irq_enable();
	local_fiq_enable();

	omap_serial_wake_trigger(0);

	printk(KERN_INFO "PM: OMAP%x is re-starting from deep sleep...\n",
		omap_rev());
}

#ifdef CONFIG_DEBUG_FS
/*
 * Read system PM registers for debugging
 */
static int omap_pm_debug_show(struct seq_file *m, void *v)
{
	ARM_SAVE(ARM_CKCTL);
	ARM_SAVE(ARM_IDLECT1);
	ARM_SAVE(ARM_IDLECT2);
	if (!(cpu_is_omap15xx()))
		ARM_SAVE(ARM_IDLECT3);
	ARM_SAVE(ARM_EWUPCT);
	ARM_SAVE(ARM_RSTCT1);
	ARM_SAVE(ARM_RSTCT2);
	ARM_SAVE(ARM_SYSST);

	ULPD_SAVE(ULPD_IT_STATUS);
	ULPD_SAVE(ULPD_CLOCK_CTRL);
	ULPD_SAVE(ULPD_SOFT_REQ);
	ULPD_SAVE(ULPD_STATUS_REQ);
	ULPD_SAVE(ULPD_DPLL_CTRL);
	ULPD_SAVE(ULPD_POWER_CTRL);

	if (cpu_is_omap7xx()) {
		MPUI7XX_SAVE(MPUI_CTRL);
		MPUI7XX_SAVE(MPUI_DSP_STATUS);
		MPUI7XX_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI7XX_SAVE(MPUI_DSP_API_CONFIG);
		MPUI7XX_SAVE(EMIFF_SDRAM_CONFIG);
		MPUI7XX_SAVE(EMIFS_CONFIG);
	} else if (cpu_is_omap15xx()) {
		MPUI1510_SAVE(MPUI_CTRL);
		MPUI1510_SAVE(MPUI_DSP_STATUS);
		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
		MPUI1510_SAVE(EMIFS_CONFIG);
	} else if (cpu_is_omap16xx()) {
		MPUI1610_SAVE(MPUI_CTRL);
		MPUI1610_SAVE(MPUI_DSP_STATUS);
		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
		MPUI1610_SAVE(EMIFS_CONFIG);
	}

	seq_printf(m,
		   "ARM_CKCTL_REG:            0x%-8x     \n"
		   "ARM_IDLECT1_REG:          0x%-8x     \n"
		   "ARM_IDLECT2_REG:          0x%-8x     \n"
		   "ARM_IDLECT3_REG:	      0x%-8x     \n"
		   "ARM_EWUPCT_REG:           0x%-8x     \n"
		   "ARM_RSTCT1_REG:           0x%-8x     \n"
		   "ARM_RSTCT2_REG:           0x%-8x     \n"
		   "ARM_SYSST_REG:            0x%-8x     \n"
		   "ULPD_IT_STATUS_REG:       0x%-4x     \n"
		   "ULPD_CLOCK_CTRL_REG:      0x%-4x     \n"
		   "ULPD_SOFT_REQ_REG:        0x%-4x     \n"
		   "ULPD_DPLL_CTRL_REG:       0x%-4x     \n"
		   "ULPD_STATUS_REQ_REG:      0x%-4x     \n"
		   "ULPD_POWER_CTRL_REG:      0x%-4x     \n",
		   ARM_SHOW(ARM_CKCTL),
		   ARM_SHOW(ARM_IDLECT1),
		   ARM_SHOW(ARM_IDLECT2),
		   ARM_SHOW(ARM_IDLECT3),
		   ARM_SHOW(ARM_EWUPCT),
		   ARM_SHOW(ARM_RSTCT1),
		   ARM_SHOW(ARM_RSTCT2),
		   ARM_SHOW(ARM_SYSST),
		   ULPD_SHOW(ULPD_IT_STATUS),
		   ULPD_SHOW(ULPD_CLOCK_CTRL),
		   ULPD_SHOW(ULPD_SOFT_REQ),
		   ULPD_SHOW(ULPD_DPLL_CTRL),
		   ULPD_SHOW(ULPD_STATUS_REQ),
		   ULPD_SHOW(ULPD_POWER_CTRL));

	if (cpu_is_omap7xx()) {
		seq_printf(m,
			   "MPUI7XX_CTRL_REG	     0x%-8x \n"
			   "MPUI7XX_DSP_STATUS_REG:      0x%-8x \n"
			   "MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
			   "MPUI7XX_DSP_API_CONFIG_REG:  0x%-8x \n"
			   "MPUI7XX_SDRAM_CONFIG_REG:    0x%-8x \n"
			   "MPUI7XX_EMIFS_CONFIG_REG:    0x%-8x \n",
			   MPUI7XX_SHOW(MPUI_CTRL),
			   MPUI7XX_SHOW(MPUI_DSP_STATUS),
			   MPUI7XX_SHOW(MPUI_DSP_BOOT_CONFIG),
			   MPUI7XX_SHOW(MPUI_DSP_API_CONFIG),
			   MPUI7XX_SHOW(EMIFF_SDRAM_CONFIG),
			   MPUI7XX_SHOW(EMIFS_CONFIG));
	} else if (cpu_is_omap15xx()) {
		seq_printf(m,
			   "MPUI1510_CTRL_REG             0x%-8x \n"
			   "MPUI1510_DSP_STATUS_REG:      0x%-8x \n"
			   "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
			   "MPUI1510_DSP_API_CONFIG_REG:  0x%-8x \n"
			   "MPUI1510_SDRAM_CONFIG_REG:    0x%-8x \n"
			   "MPUI1510_EMIFS_CONFIG_REG:    0x%-8x \n",
			   MPUI1510_SHOW(MPUI_CTRL),
			   MPUI1510_SHOW(MPUI_DSP_STATUS),
			   MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
			   MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
			   MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
			   MPUI1510_SHOW(EMIFS_CONFIG));
	} else if (cpu_is_omap16xx()) {
		seq_printf(m,
			   "MPUI1610_CTRL_REG             0x%-8x \n"
			   "MPUI1610_DSP_STATUS_REG:      0x%-8x \n"
			   "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
			   "MPUI1610_DSP_API_CONFIG_REG:  0x%-8x \n"
			   "MPUI1610_SDRAM_CONFIG_REG:    0x%-8x \n"
			   "MPUI1610_EMIFS_CONFIG_REG:    0x%-8x \n",
			   MPUI1610_SHOW(MPUI_CTRL),
			   MPUI1610_SHOW(MPUI_DSP_STATUS),
			   MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
			   MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
			   MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
			   MPUI1610_SHOW(EMIFS_CONFIG));
	}

	return 0;
}

DEFINE_SHOW_ATTRIBUTE(omap_pm_debug);

static void omap_pm_init_debugfs(void)
{
	struct dentry *d;

	d = debugfs_create_dir("pm_debug", NULL);
	debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL,
			    &omap_pm_debug_fops);
}

#endif /* CONFIG_DEBUG_FS */

/*
 *	omap_pm_prepare - Do preliminary suspend work.
 *
 */
static int omap_pm_prepare(void)
{
	/* We cannot sleep in idle until we have resumed */
	cpu_idle_poll_ctrl(true);
	return 0;
}

/*
 *	omap_pm_enter - Actually enter a sleep state.
 *	@state:		State we're entering.
 *
 */

static int omap_pm_enter(suspend_state_t state)
{
	switch (state)
	{
	case PM_SUSPEND_MEM:
		omap1_pm_suspend();
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/**
 *	omap_pm_finish - Finish up suspend sequence.
 *
 *	This is called after we wake back up (or if entering the sleep state
 *	failed).
 */

static void omap_pm_finish(void)
{
	cpu_idle_poll_ctrl(false);
}

static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
{
	return IRQ_HANDLED;
}

static const struct platform_suspend_ops omap_pm_ops = {
	.prepare	= omap_pm_prepare,
	.enter		= omap_pm_enter,
	.finish		= omap_pm_finish,
	.valid		= suspend_valid_only_mem,
};

static int __init omap_pm_init(void)
{
	int error = 0;
	int irq;

	if (!cpu_class_is_omap1())
		return -ENODEV;

	pr_info("Power Management for TI OMAP.\n");

	if (!IS_ENABLED(CONFIG_OMAP_32K_TIMER))
		pr_info("OMAP1 PM: sleep states in idle disabled due to no 32KiHz timer\n");

	if (!IS_ENABLED(CONFIG_OMAP_DM_TIMER))
		pr_info("OMAP1 PM: sleep states in idle disabled due to no DMTIMER support\n");

	if (IS_ENABLED(CONFIG_OMAP_32K_TIMER) &&
	    IS_ENABLED(CONFIG_OMAP_DM_TIMER)) {
		/* OMAP16xx only */
		pr_info("OMAP1 PM: sleep states in idle enabled\n");
		enable_dyn_sleep = 1;
	}

	/*
	 * We copy the assembler sleep/wakeup routines to SRAM.
	 * These routines need to be in SRAM as that's the only
	 * memory the MPU can see when it wakes up.
	 */
	if (cpu_is_omap7xx()) {
		omap_sram_suspend = omap_sram_push(omap7xx_cpu_suspend,
						   omap7xx_cpu_suspend_sz);
	} else if (cpu_is_omap15xx()) {
		omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
						   omap1510_cpu_suspend_sz);
	} else if (cpu_is_omap16xx()) {
		omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
						   omap1610_cpu_suspend_sz);
	}

	if (omap_sram_suspend == NULL) {
		printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
		return -ENODEV;
	}

	arm_pm_idle = omap1_pm_idle;

	if (cpu_is_omap7xx())
		irq = INT_7XX_WAKE_UP_REQ;
	else if (cpu_is_omap16xx())
		irq = INT_1610_WAKE_UP_REQ;
	else
		irq = -1;

	if (irq >= 0) {
		if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup", NULL))
			pr_err("Failed to request irq %d (peripheral wakeup)\n", irq);
	}

	/* Program new power ramp-up time
	 * (0 for most boards since we don't lower voltage when in deep sleep)
	 */
	omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);

	/* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
	omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);

	/* Configure IDLECT3 */
	if (cpu_is_omap7xx())
		omap_writel(OMAP7XX_IDLECT3_VAL, OMAP7XX_IDLECT3);
	else if (cpu_is_omap16xx())
		omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);

	suspend_set_ops(&omap_pm_ops);

#ifdef CONFIG_DEBUG_FS
	omap_pm_init_debugfs();
#endif

	error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
	if (error)
		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);

	if (cpu_is_omap16xx()) {
		/* configure LOW_PWR pin */
		omap_cfg_reg(T20_1610_LOW_PWR);
	}

	return error;
}
__initcall(omap_pm_init);


code:
/*
 * arch/arm/mach-omap1/pm.h
 *
 * Header file for OMAP1 Power Management Routines
 *
 * Author: MontaVista Software, Inc.
 *	   support@mvista.com
 *
 * Copyright 2002 MontaVista Software Inc.
 *
 * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef __ARCH_ARM_MACH_OMAP1_PM_H
#define __ARCH_ARM_MACH_OMAP1_PM_H

#include <linux/soc/ti/omap1-io.h>

/*
 * ----------------------------------------------------------------------------
 * Register and offset definitions to be used in PM assembler code
 * ----------------------------------------------------------------------------
 */
#define CLKGEN_REG_ASM_BASE		OMAP1_IO_ADDRESS(0xfffece00)
#define ARM_IDLECT1_ASM_OFFSET		0x04
#define ARM_IDLECT2_ASM_OFFSET		0x08

#define TCMIF_ASM_BASE			OMAP1_IO_ADDRESS(0xfffecc00)
#define EMIFS_CONFIG_ASM_OFFSET		0x0c
#define EMIFF_SDRAM_CONFIG_ASM_OFFSET	0x20

/*
 * ----------------------------------------------------------------------------
 * Power management bitmasks
 * ----------------------------------------------------------------------------
 */
#define IDLE_WAIT_CYCLES		0x00000fff
#define PERIPHERAL_ENABLE		0x2

#define SELF_REFRESH_MODE		0x0c000001
#define IDLE_EMIFS_REQUEST		0xc
#define MODEM_32K_EN			0x1
#define PER_EN				0x1

#define CPU_SUSPEND_SIZE		200
#define ULPD_LOW_PWR_EN			0x0001
#define ULPD_DEEP_SLEEP_TRANSITION_EN	0x0010
#define ULPD_SETUP_ANALOG_CELL_3_VAL	0
#define ULPD_POWER_CTRL_REG_VAL		0x0219

#define DSP_IDLE_DELAY			10
#define DSP_IDLE			0x0040
#define DSP_RST				0x0004
#define DSP_ENABLE			0x0002
#define SUFFICIENT_DSP_RESET_TIME	1000
#define DEFAULT_MPUI_CONFIG		0x05cf
#define ENABLE_XORCLK			0x2
#define DSP_CLOCK_ENABLE		0x2000
#define DSP_IDLE_MODE			0x2
#define TC_IDLE_REQUEST			(0x0000000c)

#define IRQ_LEVEL2			(1<<0)
#define IRQ_KEYBOARD			(1<<1)
#define IRQ_UART2			(1<<15)

#define PDE_BIT				0x08
#define PWD_EN_BIT			0x04
#define EN_PERCK_BIT			0x04

#define OMAP1510_DEEP_SLEEP_REQUEST	0x0ec7
#define OMAP1510_BIG_SLEEP_REQUEST	0x0cc5
#define OMAP1510_IDLE_LOOP_REQUEST	0x0c00
#define OMAP1510_IDLE_CLOCK_DOMAINS	0x2

/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
#define OMAP1610_IDLECT1_SLEEP_VAL	0x13c7
#define OMAP1610_IDLECT2_SLEEP_VAL	0x09c7
#define OMAP1610_IDLECT3_VAL		0x3f
#define OMAP1610_IDLECT3_SLEEP_ORMASK	0x2c
#define OMAP1610_IDLECT3		0xfffece24
#define OMAP1610_IDLE_LOOP_REQUEST	0x0400

#define OMAP7XX_IDLECT1_SLEEP_VAL	0x16c7
#define OMAP7XX_IDLECT2_SLEEP_VAL	0x09c7
#define OMAP7XX_IDLECT3_VAL		0x3f
#define OMAP7XX_IDLECT3		0xfffece24
#define OMAP7XX_IDLE_LOOP_REQUEST	0x0C00

#if     !defined(CONFIG_ARCH_OMAP730) && \
	!defined(CONFIG_ARCH_OMAP850) && \
	!defined(CONFIG_ARCH_OMAP15XX) && \
	!defined(CONFIG_ARCH_OMAP16XX)
#warning "Power management for this processor not implemented yet"
#endif

#ifndef __ASSEMBLER__

#include <linux/clk.h>

extern struct kset power_subsys;

extern void prevent_idle_sleep(void);
extern void allow_idle_sleep(void);

extern void omap1_pm_idle(void);
extern void omap1_pm_suspend(void);

extern void omap7xx_cpu_suspend(unsigned long, unsigned long);
extern void omap1510_cpu_suspend(unsigned long, unsigned long);
extern void omap1610_cpu_suspend(unsigned long, unsigned long);
extern void omap7xx_idle_loop_suspend(void);
extern void omap1510_idle_loop_suspend(void);
extern void omap1610_idle_loop_suspend(void);

extern unsigned int omap7xx_cpu_suspend_sz;
extern unsigned int omap1510_cpu_suspend_sz;
extern unsigned int omap1610_cpu_suspend_sz;
extern unsigned int omap7xx_idle_loop_suspend_sz;
extern unsigned int omap1510_idle_loop_suspend_sz;
extern unsigned int omap1610_idle_loop_suspend_sz;

#ifdef CONFIG_OMAP_SERIAL_WAKE
extern void omap_serial_wake_trigger(int enable);
#else
#define omap_serial_wakeup_init()	{}
#define omap_serial_wake_trigger(x)	{}
#endif	/* CONFIG_OMAP_SERIAL_WAKE */

#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]

#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]

#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]

#define MPUI7XX_SAVE(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x] = omap_readl(x)
#define MPUI7XX_RESTORE(x) omap_writel((mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]), (x))
#define MPUI7XX_SHOW(x) mpui7xx_sleep_save[MPUI7XX_SLEEP_SAVE_##x]

#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]

#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]

/*
 * List of global OMAP registers to preserve.
 * More ones like CP and general purpose register values are preserved
 * with the stack pointer in sleep.S.
 */

enum arm_save_state {
	ARM_SLEEP_SAVE_START = 0,
	/*
	 * MPU control registers 32 bits
	 */
	ARM_SLEEP_SAVE_ARM_CKCTL,
	ARM_SLEEP_SAVE_ARM_IDLECT1,
	ARM_SLEEP_SAVE_ARM_IDLECT2,
	ARM_SLEEP_SAVE_ARM_IDLECT3,
	ARM_SLEEP_SAVE_ARM_EWUPCT,
	ARM_SLEEP_SAVE_ARM_RSTCT1,
	ARM_SLEEP_SAVE_ARM_RSTCT2,
	ARM_SLEEP_SAVE_ARM_SYSST,
	ARM_SLEEP_SAVE_SIZE
};

enum dsp_save_state {
	DSP_SLEEP_SAVE_START = 0,
	/*
	 * DSP registers 16 bits
	 */
	DSP_SLEEP_SAVE_DSP_IDLECT2,
	DSP_SLEEP_SAVE_SIZE
};

enum ulpd_save_state {
	ULPD_SLEEP_SAVE_START = 0,
	/*
	 * ULPD registers 16 bits
	 */
	ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
	ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
	ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
	ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
	ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
	ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
	ULPD_SLEEP_SAVE_SIZE
};

enum mpui1510_save_state {
	MPUI1510_SLEEP_SAVE_START = 0,
	/*
	 * MPUI registers 32 bits
	 */
	MPUI1510_SLEEP_SAVE_MPUI_CTRL,
	MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
	MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
	MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
	MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
	MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
	MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
	MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
#if defined(CONFIG_ARCH_OMAP15XX)
	MPUI1510_SLEEP_SAVE_SIZE
#else
	MPUI1510_SLEEP_SAVE_SIZE = 0
#endif
};

enum mpui7xx_save_state {
	MPUI7XX_SLEEP_SAVE_START = 0,
	/*
	 * MPUI registers 32 bits
	 */
	MPUI7XX_SLEEP_SAVE_MPUI_CTRL,
	MPUI7XX_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
	MPUI7XX_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
	MPUI7XX_SLEEP_SAVE_MPUI_DSP_STATUS,
	MPUI7XX_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
	MPUI7XX_SLEEP_SAVE_EMIFS_CONFIG,
	MPUI7XX_SLEEP_SAVE_OMAP_IH1_MIR,
	MPUI7XX_SLEEP_SAVE_OMAP_IH2_0_MIR,
	MPUI7XX_SLEEP_SAVE_OMAP_IH2_1_MIR,
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
	MPUI7XX_SLEEP_SAVE_SIZE
#else
	MPUI7XX_SLEEP_SAVE_SIZE = 0
#endif
};

enum mpui1610_save_state {
	MPUI1610_SLEEP_SAVE_START = 0,
	/*
	 * MPUI registers 32 bits
	 */
	MPUI1610_SLEEP_SAVE_MPUI_CTRL,
	MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
	MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
	MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
	MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
	MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
	MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
	MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
	MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
	MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
	MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
#if defined(CONFIG_ARCH_OMAP16XX)
	MPUI1610_SLEEP_SAVE_SIZE
#else
	MPUI1610_SLEEP_SAVE_SIZE = 0
#endif
};

#endif /* ASSEMBLER */
#endif /* __ASM_ARCH_OMAP_PM_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Runtime PM support code for OMAP1
 *
 * Author: Kevin Hilman, Deep Root Systems, LLC
 *
 * Copyright (C) 2010 Texas Instruments, Inc.
 */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pm_clock.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/err.h>

#include "soc.h"

static struct dev_pm_domain default_pm_domain = {
	.ops = {
		USE_PM_CLK_RUNTIME_OPS
		USE_PLATFORM_PM_SLEEP_OPS
	},
};

static struct pm_clk_notifier_block platform_bus_notifier = {
	.pm_domain = &default_pm_domain,
	.con_ids = { "ick", "fck", NULL, },
};

static int __init omap1_pm_runtime_init(void)
{
	if (!cpu_class_is_omap1())
		return -ENODEV;

	pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);

	return 0;
}
core_initcall(omap1_pm_runtime_init);


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * OMAP1 reset support
 */
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/reboot.h>

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

/* ARM_SYSST bit shifts related to SoC reset sources */
#define ARM_SYSST_POR_SHIFT				5
#define ARM_SYSST_EXT_RST_SHIFT				4
#define ARM_SYSST_ARM_WDRST_SHIFT			2
#define ARM_SYSST_GLOB_SWRST_SHIFT			1

/* Standardized reset source bits (across all OMAP SoCs) */
#define OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT		0
#define OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT		1
#define OMAP_MPU_WD_RST_SRC_ID_SHIFT			3
#define OMAP_EXTWARM_RST_SRC_ID_SHIFT			5

void omap1_restart(enum reboot_mode mode, const char *cmd)
{
	/*
	 * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
	 * "Global Software Reset Affects Traffic Controller Frequency".
	 */
	if (cpu_is_omap5912()) {
		omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4), DPLL_CTL);
		omap_writew(0x8, ARM_RSTCT1);
	}

	omap_writew(1, ARM_RSTCT1);
}

/**
 * omap1_get_reset_sources - return the source of the SoC's last reset
 *
 * Returns bits that represent the last reset source for the SoC.  The
 * format is standardized across OMAPs for use by the OMAP watchdog.
 */
u32 omap1_get_reset_sources(void)
{
	u32 ret = 0;
	u16 rs;

	rs = __raw_readw(OMAP1_IO_ADDRESS(ARM_SYSST));

	if (rs & (1 << ARM_SYSST_POR_SHIFT))
		ret |= 1 << OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT;
	if (rs & (1 << ARM_SYSST_EXT_RST_SHIFT))
		ret |= 1 << OMAP_EXTWARM_RST_SRC_ID_SHIFT;
	if (rs & (1 << ARM_SYSST_ARM_WDRST_SHIFT))
		ret |= 1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT;
	if (rs & (1 << ARM_SYSST_GLOB_SWRST_SHIFT))
		ret |= 1 << OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT;

	return ret;
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/mach-omap1/serial.c
 *
 * OMAP1 serial support.
 */
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/clk.h>
#include <linux/io.h>

#include <asm/mach-types.h>

#include "serial.h"
#include "mux.h"
#include "pm.h"
#include "soc.h"

static struct clk * uart1_ck;
static struct clk * uart2_ck;
static struct clk * uart3_ck;

static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
					  int offset)
{
	offset <<= up->regshift;
	return (unsigned int)__raw_readb(up->membase + offset);
}

static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
				    int value)
{
	offset <<= p->regshift;
	__raw_writeb(value, p->membase + offset);
}

/*
 * Internal UARTs need to be initialized for the 8250 autoconfig to work
 * properly. Note that the TX watermark initialization may not be needed
 * once the 8250.c watermark handling code is merged.
 */
static void __init omap_serial_reset(struct plat_serial8250_port *p)
{
	omap_serial_outp(p, UART_OMAP_MDR1,
			UART_OMAP_MDR1_DISABLE);	/* disable UART */
	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
	omap_serial_outp(p, UART_OMAP_MDR1,
			UART_OMAP_MDR1_16X_MODE);	/* enable UART */

	if (!cpu_is_omap15xx()) {
		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
	}
}

static struct plat_serial8250_port serial_platform_data[] = {
	{
		.mapbase	= OMAP1_UART1_BASE,
		.irq		= INT_UART1,
		.flags		= UPF_BOOT_AUTOCONF,
		.iotype		= UPIO_MEM,
		.regshift	= 2,
		.uartclk	= OMAP16XX_BASE_BAUD * 16,
	},
	{
		.mapbase	= OMAP1_UART2_BASE,
		.irq		= INT_UART2,
		.flags		= UPF_BOOT_AUTOCONF,
		.iotype		= UPIO_MEM,
		.regshift	= 2,
		.uartclk	= OMAP16XX_BASE_BAUD * 16,
	},
	{
		.mapbase	= OMAP1_UART3_BASE,
		.irq		= INT_UART3,
		.flags		= UPF_BOOT_AUTOCONF,
		.iotype		= UPIO_MEM,
		.regshift	= 2,
		.uartclk	= OMAP16XX_BASE_BAUD * 16,
	},
	{ },
};

static struct platform_device serial_device = {
	.name			= "serial8250",
	.id			= PLAT8250_DEV_PLATFORM,
	.dev			= {
		.platform_data	= serial_platform_data,
	},
};

/*
 * Note that on Innovator-1510 UART2 pins conflict with USB2.
 * By default UART2 does not work on Innovator-1510 if you have
 * USB OHCI enabled. To use UART2, you must disable USB2 first.
 */
void __init omap_serial_init(void)
{
	int i;

	if (cpu_is_omap7xx()) {
		serial_platform_data[0].regshift = 0;
		serial_platform_data[1].regshift = 0;
		serial_platform_data[0].irq = INT_7XX_UART_MODEM_1;
		serial_platform_data[1].irq = INT_7XX_UART_MODEM_IRDA_2;
	}

	if (cpu_is_omap15xx()) {
		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
	}

	for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {

		/* Don't look at UARTs higher than 2 for omap7xx */
		if (cpu_is_omap7xx() && i > 1) {
			serial_platform_data[i].membase = NULL;
			serial_platform_data[i].mapbase = 0;
			continue;
		}

		/* Static mapping, never released */
		serial_platform_data[i].membase =
			ioremap(serial_platform_data[i].mapbase, SZ_2K);
		if (!serial_platform_data[i].membase) {
			printk(KERN_ERR "Could not ioremap uart%i\n", i);
			continue;
		}
		switch (i) {
		case 0:
			uart1_ck = clk_get(NULL, "uart1_ck");
			if (IS_ERR(uart1_ck))
				printk("Could not get uart1_ck\n");
			else {
				clk_prepare_enable(uart1_ck);
				if (cpu_is_omap15xx())
					clk_set_rate(uart1_ck, 12000000);
			}
			break;
		case 1:
			uart2_ck = clk_get(NULL, "uart2_ck");
			if (IS_ERR(uart2_ck))
				printk("Could not get uart2_ck\n");
			else {
				clk_prepare_enable(uart2_ck);
				if (cpu_is_omap15xx())
					clk_set_rate(uart2_ck, 12000000);
				else
					clk_set_rate(uart2_ck, 48000000);
			}
			break;
		case 2:
			uart3_ck = clk_get(NULL, "uart3_ck");
			if (IS_ERR(uart3_ck))
				printk("Could not get uart3_ck\n");
			else {
				clk_prepare_enable(uart3_ck);
				if (cpu_is_omap15xx())
					clk_set_rate(uart3_ck, 12000000);
			}
			break;
		}
		omap_serial_reset(&serial_platform_data[i]);
	}
}

#ifdef CONFIG_OMAP_SERIAL_WAKE

static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
{
	/* Need to do something with serial port right after wake-up? */
	return IRQ_HANDLED;
}

/*
 * Reroutes serial RX lines to GPIO lines for the duration of
 * sleep to allow waking up the device from serial port even
 * in deep sleep.
 */
void omap_serial_wake_trigger(int enable)
{
	if (!cpu_is_omap16xx())
		return;

	if (uart1_ck != NULL) {
		if (enable)
			omap_cfg_reg(V14_16XX_GPIO37);
		else
			omap_cfg_reg(V14_16XX_UART1_RX);
	}
	if (uart2_ck != NULL) {
		if (enable)
			omap_cfg_reg(R9_16XX_GPIO18);
		else
			omap_cfg_reg(R9_16XX_UART2_RX);
	}
	if (uart3_ck != NULL) {
		if (enable)
			omap_cfg_reg(L14_16XX_GPIO49);
		else
			omap_cfg_reg(L14_16XX_UART3_RX);
	}
}

static void __init omap_serial_set_port_wakeup(int gpio_nr)
{
	int ret;

	ret = gpio_request(gpio_nr, "UART wake");
	if (ret < 0) {
		printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
		       gpio_nr);
		return;
	}
	gpio_direction_input(gpio_nr);
	ret = request_irq(gpio_to_irq(gpio_nr), &omap_serial_wake_interrupt,
			  IRQF_TRIGGER_RISING, "serial wakeup", NULL);
	if (ret) {
		gpio_free(gpio_nr);
		printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
		       gpio_nr);
		return;
	}
	enable_irq_wake(gpio_to_irq(gpio_nr));
}

int __init omap_serial_wakeup_init(void)
{
	if (!cpu_is_omap16xx())
		return 0;

	if (uart1_ck != NULL)
		omap_serial_set_port_wakeup(37);
	if (uart2_ck != NULL)
		omap_serial_set_port_wakeup(18);
	if (uart3_ck != NULL)
		omap_serial_set_port_wakeup(49);

	return 0;
}

#endif	/* CONFIG_OMAP_SERIAL_WAKE */

static int __init omap_init(void)
{
	if (!cpu_class_is_omap1())
		return -ENODEV;

	return platform_device_register(&serial_device);
}
arch_initcall(omap_init);


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.
 */

#ifndef __ASM_ARCH_SERIAL_H
#define __ASM_ARCH_SERIAL_H

#include <linux/init.h>

/*
 * Memory entry used for the DEBUG_LL UART configuration, relative to
 * start of RAM. See also uncompress.h and debug-macro.S.
 *
 * Note that using a memory location for storing the UART configuration
 * has at least two limitations:
 *
 * 1. Kernel uncompress code cannot overlap OMAP_UART_INFO as the
 *    uncompress code could then partially overwrite itself
 * 2. We assume printascii is called at least once before paging_init,
 *    and addruart has a chance to read OMAP_UART_INFO
 */
#define OMAP_UART_INFO_OFS	0x3ffc

#define OMAP_PORT_SHIFT		2
#define OMAP7XX_PORT_SHIFT	0

#define OMAP1510_BASE_BAUD	(12000000/16)
#define OMAP16XX_BASE_BAUD	(48000000/16)

/*
 * DEBUG_LL port encoding stored into the UART1 scratchpad register by
 * decomp_setup in uncompress.h
 */
#define OMAP1UART1		11
#define OMAP1UART2		12
#define OMAP1UART3		13

#ifndef __ASSEMBLER__
extern void omap_serial_init(void);
#endif

#endif


code:
/*
 * linux/arch/arm/mach-omap1/sleep.S
 *
 * Low-level OMAP7XX/1510/1610 sleep/wakeUp support
 *
 * Initial SA1110 code:
 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
 *
 * Adapted for PXA by Nicolas Pitre:
 * Copyright (c) 2002 Monta Vista Software, Inc.
 *
 * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/linkage.h>

#include <asm/assembler.h>

#include "hardware.h"

#include "iomap.h"
#include "pm.h"

		.text

/*
 * Forces OMAP into deep sleep state
 *
 * omapXXXX_cpu_suspend()
 *
 * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
 * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
 * in register r1.
 *
 * Note: This code get's copied to internal SRAM at boot. When the OMAP
 *	 wakes up it continues execution at the point it went to sleep.
 *
 * Note: Because of errata work arounds we have processor specific functions
 *       here. They are mostly the same, but slightly different.
 *
 */

#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
	.align	3
ENTRY(omap7xx_cpu_suspend)

	@ save registers on stack
	stmfd	sp!, {r0 - r12, lr}

	@ Drain write cache
	mov	r4, #0
	mcr	p15, 0, r0, c7, c10, 4
	nop

	@ load base address of Traffic Controller
	mov	r6, #TCMIF_ASM_BASE & 0xff000000
	orr	r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
	orr	r6, r6, #TCMIF_ASM_BASE & 0x0000ff00

	@ prepare to put SDRAM into self-refresh manually
	ldr	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
	orr	r9, r7, #SELF_REFRESH_MODE & 0xff000000
	orr	r9, r9, #SELF_REFRESH_MODE & 0x000000ff
	str	r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]

	@ prepare to put EMIFS to Sleep
	ldr	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
	orr	r9, r8, #IDLE_EMIFS_REQUEST & 0xff
	str	r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00

	@ turn off clock domains
	@ do not disable PERCK (0x04)
	mov	r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff
	orr	r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00
	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]

	@ request ARM idle
	mov	r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff
	orr	r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00
	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

	@ disable instruction cache
	mrc	p15, 0, r9, c1, c0, 0
	bic	r2, r9, #0x1000
	mcr	p15, 0, r2, c1, c0, 0
	nop

/*
 * Let's wait for the next wake up event to wake us up. r0 can't be
 * used here because r0 holds ARM_IDLECT1
 */
	mov	r2, #0
	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt
/*
 * omap7xx_cpu_suspend()'s resume point.
 *
 * It will just start executing here, so we'll restore stuff from the
 * stack.
 */
	@ re-enable Icache
	mcr	p15, 0, r9, c1, c0, 0

	@ reset the ARM_IDLECT1 and ARM_IDLECT2.
	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

	@ Restore EMIFF controls
	str	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
	str	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ restore regs and return
	ldmfd	sp!, {r0 - r12, pc}

ENTRY(omap7xx_cpu_suspend_sz)
	.word	. - omap7xx_cpu_suspend
#endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */

#ifdef CONFIG_ARCH_OMAP15XX
	.align	3
ENTRY(omap1510_cpu_suspend)

	@ save registers on stack
	stmfd	sp!, {r0 - r12, lr}

	@ load base address of Traffic Controller
	mov	r4, #TCMIF_ASM_BASE & 0xff000000
	orr	r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
	orr	r4, r4, #TCMIF_ASM_BASE & 0x0000ff00

	@ work around errata of OMAP1510 PDE bit for TC shut down
	@ clear PDE bit
	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
	bic	r5, r5, #PDE_BIT & 0xff
	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ set PWD_EN bit
	and	r5, r5, #PWD_EN_BIT & 0xff
	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ prepare to put SDRAM into self-refresh manually
	ldr	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
	orr	r5, r5, #SELF_REFRESH_MODE & 0xff000000
	orr	r5, r5, #SELF_REFRESH_MODE & 0x000000ff
	str	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]

	@ prepare to put EMIFS to Sleep
	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
	orr	r5, r5, #IDLE_EMIFS_REQUEST & 0xff
	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00

	@ turn off clock domains
	mov	r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
	orr	r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]

	@ request ARM idle
	mov	r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
	orr	r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

	mov	r5, #IDLE_WAIT_CYCLES & 0xff
	orr	r5, r5, #IDLE_WAIT_CYCLES & 0xff00
l_1510_2:
	subs	r5, r5, #1
	bne	l_1510_2
/*
 * Let's wait for the next wake up event to wake us up. r0 can't be
 * used here because r0 holds ARM_IDLECT1
 */
	mov	r2, #0
	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt
/*
 * omap1510_cpu_suspend()'s resume point.
 *
 * It will just start executing here, so we'll restore stuff from the
 * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
 */
	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

	@ restore regs and return
	ldmfd	sp!, {r0 - r12, pc}

ENTRY(omap1510_cpu_suspend_sz)
	.word	. - omap1510_cpu_suspend
#endif /* CONFIG_ARCH_OMAP15XX */

#if defined(CONFIG_ARCH_OMAP16XX)
	.align	3
ENTRY(omap1610_cpu_suspend)

	@ save registers on stack
	stmfd	sp!, {r0 - r12, lr}

	@ Drain write cache
	mov	r4, #0
	mcr	p15, 0, r0, c7, c10, 4
	nop

	@ Load base address of Traffic Controller
	mov	r6, #TCMIF_ASM_BASE & 0xff000000
	orr	r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
	orr	r6, r6, #TCMIF_ASM_BASE & 0x0000ff00

	@ Prepare to put SDRAM into self-refresh manually
	ldr	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
	orr	r9, r7, #SELF_REFRESH_MODE & 0xff000000
	orr	r9, r9, #SELF_REFRESH_MODE & 0x000000ff
	str	r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]

	@ Prepare to put EMIFS to Sleep
	ldr	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
	orr	r9, r8, #IDLE_EMIFS_REQUEST & 0xff
	str	r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ Load base address of ARM_IDLECT1 and ARM_IDLECT2
	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00

	@ Turn off clock domains
	@ Do not disable PERCK (0x04)
	mov	r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
	orr	r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]

	@ Request ARM idle
	mov	r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
	orr	r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

/*
 * Let's wait for the next wake up event to wake us up. r0 can't be
 * used here because r0 holds ARM_IDLECT1
 */
	mov	r2, #0
	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt

	@ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
	@ according to this formula:
	@ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
	@ Max DPLL_MULT = 18
	@ DPLL_DIV = 1
	@ ARMDIV = 1
	@ => 74 nop-instructions
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@10
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@20
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@30
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@40
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@50
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@60
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop	@70
	nop
	nop
	nop
	nop	@74
/*
 * omap1610_cpu_suspend()'s resume point.
 *
 * It will just start executing here, so we'll restore stuff from the
 * stack.
 */
	@ Restore the ARM_IDLECT1 and ARM_IDLECT2.
	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]

	@ Restore EMIFF controls
	str	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
	str	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]

	@ Restore regs and return
	ldmfd	sp!, {r0 - r12, pc}

ENTRY(omap1610_cpu_suspend_sz)
	.word	. - omap1610_cpu_suspend
#endif /* CONFIG_ARCH_OMAP16XX */


code:
/*
 * We can move linux/soc/ti/omap1-soc.h here once the drivers are fixed
 */
#include "hardware.h"
#include "irqs.h"
#include <asm/irq.h>


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP SRAM detection and management
 *
 * Copyright (C) 2005 Nokia Corporation
 * Written by Tony Lindgren <tony@atomide.com>
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>

#include <asm/fncpy.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
#include <asm/set_memory.h>

#include <asm/mach/map.h>

#include "soc.h"
#include "sram.h"

#define OMAP1_SRAM_PA		0x20000000
#define SRAM_BOOTLOADER_SZ	0x80
#define ROUND_DOWN(value,boundary)	((value) & (~((boundary)-1)))

static void __iomem *omap_sram_base;
static unsigned long omap_sram_start;
static unsigned long omap_sram_skip;
static unsigned long omap_sram_size;
static void __iomem *omap_sram_ceil;

/*
 * Memory allocator for SRAM: calculates the new ceiling address
 * for pushing a function using the fncpy API.
 *
 * Note that fncpy requires the returned address to be aligned
 * to an 8-byte boundary.
 */
static void *omap_sram_push_address(unsigned long size)
{
	unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;

	available = omap_sram_ceil - (omap_sram_base + omap_sram_skip);

	if (size > available) {
		pr_err("Not enough space in SRAM\n");
		return NULL;
	}

	new_ceil -= size;
	new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN);
	omap_sram_ceil = IOMEM(new_ceil);

	return (void __force *)omap_sram_ceil;
}

void *omap_sram_push(void *funcp, unsigned long size)
{
	void *sram;
	unsigned long base;
	int pages;
	void *dst = NULL;

	sram = omap_sram_push_address(size);
	if (!sram)
		return NULL;

	base = (unsigned long)sram & PAGE_MASK;
	pages = PAGE_ALIGN(size) / PAGE_SIZE;

	set_memory_rw(base, pages);

	dst = fncpy(sram, funcp, size);

	set_memory_ro(base, pages);
	set_memory_x(base, pages);

	return dst;
}

/*
 * The amount of SRAM depends on the core type.
 * Note that we cannot try to test for SRAM here because writes
 * to secure SRAM will hang the system. Also the SRAM is not
 * yet mapped at this point.
 * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
 */
static void __init omap_detect_and_map_sram(void)
{
	unsigned long base;
	int pages;

	omap_sram_skip = SRAM_BOOTLOADER_SZ;
	omap_sram_start = OMAP1_SRAM_PA;

	if (cpu_is_omap7xx())
		omap_sram_size = 0x32000;	/* 200K */
	else if (cpu_is_omap15xx())
		omap_sram_size = 0x30000;	/* 192K */
	else if (cpu_is_omap1610() || cpu_is_omap1611() ||
			cpu_is_omap1621() || cpu_is_omap1710())
		omap_sram_size = 0x4000;	/* 16K */
	else {
		pr_err("Could not detect SRAM size\n");
		omap_sram_size = 0x4000;
	}

	omap_sram_start = ROUND_DOWN(omap_sram_start, PAGE_SIZE);
	omap_sram_base = __arm_ioremap_exec(omap_sram_start, omap_sram_size, 1);
	if (!omap_sram_base) {
		pr_err("SRAM: Could not map\n");
		return;
	}

	omap_sram_ceil = omap_sram_base + omap_sram_size;

	/*
	 * Looks like we need to preserve some bootloader code at the
	 * beginning of SRAM for jumping to flash for reboot to work...
	 */
	memset_io(omap_sram_base + omap_sram_skip, 0,
		  omap_sram_size - omap_sram_skip);

	base = (unsigned long)omap_sram_base;
	pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE;

	set_memory_ro(base, pages);
	set_memory_x(base, pages);
}

static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl);

void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
{
	BUG_ON(!_omap_sram_reprogram_clock);
	/* On 730, bit 13 must always be 1 */
	if (cpu_is_omap7xx())
		ckctl |= 0x2000;
	_omap_sram_reprogram_clock(dpllctl, ckctl);
}

int __init omap1_sram_init(void)
{
	omap_detect_and_map_sram();
	_omap_sram_reprogram_clock =
			omap_sram_push(omap1_sram_reprogram_clock,
					omap1_sram_reprogram_clock_sz);

	return 0;
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * linux/arch/arm/plat-omap/sram-fn.S
 *
 * Functions that need to be run in internal SRAM
 */

#include <linux/linkage.h>
#include <linux/soc/ti/omap1-io.h>

#include <asm/assembler.h>

#include "hardware.h"
#include "iomap.h"

	.text

/*
 * Reprograms ULPD and CKCTL.
 */
	.align	3
ENTRY(omap1_sram_reprogram_clock)
	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack

	mov	r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0xff000000
	orr	r2, r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0x00ff0000
	orr	r2, r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0x0000ff00

	mov	r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0xff000000
	orr	r3, r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0x00ff0000
	orr	r3, r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0x0000ff00

	tst	r0, #1 << 4			@ want lock mode?
	beq	newck				@ nope
	bic	r0, r0, #1 << 4			@ else clear lock bit
	strh	r0, [r2]			@ set dpll into bypass mode
	orr	r0, r0, #1 << 4			@ set lock bit again

newck:
	strh	r1, [r3]			@ write new ckctl value
	strh	r0, [r2]			@ write new dpll value

	mov	r4, #0x0700			@ let the clocks settle
	orr	r4, r4, #0x00ff
delay:	sub	r4, r4, #1
	cmp	r4, #0
	bne	delay

lock:	ldrh	r4, [r2], #0			@ read back dpll value
	tst	r0, #1 << 4			@ want lock mode?
	beq	out				@ nope
	tst	r4, #1 << 0			@ dpll rate locked?
	beq	lock				@ try again

out:
	ldmfd	sp!, {r0 - r12, pc}		@ restore regs and return
ENTRY(omap1_sram_reprogram_clock_sz)
	.word	. - omap1_sram_reprogram_clock


code:
/* SPDX-License-Identifier: GPL-2.0 */

extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);

int omap1_sram_init(void);
void *omap_sram_push(void *funcp, unsigned long size);

/* Do not use these */
extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
extern unsigned long omap1_sram_reprogram_clock_sz;


code:
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * OMAP Traffic Controller
 *
 * Copyright (C) 2004 Nokia Corporation
 * Author: Imre Deak <imre.deak@nokia.com>
 */

#ifndef __ASM_ARCH_TC_H
#define __ASM_ARCH_TC_H

#define TCMIF_BASE		0xfffecc00
#define OMAP_TC_OCPT1_PRIOR	(TCMIF_BASE + 0x00)
#define OMAP_TC_EMIFS_PRIOR	(TCMIF_BASE + 0x04)
#define OMAP_TC_EMIFF_PRIOR	(TCMIF_BASE + 0x08)
#define EMIFS_CONFIG		(TCMIF_BASE + 0x0c)
#define EMIFS_CS0_CONFIG	(TCMIF_BASE + 0x10)
#define EMIFS_CS1_CONFIG	(TCMIF_BASE + 0x14)
#define EMIFS_CS2_CONFIG	(TCMIF_BASE + 0x18)
#define EMIFS_CS3_CONFIG	(TCMIF_BASE + 0x1c)
#define EMIFF_SDRAM_CONFIG	(TCMIF_BASE + 0x20)
#define EMIFF_MRS		(TCMIF_BASE + 0x24)
#define TC_TIMEOUT1		(TCMIF_BASE + 0x28)
#define TC_TIMEOUT2		(TCMIF_BASE + 0x2c)
#define TC_TIMEOUT3		(TCMIF_BASE + 0x30)
#define TC_ENDIANISM		(TCMIF_BASE + 0x34)
#define EMIFF_SDRAM_CONFIG_2	(TCMIF_BASE + 0x3c)
#define EMIF_CFG_DYNAMIC_WS	(TCMIF_BASE + 0x40)
#define EMIFS_ACS0		(TCMIF_BASE + 0x50)
#define EMIFS_ACS1		(TCMIF_BASE + 0x54)
#define EMIFS_ACS2		(TCMIF_BASE + 0x58)
#define EMIFS_ACS3		(TCMIF_BASE + 0x5c)
#define OMAP_TC_OCPT2_PRIOR	(TCMIF_BASE + 0xd0)

/* external EMIFS chipselect regions */
#define	OMAP_CS0_PHYS		0x00000000
#define	OMAP_CS0_SIZE		SZ_64M

#define	OMAP_CS1_PHYS		0x04000000
#define	OMAP_CS1_SIZE		SZ_64M

#define	OMAP_CS1A_PHYS		OMAP_CS1_PHYS
#define	OMAP_CS1A_SIZE		SZ_32M

#define	OMAP_CS1B_PHYS		(OMAP_CS1A_PHYS + OMAP_CS1A_SIZE)
#define	OMAP_CS1B_SIZE		SZ_32M

#define	OMAP_CS2_PHYS		0x08000000
#define	OMAP_CS2_SIZE		SZ_64M

#define	OMAP_CS2A_PHYS		OMAP_CS2_PHYS
#define	OMAP_CS2A_SIZE		SZ_32M

#define	OMAP_CS2B_PHYS		(OMAP_CS2A_PHYS + OMAP_CS2A_SIZE)
#define	OMAP_CS2B_SIZE		SZ_32M

#define	OMAP_CS3_PHYS		0x0c000000
#define	OMAP_CS3_SIZE		SZ_64M

#ifndef	__ASSEMBLER__

/* EMIF Slow Interface Configuration Register */
#define OMAP_EMIFS_CONFIG_FR		(1 << 4)
#define OMAP_EMIFS_CONFIG_PDE		(1 << 3)
#define OMAP_EMIFS_CONFIG_PWD_EN	(1 << 2)
#define OMAP_EMIFS_CONFIG_BM		(1 << 1)
#define OMAP_EMIFS_CONFIG_WP		(1 << 0)

#define EMIFS_CCS(n)		(EMIFS_CS0_CONFIG + (4 * (n)))
#define EMIFS_ACS(n)		(EMIFS_ACS0 + (4 * (n)))

#endif	/* __ASSEMBLER__ */

#endif	/* __ASM_ARCH_TC_H */