18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OMAP WakeupGen Source file
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * OMAP WakeupGen is the interrupt controller extension used along
68c2ecf20Sopenharmony_ci * with ARM GIC to wake the CPU out from low power states on
78c2ecf20Sopenharmony_ci * external interrupts. It is responsible for generating wakeup
88c2ecf20Sopenharmony_ci * event from the incoming interrupts and enable bits. It is
98c2ecf20Sopenharmony_ci * implemented in MPU always ON power domain. During normal operation,
108c2ecf20Sopenharmony_ci * WakeupGen delivers external interrupts directly to the GIC.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc.
138c2ecf20Sopenharmony_ci *	Santosh Shilimkar <santosh.shilimkar@ti.com>
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/irq.h>
208c2ecf20Sopenharmony_ci#include <linux/irqchip.h>
218c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
228c2ecf20Sopenharmony_ci#include <linux/of_address.h>
238c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
248c2ecf20Sopenharmony_ci#include <linux/cpu.h>
258c2ecf20Sopenharmony_ci#include <linux/notifier.h>
268c2ecf20Sopenharmony_ci#include <linux/cpu_pm.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "omap-wakeupgen.h"
298c2ecf20Sopenharmony_ci#include "omap-secure.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "soc.h"
328c2ecf20Sopenharmony_ci#include "omap4-sar-layout.h"
338c2ecf20Sopenharmony_ci#include "common.h"
348c2ecf20Sopenharmony_ci#include "pm.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define AM43XX_NR_REG_BANKS	7
378c2ecf20Sopenharmony_ci#define AM43XX_IRQS		224
388c2ecf20Sopenharmony_ci#define MAX_NR_REG_BANKS	AM43XX_NR_REG_BANKS
398c2ecf20Sopenharmony_ci#define MAX_IRQS		AM43XX_IRQS
408c2ecf20Sopenharmony_ci#define DEFAULT_NR_REG_BANKS	5
418c2ecf20Sopenharmony_ci#define DEFAULT_IRQS		160
428c2ecf20Sopenharmony_ci#define WKG_MASK_ALL		0x00000000
438c2ecf20Sopenharmony_ci#define WKG_UNMASK_ALL		0xffffffff
448c2ecf20Sopenharmony_ci#define CPU_ENA_OFFSET		0x400
458c2ecf20Sopenharmony_ci#define CPU0_ID			0x0
468c2ecf20Sopenharmony_ci#define CPU1_ID			0x1
478c2ecf20Sopenharmony_ci#define OMAP4_NR_BANKS		4
488c2ecf20Sopenharmony_ci#define OMAP4_NR_IRQS		128
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define SYS_NIRQ1_EXT_SYS_IRQ_1	7
518c2ecf20Sopenharmony_ci#define SYS_NIRQ2_EXT_SYS_IRQ_2	119
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void __iomem *wakeupgen_base;
548c2ecf20Sopenharmony_cistatic void __iomem *sar_base;
558c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(wakeupgen_lock);
568c2ecf20Sopenharmony_cistatic unsigned int irq_target_cpu[MAX_IRQS];
578c2ecf20Sopenharmony_cistatic unsigned int irq_banks = DEFAULT_NR_REG_BANKS;
588c2ecf20Sopenharmony_cistatic unsigned int max_irqs = DEFAULT_IRQS;
598c2ecf20Sopenharmony_cistatic unsigned int omap_secure_apis;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_PM
628c2ecf20Sopenharmony_cistatic unsigned int wakeupgen_context[MAX_NR_REG_BANKS];
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistruct omap_wakeupgen_ops {
668c2ecf20Sopenharmony_ci	void (*save_context)(void);
678c2ecf20Sopenharmony_ci	void (*restore_context)(void);
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops *wakeupgen_ops;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci * Static helper functions.
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic inline u32 wakeupgen_readl(u8 idx, u32 cpu)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	return readl_relaxed(wakeupgen_base + OMAP_WKG_ENB_A_0 +
788c2ecf20Sopenharmony_ci				(cpu * CPU_ENA_OFFSET) + (idx * 4));
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	writel_relaxed(val, wakeupgen_base + OMAP_WKG_ENB_A_0 +
848c2ecf20Sopenharmony_ci				(cpu * CPU_ENA_OFFSET) + (idx * 4));
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline void sar_writel(u32 val, u32 offset, u8 idx)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + offset + (idx * 4));
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	/*
958c2ecf20Sopenharmony_ci	 * Each WakeupGen register controls 32 interrupt.
968c2ecf20Sopenharmony_ci	 * i.e. 1 bit per SPI IRQ
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	*reg_index = irq >> 5;
998c2ecf20Sopenharmony_ci	*bit_posn = irq %= 32;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void _wakeupgen_clear(unsigned int irq, unsigned int cpu)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	u32 val, bit_number;
1078c2ecf20Sopenharmony_ci	u8 i;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (_wakeupgen_get_irq_info(irq, &bit_number, &i))
1108c2ecf20Sopenharmony_ci		return;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	val = wakeupgen_readl(i, cpu);
1138c2ecf20Sopenharmony_ci	val &= ~BIT(bit_number);
1148c2ecf20Sopenharmony_ci	wakeupgen_writel(val, i, cpu);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void _wakeupgen_set(unsigned int irq, unsigned int cpu)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	u32 val, bit_number;
1208c2ecf20Sopenharmony_ci	u8 i;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (_wakeupgen_get_irq_info(irq, &bit_number, &i))
1238c2ecf20Sopenharmony_ci		return;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	val = wakeupgen_readl(i, cpu);
1268c2ecf20Sopenharmony_ci	val |= BIT(bit_number);
1278c2ecf20Sopenharmony_ci	wakeupgen_writel(val, i, cpu);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/*
1318c2ecf20Sopenharmony_ci * Architecture specific Mask extension
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_cistatic void wakeupgen_mask(struct irq_data *d)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	unsigned long flags;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&wakeupgen_lock, flags);
1388c2ecf20Sopenharmony_ci	_wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);
1398c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
1408c2ecf20Sopenharmony_ci	irq_chip_mask_parent(d);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/*
1448c2ecf20Sopenharmony_ci * Architecture specific Unmask extension
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistatic void wakeupgen_unmask(struct irq_data *d)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	unsigned long flags;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&wakeupgen_lock, flags);
1518c2ecf20Sopenharmony_ci	_wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);
1528c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
1538c2ecf20Sopenharmony_ci	irq_chip_unmask_parent(d);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/*
1578c2ecf20Sopenharmony_ci * The sys_nirq pins bypass peripheral modules and are wired directly
1588c2ecf20Sopenharmony_ci * to MPUSS wakeupgen. They get automatically inverted for GIC.
1598c2ecf20Sopenharmony_ci */
1608c2ecf20Sopenharmony_cistatic int wakeupgen_irq_set_type(struct irq_data *d, unsigned int type)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	bool inverted = false;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	switch (type) {
1658c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
1668c2ecf20Sopenharmony_ci		type &= ~IRQ_TYPE_LEVEL_MASK;
1678c2ecf20Sopenharmony_ci		type |= IRQ_TYPE_LEVEL_HIGH;
1688c2ecf20Sopenharmony_ci		inverted = true;
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
1718c2ecf20Sopenharmony_ci		type &= ~IRQ_TYPE_EDGE_BOTH;
1728c2ecf20Sopenharmony_ci		type |= IRQ_TYPE_EDGE_RISING;
1738c2ecf20Sopenharmony_ci		inverted = true;
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	default:
1768c2ecf20Sopenharmony_ci		break;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	if (inverted && d->hwirq != SYS_NIRQ1_EXT_SYS_IRQ_1 &&
1808c2ecf20Sopenharmony_ci	    d->hwirq != SYS_NIRQ2_EXT_SYS_IRQ_2)
1818c2ecf20Sopenharmony_ci		pr_warn("wakeupgen: irq%li polarity inverted in dts\n",
1828c2ecf20Sopenharmony_ci			d->hwirq);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return irq_chip_set_type_parent(d, type);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
1888c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic void _wakeupgen_save_masks(unsigned int cpu)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	u8 i;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++)
1958c2ecf20Sopenharmony_ci		per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void _wakeupgen_restore_masks(unsigned int cpu)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u8 i;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++)
2038c2ecf20Sopenharmony_ci		wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void _wakeupgen_set_all(unsigned int cpu, unsigned int reg)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	u8 i;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++)
2118c2ecf20Sopenharmony_ci		wakeupgen_writel(reg, i, cpu);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/*
2158c2ecf20Sopenharmony_ci * Mask or unmask all interrupts on given CPU.
2168c2ecf20Sopenharmony_ci *	0 = Mask all interrupts on the 'cpu'
2178c2ecf20Sopenharmony_ci *	1 = Unmask all interrupts on the 'cpu'
2188c2ecf20Sopenharmony_ci * Ensure that the initial mask is maintained. This is faster than
2198c2ecf20Sopenharmony_ci * iterating through GIC registers to arrive at the correct masks.
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_cistatic void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	unsigned long flags;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&wakeupgen_lock, flags);
2268c2ecf20Sopenharmony_ci	if (set) {
2278c2ecf20Sopenharmony_ci		_wakeupgen_save_masks(cpu);
2288c2ecf20Sopenharmony_ci		_wakeupgen_set_all(cpu, WKG_MASK_ALL);
2298c2ecf20Sopenharmony_ci	} else {
2308c2ecf20Sopenharmony_ci		_wakeupgen_set_all(cpu, WKG_UNMASK_ALL);
2318c2ecf20Sopenharmony_ci		_wakeupgen_restore_masks(cpu);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci#endif
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_PM
2388c2ecf20Sopenharmony_cistatic inline void omap4_irq_save_context(void)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	u32 i, val;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (omap_rev() == OMAP4430_REV_ES1_0)
2438c2ecf20Sopenharmony_ci		return;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++) {
2468c2ecf20Sopenharmony_ci		/* Save the CPUx interrupt mask for IRQ 0 to 127 */
2478c2ecf20Sopenharmony_ci		val = wakeupgen_readl(i, 0);
2488c2ecf20Sopenharmony_ci		sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i);
2498c2ecf20Sopenharmony_ci		val = wakeupgen_readl(i, 1);
2508c2ecf20Sopenharmony_ci		sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		/*
2538c2ecf20Sopenharmony_ci		 * Disable the secure interrupts for CPUx. The restore
2548c2ecf20Sopenharmony_ci		 * code blindly restores secure and non-secure interrupt
2558c2ecf20Sopenharmony_ci		 * masks from SAR RAM. Secure interrupts are not suppose
2568c2ecf20Sopenharmony_ci		 * to be enabled from HLOS. So overwrite the SAR location
2578c2ecf20Sopenharmony_ci		 * so that the secure interrupt remains disabled.
2588c2ecf20Sopenharmony_ci		 */
2598c2ecf20Sopenharmony_ci		sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i);
2608c2ecf20Sopenharmony_ci		sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i);
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Save AuxBoot* registers */
2648c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
2658c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + AUXCOREBOOT0_OFFSET);
2668c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_1);
2678c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + AUXCOREBOOT1_OFFSET);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* Save SyncReq generation logic */
2708c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_MASK);
2718c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + PTMSYNCREQ_MASK_OFFSET);
2728c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_EN);
2738c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + PTMSYNCREQ_EN_OFFSET);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* Set the Backup Bit Mask status */
2768c2ecf20Sopenharmony_ci	val = readl_relaxed(sar_base + SAR_BACKUP_STATUS_OFFSET);
2778c2ecf20Sopenharmony_ci	val |= SAR_BACKUP_STATUS_WAKEUPGEN;
2788c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + SAR_BACKUP_STATUS_OFFSET);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic inline void omap5_irq_save_context(void)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	u32 i, val;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++) {
2878c2ecf20Sopenharmony_ci		/* Save the CPUx interrupt mask for IRQ 0 to 159 */
2888c2ecf20Sopenharmony_ci		val = wakeupgen_readl(i, 0);
2898c2ecf20Sopenharmony_ci		sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU0, i);
2908c2ecf20Sopenharmony_ci		val = wakeupgen_readl(i, 1);
2918c2ecf20Sopenharmony_ci		sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU1, i);
2928c2ecf20Sopenharmony_ci		sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0, i);
2938c2ecf20Sopenharmony_ci		sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1, i);
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Save AuxBoot* registers */
2978c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
2988c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT0_OFFSET);
2998c2ecf20Sopenharmony_ci	val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0);
3008c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT1_OFFSET);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* Set the Backup Bit Mask status */
3038c2ecf20Sopenharmony_ci	val = readl_relaxed(sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET);
3048c2ecf20Sopenharmony_ci	val |= SAR_BACKUP_STATUS_WAKEUPGEN;
3058c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic inline void am43xx_irq_save_context(void)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	u32 i;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++) {
3148c2ecf20Sopenharmony_ci		wakeupgen_context[i] = wakeupgen_readl(i, 0);
3158c2ecf20Sopenharmony_ci		wakeupgen_writel(0, i, CPU0_ID);
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/*
3208c2ecf20Sopenharmony_ci * Save WakeupGen interrupt context in SAR BANK3. Restore is done by
3218c2ecf20Sopenharmony_ci * ROM code. WakeupGen IP is integrated along with GIC to manage the
3228c2ecf20Sopenharmony_ci * interrupt wakeups from CPU low power states. It manages
3238c2ecf20Sopenharmony_ci * masking/unmasking of Shared peripheral interrupts(SPI). So the
3248c2ecf20Sopenharmony_ci * interrupt enable/disable control should be in sync and consistent
3258c2ecf20Sopenharmony_ci * at WakeupGen and GIC so that interrupts are not lost.
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_cistatic void irq_save_context(void)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	/* DRA7 has no SAR to save */
3308c2ecf20Sopenharmony_ci	if (soc_is_dra7xx())
3318c2ecf20Sopenharmony_ci		return;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (wakeupgen_ops && wakeupgen_ops->save_context)
3348c2ecf20Sopenharmony_ci		wakeupgen_ops->save_context();
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/*
3388c2ecf20Sopenharmony_ci * Clear WakeupGen SAR backup status.
3398c2ecf20Sopenharmony_ci */
3408c2ecf20Sopenharmony_cistatic void irq_sar_clear(void)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	u32 val;
3438c2ecf20Sopenharmony_ci	u32 offset = SAR_BACKUP_STATUS_OFFSET;
3448c2ecf20Sopenharmony_ci	/* DRA7 has no SAR to save */
3458c2ecf20Sopenharmony_ci	if (soc_is_dra7xx())
3468c2ecf20Sopenharmony_ci		return;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (soc_is_omap54xx())
3498c2ecf20Sopenharmony_ci		offset = OMAP5_SAR_BACKUP_STATUS_OFFSET;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	val = readl_relaxed(sar_base + offset);
3528c2ecf20Sopenharmony_ci	val &= ~SAR_BACKUP_STATUS_WAKEUPGEN;
3538c2ecf20Sopenharmony_ci	writel_relaxed(val, sar_base + offset);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void am43xx_irq_restore_context(void)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	u32 i;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++)
3618c2ecf20Sopenharmony_ci		wakeupgen_writel(wakeupgen_context[i], i, CPU0_ID);
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic void irq_restore_context(void)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	if (wakeupgen_ops && wakeupgen_ops->restore_context)
3678c2ecf20Sopenharmony_ci		wakeupgen_ops->restore_context();
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci/*
3718c2ecf20Sopenharmony_ci * Save GIC and Wakeupgen interrupt context using secure API
3728c2ecf20Sopenharmony_ci * for HS/EMU devices.
3738c2ecf20Sopenharmony_ci */
3748c2ecf20Sopenharmony_cistatic void irq_save_secure_context(void)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	u32 ret;
3778c2ecf20Sopenharmony_ci	ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX,
3788c2ecf20Sopenharmony_ci				FLAG_START_CRITICAL,
3798c2ecf20Sopenharmony_ci				0, 0, 0, 0, 0);
3808c2ecf20Sopenharmony_ci	if (ret != API_HAL_RET_VALUE_OK)
3818c2ecf20Sopenharmony_ci		pr_err("GIC and Wakeupgen context save failed\n");
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* Define ops for context save and restore for each SoC */
3858c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops omap4_wakeupgen_ops = {
3868c2ecf20Sopenharmony_ci	.save_context = omap4_irq_save_context,
3878c2ecf20Sopenharmony_ci	.restore_context = irq_sar_clear,
3888c2ecf20Sopenharmony_ci};
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops omap5_wakeupgen_ops = {
3918c2ecf20Sopenharmony_ci	.save_context = omap5_irq_save_context,
3928c2ecf20Sopenharmony_ci	.restore_context = irq_sar_clear,
3938c2ecf20Sopenharmony_ci};
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops am43xx_wakeupgen_ops = {
3968c2ecf20Sopenharmony_ci	.save_context = am43xx_irq_save_context,
3978c2ecf20Sopenharmony_ci	.restore_context = am43xx_irq_restore_context,
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci#else
4008c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops omap4_wakeupgen_ops = {};
4018c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops omap5_wakeupgen_ops = {};
4028c2ecf20Sopenharmony_cistatic struct omap_wakeupgen_ops am43xx_wakeupgen_ops = {};
4038c2ecf20Sopenharmony_ci#endif
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
4068c2ecf20Sopenharmony_cistatic int omap_wakeupgen_cpu_online(unsigned int cpu)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	wakeupgen_irqmask_all(cpu, 0);
4098c2ecf20Sopenharmony_ci	return 0;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int omap_wakeupgen_cpu_dead(unsigned int cpu)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	wakeupgen_irqmask_all(cpu, 1);
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic void __init irq_hotplug_init(void)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "arm/omap-wake:online",
4218c2ecf20Sopenharmony_ci				  omap_wakeupgen_cpu_online, NULL);
4228c2ecf20Sopenharmony_ci	cpuhp_setup_state_nocalls(CPUHP_ARM_OMAP_WAKE_DEAD,
4238c2ecf20Sopenharmony_ci				  "arm/omap-wake:dead", NULL,
4248c2ecf20Sopenharmony_ci				  omap_wakeupgen_cpu_dead);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci#else
4278c2ecf20Sopenharmony_cistatic void __init irq_hotplug_init(void)
4288c2ecf20Sopenharmony_ci{}
4298c2ecf20Sopenharmony_ci#endif
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_PM
4328c2ecf20Sopenharmony_cistatic int irq_notifier(struct notifier_block *self, unsigned long cmd,	void *v)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	switch (cmd) {
4358c2ecf20Sopenharmony_ci	case CPU_CLUSTER_PM_ENTER:
4368c2ecf20Sopenharmony_ci		if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
4378c2ecf20Sopenharmony_ci			irq_save_context();
4388c2ecf20Sopenharmony_ci		else
4398c2ecf20Sopenharmony_ci			irq_save_secure_context();
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case CPU_CLUSTER_PM_EXIT:
4428c2ecf20Sopenharmony_ci		if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx())
4438c2ecf20Sopenharmony_ci			irq_restore_context();
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci	return NOTIFY_OK;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic struct notifier_block irq_notifier_block = {
4508c2ecf20Sopenharmony_ci	.notifier_call = irq_notifier,
4518c2ecf20Sopenharmony_ci};
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void __init irq_pm_init(void)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	/* FIXME: Remove this when MPU OSWR support is added */
4568c2ecf20Sopenharmony_ci	if (!IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE))
4578c2ecf20Sopenharmony_ci		cpu_pm_register_notifier(&irq_notifier_block);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci#else
4608c2ecf20Sopenharmony_cistatic void __init irq_pm_init(void)
4618c2ecf20Sopenharmony_ci{}
4628c2ecf20Sopenharmony_ci#endif
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_civoid __iomem *omap_get_wakeupgen_base(void)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	return wakeupgen_base;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ciint omap_secure_apis_support(void)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	return omap_secure_apis;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic struct irq_chip wakeupgen_chip = {
4758c2ecf20Sopenharmony_ci	.name			= "WUGEN",
4768c2ecf20Sopenharmony_ci	.irq_eoi		= irq_chip_eoi_parent,
4778c2ecf20Sopenharmony_ci	.irq_mask		= wakeupgen_mask,
4788c2ecf20Sopenharmony_ci	.irq_unmask		= wakeupgen_unmask,
4798c2ecf20Sopenharmony_ci	.irq_retrigger		= irq_chip_retrigger_hierarchy,
4808c2ecf20Sopenharmony_ci	.irq_set_type		= wakeupgen_irq_set_type,
4818c2ecf20Sopenharmony_ci	.flags			= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
4828c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
4838c2ecf20Sopenharmony_ci	.irq_set_affinity	= irq_chip_set_affinity_parent,
4848c2ecf20Sopenharmony_ci#endif
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic int wakeupgen_domain_translate(struct irq_domain *d,
4888c2ecf20Sopenharmony_ci				      struct irq_fwspec *fwspec,
4898c2ecf20Sopenharmony_ci				      unsigned long *hwirq,
4908c2ecf20Sopenharmony_ci				      unsigned int *type)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	if (is_of_node(fwspec->fwnode)) {
4938c2ecf20Sopenharmony_ci		if (fwspec->param_count != 3)
4948c2ecf20Sopenharmony_ci			return -EINVAL;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		/* No PPI should point to this domain */
4978c2ecf20Sopenharmony_ci		if (fwspec->param[0] != 0)
4988c2ecf20Sopenharmony_ci			return -EINVAL;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci		*hwirq = fwspec->param[1];
5018c2ecf20Sopenharmony_ci		*type = fwspec->param[2];
5028c2ecf20Sopenharmony_ci		return 0;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	return -EINVAL;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic int wakeupgen_domain_alloc(struct irq_domain *domain,
5098c2ecf20Sopenharmony_ci				  unsigned int virq,
5108c2ecf20Sopenharmony_ci				  unsigned int nr_irqs, void *data)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct irq_fwspec *fwspec = data;
5138c2ecf20Sopenharmony_ci	struct irq_fwspec parent_fwspec;
5148c2ecf20Sopenharmony_ci	irq_hw_number_t hwirq;
5158c2ecf20Sopenharmony_ci	int i;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (fwspec->param_count != 3)
5188c2ecf20Sopenharmony_ci		return -EINVAL;	/* Not GIC compliant */
5198c2ecf20Sopenharmony_ci	if (fwspec->param[0] != 0)
5208c2ecf20Sopenharmony_ci		return -EINVAL;	/* No PPI should point to this domain */
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	hwirq = fwspec->param[1];
5238c2ecf20Sopenharmony_ci	if (hwirq >= MAX_IRQS)
5248c2ecf20Sopenharmony_ci		return -EINVAL;	/* Can't deal with this */
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	for (i = 0; i < nr_irqs; i++)
5278c2ecf20Sopenharmony_ci		irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
5288c2ecf20Sopenharmony_ci					      &wakeupgen_chip, NULL);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	parent_fwspec = *fwspec;
5318c2ecf20Sopenharmony_ci	parent_fwspec.fwnode = domain->parent->fwnode;
5328c2ecf20Sopenharmony_ci	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
5338c2ecf20Sopenharmony_ci					    &parent_fwspec);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic const struct irq_domain_ops wakeupgen_domain_ops = {
5378c2ecf20Sopenharmony_ci	.translate	= wakeupgen_domain_translate,
5388c2ecf20Sopenharmony_ci	.alloc		= wakeupgen_domain_alloc,
5398c2ecf20Sopenharmony_ci	.free		= irq_domain_free_irqs_common,
5408c2ecf20Sopenharmony_ci};
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci/*
5438c2ecf20Sopenharmony_ci * Initialise the wakeupgen module.
5448c2ecf20Sopenharmony_ci */
5458c2ecf20Sopenharmony_cistatic int __init wakeupgen_init(struct device_node *node,
5468c2ecf20Sopenharmony_ci				 struct device_node *parent)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct irq_domain *parent_domain, *domain;
5498c2ecf20Sopenharmony_ci	int i;
5508c2ecf20Sopenharmony_ci	unsigned int boot_cpu = smp_processor_id();
5518c2ecf20Sopenharmony_ci	u32 val;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (!parent) {
5548c2ecf20Sopenharmony_ci		pr_err("%pOF: no parent, giving up\n", node);
5558c2ecf20Sopenharmony_ci		return -ENODEV;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	parent_domain = irq_find_host(parent);
5598c2ecf20Sopenharmony_ci	if (!parent_domain) {
5608c2ecf20Sopenharmony_ci		pr_err("%pOF: unable to obtain parent domain\n", node);
5618c2ecf20Sopenharmony_ci		return -ENXIO;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	/* Not supported on OMAP4 ES1.0 silicon */
5648c2ecf20Sopenharmony_ci	if (omap_rev() == OMAP4430_REV_ES1_0) {
5658c2ecf20Sopenharmony_ci		WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n");
5668c2ecf20Sopenharmony_ci		return -EPERM;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* Static mapping, never released */
5708c2ecf20Sopenharmony_ci	wakeupgen_base = of_iomap(node, 0);
5718c2ecf20Sopenharmony_ci	if (WARN_ON(!wakeupgen_base))
5728c2ecf20Sopenharmony_ci		return -ENOMEM;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	if (cpu_is_omap44xx()) {
5758c2ecf20Sopenharmony_ci		irq_banks = OMAP4_NR_BANKS;
5768c2ecf20Sopenharmony_ci		max_irqs = OMAP4_NR_IRQS;
5778c2ecf20Sopenharmony_ci		omap_secure_apis = 1;
5788c2ecf20Sopenharmony_ci		wakeupgen_ops = &omap4_wakeupgen_ops;
5798c2ecf20Sopenharmony_ci	} else if (soc_is_omap54xx()) {
5808c2ecf20Sopenharmony_ci		wakeupgen_ops = &omap5_wakeupgen_ops;
5818c2ecf20Sopenharmony_ci	} else if (soc_is_am43xx()) {
5828c2ecf20Sopenharmony_ci		irq_banks = AM43XX_NR_REG_BANKS;
5838c2ecf20Sopenharmony_ci		max_irqs = AM43XX_IRQS;
5848c2ecf20Sopenharmony_ci		wakeupgen_ops = &am43xx_wakeupgen_ops;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	domain = irq_domain_add_hierarchy(parent_domain, 0, max_irqs,
5888c2ecf20Sopenharmony_ci					  node, &wakeupgen_domain_ops,
5898c2ecf20Sopenharmony_ci					  NULL);
5908c2ecf20Sopenharmony_ci	if (!domain) {
5918c2ecf20Sopenharmony_ci		iounmap(wakeupgen_base);
5928c2ecf20Sopenharmony_ci		return -ENOMEM;
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/* Clear all IRQ bitmasks at wakeupGen level */
5968c2ecf20Sopenharmony_ci	for (i = 0; i < irq_banks; i++) {
5978c2ecf20Sopenharmony_ci		wakeupgen_writel(0, i, CPU0_ID);
5988c2ecf20Sopenharmony_ci		if (!soc_is_am43xx())
5998c2ecf20Sopenharmony_ci			wakeupgen_writel(0, i, CPU1_ID);
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	/*
6038c2ecf20Sopenharmony_ci	 * FIXME: Add support to set_smp_affinity() once the core
6048c2ecf20Sopenharmony_ci	 * GIC code has necessary hooks in place.
6058c2ecf20Sopenharmony_ci	 */
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	/* Associate all the IRQs to boot CPU like GIC init does. */
6088c2ecf20Sopenharmony_ci	for (i = 0; i < max_irqs; i++)
6098c2ecf20Sopenharmony_ci		irq_target_cpu[i] = boot_cpu;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	/*
6128c2ecf20Sopenharmony_ci	 * Enables OMAP5 ES2 PM Mode using ES2_PM_MODE in AMBA_IF_MODE
6138c2ecf20Sopenharmony_ci	 * 0x0:	ES1 behavior, CPU cores would enter and exit OFF mode together.
6148c2ecf20Sopenharmony_ci	 * 0x1:	ES2 behavior, CPU cores are allowed to enter/exit OFF mode
6158c2ecf20Sopenharmony_ci	 * independently.
6168c2ecf20Sopenharmony_ci	 * This needs to be set one time thanks to always ON domain.
6178c2ecf20Sopenharmony_ci	 *
6188c2ecf20Sopenharmony_ci	 * We do not support ES1 behavior anymore. OMAP5 is assumed to be
6198c2ecf20Sopenharmony_ci	 * ES2.0, and the same is applicable for DRA7.
6208c2ecf20Sopenharmony_ci	 */
6218c2ecf20Sopenharmony_ci	if (soc_is_omap54xx() || soc_is_dra7xx()) {
6228c2ecf20Sopenharmony_ci		val = __raw_readl(wakeupgen_base + OMAP_AMBA_IF_MODE);
6238c2ecf20Sopenharmony_ci		val |= BIT(5);
6248c2ecf20Sopenharmony_ci		omap_smc1(OMAP5_MON_AMBA_IF_INDEX, val);
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	irq_hotplug_init();
6288c2ecf20Sopenharmony_ci	irq_pm_init();
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	sar_base = omap4_get_sar_ram_base();
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ciIRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
635