From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- arch/arm/mach-omap2/omap-wakeupgen.c | 634 +++++++++++++++++++++++++++++++++++ 1 file changed, 634 insertions(+) create mode 100644 arch/arm/mach-omap2/omap-wakeupgen.c (limited to 'arch/arm/mach-omap2/omap-wakeupgen.c') diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c new file mode 100644 index 000000000..8d21e3a3c --- /dev/null +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OMAP WakeupGen Source file + * + * OMAP WakeupGen is the interrupt controller extension used along + * with ARM GIC to wake the CPU out from low power states on + * external interrupts. It is responsible for generating wakeup + * event from the incoming interrupts and enable bits. It is + * implemented in MPU always ON power domain. During normal operation, + * WakeupGen delivers external interrupts directly to the GIC. + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Santosh Shilimkar + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "omap-wakeupgen.h" +#include "omap-secure.h" + +#include "soc.h" +#include "omap4-sar-layout.h" +#include "common.h" +#include "pm.h" + +#define AM43XX_NR_REG_BANKS 7 +#define AM43XX_IRQS 224 +#define MAX_NR_REG_BANKS AM43XX_NR_REG_BANKS +#define MAX_IRQS AM43XX_IRQS +#define DEFAULT_NR_REG_BANKS 5 +#define DEFAULT_IRQS 160 +#define WKG_MASK_ALL 0x00000000 +#define WKG_UNMASK_ALL 0xffffffff +#define CPU_ENA_OFFSET 0x400 +#define CPU0_ID 0x0 +#define CPU1_ID 0x1 +#define OMAP4_NR_BANKS 4 +#define OMAP4_NR_IRQS 128 + +#define SYS_NIRQ1_EXT_SYS_IRQ_1 7 +#define SYS_NIRQ2_EXT_SYS_IRQ_2 119 + +static void __iomem *wakeupgen_base; +static void __iomem *sar_base; +static DEFINE_RAW_SPINLOCK(wakeupgen_lock); +static unsigned int irq_target_cpu[MAX_IRQS]; +static unsigned int irq_banks = DEFAULT_NR_REG_BANKS; +static unsigned int max_irqs = DEFAULT_IRQS; +static unsigned int omap_secure_apis; + +#ifdef CONFIG_CPU_PM +static unsigned int wakeupgen_context[MAX_NR_REG_BANKS]; +#endif + +struct omap_wakeupgen_ops { + void (*save_context)(void); + void (*restore_context)(void); +}; + +static struct omap_wakeupgen_ops *wakeupgen_ops; + +/* + * Static helper functions. + */ +static inline u32 wakeupgen_readl(u8 idx, u32 cpu) +{ + return readl_relaxed(wakeupgen_base + OMAP_WKG_ENB_A_0 + + (cpu * CPU_ENA_OFFSET) + (idx * 4)); +} + +static inline void wakeupgen_writel(u32 val, u8 idx, u32 cpu) +{ + writel_relaxed(val, wakeupgen_base + OMAP_WKG_ENB_A_0 + + (cpu * CPU_ENA_OFFSET) + (idx * 4)); +} + +static inline void sar_writel(u32 val, u32 offset, u8 idx) +{ + writel_relaxed(val, sar_base + offset + (idx * 4)); +} + +static inline int _wakeupgen_get_irq_info(u32 irq, u32 *bit_posn, u8 *reg_index) +{ + /* + * Each WakeupGen register controls 32 interrupt. + * i.e. 1 bit per SPI IRQ + */ + *reg_index = irq >> 5; + *bit_posn = irq %= 32; + + return 0; +} + +static void _wakeupgen_clear(unsigned int irq, unsigned int cpu) +{ + u32 val, bit_number; + u8 i; + + if (_wakeupgen_get_irq_info(irq, &bit_number, &i)) + return; + + val = wakeupgen_readl(i, cpu); + val &= ~BIT(bit_number); + wakeupgen_writel(val, i, cpu); +} + +static void _wakeupgen_set(unsigned int irq, unsigned int cpu) +{ + u32 val, bit_number; + u8 i; + + if (_wakeupgen_get_irq_info(irq, &bit_number, &i)) + return; + + val = wakeupgen_readl(i, cpu); + val |= BIT(bit_number); + wakeupgen_writel(val, i, cpu); +} + +/* + * Architecture specific Mask extension + */ +static void wakeupgen_mask(struct irq_data *d) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&wakeupgen_lock, flags); + _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); + irq_chip_mask_parent(d); +} + +/* + * Architecture specific Unmask extension + */ +static void wakeupgen_unmask(struct irq_data *d) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&wakeupgen_lock, flags); + _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); + irq_chip_unmask_parent(d); +} + +/* + * The sys_nirq pins bypass peripheral modules and are wired directly + * to MPUSS wakeupgen. They get automatically inverted for GIC. + */ +static int wakeupgen_irq_set_type(struct irq_data *d, unsigned int type) +{ + bool inverted = false; + + switch (type) { + case IRQ_TYPE_LEVEL_LOW: + type &= ~IRQ_TYPE_LEVEL_MASK; + type |= IRQ_TYPE_LEVEL_HIGH; + inverted = true; + break; + case IRQ_TYPE_EDGE_FALLING: + type &= ~IRQ_TYPE_EDGE_BOTH; + type |= IRQ_TYPE_EDGE_RISING; + inverted = true; + break; + default: + break; + } + + if (inverted && d->hwirq != SYS_NIRQ1_EXT_SYS_IRQ_1 && + d->hwirq != SYS_NIRQ2_EXT_SYS_IRQ_2) + pr_warn("wakeupgen: irq%li polarity inverted in dts\n", + d->hwirq); + + return irq_chip_set_type_parent(d, type); +} + +#ifdef CONFIG_HOTPLUG_CPU +static DEFINE_PER_CPU(u32 [MAX_NR_REG_BANKS], irqmasks); + +static void _wakeupgen_save_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + per_cpu(irqmasks, cpu)[i] = wakeupgen_readl(i, cpu); +} + +static void _wakeupgen_restore_masks(unsigned int cpu) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + wakeupgen_writel(per_cpu(irqmasks, cpu)[i], i, cpu); +} + +static void _wakeupgen_set_all(unsigned int cpu, unsigned int reg) +{ + u8 i; + + for (i = 0; i < irq_banks; i++) + wakeupgen_writel(reg, i, cpu); +} + +/* + * Mask or unmask all interrupts on given CPU. + * 0 = Mask all interrupts on the 'cpu' + * 1 = Unmask all interrupts on the 'cpu' + * Ensure that the initial mask is maintained. This is faster than + * iterating through GIC registers to arrive at the correct masks. + */ +static void wakeupgen_irqmask_all(unsigned int cpu, unsigned int set) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&wakeupgen_lock, flags); + if (set) { + _wakeupgen_save_masks(cpu); + _wakeupgen_set_all(cpu, WKG_MASK_ALL); + } else { + _wakeupgen_set_all(cpu, WKG_UNMASK_ALL); + _wakeupgen_restore_masks(cpu); + } + raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); +} +#endif + +#ifdef CONFIG_CPU_PM +static inline void omap4_irq_save_context(void) +{ + u32 i, val; + + if (omap_rev() == OMAP4430_REV_ES1_0) + return; + + for (i = 0; i < irq_banks; i++) { + /* Save the CPUx interrupt mask for IRQ 0 to 127 */ + val = wakeupgen_readl(i, 0); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU0, i); + val = wakeupgen_readl(i, 1); + sar_writel(val, WAKEUPGENENB_OFFSET_CPU1, i); + + /* + * Disable the secure interrupts for CPUx. The restore + * code blindly restores secure and non-secure interrupt + * masks from SAR RAM. Secure interrupts are not suppose + * to be enabled from HLOS. So overwrite the SAR location + * so that the secure interrupt remains disabled. + */ + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU0, i); + sar_writel(0x0, WAKEUPGENENB_SECURE_OFFSET_CPU1, i); + } + + /* Save AuxBoot* registers */ + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + AUXCOREBOOT0_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_1); + writel_relaxed(val, sar_base + AUXCOREBOOT1_OFFSET); + + /* Save SyncReq generation logic */ + val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_MASK); + writel_relaxed(val, sar_base + PTMSYNCREQ_MASK_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_PTMSYNCREQ_EN); + writel_relaxed(val, sar_base + PTMSYNCREQ_EN_OFFSET); + + /* Set the Backup Bit Mask status */ + val = readl_relaxed(sar_base + SAR_BACKUP_STATUS_OFFSET); + val |= SAR_BACKUP_STATUS_WAKEUPGEN; + writel_relaxed(val, sar_base + SAR_BACKUP_STATUS_OFFSET); + +} + +static inline void omap5_irq_save_context(void) +{ + u32 i, val; + + for (i = 0; i < irq_banks; i++) { + /* Save the CPUx interrupt mask for IRQ 0 to 159 */ + val = wakeupgen_readl(i, 0); + sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU0, i); + val = wakeupgen_readl(i, 1); + sar_writel(val, OMAP5_WAKEUPGENENB_OFFSET_CPU1, i); + sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU0, i); + sar_writel(0x0, OMAP5_WAKEUPGENENB_SECURE_OFFSET_CPU1, i); + } + + /* Save AuxBoot* registers */ + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT0_OFFSET); + val = readl_relaxed(wakeupgen_base + OMAP_AUX_CORE_BOOT_0); + writel_relaxed(val, sar_base + OMAP5_AUXCOREBOOT1_OFFSET); + + /* Set the Backup Bit Mask status */ + val = readl_relaxed(sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET); + val |= SAR_BACKUP_STATUS_WAKEUPGEN; + writel_relaxed(val, sar_base + OMAP5_SAR_BACKUP_STATUS_OFFSET); + +} + +static inline void am43xx_irq_save_context(void) +{ + u32 i; + + for (i = 0; i < irq_banks; i++) { + wakeupgen_context[i] = wakeupgen_readl(i, 0); + wakeupgen_writel(0, i, CPU0_ID); + } +} + +/* + * Save WakeupGen interrupt context in SAR BANK3. Restore is done by + * ROM code. WakeupGen IP is integrated along with GIC to manage the + * interrupt wakeups from CPU low power states. It manages + * masking/unmasking of Shared peripheral interrupts(SPI). So the + * interrupt enable/disable control should be in sync and consistent + * at WakeupGen and GIC so that interrupts are not lost. + */ +static void irq_save_context(void) +{ + /* DRA7 has no SAR to save */ + if (soc_is_dra7xx()) + return; + + if (wakeupgen_ops && wakeupgen_ops->save_context) + wakeupgen_ops->save_context(); +} + +/* + * Clear WakeupGen SAR backup status. + */ +static void irq_sar_clear(void) +{ + u32 val; + u32 offset = SAR_BACKUP_STATUS_OFFSET; + /* DRA7 has no SAR to save */ + if (soc_is_dra7xx()) + return; + + if (soc_is_omap54xx()) + offset = OMAP5_SAR_BACKUP_STATUS_OFFSET; + + val = readl_relaxed(sar_base + offset); + val &= ~SAR_BACKUP_STATUS_WAKEUPGEN; + writel_relaxed(val, sar_base + offset); +} + +static void am43xx_irq_restore_context(void) +{ + u32 i; + + for (i = 0; i < irq_banks; i++) + wakeupgen_writel(wakeupgen_context[i], i, CPU0_ID); +} + +static void irq_restore_context(void) +{ + if (wakeupgen_ops && wakeupgen_ops->restore_context) + wakeupgen_ops->restore_context(); +} + +/* + * Save GIC and Wakeupgen interrupt context using secure API + * for HS/EMU devices. + */ +static void irq_save_secure_context(void) +{ + u32 ret; + ret = omap_secure_dispatcher(OMAP4_HAL_SAVEGIC_INDEX, + FLAG_START_CRITICAL, + 0, 0, 0, 0, 0); + if (ret != API_HAL_RET_VALUE_OK) + pr_err("GIC and Wakeupgen context save failed\n"); +} + +/* Define ops for context save and restore for each SoC */ +static struct omap_wakeupgen_ops omap4_wakeupgen_ops = { + .save_context = omap4_irq_save_context, + .restore_context = irq_sar_clear, +}; + +static struct omap_wakeupgen_ops omap5_wakeupgen_ops = { + .save_context = omap5_irq_save_context, + .restore_context = irq_sar_clear, +}; + +static struct omap_wakeupgen_ops am43xx_wakeupgen_ops = { + .save_context = am43xx_irq_save_context, + .restore_context = am43xx_irq_restore_context, +}; +#else +static struct omap_wakeupgen_ops omap4_wakeupgen_ops = {}; +static struct omap_wakeupgen_ops omap5_wakeupgen_ops = {}; +static struct omap_wakeupgen_ops am43xx_wakeupgen_ops = {}; +#endif + +#ifdef CONFIG_HOTPLUG_CPU +static int omap_wakeupgen_cpu_online(unsigned int cpu) +{ + wakeupgen_irqmask_all(cpu, 0); + return 0; +} + +static int omap_wakeupgen_cpu_dead(unsigned int cpu) +{ + wakeupgen_irqmask_all(cpu, 1); + return 0; +} + +static void __init irq_hotplug_init(void) +{ + cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "arm/omap-wake:online", + omap_wakeupgen_cpu_online, NULL); + cpuhp_setup_state_nocalls(CPUHP_ARM_OMAP_WAKE_DEAD, + "arm/omap-wake:dead", NULL, + omap_wakeupgen_cpu_dead); +} +#else +static void __init irq_hotplug_init(void) +{} +#endif + +#ifdef CONFIG_CPU_PM +static int irq_notifier(struct notifier_block *self, unsigned long cmd, void *v) +{ + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx()) + irq_save_context(); + else + irq_save_secure_context(); + break; + case CPU_CLUSTER_PM_EXIT: + if (omap_type() == OMAP2_DEVICE_TYPE_GP || soc_is_am43xx()) + irq_restore_context(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block irq_notifier_block = { + .notifier_call = irq_notifier, +}; + +static void __init irq_pm_init(void) +{ + /* FIXME: Remove this when MPU OSWR support is added */ + if (!IS_PM44XX_ERRATUM(PM_OMAP4_CPU_OSWR_DISABLE)) + cpu_pm_register_notifier(&irq_notifier_block); +} +#else +static void __init irq_pm_init(void) +{} +#endif + +void __iomem *omap_get_wakeupgen_base(void) +{ + return wakeupgen_base; +} + +int omap_secure_apis_support(void) +{ + return omap_secure_apis; +} + +static struct irq_chip wakeupgen_chip = { + .name = "WUGEN", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = wakeupgen_mask, + .irq_unmask = wakeupgen_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = wakeupgen_irq_set_type, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif +}; + +static int wakeupgen_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; + + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; +} + +static int wakeupgen_domain_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + irq_hw_number_t hwirq; + int i; + + if (fwspec->param_count != 3) + return -EINVAL; /* Not GIC compliant */ + if (fwspec->param[0] != 0) + return -EINVAL; /* No PPI should point to this domain */ + + hwirq = fwspec->param[1]; + if (hwirq >= MAX_IRQS) + return -EINVAL; /* Can't deal with this */ + + for (i = 0; i < nr_irqs; i++) + irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, + &wakeupgen_chip, NULL); + + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); +} + +static const struct irq_domain_ops wakeupgen_domain_ops = { + .translate = wakeupgen_domain_translate, + .alloc = wakeupgen_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +/* + * Initialise the wakeupgen module. + */ +static int __init wakeupgen_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + int i; + unsigned int boot_cpu = smp_processor_id(); + u32 val; + + if (!parent) { + pr_err("%pOF: no parent, giving up\n", node); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%pOF: unable to obtain parent domain\n", node); + return -ENXIO; + } + /* Not supported on OMAP4 ES1.0 silicon */ + if (omap_rev() == OMAP4430_REV_ES1_0) { + WARN(1, "WakeupGen: Not supported on OMAP4430 ES1.0\n"); + return -EPERM; + } + + /* Static mapping, never released */ + wakeupgen_base = of_iomap(node, 0); + if (WARN_ON(!wakeupgen_base)) + return -ENOMEM; + + if (cpu_is_omap44xx()) { + irq_banks = OMAP4_NR_BANKS; + max_irqs = OMAP4_NR_IRQS; + omap_secure_apis = 1; + wakeupgen_ops = &omap4_wakeupgen_ops; + } else if (soc_is_omap54xx()) { + wakeupgen_ops = &omap5_wakeupgen_ops; + } else if (soc_is_am43xx()) { + irq_banks = AM43XX_NR_REG_BANKS; + max_irqs = AM43XX_IRQS; + wakeupgen_ops = &am43xx_wakeupgen_ops; + } + + domain = irq_domain_add_hierarchy(parent_domain, 0, max_irqs, + node, &wakeupgen_domain_ops, + NULL); + if (!domain) { + iounmap(wakeupgen_base); + return -ENOMEM; + } + + /* Clear all IRQ bitmasks at wakeupGen level */ + for (i = 0; i < irq_banks; i++) { + wakeupgen_writel(0, i, CPU0_ID); + if (!soc_is_am43xx()) + wakeupgen_writel(0, i, CPU1_ID); + } + + /* + * FIXME: Add support to set_smp_affinity() once the core + * GIC code has necessary hooks in place. + */ + + /* Associate all the IRQs to boot CPU like GIC init does. */ + for (i = 0; i < max_irqs; i++) + irq_target_cpu[i] = boot_cpu; + + /* + * Enables OMAP5 ES2 PM Mode using ES2_PM_MODE in AMBA_IF_MODE + * 0x0: ES1 behavior, CPU cores would enter and exit OFF mode together. + * 0x1: ES2 behavior, CPU cores are allowed to enter/exit OFF mode + * independently. + * This needs to be set one time thanks to always ON domain. + * + * We do not support ES1 behavior anymore. OMAP5 is assumed to be + * ES2.0, and the same is applicable for DRA7. + */ + if (soc_is_omap54xx() || soc_is_dra7xx()) { + val = __raw_readl(wakeupgen_base + OMAP_AMBA_IF_MODE); + val |= BIT(5); + omap_smc1(OMAP5_MON_AMBA_IF_INDEX, val); + } + + irq_hotplug_init(); + irq_pm_init(); + + sar_base = omap4_get_sar_ram_base(); + + return 0; +} +IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init); -- cgit v1.2.3