code:
/*
 * linux/arch/arm/mach-omap1/time.c
 *
 * OMAP Timers
 *
 * Copyright (C) 2004 Nokia Corporation
 * Partial timer rewrite and additional dynamic tick timer support by
 * Tony Lindgen <tony@atomide.com> and
 * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 *
 * MPU timer code based on the older MPU timer code for OMAP
 * Copyright (C) 2000 RidgeRun, Inc.
 * Author: Greg Lonnon <glonnon@ridgerun.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/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/sched_clock.h>

#include <asm/irq.h>

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

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

#ifdef CONFIG_OMAP_MPU_TIMER

#define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
#define OMAP_MPU_TIMER_OFFSET		0x100

typedef struct {
	u32 cntl;			/* CNTL_TIMER, R/W */
	u32 load_tim;			/* LOAD_TIM,   W */
	u32 read_tim;			/* READ_TIM,   R */
} omap_mpu_timer_regs_t;

#define omap_mpu_timer_base(n)							\
((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE +	\
				 (n)*OMAP_MPU_TIMER_OFFSET))

static inline unsigned long notrace omap_mpu_timer_read(int nr)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
	return readl(&timer->read_tim);
}

static inline void omap_mpu_set_autoreset(int nr)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);

	writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
}

static inline void omap_mpu_remove_autoreset(int nr)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);

	writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
}

static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
					int autoreset)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
	unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;

	if (autoreset)
		timerflags |= MPU_TIMER_AR;

	writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
	udelay(1);
	writel(load_val, &timer->load_tim);
        udelay(1);
	writel(timerflags, &timer->cntl);
}

static inline void omap_mpu_timer_stop(int nr)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);

	writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
}

/*
 * ---------------------------------------------------------------------------
 * MPU timer 1 ... count down to zero, interrupt, reload
 * ---------------------------------------------------------------------------
 */
static int omap_mpu_set_next_event(unsigned long cycles,
				   struct clock_event_device *evt)
{
	omap_mpu_timer_start(0, cycles, 0);
	return 0;
}

static int omap_mpu_set_oneshot(struct clock_event_device *evt)
{
	omap_mpu_timer_stop(0);
	omap_mpu_remove_autoreset(0);
	return 0;
}

static int omap_mpu_set_periodic(struct clock_event_device *evt)
{
	omap_mpu_set_autoreset(0);
	return 0;
}

static struct clock_event_device clockevent_mpu_timer1 = {
	.name			= "mpu_timer1",
	.features		= CLOCK_EVT_FEAT_PERIODIC |
				  CLOCK_EVT_FEAT_ONESHOT,
	.set_next_event		= omap_mpu_set_next_event,
	.set_state_periodic	= omap_mpu_set_periodic,
	.set_state_oneshot	= omap_mpu_set_oneshot,
};

static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = &clockevent_mpu_timer1;

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static __init void omap_init_mpu_timer(unsigned long rate)
{
	if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
			IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
		pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
	omap_mpu_timer_start(0, (rate / HZ) - 1, 1);

	clockevent_mpu_timer1.cpumask = cpumask_of(0);
	clockevents_config_and_register(&clockevent_mpu_timer1, rate,
					1, -1);
}

/*
 * ---------------------------------------------------------------------------
 * MPU timer 2 ... free running 32-bit clock source and scheduler clock
 * ---------------------------------------------------------------------------
 */

static u64 notrace omap_mpu_read_sched_clock(void)
{
	return ~omap_mpu_timer_read(1);
}

static void __init omap_init_clocksource(unsigned long rate)
{
	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
	static char err[] __initdata = KERN_ERR
			"%s: can't register clocksource!\n";

	omap_mpu_timer_start(1, ~0, 1);
	sched_clock_register(omap_mpu_read_sched_clock, 32, rate);

	if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
			300, 32, clocksource_mmio_readl_down))
		printk(err, "mpu_timer2");
}

static void __init omap_mpu_timer_init(void)
{
	struct clk	*ck_ref = clk_get(NULL, "ck_ref");
	unsigned long	rate;

	BUG_ON(IS_ERR(ck_ref));

	rate = clk_get_rate(ck_ref);
	clk_put(ck_ref);

	/* PTV = 0 */
	rate /= 2;

	omap_init_mpu_timer(rate);
	omap_init_clocksource(rate);
}

#else
static inline void omap_mpu_timer_init(void)
{
	pr_err("Bogus timer, should not happen\n");
}
#endif	/* CONFIG_OMAP_MPU_TIMER */

/*
 * ---------------------------------------------------------------------------
 * Timer initialization
 * ---------------------------------------------------------------------------
 */
void __init omap1_timer_init(void)
{
	omap1_clk_init();
	omap1_mux_init();

	if (omap_32k_timer_init() != 0)
		omap_mpu_timer_init();
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP1 Dual-Mode Timers - platform device registration
 *
 * Contains first level initialization routines which internally
 * generates timer device information and registers with linux
 * device model. It also has a low level function to change the timer
 * input clock source.
 *
 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
 * Thara Gopinath <thara@ti.com>
 */

#include <linux/clk.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dmtimer-omap.h>
#include <linux/soc/ti/omap1-io.h>

#include <clocksource/timer-ti-dm.h>

#include "soc.h"

#define OMAP1610_GPTIMER1_BASE		0xfffb1400
#define OMAP1610_GPTIMER2_BASE		0xfffb1c00
#define OMAP1610_GPTIMER3_BASE		0xfffb2400
#define OMAP1610_GPTIMER4_BASE		0xfffb2c00
#define OMAP1610_GPTIMER5_BASE		0xfffb3400
#define OMAP1610_GPTIMER6_BASE		0xfffb3c00
#define OMAP1610_GPTIMER7_BASE		0xfffb7400
#define OMAP1610_GPTIMER8_BASE		0xfffbd400

#define OMAP1_DM_TIMER_COUNT		8

static int omap1_dm_timer_set_src(struct platform_device *pdev,
				int source)
{
	int n = (pdev->id - 1) << 1;
	u32 l;

	l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
	l |= source << n;
	omap_writel(l, MOD_CONF_CTRL_1);

	return 0;
}

static int __init omap1_dm_timer_init(void)
{
	int i;
	int ret;
	struct dmtimer_platform_data *pdata;
	struct platform_device *pdev;

	if (!cpu_is_omap16xx())
		return 0;

	for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
		struct resource res[2];
		u32 base, irq;

		switch (i) {
		case 1:
			base = OMAP1610_GPTIMER1_BASE;
			irq = INT_1610_GPTIMER1;
			break;
		case 2:
			base = OMAP1610_GPTIMER2_BASE;
			irq = INT_1610_GPTIMER2;
			break;
		case 3:
			base = OMAP1610_GPTIMER3_BASE;
			irq = INT_1610_GPTIMER3;
			break;
		case 4:
			base = OMAP1610_GPTIMER4_BASE;
			irq = INT_1610_GPTIMER4;
			break;
		case 5:
			base = OMAP1610_GPTIMER5_BASE;
			irq = INT_1610_GPTIMER5;
			break;
		case 6:
			base = OMAP1610_GPTIMER6_BASE;
			irq = INT_1610_GPTIMER6;
			break;
		case 7:
			base = OMAP1610_GPTIMER7_BASE;
			irq = INT_1610_GPTIMER7;
			break;
		case 8:
			base = OMAP1610_GPTIMER8_BASE;
			irq = INT_1610_GPTIMER8;
			break;
		default:
			/*
			 * not supposed to reach here.
			 * this is to remove warning.
			 */
			return -EINVAL;
		}

		pdev = platform_device_alloc("omap_timer", i);
		if (!pdev) {
			pr_err("%s: Failed to device alloc for dmtimer%d\n",
				__func__, i);
			return -ENOMEM;
		}

		memset(res, 0, 2 * sizeof(struct resource));
		res[0].start = base;
		res[0].end = base + 0x46;
		res[0].flags = IORESOURCE_MEM;
		res[1].start = irq;
		res[1].end = irq;
		res[1].flags = IORESOURCE_IRQ;
		ret = platform_device_add_resources(pdev, res,
				ARRAY_SIZE(res));
		if (ret) {
			dev_err(&pdev->dev, "%s: Failed to add resources.\n",
				__func__);
			goto err_free_pdev;
		}

		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
		if (!pdata) {
			ret = -ENOMEM;
			goto err_free_pdata;
		}

		pdata->set_timer_src = omap1_dm_timer_set_src;
		pdata->timer_capability = OMAP_TIMER_ALWON |
				OMAP_TIMER_NEEDS_RESET | OMAP_TIMER_HAS_DSP_IRQ;

		ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
		if (ret) {
			dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
				__func__);
			goto err_free_pdata;
		}

		ret = platform_device_add(pdev);
		if (ret) {
			dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
				__func__);
			goto err_free_pdata;
		}

		dev_dbg(&pdev->dev, " Registered.\n");
	}

	return 0;

err_free_pdata:
	kfree(pdata);

err_free_pdev:
	platform_device_unregister(pdev);

	return ret;
}
arch_initcall(omap1_dm_timer_init);

repo_name: angery/linux


code:
/*
 * linux/arch/arm/mach-omap1/timer32k.c
 *
 * OMAP 32K Timer
 *
 * Copyright (C) 2004 - 2005 Nokia Corporation
 * Partial timer rewrite and additional dynamic tick timer support by
 * Tony Lindgen <tony@atomide.com> and
 * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 * OMAP Dual-mode timer framework support by Timo Teras
 *
 * MPU timer code based on the older MPU timer code for OMAP
 * Copyright (C) 2000 RidgeRun, Inc.
 * Author: Greg Lonnon <glonnon@ridgerun.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/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
#include <linux/sched_clock.h>

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

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

/*
 * ---------------------------------------------------------------------------
 * 32KHz OS timer
 *
 * This currently works only on 16xx, as 1510 does not have the continuous
 * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
 * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
 * on 1510 would be possible, but the timer would not be as accurate as
 * with the 32KHz synchronized timer.
 * ---------------------------------------------------------------------------
 */

/* 16xx specific defines */
#define OMAP1_32K_TIMER_BASE		0xfffb9000
#define OMAP1_32KSYNC_TIMER_BASE	0xfffbc400
#define OMAP1_32K_TIMER_CR		0x08
#define OMAP1_32K_TIMER_TVR		0x00
#define OMAP1_32K_TIMER_TCR		0x04

#define OMAP_32K_TICKS_PER_SEC		(32768)

/*
 * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
 * so with HZ = 128, TVR = 255.
 */
#define OMAP_32K_TIMER_TICK_PERIOD	((OMAP_32K_TICKS_PER_SEC / HZ) - 1)

#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate)			\
				(((nr_jiffies) * (clock_rate)) / HZ)

static inline void omap_32k_timer_write(int val, int reg)
{
	omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
}

static inline void omap_32k_timer_start(unsigned long load_val)
{
	if (!load_val)
		load_val = 1;
	omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
	omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
}

static inline void omap_32k_timer_stop(void)
{
	omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
}

#define omap_32k_timer_ack_irq()

static int omap_32k_timer_set_next_event(unsigned long delta,
					 struct clock_event_device *dev)
{
	omap_32k_timer_start(delta);

	return 0;
}

static int omap_32k_timer_shutdown(struct clock_event_device *evt)
{
	omap_32k_timer_stop();
	return 0;
}

static int omap_32k_timer_set_periodic(struct clock_event_device *evt)
{
	omap_32k_timer_stop();
	omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
	return 0;
}

static struct clock_event_device clockevent_32k_timer = {
	.name			= "32k-timer",
	.features		= CLOCK_EVT_FEAT_PERIODIC |
				  CLOCK_EVT_FEAT_ONESHOT,
	.set_next_event		= omap_32k_timer_set_next_event,
	.set_state_shutdown	= omap_32k_timer_shutdown,
	.set_state_periodic	= omap_32k_timer_set_periodic,
	.set_state_oneshot	= omap_32k_timer_shutdown,
	.tick_resume		= omap_32k_timer_shutdown,
};

static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
{
	struct clock_event_device *evt = &clockevent_32k_timer;
	omap_32k_timer_ack_irq();

	evt->event_handler(evt);

	return IRQ_HANDLED;
}

static __init void omap_init_32k_timer(void)
{
	if (request_irq(INT_OS_TIMER, omap_32k_timer_interrupt,
			IRQF_TIMER | IRQF_IRQPOLL, "32KHz timer", NULL))
		pr_err("Failed to request irq %d(32KHz timer)\n", INT_OS_TIMER);

	clockevent_32k_timer.cpumask = cpumask_of(0);
	clockevents_config_and_register(&clockevent_32k_timer,
					OMAP_32K_TICKS_PER_SEC, 1, 0xfffffffe);
}

/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
#define OMAP2_32KSYNCNT_REV_OFF		0x0
#define OMAP2_32KSYNCNT_REV_SCHEME	(0x3 << 30)
#define OMAP2_32KSYNCNT_CR_OFF_LOW	0x10
#define OMAP2_32KSYNCNT_CR_OFF_HIGH	0x30

/*
 * 32KHz clocksource ... always available, on pretty most chips except
 * OMAP 730 and 1510.  Other timers could be used as clocksources, with
 * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
 * but systems won't necessarily want to spend resources that way.
 */
static void __iomem *sync32k_cnt_reg;

static u64 notrace omap_32k_read_sched_clock(void)
{
	return sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
}

/**
 * omap_read_persistent_clock64 -  Return time from a persistent clock.
 *
 * Reads the time from a source which isn't disabled during PM, the
 * 32k sync timer.  Convert the cycles elapsed since last read into
 * nsecs and adds to a monotonically increasing timespec64.
 */
static struct timespec64 persistent_ts;
static cycles_t cycles;
static unsigned int persistent_mult, persistent_shift;

static void omap_read_persistent_clock64(struct timespec64 *ts)
{
	unsigned long long nsecs;
	cycles_t last_cycles;

	last_cycles = cycles;
	cycles = sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;

	nsecs = clocksource_cyc2ns(cycles - last_cycles,
					persistent_mult, persistent_shift);

	timespec64_add_ns(&persistent_ts, nsecs);

	*ts = persistent_ts;
}

/**
 * omap_init_clocksource_32k - setup and register counter 32k as a
 * kernel clocksource
 * @pbase: base addr of counter_32k module
 * @size: size of counter_32k to map
 *
 * Returns 0 upon success or negative error code upon failure.
 *
 */
static int __init omap_init_clocksource_32k(void __iomem *vbase)
{
	int ret;

	/*
	 * 32k sync Counter IP register offsets vary between the
	 * highlander version and the legacy ones.
	 * The 'SCHEME' bits(30-31) of the revision register is used
	 * to identify the version.
	 */
	if (readl_relaxed(vbase + OMAP2_32KSYNCNT_REV_OFF) &
						OMAP2_32KSYNCNT_REV_SCHEME)
		sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_HIGH;
	else
		sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_LOW;

	/*
	 * 120000 rough estimate from the calculations in
	 * __clocksource_update_freq_scale.
	 */
	clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
			32768, NSEC_PER_SEC, 120000);

	ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
				250, 32, clocksource_mmio_readl_up);
	if (ret) {
		pr_err("32k_counter: can't register clocksource\n");
		return ret;
	}

	sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
	register_persistent_clock(omap_read_persistent_clock64);
	pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");

	return 0;
}

/*
 * ---------------------------------------------------------------------------
 * Timer initialization
 * ---------------------------------------------------------------------------
 */
int __init omap_32k_timer_init(void)
{
	int ret = -ENODEV;

	if (cpu_is_omap16xx()) {
		void __iomem *base;
		struct clk *sync32k_ick;

		base = ioremap(OMAP1_32KSYNC_TIMER_BASE, SZ_1K);
		if (!base) {
			pr_err("32k_counter: failed to map base addr\n");
			return -ENODEV;
		}

		sync32k_ick = clk_get(NULL, "omap_32ksync_ick");
		if (!IS_ERR(sync32k_ick))
			clk_prepare_enable(sync32k_ick);

		ret = omap_init_clocksource_32k(base);
	}

	if (!ret)
		omap_init_32k_timer();

	return ret;
}


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Platform level USB initialization for FS USB OTG controller on omap1
 *
 * Copyright (C) 2004 Texas Instruments, Inc.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-map-ops.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/soc/ti/omap1-io.h>

#include <asm/irq.h>

#include "hardware.h"
#include "mux.h"
#include "usb.h"
#include "common.h"

/* These routines should handle the standard chip-specific modes
 * for usb0/1/2 ports, covering basic mux and transceiver setup.
 *
 * Some board-*.c files will need to set up additional mux options,
 * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
 */

/* TESTED ON:
 *  - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
 *  - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables
 *  - 5912 OSK UDC, with *nonstandard* A-to-A cable
 *  - 1510 Innovator UDC with bundled usb0 cable
 *  - 1510 Innovator OHCI with bundled usb1/usb2 cable
 *  - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
 *  - 1710 custom development board using alternate pin group
 *  - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables
 */

#define INT_USB_IRQ_GEN		IH2_BASE + 20
#define INT_USB_IRQ_NISO	IH2_BASE + 30
#define INT_USB_IRQ_ISO		IH2_BASE + 29
#define INT_USB_IRQ_HGEN	INT_USB_HHC_1
#define INT_USB_IRQ_OTG		IH2_BASE + 8

#ifdef	CONFIG_ARCH_OMAP_OTG

static void __init
omap_otg_init(struct omap_usb_config *config)
{
	u32		syscon;
	int		alt_pingroup = 0;
	u16		w;

	/* NOTE:  no bus or clock setup (yet?) */

	syscon = omap_readl(OTG_SYSCON_1) & 0xffff;
	if (!(syscon & OTG_RESET_DONE))
		pr_debug("USB resets not complete?\n");

	//omap_writew(0, OTG_IRQ_EN);

	/* pin muxing and transceiver pinouts */
	if (config->pins[0] > 2)	/* alt pingroup 2 */
		alt_pingroup = 1;
	syscon |= config->usb0_init(config->pins[0], is_usb0_device(config));
	syscon |= config->usb1_init(config->pins[1]);
	syscon |= config->usb2_init(config->pins[2], alt_pingroup);
	pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
	omap_writel(syscon, OTG_SYSCON_1);

	syscon = config->hmc_mode;
	syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
#ifdef	CONFIG_USB_OTG
	if (config->otg)
		syscon |= OTG_EN;
#endif
	pr_debug("USB_TRANSCEIVER_CTRL = %03x\n",
		 omap_readl(USB_TRANSCEIVER_CTRL));
	pr_debug("OTG_SYSCON_2 = %08x\n", omap_readl(OTG_SYSCON_2));
	omap_writel(syscon, OTG_SYSCON_2);

	printk("USB: hmc %d", config->hmc_mode);
	if (!alt_pingroup)
		pr_cont(", usb2 alt %d wires", config->pins[2]);
	else if (config->pins[0])
		pr_cont(", usb0 %d wires%s", config->pins[0],
			is_usb0_device(config) ? " (dev)" : "");
	if (config->pins[1])
		pr_cont(", usb1 %d wires", config->pins[1]);
	if (!alt_pingroup && config->pins[2])
		pr_cont(", usb2 %d wires", config->pins[2]);
	if (config->otg)
		pr_cont(", Mini-AB on usb%d", config->otg - 1);
	pr_cont("\n");

	/* leave USB clocks/controllers off until needed */
	w = omap_readw(ULPD_SOFT_REQ);
	w &= ~SOFT_USB_CLK_REQ;
	omap_writew(w, ULPD_SOFT_REQ);

	w = omap_readw(ULPD_CLOCK_CTRL);
	w &= ~USB_MCLK_EN;
	w |= DIS_USB_PVCI_CLK;
	omap_writew(w, ULPD_CLOCK_CTRL);

	syscon = omap_readl(OTG_SYSCON_1);
	syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;

#if IS_ENABLED(CONFIG_USB_OMAP)
	if (config->otg || config->register_dev) {
		struct platform_device *udc_device = config->udc_device;
		int status;

		syscon &= ~DEV_IDLE_EN;
		udc_device->dev.platform_data = config;
		status = platform_device_register(udc_device);
		if (status)
			pr_debug("can't register UDC device, %d\n", status);
	}
#endif

#if	IS_ENABLED(CONFIG_USB_OHCI_HCD)
	if (config->otg || config->register_host) {
		struct platform_device *ohci_device = config->ohci_device;
		int status;

		syscon &= ~HST_IDLE_EN;
		ohci_device->dev.platform_data = config;
		status = platform_device_register(ohci_device);
		if (status)
			pr_debug("can't register OHCI device, %d\n", status);
	}
#endif

#ifdef	CONFIG_USB_OTG
	if (config->otg) {
		struct platform_device *otg_device = config->otg_device;
		int status;

		syscon &= ~OTG_IDLE_EN;
		otg_device->dev.platform_data = config;
		status = platform_device_register(otg_device);
		if (status)
			pr_debug("can't register OTG device, %d\n", status);
	}
#endif
	pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
	omap_writel(syscon, OTG_SYSCON_1);
}

#else
static void omap_otg_init(struct omap_usb_config *config) {}
#endif

#if IS_ENABLED(CONFIG_USB_OMAP)

static struct resource udc_resources[] = {
	/* order is significant! */
	{		/* registers */
		.start		= UDC_BASE,
		.end		= UDC_BASE + 0xff,
		.flags		= IORESOURCE_MEM,
	}, {		/* general IRQ */
		.start		= INT_USB_IRQ_GEN,
		.flags		= IORESOURCE_IRQ,
	}, {		/* PIO IRQ */
		.start		= INT_USB_IRQ_NISO,
		.flags		= IORESOURCE_IRQ,
	}, {		/* SOF IRQ */
		.start		= INT_USB_IRQ_ISO,
		.flags		= IORESOURCE_IRQ,
	},
};

static u64 udc_dmamask = ~(u32)0;

static struct platform_device udc_device = {
	.name		= "omap_udc",
	.id		= -1,
	.dev = {
		.dma_mask		= &udc_dmamask,
		.coherent_dma_mask	= 0xffffffff,
	},
	.num_resources	= ARRAY_SIZE(udc_resources),
	.resource	= udc_resources,
};

static inline void udc_device_init(struct omap_usb_config *pdata)
{
	/* IRQ numbers for omap7xx */
	if(cpu_is_omap7xx()) {
		udc_resources[1].start = INT_7XX_USB_GENI;
		udc_resources[2].start = INT_7XX_USB_NON_ISO;
		udc_resources[3].start = INT_7XX_USB_ISO;
	}
	pdata->udc_device = &udc_device;
}

#else

static inline void udc_device_init(struct omap_usb_config *pdata)
{
}

#endif

/* The dmamask must be set for OHCI to work */
static u64 ohci_dmamask = ~(u32)0;

static struct resource ohci_resources[] = {
	{
		.start	= OMAP_OHCI_BASE,
		.end	= OMAP_OHCI_BASE + 0xff,
		.flags	= IORESOURCE_MEM,
	},
	{
		.start	= INT_USB_IRQ_HGEN,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device ohci_device = {
	.name			= "ohci",
	.id			= -1,
	.dev = {
		.dma_mask		= &ohci_dmamask,
		.coherent_dma_mask	= 0xffffffff,
	},
	.num_resources	= ARRAY_SIZE(ohci_resources),
	.resource		= ohci_resources,
};

static inline void ohci_device_init(struct omap_usb_config *pdata)
{
	if (!IS_ENABLED(CONFIG_USB_OHCI_HCD))
		return;

	if (cpu_is_omap7xx())
		ohci_resources[1].start = INT_7XX_USB_HHC_1;
	pdata->ohci_device = &ohci_device;
	pdata->ocpi_enable = &ocpi_enable;
}

#if	defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)

static struct resource otg_resources[] = {
	/* order is significant! */
	{
		.start		= OTG_BASE,
		.end		= OTG_BASE + 0xff,
		.flags		= IORESOURCE_MEM,
	}, {
		.start		= INT_USB_IRQ_OTG,
		.flags		= IORESOURCE_IRQ,
	},
};

static struct platform_device otg_device = {
	.name		= "omap_otg",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(otg_resources),
	.resource	= otg_resources,
};

static inline void otg_device_init(struct omap_usb_config *pdata)
{
	if (cpu_is_omap7xx())
		otg_resources[1].start = INT_7XX_USB_OTG;
	pdata->otg_device = &otg_device;
}

#else

static inline void otg_device_init(struct omap_usb_config *pdata)
{
}

#endif

static u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device)
{
	u32	syscon1 = 0;

	if (nwires == 0) {
		if (!cpu_is_omap15xx()) {
			u32 l;

			/* pulldown D+/D- */
			l = omap_readl(USB_TRANSCEIVER_CTRL);
			l &= ~(3 << 1);
			omap_writel(l, USB_TRANSCEIVER_CTRL);
		}
		return 0;
	}

	if (is_device) {
		if (cpu_is_omap7xx()) {
			omap_cfg_reg(AA17_7XX_USB_DM);
			omap_cfg_reg(W16_7XX_USB_PU_EN);
			omap_cfg_reg(W17_7XX_USB_VBUSI);
			omap_cfg_reg(W18_7XX_USB_DMCK_OUT);
			omap_cfg_reg(W19_7XX_USB_DCRST);
		} else
			omap_cfg_reg(W4_USB_PUEN);
	}

	if (nwires == 2) {
		u32 l;

		// omap_cfg_reg(P9_USB_DP);
		// omap_cfg_reg(R8_USB_DM);

		if (cpu_is_omap15xx()) {
			/* This works on 1510-Innovator */
			return 0;
		}

		/* NOTES:
		 *  - peripheral should configure VBUS detection!
		 *  - only peripherals may use the internal D+/D- pulldowns
		 *  - OTG support on this port not yet written
		 */

		/* Don't do this for omap7xx -- it causes USB to not work correctly */
		if (!cpu_is_omap7xx()) {
			l = omap_readl(USB_TRANSCEIVER_CTRL);
			l &= ~(7 << 4);
			if (!is_device)
				l |= (3 << 1);
			omap_writel(l, USB_TRANSCEIVER_CTRL);
		}

		return 3 << 16;
	}

	/* alternate pin config, external transceiver */
	if (cpu_is_omap15xx()) {
		printk(KERN_ERR "no usb0 alt pin config on 15xx\n");
		return 0;
	}

	omap_cfg_reg(V6_USB0_TXD);
	omap_cfg_reg(W9_USB0_TXEN);
	omap_cfg_reg(W5_USB0_SE0);
	if (nwires != 3)
		omap_cfg_reg(Y5_USB0_RCV);

	/* NOTE:  SPEED and SUSP aren't configured here.  OTG hosts
	 * may be able to use I2C requests to set those bits along
	 * with VBUS switching and overcurrent detection.
	 */

	if (nwires != 6) {
		u32 l;

		l = omap_readl(USB_TRANSCEIVER_CTRL);
		l &= ~CONF_USB2_UNI_R;
		omap_writel(l, USB_TRANSCEIVER_CTRL);
	}

	switch (nwires) {
	case 3:
		syscon1 = 2;
		break;
	case 4:
		syscon1 = 1;
		break;
	case 6:
		syscon1 = 3;
		{
			u32 l;

			omap_cfg_reg(AA9_USB0_VP);
			omap_cfg_reg(R9_USB0_VM);
			l = omap_readl(USB_TRANSCEIVER_CTRL);
			l |= CONF_USB2_UNI_R;
			omap_writel(l, USB_TRANSCEIVER_CTRL);
		}
		break;
	default:
		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
			0, nwires);
	}

	return syscon1 << 16;
}

static u32 __init omap1_usb1_init(unsigned nwires)
{
	u32	syscon1 = 0;

	if (!cpu_is_omap15xx() && nwires != 6) {
		u32 l;

		l = omap_readl(USB_TRANSCEIVER_CTRL);
		l &= ~CONF_USB1_UNI_R;
		omap_writel(l, USB_TRANSCEIVER_CTRL);
	}
	if (nwires == 0)
		return 0;

	/* external transceiver */
	omap_cfg_reg(USB1_TXD);
	omap_cfg_reg(USB1_TXEN);
	if (nwires != 3)
		omap_cfg_reg(USB1_RCV);

	if (cpu_is_omap15xx()) {
		omap_cfg_reg(USB1_SEO);
		omap_cfg_reg(USB1_SPEED);
		// SUSP
	} else if (cpu_is_omap1610() || cpu_is_omap5912()) {
		omap_cfg_reg(W13_1610_USB1_SE0);
		omap_cfg_reg(R13_1610_USB1_SPEED);
		// SUSP
	} else if (cpu_is_omap1710()) {
		omap_cfg_reg(R13_1710_USB1_SE0);
		// SUSP
	} else {
		pr_debug("usb%d cpu unrecognized\n", 1);
		return 0;
	}

	switch (nwires) {
	case 2:
		goto bad;
	case 3:
		syscon1 = 2;
		break;
	case 4:
		syscon1 = 1;
		break;
	case 6:
		syscon1 = 3;
		omap_cfg_reg(USB1_VP);
		omap_cfg_reg(USB1_VM);
		if (!cpu_is_omap15xx()) {
			u32 l;

			l = omap_readl(USB_TRANSCEIVER_CTRL);
			l |= CONF_USB1_UNI_R;
			omap_writel(l, USB_TRANSCEIVER_CTRL);
		}
		break;
	default:
bad:
		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
			1, nwires);
	}

	return syscon1 << 20;
}

static u32 __init omap1_usb2_init(unsigned nwires, unsigned alt_pingroup)
{
	u32	syscon1 = 0;

	/* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
	if (alt_pingroup || nwires == 0)
		return 0;

	if (!cpu_is_omap15xx() && nwires != 6) {
		u32 l;

		l = omap_readl(USB_TRANSCEIVER_CTRL);
		l &= ~CONF_USB2_UNI_R;
		omap_writel(l, USB_TRANSCEIVER_CTRL);
	}

	/* external transceiver */
	if (cpu_is_omap15xx()) {
		omap_cfg_reg(USB2_TXD);
		omap_cfg_reg(USB2_TXEN);
		omap_cfg_reg(USB2_SEO);
		if (nwires != 3)
			omap_cfg_reg(USB2_RCV);
		/* there is no USB2_SPEED */
	} else if (cpu_is_omap16xx()) {
		omap_cfg_reg(V6_USB2_TXD);
		omap_cfg_reg(W9_USB2_TXEN);
		omap_cfg_reg(W5_USB2_SE0);
		if (nwires != 3)
			omap_cfg_reg(Y5_USB2_RCV);
		// FIXME omap_cfg_reg(USB2_SPEED);
	} else {
		pr_debug("usb%d cpu unrecognized\n", 1);
		return 0;
	}

	// omap_cfg_reg(USB2_SUSP);

	switch (nwires) {
	case 2:
		goto bad;
	case 3:
		syscon1 = 2;
		break;
	case 4:
		syscon1 = 1;
		break;
	case 5:
		goto bad;
	case 6:
		syscon1 = 3;
		if (cpu_is_omap15xx()) {
			omap_cfg_reg(USB2_VP);
			omap_cfg_reg(USB2_VM);
		} else {
			u32 l;

			omap_cfg_reg(AA9_USB2_VP);
			omap_cfg_reg(R9_USB2_VM);
			l = omap_readl(USB_TRANSCEIVER_CTRL);
			l |= CONF_USB2_UNI_R;
			omap_writel(l, USB_TRANSCEIVER_CTRL);
		}
		break;
	default:
bad:
		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
			2, nwires);
	}

	return syscon1 << 24;
}

#ifdef	CONFIG_ARCH_OMAP15XX
/* OMAP-1510 OHCI has its own MMU for DMA */
#define OMAP1510_LB_MEMSIZE	32	/* Should be same as SDRAM size */
#define OMAP1510_LB_CLOCK_DIV	0xfffec10c
#define OMAP1510_LB_MMU_CTL	0xfffec208
#define OMAP1510_LB_MMU_LCK	0xfffec224
#define OMAP1510_LB_MMU_LD_TLB	0xfffec228
#define OMAP1510_LB_MMU_CAM_H	0xfffec22c
#define OMAP1510_LB_MMU_CAM_L	0xfffec230
#define OMAP1510_LB_MMU_RAM_H	0xfffec234
#define OMAP1510_LB_MMU_RAM_L	0xfffec238

/*
 * Bus address is physical address, except for OMAP-1510 Local Bus.
 * OMAP-1510 bus address is translated into a Local Bus address if the
 * OMAP bus type is lbus.
 */
#define OMAP1510_LB_OFFSET	   UL(0x30000000)

/*
 * OMAP-1510 specific Local Bus clock on/off
 */
static int omap_1510_local_bus_power(int on)
{
	if (on) {
		omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL);
		udelay(200);
	} else {
		omap_writel(0, OMAP1510_LB_MMU_CTL);
	}

	return 0;
}

/*
 * OMAP-1510 specific Local Bus initialization
 * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
 *       See also arch/mach-omap/memory.h for __virt_to_dma() and
 *       __dma_to_virt() which need to match with the physical
 *       Local Bus address below.
 */
static int omap_1510_local_bus_init(void)
{
	unsigned int tlb;
	unsigned long lbaddr, physaddr;

	omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
	       OMAP1510_LB_CLOCK_DIV);

	/* Configure the Local Bus MMU table */
	for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) {
		lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
		physaddr = tlb * 0x00100000 + PHYS_OFFSET;
		omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
		omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
		       OMAP1510_LB_MMU_CAM_L);
		omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
		omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
		omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK);
		omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB);
	}

	/* Enable the walking table */
	omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL);
	udelay(200);

	return 0;
}

static void omap_1510_local_bus_reset(void)
{
	omap_1510_local_bus_power(1);
	omap_1510_local_bus_init();
}

/* ULPD_DPLL_CTRL */
#define DPLL_IOB		(1 << 13)
#define DPLL_PLL_ENABLE		(1 << 4)
#define DPLL_LOCK		(1 << 0)

/* ULPD_APLL_CTRL */
#define APLL_NDPLL_SWITCH	(1 << 0)

static void __init omap_1510_usb_init(struct omap_usb_config *config)
{
	unsigned int val;
	u16 w;

	config->usb0_init(config->pins[0], is_usb0_device(config));
	config->usb1_init(config->pins[1]);
	config->usb2_init(config->pins[2], 0);

	val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
	val |= (config->hmc_mode << 1);
	omap_writel(val, MOD_CONF_CTRL_0);

	printk("USB: hmc %d", config->hmc_mode);
	if (config->pins[0])
		pr_cont(", usb0 %d wires%s", config->pins[0],
			is_usb0_device(config) ? " (dev)" : "");
	if (config->pins[1])
		pr_cont(", usb1 %d wires", config->pins[1]);
	if (config->pins[2])
		pr_cont(", usb2 %d wires", config->pins[2]);
	pr_cont("\n");

	/* use DPLL for 48 MHz function clock */
	pr_debug("APLL %04x DPLL %04x REQ %04x\n", omap_readw(ULPD_APLL_CTRL),
			omap_readw(ULPD_DPLL_CTRL), omap_readw(ULPD_SOFT_REQ));

	w = omap_readw(ULPD_APLL_CTRL);
	w &= ~APLL_NDPLL_SWITCH;
	omap_writew(w, ULPD_APLL_CTRL);

	w = omap_readw(ULPD_DPLL_CTRL);
	w |= DPLL_IOB | DPLL_PLL_ENABLE;
	omap_writew(w, ULPD_DPLL_CTRL);

	w = omap_readw(ULPD_SOFT_REQ);
	w |= SOFT_UDC_REQ | SOFT_DPLL_REQ;
	omap_writew(w, ULPD_SOFT_REQ);

	while (!(omap_readw(ULPD_DPLL_CTRL) & DPLL_LOCK))
		cpu_relax();

#if IS_ENABLED(CONFIG_USB_OMAP)
	if (config->register_dev) {
		int status;

		udc_device.dev.platform_data = config;
		status = platform_device_register(&udc_device);
		if (status)
			pr_debug("can't register UDC device, %d\n", status);
		/* udc driver gates 48MHz by D+ pullup */
	}
#endif

	if (IS_ENABLED(CONFIG_USB_OHCI_HCD) && config->register_host) {
		int status;

		ohci_device.dev.platform_data = config;
		dma_direct_set_offset(&ohci_device.dev, PHYS_OFFSET,
				      OMAP1510_LB_OFFSET, (u64)-1);
		status = platform_device_register(&ohci_device);
		if (status)
			pr_debug("can't register OHCI device, %d\n", status);
		/* hcd explicitly gates 48MHz */

		config->lb_reset = omap_1510_local_bus_reset;
	}
}

#else
static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
#endif

void __init omap1_usb_init(struct omap_usb_config *_pdata)
{
	struct omap_usb_config *pdata;

	pdata = kmemdup(_pdata, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return;

	pdata->usb0_init = omap1_usb0_init;
	pdata->usb1_init = omap1_usb1_init;
	pdata->usb2_init = omap1_usb2_init;
	udc_device_init(pdata);
	ohci_device_init(pdata);
	otg_device_init(pdata);

	if (cpu_is_omap7xx() || cpu_is_omap16xx())
		omap_otg_init(pdata);
	else if (cpu_is_omap15xx())
		omap_1510_usb_init(pdata);
	else
		printk(KERN_ERR "USB: No init for your chip yet\n");
}


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * fixme correct answer depends on hmc_mode,
 * as does (on omap1) any nonzero value for config->otg port number
 */
#include <linux/platform_data/usb-omap1.h>
#include <linux/soc/ti/omap1-usb.h>

#if IS_ENABLED(CONFIG_USB_OMAP)
#define	is_usb0_device(config)	1
#else
#define	is_usb0_device(config)	0
#endif

#if IS_ENABLED(CONFIG_USB_SUPPORT)
void omap1_usb_init(struct omap_usb_config *pdata);
#else
static inline void omap1_usb_init(struct omap_usb_config *pdata)
{
}
#endif

#define OMAP1_OHCI_BASE			0xfffba000
#define OMAP2_OHCI_BASE			0x4805e000
#define OMAP_OHCI_BASE			OMAP1_OHCI_BASE


code:
# SPDX-License-Identifier: GPL-2.0-only
pm-asm-offsets.h


code:
# SPDX-License-Identifier: GPL-2.0-only
menu "TI OMAP/AM/DM/DRA Family"
	depends on ARCH_MULTI_V6 || ARCH_MULTI_V7

config OMAP_HWMOD
	bool

config ARCH_OMAP2
	bool "TI OMAP2"
	depends on ARCH_MULTI_V6
	select ARCH_OMAP2PLUS
	select CPU_V6
	select OMAP_HWMOD
	select SOC_HAS_OMAP2_SDRC

config ARCH_OMAP3
	bool "TI OMAP3"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARM_CPU_SUSPEND
	select OMAP_HWMOD
	select OMAP_INTERCONNECT
	select PM_OPP
	select SOC_HAS_OMAP2_SDRC
	select ARM_ERRATA_430973

config ARCH_OMAP4
	bool "TI OMAP4"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
	select ARM_CPU_SUSPEND
	select ARM_ERRATA_720789
	select ARM_GIC
	select HAVE_ARM_SCU if SMP
	select HAVE_ARM_TWD if SMP
	select OMAP_INTERCONNECT
	select OMAP_INTERCONNECT_BARRIER
	select PL310_ERRATA_588369 if CACHE_L2X0
	select PL310_ERRATA_727915 if CACHE_L2X0
	select PM_OPP
	select PM if CPU_IDLE
	select ARM_ERRATA_754322
	select ARM_ERRATA_775420
	select OMAP_INTERCONNECT

config SOC_OMAP5
	bool "TI OMAP5"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARM_CPU_SUSPEND
	select ARM_GIC
	select HAVE_ARM_SCU if SMP
	select HAVE_ARM_ARCH_TIMER
	select ARM_ERRATA_798181 if SMP
	select OMAP_INTERCONNECT
	select OMAP_INTERCONNECT_BARRIER
	select PM_OPP
	select ZONE_DMA if ARM_LPAE

config SOC_AM33XX
	bool "TI AM33XX"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARM_CPU_SUSPEND

config SOC_AM43XX
	bool "TI AM43x"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARM_GIC
	select MACH_OMAP_GENERIC
	select HAVE_ARM_SCU
	select GENERIC_CLOCKEVENTS_BROADCAST
	select HAVE_ARM_TWD
	select ARM_ERRATA_754322
	select ARM_ERRATA_775420
	select OMAP_INTERCONNECT
	select ARM_CPU_SUSPEND

config SOC_DRA7XX
	bool "TI DRA7XX"
	depends on ARCH_MULTI_V7
	select ARCH_OMAP2PLUS
	select ARM_CPU_SUSPEND
	select ARM_GIC
	select HAVE_ARM_SCU if SMP
	select HAVE_ARM_ARCH_TIMER
	select IRQ_CROSSBAR
	select ARM_ERRATA_798181 if SMP
	select OMAP_INTERCONNECT
	select OMAP_INTERCONNECT_BARRIER
	select PM_OPP
	select ZONE_DMA if ARM_LPAE
	select PINCTRL_TI_IODELAY if OF && PINCTRL

config ARCH_OMAP2PLUS
	bool
	select ARCH_HAS_BANDGAP
	select ARCH_HAS_RESET_CONTROLLER
	select ARCH_OMAP
	select CLKSRC_MMIO
	select GENERIC_IRQ_CHIP
	select GPIOLIB
	select MACH_OMAP_GENERIC
	select MEMORY
	select MFD_SYSCON
	select OMAP_DM_SYSTIMER
	select OMAP_DM_TIMER
	select OMAP_GPMC
	select PINCTRL
	select PM
	select PM_GENERIC_DOMAINS
	select PM_GENERIC_DOMAINS_OF
	select RESET_CONTROLLER
	select SOC_BUS
	select TI_SYSC
	select OMAP_IRQCHIP
	select CLKSRC_TI_32K
	help
	  Systems based on OMAP2, OMAP3, OMAP4 or OMAP5

config OMAP_INTERCONNECT_BARRIER
	bool
	select ARM_HEAVY_MB

config ARCH_OMAP
	bool

if ARCH_OMAP2PLUS

menu "TI OMAP2/3/4 Specific Features"

config ARCH_OMAP2PLUS_TYPICAL
	bool "Typical OMAP configuration"
	default y
	select AEABI
	select HIGHMEM
	select I2C
	select I2C_OMAP
	select MENELAUS if ARCH_OMAP2
	select NEON if CPU_V7
	select REGULATOR
	select REGULATOR_FIXED_VOLTAGE
	select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
	select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
	select VFP
	help
	  Compile a kernel suitable for booting most boards

config SOC_HAS_OMAP2_SDRC
	bool "OMAP2 SDRAM Controller support"

config SOC_HAS_REALTIME_COUNTER
	bool "Real time free running counter"
	depends on SOC_OMAP5 || SOC_DRA7XX
	default y

config POWER_AVS_OMAP
	bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
	depends on (ARCH_OMAP3 || ARCH_OMAP4) && PM
	select POWER_SUPPLY
	help
	  Say Y to enable AVS(Adaptive Voltage Scaling)
	  support on OMAP containing the version 1 or
	  version 2 of the SmartReflex IP.
	  V1 is the 65nm version used in OMAP3430.
	  V2 is the update for the 45nm version of the IP used in OMAP3630
	  and OMAP4430

	  Please note, that by default SmartReflex is only
	  initialized and not enabled. To enable the automatic voltage
	  compensation for vdd mpu and vdd core from user space,
	  user must write 1 to
		/debug/smartreflex/sr_<X>/autocomp,
	  where X is mpu_iva or core for OMAP3.
	  Optionally autocompensation can be enabled in the kernel
	  by default during system init via the enable_on_init flag
	  which an be passed as platform data to the smartreflex driver.

config POWER_AVS_OMAP_CLASS3
	bool "Class 3 mode of Smartreflex Implementation"
	depends on POWER_AVS_OMAP && TWL4030_CORE
	help
	  Say Y to enable Class 3 implementation of Smartreflex

	  Class 3 implementation of Smartreflex employs continuous hardware
	  voltage calibration.

config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
	bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
	depends on ARCH_OMAP3 && PM
	help
	  Without this option, L2 Auxiliary control register contents are
	  lost during off-mode entry on HS/EMU devices. This feature
	  requires support from PPA / boot-loader in HS/EMU devices, which
	  currently does not exist by default.

config OMAP3_L2_AUX_SECURE_SERVICE_SET_ID
	int "Service ID for the support routine to set L2 AUX control"
	depends on OMAP3_L2_AUX_SECURE_SAVE_RESTORE
	default 43
	help
	  PPA routine service ID for setting L2 auxiliary control register.

comment "OMAP Core Type"
	depends on ARCH_OMAP2

config SOC_OMAP2420
	bool "OMAP2420 support"
	depends on ARCH_OMAP2
	default y
	select OMAP_DM_SYSTIMER
	select OMAP_DM_TIMER
	select SOC_HAS_OMAP2_SDRC

config SOC_OMAP2430
	bool "OMAP2430 support"
	depends on ARCH_OMAP2
	default y
	select SOC_HAS_OMAP2_SDRC

config SOC_OMAP3430
	bool "OMAP3430 support"
	depends on ARCH_OMAP3
	default y
	select SOC_HAS_OMAP2_SDRC

config SOC_TI81XX
	bool "TI81XX support"
	depends on ARCH_OMAP3
	default y

comment "OMAP Legacy Platform Data Board Type"
	depends on ARCH_OMAP2PLUS

config MACH_OMAP_GENERIC
	bool

config MACH_OMAP2_TUSB6010
	bool
	depends on ARCH_OMAP2 && SOC_OMAP2420
	default y if MACH_NOKIA_N8X0

config MACH_NOKIA_N810
	bool

config MACH_NOKIA_N810_WIMAX
	bool

config MACH_NOKIA_N8X0
	bool "Nokia N800/N810"
	depends on SOC_OMAP2420
	default y
	select MACH_NOKIA_N810
	select MACH_NOKIA_N810_WIMAX

config OMAP3_SDRC_AC_TIMING
	bool "Enable SDRC AC timing register changes"
	depends on ARCH_OMAP3
	help
	  If you know that none of your system initiators will attempt to
	  access SDRAM during CORE DVFS, select Y here.  This should boost
	  SDRAM performance at lower CORE OPPs.  There are relatively few
	  users who will wish to say yes at this point - almost everyone will
	  wish to say no.  Selecting yes without understanding what is
	  going on could result in system crashes;

endmenu

endif

config OMAP5_ERRATA_801819
	bool "Errata 801819: An eviction from L1 data cache might stall indefinitely"
	depends on SOC_OMAP5 || SOC_DRA7XX
	help
	  A livelock can occur in the L2 cache arbitration that might prevent
	  a snoop from completing. Under certain conditions this can cause the
	  system to deadlock.

endmenu


code:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#

# Common support
obj-y := id.o io.o control.o devices.o fb.o pm.o \
	 common.o dma.o omap-headsmp.o sram.o

hwmod-common				= omap_hwmod.o omap_hwmod_reset.o \
					  omap_hwmod_common_data.o \
					  omap_hwmod_common_ipblock_data.o \
					  omap_device.o display.o hdq1w.o \
					  i2c.o wd_timer.o
clock-common				= clock.o
secure-common				= omap-smc.o omap-secure.o

obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
obj-$(CONFIG_ARCH_OMAP4) += $(secure-common)
obj-$(CONFIG_SOC_AM33XX) += $(secure-common)
obj-$(CONFIG_SOC_OMAP5)  += $(secure-common)
obj-$(CONFIG_SOC_AM43XX) += $(secure-common)
obj-$(CONFIG_SOC_DRA7XX) += $(secure-common)

ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
obj-$(CONFIG_OMAP_HWMOD) += mcbsp.o
endif

obj-$(CONFIG_TWL4030_CORE) += omap_twl.o

ifneq ($(CONFIG_MFD_CPCAP),)
obj-y 					+= pmic-cpcap.o
endif

obj-$(CONFIG_SOC_HAS_OMAP2_SDRC)	+= sdrc.o

# SMP support ONLY available for OMAP4

smp-$(CONFIG_SMP)			+= omap-smp.o
smp-$(CONFIG_HOTPLUG_CPU)		+= omap-hotplug.o
omap-4-5-common				=  omap4-common.o omap-wakeupgen.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-common) $(smp-y) sleep44xx.o
obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-common) $(smp-y) sleep44xx.o
obj-$(CONFIG_SOC_AM43XX)		+= $(omap-4-5-common)
obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-4-5-common) $(smp-y) sleep44xx.o

omap5-dra7-common-$(CONFIG_SOC_HAS_REALTIME_COUNTER) =  timer.o
obj-$(CONFIG_SOC_OMAP5)			+= $(omap5-dra7-common-y)
obj-$(CONFIG_SOC_DRA7XX)		+= $(omap5-dra7-common-y)

# Functions loaded to SRAM
obj-$(CONFIG_SOC_OMAP2420)		+= sram242x.o
obj-$(CONFIG_SOC_OMAP2430)		+= sram243x.o

# Restart code (OMAP4/5 currently in omap4-common.c)
obj-$(CONFIG_SOC_OMAP2420)		+= omap2-restart.o
obj-$(CONFIG_SOC_OMAP2430)		+= omap2-restart.o
obj-$(CONFIG_SOC_TI81XX)		+= ti81xx-restart.o
obj-$(CONFIG_SOC_AM33XX)		+= am33xx-restart.o
obj-$(CONFIG_SOC_AM43XX)		+= omap4-restart.o
obj-$(CONFIG_ARCH_OMAP3)		+= omap3-restart.o
obj-$(CONFIG_ARCH_OMAP4)		+= omap4-restart.o
obj-$(CONFIG_SOC_OMAP5)			+= omap4-restart.o
obj-$(CONFIG_SOC_DRA7XX)		+= omap4-restart.o

# SMS/SDRC
obj-$(CONFIG_ARCH_OMAP2)		+= sdrc2xxx.o
# obj-$(CONFIG_ARCH_OMAP3)		+= sdrc3xxx.o

# OPP table initialization
ifeq ($(CONFIG_PM_OPP),y)
obj-$(CONFIG_ARCH_OMAP3)		+= opp3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4)		+= opp4xxx_data.o
endif

# Power Management
omap-4-5-pm-common			= omap-mpuss-lowpower.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-pm-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-pm-common)

ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o
omap-4-5-pm-common			+= pm44xx.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-pm-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-pm-common)
obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-4-5-pm-common)
obj-$(CONFIG_SOC_AM33XX)		+= pm33xx-core.o sleep33xx.o
obj-$(CONFIG_SOC_AM43XX)		+= pm33xx-core.o sleep43xx.o
obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o

obj-$(CONFIG_POWER_AVS_OMAP)		+= sr_device.o
obj-$(CONFIG_POWER_AVS_OMAP_CLASS3)    += smartreflex-class3.o

endif

ifeq ($(CONFIG_CPU_IDLE),y)
obj-$(CONFIG_ARCH_OMAP3)                += cpuidle34xx.o
omap-4-5-idle-common			=  cpuidle44xx.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-4-5-idle-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(omap-4-5-idle-common)
obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-4-5-idle-common)
endif

# PRCM
obj-y					+= prm_common.o cm_common.o
obj-$(CONFIG_ARCH_OMAP2)		+= prm2xxx_3xxx.o prm2xxx.o cm2xxx.o
obj-$(CONFIG_ARCH_OMAP3)		+= prm2xxx_3xxx.o prm3xxx.o cm3xxx.o
obj-$(CONFIG_ARCH_OMAP3)		+= vc3xxx_data.o vp3xxx_data.o
omap-prcm-4-5-common			=  cminst44xx.o prm44xx.o \
					   prcm_mpu44xx.o prminst44xx.o \
					   vc44xx_data.o vp44xx_data.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(omap-prcm-4-5-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(omap-prcm-4-5-common)
obj-$(CONFIG_SOC_DRA7XX)		+= $(omap-prcm-4-5-common)
am33xx-43xx-prcm-common			+= prm33xx.o cm33xx.o
obj-$(CONFIG_SOC_TI81XX)		+= $(am33xx-43xx-prcm-common)
obj-$(CONFIG_SOC_AM33XX)		+= $(am33xx-43xx-prcm-common)
obj-$(CONFIG_SOC_AM43XX)		+= $(omap-prcm-4-5-common) \
					   $(am33xx-43xx-prcm-common)

# OMAP voltage domains
voltagedomain-common			:= voltage.o vc.o vp.o
obj-$(CONFIG_ARCH_OMAP2)		+= $(voltagedomain-common)
obj-$(CONFIG_ARCH_OMAP2)		+= voltagedomains2xxx_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= $(voltagedomain-common)
obj-$(CONFIG_ARCH_OMAP3)		+= voltagedomains3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(voltagedomain-common)
obj-$(CONFIG_ARCH_OMAP4)		+= voltagedomains44xx_data.o
obj-$(CONFIG_SOC_AM33XX)		+= $(voltagedomain-common)
obj-$(CONFIG_SOC_AM43XX)		+= $(voltagedomain-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(voltagedomain-common)
obj-$(CONFIG_SOC_OMAP5)                += voltagedomains54xx_data.o
obj-$(CONFIG_SOC_DRA7XX)		+= $(voltagedomain-common)

# OMAP powerdomain framework
powerdomain-common			+= powerdomain.o powerdomain-common.o
obj-$(CONFIG_ARCH_OMAP2)		+= $(powerdomain-common)
obj-$(CONFIG_ARCH_OMAP2)		+= powerdomains2xxx_data.o
obj-$(CONFIG_ARCH_OMAP2)		+= powerdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= $(powerdomain-common)
obj-$(CONFIG_ARCH_OMAP3)		+= powerdomains3xxx_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= powerdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(powerdomain-common)
obj-$(CONFIG_ARCH_OMAP4)		+= powerdomains44xx_data.o
obj-$(CONFIG_SOC_AM33XX)		+= $(powerdomain-common)
obj-$(CONFIG_SOC_AM33XX)		+= powerdomains33xx_data.o
obj-$(CONFIG_SOC_AM43XX)		+= $(powerdomain-common)
obj-$(CONFIG_SOC_AM43XX)		+= powerdomains43xx_data.o
obj-$(CONFIG_SOC_OMAP5)			+= $(powerdomain-common)
obj-$(CONFIG_SOC_OMAP5)			+= powerdomains54xx_data.o
obj-$(CONFIG_SOC_DRA7XX)		+= $(powerdomain-common)
obj-$(CONFIG_SOC_DRA7XX)		+= powerdomains7xx_data.o

# PRCM clockdomain control
clockdomain-common			+= clockdomain.o
obj-$(CONFIG_ARCH_OMAP2)		+= $(clockdomain-common)
obj-$(CONFIG_ARCH_OMAP2)		+= clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_SOC_OMAP2420)		+= clockdomains2420_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= clockdomains2430_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= $(clockdomain-common)
obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= clockdomains3xxx_data.o
obj-$(CONFIG_ARCH_OMAP4)		+= $(clockdomain-common)
obj-$(CONFIG_ARCH_OMAP4)		+= clockdomains44xx_data.o
obj-$(CONFIG_SOC_AM33XX)		+= $(clockdomain-common)
obj-$(CONFIG_SOC_AM33XX)		+= clockdomains33xx_data.o
obj-$(CONFIG_SOC_TI81XX)		+= $(clockdomain-common)
obj-$(CONFIG_SOC_TI81XX)		+= clockdomains81xx_data.o
obj-$(CONFIG_SOC_AM43XX)		+= $(clockdomain-common)
obj-$(CONFIG_SOC_AM43XX)		+= clockdomains43xx_data.o
obj-$(CONFIG_SOC_OMAP5)			+= $(clockdomain-common)
obj-$(CONFIG_SOC_OMAP5)			+= clockdomains54xx_data.o
obj-$(CONFIG_SOC_DRA7XX)		+= $(clockdomain-common)
obj-$(CONFIG_SOC_DRA7XX)		+= clockdomains7xx_data.o

# Clock framework
obj-$(CONFIG_ARCH_OMAP2)		+= $(clock-common)
obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpllcore.o
obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_virt_prcm_set.o
obj-$(CONFIG_ARCH_OMAP2)		+= clkt2xxx_dpll.o
obj-$(CONFIG_ARCH_OMAP3)		+= $(clock-common)
obj-$(CONFIG_ARCH_OMAP4)		+= $(clock-common)
obj-$(CONFIG_SOC_AM33XX)		+= $(clock-common)
obj-$(CONFIG_SOC_OMAP5)			+= $(clock-common)
obj-$(CONFIG_SOC_DRA7XX)		+= $(clock-common)
obj-$(CONFIG_SOC_AM43XX)		+= $(clock-common)

# OMAP2 clock rate set data (old "OPP" data)
obj-$(CONFIG_SOC_OMAP2420)		+= opp2420_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= opp2430_data.o

# hwmod data
obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_ipblock_data.o
obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_3xxx_ipblock_data.o
obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2xxx_interconnect_data.o
obj-$(CONFIG_SOC_OMAP2420)		+= omap_hwmod_2420_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= omap_hwmod_2xxx_ipblock_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= omap_hwmod_2xxx_3xxx_ipblock_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= omap_hwmod_2xxx_interconnect_data.o
obj-$(CONFIG_SOC_OMAP2430)		+= omap_hwmod_2430_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_2xxx_3xxx_ipblock_data.o
obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_3xxx_data.o
obj-$(CONFIG_SOC_TI81XX)		+= omap_hwmod_81xx_data.o

# OMAP2420 MSDI controller integration support ("MMC")
obj-$(CONFIG_SOC_OMAP2420)		+= msdi.o

# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o pdata-quirks.o
obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0.o

# Platform specific device init code

obj-y					+= omap_phy_internal.o

obj-$(CONFIG_MACH_OMAP2_TUSB6010)	+= usb-tusb6010.o

$(obj)/pm-asm-offsets.h: $(obj)/pm-asm-offsets.s FORCE
	$(call filechk,offsets,__TI_PM_ASM_OFFSETS_H__)

$(obj)/sleep33xx.o $(obj)/sleep43xx.o: $(obj)/pm-asm-offsets.h

targets += pm-asm-offsets.s
clean-files += pm-asm-offsets.h

obj-$(CONFIG_OMAP_IOMMU)		+= omap-iommu.o


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * am33xx-restart.c - Code common to all AM33xx machines.
 */
#include <linux/kernel.h>
#include <linux/reboot.h>

#include "common.h"
#include "prm.h"

/**
 * am3xx_restart - trigger a software restart of the SoC
 * @mode: the "reboot mode", see arch/arm/kernel/{setup,process}.c
 * @cmd: passed from the userspace program rebooting the system (if provided)
 *
 * Resets the SoC.  For @cmd, see the 'reboot' syscall in
 * kernel/sys.c.  No return value.
 */
void am33xx_restart(enum reboot_mode mode, const char *cmd)
{
	/* TODO: Handle mode and cmd if necessary */

	omap_prm_reset_system();
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * This file contains the address info for various AM33XX modules.
 *
 * Copyright (C) 2011 Texas Instruments, Inc. - https://www.ti.com/
 */

#ifndef __ASM_ARCH_AM33XX_H
#define __ASM_ARCH_AM33XX_H

#define L4_SLOW_AM33XX_BASE	0x48000000

#define AM33XX_SCM_BASE		0x44E10000
#define AM33XX_CTRL_BASE	AM33XX_SCM_BASE
#define AM33XX_PRCM_BASE	0x44E00000
#define AM43XX_PRCM_BASE	0x44DF0000
#define AM33XX_TAP_BASE		(AM33XX_CTRL_BASE + 0x3FC)

#endif /* __ASM_ARCH_AM33XX_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2005 Nokia Corporation
 * Author: Paul Mundt <paul.mundt@nokia.com>
 *
 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
 *
 * Modified from the original mach-omap/omap2/board-generic.c did by Paul
 * to support the OMAP2+ device tree boards with an unique board file.
 */
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
#include <linux/clocksource.h>

#include <asm/setup.h>
#include <asm/mach/arch.h>
#include <asm/system_info.h>

#include "common.h"

static const struct of_device_id omap_dt_match_table[] __initconst = {
	{ .compatible = "simple-bus", },
	{ .compatible = "ti,omap-infra", },
	{ }
};

static void __init __maybe_unused omap_generic_init(void)
{
	pdata_quirks_init(omap_dt_match_table);
	omap_soc_device_init();
}

/* Clocks are needed early, see drivers/clocksource for the rest */
static void __init __maybe_unused omap_init_time_of(void)
{
	omap_clk_init();
	timer_probe();
}

/* Used by am437x for ARM timer in non-SMP configurations */
#if !defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
void tick_broadcast(const struct cpumask *mask)
{
}
#endif

#ifdef CONFIG_SOC_OMAP2420
static const char *const omap242x_boards_compat[] __initconst = {
	"ti,omap2420",
	NULL,
};

DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap242x_map_io,
	.init_early	= omap2420_init_early,
	.init_machine	= omap_generic_init,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap242x_boards_compat,
	.restart	= omap2xxx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_OMAP2430
static const char *const omap243x_boards_compat[] __initconst = {
	"ti,omap2430",
	NULL,
};

DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap243x_map_io,
	.init_early	= omap2430_init_early,
	.init_machine	= omap_generic_init,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap243x_boards_compat,
	.restart	= omap2xxx_restart,
MACHINE_END
#endif

#ifdef CONFIG_ARCH_OMAP3
/* Some boards need board name for legacy userspace in /proc/cpuinfo */
static const char *const n900_boards_compat[] __initconst = {
	"nokia,omap3-n900",
	NULL,
};

/* Set system_rev from atags */
static void __init rx51_set_system_rev(const struct tag *tags)
{
	const struct tag *tag;

	if (tags->hdr.tag != ATAG_CORE)
		return;

	for_each_tag(tag, tags) {
		if (tag->hdr.tag == ATAG_REVISION) {
			system_rev = tag->u.revision.rev;
			break;
		}
	}
}

/* Legacy userspace on Nokia N900 needs ATAGS exported in /proc/atags,
 * save them while the data is still not overwritten
 */
static void __init rx51_reserve(void)
{
	const struct tag *tags = (const struct tag *)(PAGE_OFFSET + 0x100);

	save_atags(tags);
	rx51_set_system_rev(tags);
	omap_reserve();
}

DT_MACHINE_START(OMAP3_N900_DT, "Nokia RX-51 board")
	.reserve	= rx51_reserve,
	.map_io		= omap3_map_io,
	.init_early	= omap3430_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= omap3_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= n900_boards_compat,
	.restart	= omap3xxx_restart,
MACHINE_END

/* Generic omap3 boards, most boards can use these */
static const char *const omap3_boards_compat[] __initconst = {
	"ti,omap3430",
	"ti,omap3",
	NULL,
};

DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap3_map_io,
	.init_early	= omap3430_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= omap3_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap3_boards_compat,
	.restart	= omap3xxx_restart,
MACHINE_END

static const char *const omap36xx_boards_compat[] __initconst = {
	"ti,omap3630",
	"ti,omap36xx",
	NULL,
};

DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap3_map_io,
	.init_early	= omap3630_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= omap3_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap36xx_boards_compat,
	.restart	= omap3xxx_restart,
MACHINE_END

static const char *const omap3_gp_boards_compat[] __initconst = {
	"ti,omap3-beagle",
	"timll,omap3-devkit8000",
	NULL,
};

DT_MACHINE_START(OMAP3_GP_DT, "Generic OMAP3-GP (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap3_map_io,
	.init_early	= omap3430_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= omap3_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap3_gp_boards_compat,
	.restart	= omap3xxx_restart,
MACHINE_END

static const char *const am3517_boards_compat[] __initconst = {
	"ti,am3517",
	NULL,
};

DT_MACHINE_START(AM3517_DT, "Generic AM3517 (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= omap3_map_io,
	.init_early	= am35xx_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= omap3_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= am3517_boards_compat,
	.restart	= omap3xxx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_TI81XX
static const char *const ti814x_boards_compat[] __initconst = {
	"ti,dm8148",
	"ti,dm814",
	NULL,
};

DT_MACHINE_START(TI814X_DT, "Generic ti814x (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= ti81xx_map_io,
	.init_early	= ti814x_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= ti81xx_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= ti814x_boards_compat,
	.restart	= ti81xx_restart,
MACHINE_END

static const char *const ti816x_boards_compat[] __initconst = {
	"ti,dm8168",
	"ti,dm816",
	NULL,
};

DT_MACHINE_START(TI816X_DT, "Generic ti816x (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= ti81xx_map_io,
	.init_early	= ti816x_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= ti81xx_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= ti816x_boards_compat,
	.restart	= ti81xx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_AM33XX
static const char *const am33xx_boards_compat[] __initconst = {
	"ti,am33xx",
	NULL,
};

DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
	.reserve	= omap_reserve,
	.map_io		= am33xx_map_io,
	.init_early	= am33xx_init_early,
	.init_machine	= omap_generic_init,
	.init_late	= am33xx_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= am33xx_boards_compat,
	.restart	= am33xx_restart,
MACHINE_END
#endif

#ifdef CONFIG_ARCH_OMAP4
static const char *const omap4_boards_compat[] __initconst = {
	"ti,omap4460",
	"ti,omap4430",
	"ti,omap4",
	NULL,
};

DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
	.l2c_aux_val	= OMAP_L2C_AUX_CTRL,
	.l2c_aux_mask	= 0xcf9fffff,
	.l2c_write_sec	= omap4_l2c310_write_sec,
	.reserve	= omap_reserve,
	.smp		= smp_ops(omap4_smp_ops),
	.map_io		= omap4_map_io,
	.init_early	= omap4430_init_early,
	.init_irq	= omap_gic_of_init,
	.init_machine	= omap_generic_init,
	.init_late	= omap4430_init_late,
	.init_time	= omap_init_time_of,
	.dt_compat	= omap4_boards_compat,
	.restart	= omap44xx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_OMAP5
static const char *const omap5_boards_compat[] __initconst = {
	"ti,omap5432",
	"ti,omap5430",
	"ti,omap5",
	NULL,
};

DT_MACHINE_START(OMAP5_DT, "Generic OMAP5 (Flattened Device Tree)")
#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
	.dma_zone_size	= SZ_2G,
#endif
	.reserve	= omap_reserve,
	.smp		= smp_ops(omap4_smp_ops),
	.map_io		= omap5_map_io,
	.init_early	= omap5_init_early,
	.init_irq	= omap_gic_of_init,
	.init_machine	= omap_generic_init,
	.init_late	= omap5_init_late,
	.init_time	= omap5_realtime_timer_init,
	.dt_compat	= omap5_boards_compat,
	.restart	= omap44xx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_AM43XX
static const char *const am43_boards_compat[] __initconst = {
	"ti,am4372",
	"ti,am43",
	NULL,
};

DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)")
	.l2c_aux_val	= OMAP_L2C_AUX_CTRL,
	.l2c_aux_mask	= 0xcf9fffff,
	.l2c_write_sec	= omap4_l2c310_write_sec,
	.map_io		= am33xx_map_io,
	.init_early	= am43xx_init_early,
	.init_late	= am43xx_init_late,
	.init_irq	= omap_gic_of_init,
	.init_machine	= omap_generic_init,
	.init_time	= omap_init_time_of,
	.dt_compat	= am43_boards_compat,
	.restart	= omap44xx_restart,
MACHINE_END
#endif

#ifdef CONFIG_SOC_DRA7XX
static const char *const dra74x_boards_compat[] __initconst = {
	"ti,dra762",
	"ti,am5728",
	"ti,am5726",
	"ti,dra742",
	"ti,dra7",
	NULL,
};

DT_MACHINE_START(DRA74X_DT, "Generic DRA74X (Flattened Device Tree)")
#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
	.dma_zone_size	= SZ_2G,
#endif
	.reserve	= omap_reserve,
	.smp		= smp_ops(omap4_smp_ops),
	.map_io		= dra7xx_map_io,
	.init_early	= dra7xx_init_early,
	.init_late	= dra7xx_init_late,
	.init_irq	= omap_gic_of_init,
	.init_machine	= omap_generic_init,
	.init_time	= omap5_realtime_timer_init,
	.dt_compat	= dra74x_boards_compat,
	.restart	= omap44xx_restart,
MACHINE_END

static const char *const dra72x_boards_compat[] __initconst = {
	"ti,am5718",
	"ti,am5716",
	"ti,dra722",
	"ti,dra718",
	NULL,
};

DT_MACHINE_START(DRA72X_DT, "Generic DRA72X (Flattened Device Tree)")
#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
	.dma_zone_size	= SZ_2G,
#endif
	.reserve	= omap_reserve,
	.map_io		= dra7xx_map_io,
	.init_early	= dra7xx_init_early,
	.init_late	= dra7xx_init_late,
	.init_irq	= omap_gic_of_init,
	.init_machine	= omap_generic_init,
	.init_time	= omap5_realtime_timer_init,
	.dt_compat	= dra72x_boards_compat,
	.restart	= omap44xx_restart,
MACHINE_END
#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * linux/arch/arm/mach-omap2/board-n8x0.c
 *
 * Copyright (C) 2005-2009 Nokia Corporation
 * Author: Juha Yrjola <juha.yrjola@nokia.com>
 *
 * Modified from mach-omap2/board-generic.c
 */

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/stddef.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/usb/musb.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/platform_data/mmc-omap.h>
#include <linux/mfd/menelaus.h>

#include <asm/mach/arch.h>
#include <asm/mach-types.h>

#include "common.h"
#include "mmc.h"
#include "soc.h"
#include "common-board-devices.h"

#define TUSB6010_ASYNC_CS	1
#define TUSB6010_SYNC_CS	4
#define TUSB6010_GPIO_INT	58
#define TUSB6010_GPIO_ENABLE	0
#define TUSB6010_DMACHAN	0x3f

#define NOKIA_N810_WIMAX	(1 << 2)
#define NOKIA_N810		(1 << 1)
#define NOKIA_N800		(1 << 0)

static u32 board_caps;

#define board_is_n800()		(board_caps & NOKIA_N800)
#define board_is_n810()		(board_caps & NOKIA_N810)
#define board_is_n810_wimax()	(board_caps & NOKIA_N810_WIMAX)

static void board_check_revision(void)
{
	if (of_machine_is_compatible("nokia,n800"))
		board_caps = NOKIA_N800;
	else if (of_machine_is_compatible("nokia,n810"))
		board_caps = NOKIA_N810;
	else if (of_machine_is_compatible("nokia,n810-wimax"))
		board_caps = NOKIA_N810_WIMAX;

	if (!board_caps)
		pr_err("Unknown board\n");
}

#if IS_ENABLED(CONFIG_USB_MUSB_TUSB6010)
/*
 * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
 * 1.5 V voltage regulators of PM companion chip. Companion chip will then
 * provide then PGOOD signal to TUSB6010 which will release it from reset.
 */
static int tusb_set_power(int state)
{
	int i, retval = 0;

	if (state) {
		gpio_set_value(TUSB6010_GPIO_ENABLE, 1);
		msleep(1);

		/* Wait until TUSB6010 pulls INT pin down */
		i = 100;
		while (i && gpio_get_value(TUSB6010_GPIO_INT)) {
			msleep(1);
			i--;
		}

		if (!i) {
			printk(KERN_ERR "tusb: powerup failed\n");
			retval = -ENODEV;
		}
	} else {
		gpio_set_value(TUSB6010_GPIO_ENABLE, 0);
		msleep(10);
	}

	return retval;
}

static struct musb_hdrc_config musb_config = {
	.multipoint	= 1,
	.dyn_fifo	= 1,
	.num_eps	= 16,
	.ram_bits	= 12,
};

static struct musb_hdrc_platform_data tusb_data = {
	.mode		= MUSB_OTG,
	.set_power	= tusb_set_power,
	.min_power	= 25,	/* x2 = 50 mA drawn from VBUS as peripheral */
	.power		= 100,	/* Max 100 mA VBUS for host mode */
	.config		= &musb_config,
};

static void __init n8x0_usb_init(void)
{
	int ret = 0;
	static const char announce[] __initconst = KERN_INFO "TUSB 6010\n";

	/* PM companion chip power control pin */
	ret = gpio_request_one(TUSB6010_GPIO_ENABLE, GPIOF_OUT_INIT_LOW,
			       "TUSB6010 enable");
	if (ret != 0) {
		printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
		       TUSB6010_GPIO_ENABLE);
		return;
	}
	tusb_set_power(0);

	ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
					TUSB6010_ASYNC_CS, TUSB6010_SYNC_CS,
					TUSB6010_GPIO_INT, TUSB6010_DMACHAN);
	if (ret != 0)
		goto err;

	printk(announce);

	return;

err:
	gpio_free(TUSB6010_GPIO_ENABLE);
}
#else

static void __init n8x0_usb_init(void) {}

#endif /*CONFIG_USB_MUSB_TUSB6010 */

static struct omap2_mcspi_device_config p54spi_mcspi_config = {
	.turbo_mode	= 0,
};

static struct spi_board_info n800_spi_board_info[] __initdata = {
	{
		.modalias	= "p54spi",
		.bus_num	= 2,
		.chip_select	= 0,
		.max_speed_hz   = 48000000,
		.controller_data = &p54spi_mcspi_config,
	},
};

#if defined(CONFIG_MENELAUS) && IS_ENABLED(CONFIG_MMC_OMAP)

/*
 * On both N800 and N810, only the first of the two MMC controllers is in use.
 * The two MMC slots are multiplexed via Menelaus companion chip over I2C.
 * On N800, both slots are powered via Menelaus. On N810, only one of the
 * slots is powered via Menelaus. The N810 EMMC is powered via GPIO.
 *
 * VMMC				slot 1 on both N800 and N810
 * VDCDC3_APE and VMCS2_APE	slot 2 on N800
 * GPIO23 and GPIO9		slot 2 EMMC on N810
 *
 */
#define N8X0_SLOT_SWITCH_GPIO	96
#define N810_EMMC_VSD_GPIO	23
#define N810_EMMC_VIO_GPIO	9

static int slot1_cover_open;
static int slot2_cover_open;
static struct device *mmc_device;

static int n8x0_mmc_switch_slot(struct device *dev, int slot)
{
#ifdef CONFIG_MMC_DEBUG
	dev_dbg(dev, "Choose slot %d\n", slot + 1);
#endif
	gpio_set_value(N8X0_SLOT_SWITCH_GPIO, slot);
	return 0;
}

static int n8x0_mmc_set_power_menelaus(struct device *dev, int slot,
					int power_on, int vdd)
{
	int mV;

#ifdef CONFIG_MMC_DEBUG
	dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
		power_on ? "on" : "off", vdd);
#endif
	if (slot == 0) {
		if (!power_on)
			return menelaus_set_vmmc(0);
		switch (1 << vdd) {
		case MMC_VDD_33_34:
		case MMC_VDD_32_33:
		case MMC_VDD_31_32:
			mV = 3100;
			break;
		case MMC_VDD_30_31:
			mV = 3000;
			break;
		case MMC_VDD_28_29:
			mV = 2800;
			break;
		case MMC_VDD_165_195:
			mV = 1850;
			break;
		default:
			BUG();
		}
		return menelaus_set_vmmc(mV);
	} else {
		if (!power_on)
			return menelaus_set_vdcdc(3, 0);
		switch (1 << vdd) {
		case MMC_VDD_33_34:
		case MMC_VDD_32_33:
			mV = 3300;
			break;
		case MMC_VDD_30_31:
		case MMC_VDD_29_30:
			mV = 3000;
			break;
		case MMC_VDD_28_29:
		case MMC_VDD_27_28:
			mV = 2800;
			break;
		case MMC_VDD_24_25:
		case MMC_VDD_23_24:
			mV = 2400;
			break;
		case MMC_VDD_22_23:
		case MMC_VDD_21_22:
			mV = 2200;
			break;
		case MMC_VDD_20_21:
			mV = 2000;
			break;
		case MMC_VDD_165_195:
			mV = 1800;
			break;
		default:
			BUG();
		}
		return menelaus_set_vdcdc(3, mV);
	}
	return 0;
}

static void n810_set_power_emmc(struct device *dev,
					 int power_on)
{
	dev_dbg(dev, "Set EMMC power %s\n", power_on ? "on" : "off");

	if (power_on) {
		gpio_set_value(N810_EMMC_VSD_GPIO, 1);
		msleep(1);
		gpio_set_value(N810_EMMC_VIO_GPIO, 1);
		msleep(1);
	} else {
		gpio_set_value(N810_EMMC_VIO_GPIO, 0);
		msleep(50);
		gpio_set_value(N810_EMMC_VSD_GPIO, 0);
		msleep(50);
	}
}

static int n8x0_mmc_set_power(struct device *dev, int slot, int power_on,
			      int vdd)
{
	if (board_is_n800() || slot == 0)
		return n8x0_mmc_set_power_menelaus(dev, slot, power_on, vdd);

	n810_set_power_emmc(dev, power_on);

	return 0;
}

static int n8x0_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
{
	int r;

	dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
		bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
	BUG_ON(slot != 0 && slot != 1);
	slot++;
	switch (bus_mode) {
	case MMC_BUSMODE_OPENDRAIN:
		r = menelaus_set_mmc_opendrain(slot, 1);
		break;
	case MMC_BUSMODE_PUSHPULL:
		r = menelaus_set_mmc_opendrain(slot, 0);
		break;
	default:
		BUG();
	}
	if (r != 0 && printk_ratelimit())
		dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
			slot);
	return r;
}

static int n8x0_mmc_get_cover_state(struct device *dev, int slot)
{
	slot++;
	BUG_ON(slot != 1 && slot != 2);
	if (slot == 1)
		return slot1_cover_open;
	else
		return slot2_cover_open;
}

static void n8x0_mmc_callback(void *data, u8 card_mask)
{
#ifdef CONFIG_MMC_OMAP
	int bit, *openp, index;

	if (board_is_n800()) {
		bit = 1 << 1;
		openp = &slot2_cover_open;
		index = 1;
	} else {
		bit = 1;
		openp = &slot1_cover_open;
		index = 0;
	}

	if (card_mask & bit)
		*openp = 1;
	else
		*openp = 0;

	omap_mmc_notify_cover_event(mmc_device, index, *openp);
#else
	pr_warn("MMC: notify cover event not available\n");
#endif
}

static int n8x0_mmc_late_init(struct device *dev)
{
	int r, bit, *openp;
	int vs2sel;

	mmc_device = dev;

	r = menelaus_set_slot_sel(1);
	if (r < 0)
		return r;

	if (board_is_n800())
		vs2sel = 0;
	else
		vs2sel = 2;

	r = menelaus_set_mmc_slot(2, 0, vs2sel, 1);
	if (r < 0)
		return r;

	n8x0_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */
	n8x0_mmc_set_power(dev, 1, MMC_POWER_ON, 16);

	r = menelaus_set_mmc_slot(1, 1, 0, 1);
	if (r < 0)
		return r;
	r = menelaus_set_mmc_slot(2, 1, vs2sel, 1);
	if (r < 0)
		return r;

	r = menelaus_get_slot_pin_states();
	if (r < 0)
		return r;

	if (board_is_n800()) {
		bit = 1 << 1;
		openp = &slot2_cover_open;
	} else {
		bit = 1;
		openp = &slot1_cover_open;
		slot2_cover_open = 0;
	}

	/* All slot pin bits seem to be inversed until first switch change */
	if (r == 0xf || r == (0xf & ~bit))
		r = ~r;

	if (r & bit)
		*openp = 1;
	else
		*openp = 0;

	r = menelaus_register_mmc_callback(n8x0_mmc_callback, NULL);

	return r;
}

static void n8x0_mmc_shutdown(struct device *dev)
{
	int vs2sel;

	if (board_is_n800())
		vs2sel = 0;
	else
		vs2sel = 2;

	menelaus_set_mmc_slot(1, 0, 0, 0);
	menelaus_set_mmc_slot(2, 0, vs2sel, 0);
}

static void n8x0_mmc_cleanup(struct device *dev)
{
	menelaus_unregister_mmc_callback();

	gpio_free(N8X0_SLOT_SWITCH_GPIO);

	if (board_is_n810()) {
		gpio_free(N810_EMMC_VSD_GPIO);
		gpio_free(N810_EMMC_VIO_GPIO);
	}
}

/*
 * MMC controller1 has two slots that are multiplexed via I2C.
 * MMC controller2 is not in use.
 */
static struct omap_mmc_platform_data mmc1_data = {
	.nr_slots			= 0,
	.switch_slot			= n8x0_mmc_switch_slot,
	.init				= n8x0_mmc_late_init,
	.cleanup			= n8x0_mmc_cleanup,
	.shutdown			= n8x0_mmc_shutdown,
	.max_freq			= 24000000,
	.slots[0] = {
		.wires			= 4,
		.set_power		= n8x0_mmc_set_power,
		.set_bus_mode		= n8x0_mmc_set_bus_mode,
		.get_cover_state	= n8x0_mmc_get_cover_state,
		.ocr_mask		= MMC_VDD_165_195 | MMC_VDD_30_31 |
						MMC_VDD_32_33   | MMC_VDD_33_34,
		.name			= "internal",
	},
	.slots[1] = {
		.set_power		= n8x0_mmc_set_power,
		.set_bus_mode		= n8x0_mmc_set_bus_mode,
		.get_cover_state	= n8x0_mmc_get_cover_state,
		.ocr_mask		= MMC_VDD_165_195 | MMC_VDD_20_21 |
						MMC_VDD_21_22 | MMC_VDD_22_23 |
						MMC_VDD_23_24 | MMC_VDD_24_25 |
						MMC_VDD_27_28 | MMC_VDD_28_29 |
						MMC_VDD_29_30 | MMC_VDD_30_31 |
						MMC_VDD_32_33 | MMC_VDD_33_34,
		.name			= "external",
	},
};

static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];

static struct gpio n810_emmc_gpios[] __initdata = {
	{ N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vddf" },
	{ N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vdd"  },
};

static void __init n8x0_mmc_init(void)
{
	int err;

	if (board_is_n810()) {
		mmc1_data.slots[0].name = "external";

		/*
		 * Some Samsung Movinand chips do not like open-ended
		 * multi-block reads and fall to braind-dead state
		 * while doing so. Reducing the number of blocks in
		 * the transfer or delays in clock disable do not help
		 */
		mmc1_data.slots[1].name = "internal";
		mmc1_data.slots[1].ban_openended = 1;
	}

	err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW,
			       "MMC slot switch");
	if (err)
		return;

	if (board_is_n810()) {
		err = gpio_request_array(n810_emmc_gpios,
					 ARRAY_SIZE(n810_emmc_gpios));
		if (err) {
			gpio_free(N8X0_SLOT_SWITCH_GPIO);
			return;
		}
	}

	mmc1_data.nr_slots = 2;
	mmc_data[0] = &mmc1_data;
}
#else
static struct omap_mmc_platform_data mmc1_data;
void __init n8x0_mmc_init(void)
{
}
#endif	/* CONFIG_MMC_OMAP */

#ifdef CONFIG_MENELAUS

static int n8x0_auto_sleep_regulators(void)
{
	u32 val;
	int ret;

	val = EN_VPLL_SLEEP | EN_VMMC_SLEEP    \
		| EN_VAUX_SLEEP | EN_VIO_SLEEP \
		| EN_VMEM_SLEEP | EN_DC3_SLEEP \
		| EN_VC_SLEEP | EN_DC2_SLEEP;

	ret = menelaus_set_regulator_sleep(1, val);
	if (ret < 0) {
		pr_err("Could not set regulators to sleep on menelaus: %u\n",
		       ret);
		return ret;
	}
	return 0;
}

static int n8x0_auto_voltage_scale(void)
{
	int ret;

	ret = menelaus_set_vcore_hw(1400, 1050);
	if (ret < 0) {
		pr_err("Could not set VCORE voltage on menelaus: %u\n", ret);
		return ret;
	}
	return 0;
}

static int n8x0_menelaus_late_init(struct device *dev)
{
	int ret;

	ret = n8x0_auto_voltage_scale();
	if (ret < 0)
		return ret;
	ret = n8x0_auto_sleep_regulators();
	if (ret < 0)
		return ret;
	return 0;
}

#else
static int n8x0_menelaus_late_init(struct device *dev)
{
	return 0;
}
#endif

struct menelaus_platform_data n8x0_menelaus_platform_data = {
	.late_init = n8x0_menelaus_late_init,
};

static int __init n8x0_late_initcall(void)
{
	if (!board_caps)
		return -ENODEV;

	n8x0_mmc_init();
	n8x0_usb_init();

	return 0;
}
omap_late_initcall(n8x0_late_initcall);

/*
 * Legacy init pdata init for n8x0. Note that we want to follow the
 * I2C bus numbering starting at 0 for device tree like other omaps.
 */
void * __init n8x0_legacy_init(void)
{
	board_check_revision();
	spi_register_board_info(n800_spi_board_info,
				ARRAY_SIZE(n800_spi_board_info));
	return &mmc1_data;
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP2-specific DPLL control functions
 *
 * Copyright (C) 2011 Nokia Corporation
 * Paul Walmsley
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>

#include "clock.h"
#include "cm2xxx.h"
#include "cm-regbits-24xx.h"

/* Private functions */

/**
 * _allow_idle - enable DPLL autoidle bits
 * @clk: struct clk * of the DPLL to operate on
 *
 * Enable DPLL automatic idle control.  The DPLL will enter low-power
 * stop when its downstream clocks are gated.  No return value.
 * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1
 * instead.  Add some mechanism to optionally enter this mode.
 */
static void _allow_idle(struct clk_hw_omap *clk)
{
	if (!clk || !clk->dpll_data)
		return;

	omap2xxx_cm_set_dpll_auto_low_power_stop();
}

/**
 * _deny_idle - prevent DPLL from automatically idling
 * @clk: struct clk * of the DPLL to operate on
 *
 * Disable DPLL automatic idle control.  No return value.
 */
static void _deny_idle(struct clk_hw_omap *clk)
{
	if (!clk || !clk->dpll_data)
		return;

	omap2xxx_cm_set_dpll_disable_autoidle();
}

/* Public data */
const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll = {
	.allow_idle	= _allow_idle,
	.deny_idle	= _deny_idle,
};


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * DPLL + CORE_CLK composite clock functions
 *
 * Copyright (C) 2005-2008 Texas Instruments, Inc.
 * Copyright (C) 2004-2010 Nokia Corporation
 *
 * Contacts:
 * Richard Woodruff <r-woodruff2@ti.com>
 * Paul Walmsley
 *
 * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
 * Gordon McNutt and RidgeRun, Inc.
 *
 * XXX The DPLL and CORE clocks should be split into two separate clock
 * types.
 */
#undef DEBUG

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>

#include "clock.h"
#include "clock2xxx.h"
#include "opp2xxx.h"
#include "cm2xxx.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "sram.h"

/* #define DOWN_VARIABLE_DPLL 1 */		/* Experimental */

/*
 * dpll_core_ck: pointer to the combined dpll_ck + core_ck on OMAP2xxx
 * (currently defined as "dpll_ck" in the OMAP2xxx clock tree).  Set
 * during dpll_ck init and used later by omap2xxx_clk_get_core_rate().
 */
static struct clk_hw_omap *dpll_core_ck;

/**
 * omap2xxx_clk_get_core_rate - return the CORE_CLK rate
 *
 * Returns the CORE_CLK rate.  CORE_CLK can have one of three rate
 * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz
 * (the latter is unusual).  This currently should be called with
 * struct clk *dpll_ck, which is a composite clock of dpll_ck and
 * core_ck.
 */
unsigned long omap2xxx_clk_get_core_rate(void)
{
	long long core_clk;
	u32 v;

	WARN_ON(!dpll_core_ck);

	core_clk = omap2_get_dpll_rate(dpll_core_ck);

	v = omap2xxx_cm_get_core_clk_src();

	if (v == CORE_CLK_SRC_32K)
		core_clk = 32768;
	else
		core_clk *= v;

	return core_clk;
}

/*
 * Uses the current prcm set to tell if a rate is valid.
 * You can go slower, but not faster within a given rate set.
 */
static long omap2_dpllcore_round_rate(unsigned long target_rate)
{
	u32 high, low, core_clk_src;

	core_clk_src = omap2xxx_cm_get_core_clk_src();

	if (core_clk_src == CORE_CLK_SRC_DPLL) {	/* DPLL clockout */
		high = curr_prcm_set->dpll_speed * 2;
		low = curr_prcm_set->dpll_speed;
	} else {				/* DPLL clockout x 2 */
		high = curr_prcm_set->dpll_speed;
		low = curr_prcm_set->dpll_speed / 2;
	}

#ifdef DOWN_VARIABLE_DPLL
	if (target_rate > high)
		return high;
	else
		return target_rate;
#else
	if (target_rate > low)
		return high;
	else
		return low;
#endif

}

unsigned long omap2_dpllcore_recalc(struct clk_hw *hw,
				    unsigned long parent_rate)
{
	return omap2xxx_clk_get_core_rate();
}

int omap2_reprogram_dpllcore(struct clk_hw *hw, unsigned long rate,
			     unsigned long parent_rate)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
	u32 cur_rate, low, mult, div, valid_rate, done_rate;
	u32 bypass = 0;
	struct prcm_config tmpset;
	const struct dpll_data *dd;

	cur_rate = omap2xxx_clk_get_core_rate();
	mult = omap2xxx_cm_get_core_clk_src();

	if ((rate == (cur_rate / 2)) && (mult == 2)) {
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
	} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
	} else if (rate != cur_rate) {
		valid_rate = omap2_dpllcore_round_rate(rate);
		if (valid_rate != rate)
			return -EINVAL;

		if (mult == 1)
			low = curr_prcm_set->dpll_speed;
		else
			low = curr_prcm_set->dpll_speed / 2;

		dd = clk->dpll_data;
		if (!dd)
			return -EINVAL;

		tmpset.cm_clksel1_pll =
			omap_clk_ll_ops.clk_readl(&dd->mult_div1_reg);
		tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
					   dd->div1_mask);
		div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
		tmpset.cm_clksel2_pll = omap2xxx_cm_get_core_pll_config();
		tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
		if (rate > low) {
			tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
			mult = ((rate / 2) / 1000000);
			done_rate = CORE_CLK_SRC_DPLL_X2;
		} else {
			tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
			mult = (rate / 1000000);
			done_rate = CORE_CLK_SRC_DPLL;
		}
		tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
		tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));

		/* Worst case */
		tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;

		if (rate == curr_prcm_set->xtal_speed)	/* If asking for 1-1 */
			bypass = 1;

		/* For omap2xxx_sdrc_init_params() */
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);

		/* Force dll lock mode */
		omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
			       bypass);

		/* Errata: ret dll entry state */
		omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
		omap2xxx_sdrc_reprogram(done_rate, 0);
	}

	return 0;
}

/**
 * omap2xxx_clkt_dpllcore_init - clk init function for dpll_ck
 * @clk: struct clk *dpll_ck
 *
 * Store a local copy of @clk in dpll_core_ck so other code can query
 * the core rate without having to clk_get(), which can sleep.  Must
 * only be called once.  No return value.  XXX If the clock
 * registration process is ever changed such that dpll_ck is no longer
 * statically defined, this code may need to change to increment some
 * kind of use count on dpll_ck.
 */
void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw)
{
	WARN(dpll_core_ck, "dpll_core_ck already set - should never happen");
	dpll_core_ck = to_clk_hw_omap(hw);
}


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * OMAP2xxx DVFS virtual clock functions
 *
 * Copyright (C) 2005-2008, 2012 Texas Instruments, Inc.
 * Copyright (C) 2004-2010 Nokia Corporation
 *
 * Contacts:
 * Richard Woodruff <r-woodruff2@ti.com>
 * Paul Walmsley
 *
 * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
 * Gordon McNutt and RidgeRun, Inc.
 *
 * XXX Some of this code should be replaceable by the upcoming OPP layer
 * code.  However, some notion of "rate set" is probably still necessary
 * for OMAP2xxx at least.  Rate sets should be generalized so they can be
 * used for any OMAP chip, not just OMAP2xxx.  In particular, Richard Woodruff
 * has in the past expressed a preference to use rate sets for OPP changes,
 * rather than dynamically recalculating the clock tree, so if someone wants
 * this badly enough to write the code to handle it, we should support it
 * as an option.
 */
#undef DEBUG

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>

#include "soc.h"
#include "clock.h"
#include "clock2xxx.h"
#include "opp2xxx.h"
#include "cm2xxx.h"
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "sram.h"

const struct prcm_config *curr_prcm_set;
const struct prcm_config *rate_table;

/*
 * sys_ck_rate: the rate of the external high-frequency clock
 * oscillator on the board.  Set by the SoC-specific clock init code.
 * Once set during a boot, will not change.
 */
static unsigned long sys_ck_rate;

/**
 * omap2_table_mpu_recalc - just return the MPU speed
 * @clk: virt_prcm_set struct clk
 *
 * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
 */
unsigned long omap2_table_mpu_recalc(struct clk_hw *clk,
				     unsigned long parent_rate)
{
	return curr_prcm_set->mpu_speed;
}

/*
 * Look for a rate equal or less than the target rate given a configuration set.
 *
 * What's not entirely clear is "which" field represents the key field.
 * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
 * just uses the ARM rates.
 */
long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate,
			       unsigned long *parent_rate)
{
	const struct prcm_config *ptr;
	long highest_rate;

	highest_rate = -EINVAL;

	for (ptr = rate_table; ptr->mpu_speed; ptr++) {
		if (!(ptr->flags & cpu_mask))
			continue;
		if (ptr->xtal_speed != sys_ck_rate)
			continue;

		highest_rate = ptr->mpu_speed;

		/* Can check only after xtal frequency check */
		if (ptr->mpu_speed <= rate)
			break;
	}
	return highest_rate;
}

/* Sets basic clocks based on the specified rate */
int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
			    unsigned long parent_rate)
{
	u32 cur_rate, done_rate, bypass = 0;
	const struct prcm_config *prcm;
	unsigned long found_speed = 0;
	unsigned long flags;

	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
		if (!(prcm->flags & cpu_mask))
			continue;

		if (prcm->xtal_speed != sys_ck_rate)
			continue;

		if (prcm->mpu_speed <= rate) {
			found_speed = prcm->mpu_speed;
			break;
		}
	}

	if (!found_speed) {
		printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
		       rate / 1000000);
		return -EINVAL;
	}

	curr_prcm_set = prcm;
	cur_rate = omap2xxx_clk_get_core_rate();

	if (prcm->dpll_speed == cur_rate / 2) {
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
	} else if (prcm->dpll_speed == cur_rate * 2) {
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
	} else if (prcm->dpll_speed != cur_rate) {
		local_irq_save(flags);

		if (prcm->dpll_speed == prcm->xtal_speed)
			bypass = 1;

		if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
		    CORE_CLK_SRC_DPLL_X2)
			done_rate = CORE_CLK_SRC_DPLL_X2;
		else
			done_rate = CORE_CLK_SRC_DPLL;

		omap2xxx_cm_set_mod_dividers(prcm->cm_clksel_mpu,
					     prcm->cm_clksel_dsp,
					     prcm->cm_clksel_gfx,
					     prcm->cm_clksel1_core,
					     prcm->cm_clksel_mdm);

		/* x2 to enter omap2xxx_sdrc_init_params() */
		omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);

		omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
			       bypass);

		omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
		omap2xxx_sdrc_reprogram(done_rate, 0);

		local_irq_restore(flags);
	}

	return 0;
}

/**
 * omap2xxx_clkt_vps_check_bootloader_rate - determine which of the rate
 * table sets matches the current CORE DPLL hardware rate
 *
 * Check the MPU rate set by bootloader.  Sets the 'curr_prcm_set'
 * global to point to the active rate set when found; otherwise, sets
 * it to NULL.  No return value;
 */
void omap2xxx_clkt_vps_check_bootloader_rates(void)
{
	const struct prcm_config *prcm = NULL;
	unsigned long rate;

	rate = omap2xxx_clk_get_core_rate();
	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
		if (!(prcm->flags & cpu_mask))
			continue;
		if (prcm->xtal_speed != sys_ck_rate)
			continue;
		if (prcm->dpll_speed <= rate)
			break;
	}
	curr_prcm_set = prcm;
}

/**
 * omap2xxx_clkt_vps_late_init - store a copy of the sys_ck rate
 *
 * Store a copy of the sys_ck rate for later use by the OMAP2xxx DVFS
 * code.  (The sys_ck rate does not -- or rather, must not -- change
 * during kernel runtime.)  Must be called after we have a valid
 * sys_ck rate, but before the virt_prcm_set clock rate is
 * recalculated.  No return value.
 */
void omap2xxx_clkt_vps_late_init(void)
{
	struct clk *c;

	c = clk_get(NULL, "sys_ck");
	if (IS_ERR(c)) {
		WARN(1, "could not locate sys_ck\n");
	} else {
		sys_ck_rate = clk_get_rate(c);
		clk_put(c);
	}
}

#ifdef CONFIG_OF
#include <linux/clk-provider.h>
#include <linux/clkdev.h>

static const struct clk_ops virt_prcm_set_ops = {
	.recalc_rate	= &omap2_table_mpu_recalc,
	.set_rate	= &omap2_select_table_rate,
	.round_rate	= &omap2_round_to_table_rate,
};

/**
 * omap2xxx_clkt_vps_init - initialize virt_prcm_set clock
 *
 * Does a manual init for the virtual prcm DVFS clock for OMAP2. This
 * function is called only from omap2 DT clock init, as the virtual
 * node is not modelled in the DT clock data.
 */
void omap2xxx_clkt_vps_init(void)
{
	struct clk_init_data init = { NULL };
	struct clk_hw_omap *hw = NULL;
	struct clk *clk;
	const char *parent_name = "mpu_ck";

	omap2xxx_clkt_vps_late_init();
	omap2xxx_clkt_vps_check_bootloader_rates();

	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
	if (!hw)
		return;
	init.name = "virt_prcm_set";
	init.ops = &virt_prcm_set_ops;
	init.parent_names = &parent_name;
	init.num_parents = 1;

	hw->hw.init = &init;

	clk = clk_register(NULL, &hw->hw);
	if (IS_ERR(clk)) {
		printk(KERN_ERR "Failed to register clock\n");
		kfree(hw);
		return;
	}

	clkdev_create(clk, "cpufreq_ck", NULL);
}
#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/arch/arm/mach-omap2/clock.c
 *
 *  Copyright (C) 2005-2008 Texas Instruments, Inc.
 *  Copyright (C) 2004-2010 Nokia Corporation
 *
 *  Contacts:
 *  Richard Woodruff <r-woodruff2@ti.com>
 *  Paul Walmsley
 */
#undef DEBUG

#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/of_address.h>
#include <asm/cpu.h>

#include <trace/events/power.h>

#include "soc.h"
#include "clockdomain.h"
#include "clock.h"
#include "cm.h"
#include "cm2xxx.h"
#include "cm3xxx.h"
#include "cm-regbits-24xx.h"
#include "cm-regbits-34xx.h"
#include "common.h"

u16 cpu_mask;

/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
#define OMAP3430_DPLL_FINT_BAND1_MIN	750000
#define OMAP3430_DPLL_FINT_BAND1_MAX	2100000
#define OMAP3430_DPLL_FINT_BAND2_MIN	7500000
#define OMAP3430_DPLL_FINT_BAND2_MAX	21000000

/*
 * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx.
 * From device data manual section 4.3 "DPLL and DLL Specifications".
 */
#define OMAP3PLUS_DPLL_FINT_MIN		32000
#define OMAP3PLUS_DPLL_FINT_MAX		52000000

struct ti_clk_ll_ops omap_clk_ll_ops = {
	.clkdm_clk_enable = clkdm_clk_enable,
	.clkdm_clk_disable = clkdm_clk_disable,
	.clkdm_lookup = clkdm_lookup,
	.cm_wait_module_ready = omap_cm_wait_module_ready,
	.cm_split_idlest_reg = cm_split_idlest_reg,
};

/**
 * omap2_clk_setup_ll_ops - setup clock driver low-level ops
 *
 * Sets up clock driver low-level platform ops. These are needed
 * for register accesses and various other misc platform operations.
 * Returns 0 on success, -EBUSY if low level ops have been registered
 * already.
 */
int __init omap2_clk_setup_ll_ops(void)
{
	return ti_clk_setup_ll_ops(&omap_clk_ll_ops);
}

/*
 * OMAP2+ specific clock functions
 */

/**
 * ti_clk_init_features - init clock features struct for the SoC
 *
 * Initializes the clock features struct based on the SoC type.
 */
void __init ti_clk_init_features(void)
{
	struct ti_clk_features features = { 0 };
	/* Fint setup for DPLLs */
	if (cpu_is_omap3430()) {
		features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
		features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
		features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX;
		features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN;
	} else {
		features.fint_min = OMAP3PLUS_DPLL_FINT_MIN;
		features.fint_max = OMAP3PLUS_DPLL_FINT_MAX;
	}

	/* Bypass value setup for DPLLs */
	if (cpu_is_omap24xx()) {
		features.dpll_bypass_vals |=
			(1 << OMAP2XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP2XXX_EN_DPLL_FRBYPASS);
	} else if (cpu_is_omap34xx()) {
		features.dpll_bypass_vals |=
			(1 << OMAP3XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP3XXX_EN_DPLL_FRBYPASS);
	} else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() ||
		   soc_is_omap54xx() || soc_is_dra7xx()) {
		features.dpll_bypass_vals |=
			(1 << OMAP4XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_FRBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_MNBYPASS);
	}

	/* Jitter correction only available on OMAP343X */
	if (cpu_is_omap343x())
		features.flags |= TI_CLK_DPLL_HAS_FREQSEL;

	if (omap_type() == OMAP2_DEVICE_TYPE_GP)
		features.flags |= TI_CLK_DEVICE_TYPE_GP;

	/* Idlest value for interface clocks.
	 * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
	 * 34xx reverses this, just to keep us on our toes
	 * AM35xx uses both, depending on the module.
	 */
	if (cpu_is_omap24xx())
		features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
	else if (cpu_is_omap34xx())
		features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;

	/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
	if (omap_rev() == OMAP3430_REV_ES1_0)
		features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;

	/* Errata I810 for omap5 / dra7 */
	if (soc_is_omap54xx() || soc_is_dra7xx())
		features.flags |= TI_CLK_ERRATA_I810;

	ti_clk_setup_features(&features);
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 *  linux/arch/arm/mach-omap2/clock.h
 *
 *  Copyright (C) 2005-2009 Texas Instruments, Inc.
 *  Copyright (C) 2004-2011 Nokia Corporation
 *
 *  Contacts:
 *  Richard Woodruff <r-woodruff2@ti.com>
 *  Paul Walmsley
 */

#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK_H

#include <linux/kernel.h>
#include <linux/list.h>

#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>

/* struct clksel_rate.flags possibilities */
#define RATE_IN_242X		(1 << 0)
#define RATE_IN_243X		(1 << 1)
#define RATE_IN_3430ES1		(1 << 2)	/* 3430ES1 rates only */
#define RATE_IN_3430ES2PLUS	(1 << 3)	/* 3430 ES >= 2 rates only */
#define RATE_IN_36XX		(1 << 4)
#define RATE_IN_4430		(1 << 5)
#define RATE_IN_TI816X		(1 << 6)
#define RATE_IN_4460		(1 << 7)
#define RATE_IN_AM33XX		(1 << 8)
#define RATE_IN_TI814X		(1 << 9)

#define RATE_IN_24XX		(RATE_IN_242X | RATE_IN_243X)
#define RATE_IN_34XX		(RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS)
#define RATE_IN_3XXX		(RATE_IN_34XX | RATE_IN_36XX)
#define RATE_IN_44XX		(RATE_IN_4430 | RATE_IN_4460)

/* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */
#define RATE_IN_3430ES2PLUS_36XX	(RATE_IN_3430ES2PLUS | RATE_IN_36XX)

/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
#define CORE_CLK_SRC_32K		0x0
#define CORE_CLK_SRC_DPLL		0x1
#define CORE_CLK_SRC_DPLL_X2		0x2

/* OMAP2xxx CM_CLKEN_PLL.EN_DPLL bits - for omap2_get_dpll_rate() */
#define OMAP2XXX_EN_DPLL_LPBYPASS		0x1
#define OMAP2XXX_EN_DPLL_FRBYPASS		0x2
#define OMAP2XXX_EN_DPLL_LOCKED			0x3

/* OMAP3xxx CM_CLKEN_PLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
#define OMAP3XXX_EN_DPLL_LPBYPASS		0x5
#define OMAP3XXX_EN_DPLL_FRBYPASS		0x6
#define OMAP3XXX_EN_DPLL_LOCKED			0x7

/* OMAP4xxx CM_CLKMODE_DPLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
#define OMAP4XXX_EN_DPLL_MNBYPASS		0x4
#define OMAP4XXX_EN_DPLL_LPBYPASS		0x5
#define OMAP4XXX_EN_DPLL_FRBYPASS		0x6
#define OMAP4XXX_EN_DPLL_LOCKED			0x7

extern struct ti_clk_ll_ops omap_clk_ll_ops;

extern u16 cpu_mask;

extern const struct clkops clkops_omap2_dflt_wait;
extern const struct clkops clkops_omap2_dflt;

extern struct clk_functions omap2_clk_functions;

int __init omap2_clk_setup_ll_ops(void);

void __init ti_clk_init_features(void);
#endif


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * OMAP2 clock function prototypes and macros
 *
 * Copyright (C) 2005-2010 Texas Instruments, Inc.
 * Copyright (C) 2004-2010 Nokia Corporation
 */

#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK2XXX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK2XXX_H

#include <linux/clk-provider.h>
#include "clock.h"

unsigned long omap2_table_mpu_recalc(struct clk_hw *clk,
				     unsigned long parent_rate);
int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
			    unsigned long parent_rate);
long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate,
			       unsigned long *parent_rate);
unsigned long omap2xxx_sys_clk_recalc(struct clk_hw *clk,
				      unsigned long parent_rate);
unsigned long omap2_osc_clk_recalc(struct clk_hw *clk,
				   unsigned long parent_rate);
void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw);
unsigned long omap2xxx_clk_get_core_rate(void);
u32 omap2xxx_get_sysclkdiv(void);
void omap2xxx_clk_prepare_for_reboot(void);
void omap2xxx_clkt_vps_check_bootloader_rates(void);
void omap2xxx_clkt_vps_late_init(void);

#ifdef CONFIG_SOC_OMAP2420
int omap2420_clk_init(void);
#else
#define omap2420_clk_init()	do { } while(0)
#endif

#ifdef CONFIG_SOC_OMAP2430
int omap2430_clk_init(void);
#else
#define omap2430_clk_init()	do { } while(0)
#endif

extern struct clk_hw *dclk_hw;

#endif


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * OMAP3-common clock function prototypes and macros
 *
 * Copyright (C) 2007-2010 Texas Instruments, Inc.
 * Copyright (C) 2007-2010 Nokia Corporation
 */

#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H

int omap3xxx_clk_init(void);
int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate,
					unsigned long parent_rate);

extern struct clk *sdrc_ick_p;
extern struct clk *arm_fck_p;

extern const struct clkops clkops_noncore_dpll_ops;

#endif