cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

flipper-pic.c (5217B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * arch/powerpc/platforms/embedded6xx/flipper-pic.c
      4 *
      5 * Nintendo GameCube/Wii "Flipper" interrupt controller support.
      6 * Copyright (C) 2004-2009 The GameCube Linux Team
      7 * Copyright (C) 2007,2008,2009 Albert Herranz
      8 */
      9#define DRV_MODULE_NAME "flipper-pic"
     10#define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
     11
     12#include <linux/kernel.h>
     13#include <linux/init.h>
     14#include <linux/irq.h>
     15#include <linux/irqdomain.h>
     16#include <linux/of.h>
     17#include <linux/of_address.h>
     18#include <asm/io.h>
     19
     20#include "flipper-pic.h"
     21
     22#define FLIPPER_NR_IRQS		32
     23
     24/*
     25 * Each interrupt has a corresponding bit in both
     26 * the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers.
     27 *
     28 * Enabling/disabling an interrupt line involves setting/clearing
     29 * the corresponding bit in IMR.
     30 * Except for the RSW interrupt, all interrupts get deasserted automatically
     31 * when the source deasserts the interrupt.
     32 */
     33#define FLIPPER_ICR		0x00
     34#define FLIPPER_ICR_RSS		(1<<16) /* reset switch state */
     35
     36#define FLIPPER_IMR		0x04
     37
     38#define FLIPPER_RESET		0x24
     39
     40
     41/*
     42 * IRQ chip hooks.
     43 *
     44 */
     45
     46static void flipper_pic_mask_and_ack(struct irq_data *d)
     47{
     48	int irq = irqd_to_hwirq(d);
     49	void __iomem *io_base = irq_data_get_irq_chip_data(d);
     50	u32 mask = 1 << irq;
     51
     52	clrbits32(io_base + FLIPPER_IMR, mask);
     53	/* this is at least needed for RSW */
     54	out_be32(io_base + FLIPPER_ICR, mask);
     55}
     56
     57static void flipper_pic_ack(struct irq_data *d)
     58{
     59	int irq = irqd_to_hwirq(d);
     60	void __iomem *io_base = irq_data_get_irq_chip_data(d);
     61
     62	/* this is at least needed for RSW */
     63	out_be32(io_base + FLIPPER_ICR, 1 << irq);
     64}
     65
     66static void flipper_pic_mask(struct irq_data *d)
     67{
     68	int irq = irqd_to_hwirq(d);
     69	void __iomem *io_base = irq_data_get_irq_chip_data(d);
     70
     71	clrbits32(io_base + FLIPPER_IMR, 1 << irq);
     72}
     73
     74static void flipper_pic_unmask(struct irq_data *d)
     75{
     76	int irq = irqd_to_hwirq(d);
     77	void __iomem *io_base = irq_data_get_irq_chip_data(d);
     78
     79	setbits32(io_base + FLIPPER_IMR, 1 << irq);
     80}
     81
     82
     83static struct irq_chip flipper_pic = {
     84	.name		= "flipper-pic",
     85	.irq_ack	= flipper_pic_ack,
     86	.irq_mask_ack	= flipper_pic_mask_and_ack,
     87	.irq_mask	= flipper_pic_mask,
     88	.irq_unmask	= flipper_pic_unmask,
     89};
     90
     91/*
     92 * IRQ host hooks.
     93 *
     94 */
     95
     96static struct irq_domain *flipper_irq_host;
     97
     98static int flipper_pic_map(struct irq_domain *h, unsigned int virq,
     99			   irq_hw_number_t hwirq)
    100{
    101	irq_set_chip_data(virq, h->host_data);
    102	irq_set_status_flags(virq, IRQ_LEVEL);
    103	irq_set_chip_and_handler(virq, &flipper_pic, handle_level_irq);
    104	return 0;
    105}
    106
    107static const struct irq_domain_ops flipper_irq_domain_ops = {
    108	.map = flipper_pic_map,
    109};
    110
    111/*
    112 * Platform hooks.
    113 *
    114 */
    115
    116static void __flipper_quiesce(void __iomem *io_base)
    117{
    118	/* mask and ack all IRQs */
    119	out_be32(io_base + FLIPPER_IMR, 0x00000000);
    120	out_be32(io_base + FLIPPER_ICR, 0xffffffff);
    121}
    122
    123static struct irq_domain * __init flipper_pic_init(struct device_node *np)
    124{
    125	struct device_node *pi;
    126	struct irq_domain *irq_domain = NULL;
    127	struct resource res;
    128	void __iomem *io_base;
    129	int retval;
    130
    131	pi = of_get_parent(np);
    132	if (!pi) {
    133		pr_err("no parent found\n");
    134		goto out;
    135	}
    136	if (!of_device_is_compatible(pi, "nintendo,flipper-pi")) {
    137		pr_err("unexpected parent compatible\n");
    138		goto out;
    139	}
    140
    141	retval = of_address_to_resource(pi, 0, &res);
    142	if (retval) {
    143		pr_err("no io memory range found\n");
    144		goto out;
    145	}
    146	io_base = ioremap(res.start, resource_size(&res));
    147
    148	pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base);
    149
    150	__flipper_quiesce(io_base);
    151
    152	irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS,
    153				  &flipper_irq_domain_ops, io_base);
    154	if (!irq_domain) {
    155		pr_err("failed to allocate irq_domain\n");
    156		return NULL;
    157	}
    158
    159out:
    160	return irq_domain;
    161}
    162
    163unsigned int flipper_pic_get_irq(void)
    164{
    165	void __iomem *io_base = flipper_irq_host->host_data;
    166	int irq;
    167	u32 irq_status;
    168
    169	irq_status = in_be32(io_base + FLIPPER_ICR) &
    170		     in_be32(io_base + FLIPPER_IMR);
    171	if (irq_status == 0)
    172		return 0;	/* no more IRQs pending */
    173
    174	irq = __ffs(irq_status);
    175	return irq_linear_revmap(flipper_irq_host, irq);
    176}
    177
    178/*
    179 * Probe function.
    180 *
    181 */
    182
    183void __init flipper_pic_probe(void)
    184{
    185	struct device_node *np;
    186
    187	np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-pic");
    188	BUG_ON(!np);
    189
    190	flipper_irq_host = flipper_pic_init(np);
    191	BUG_ON(!flipper_irq_host);
    192
    193	irq_set_default_host(flipper_irq_host);
    194
    195	of_node_put(np);
    196}
    197
    198/*
    199 * Misc functions related to the flipper chipset.
    200 *
    201 */
    202
    203/**
    204 * flipper_quiesce() - quiesce flipper irq controller
    205 *
    206 * Mask and ack all interrupt sources.
    207 *
    208 */
    209void flipper_quiesce(void)
    210{
    211	void __iomem *io_base = flipper_irq_host->host_data;
    212
    213	__flipper_quiesce(io_base);
    214}
    215
    216/*
    217 * Resets the platform.
    218 */
    219void flipper_platform_reset(void)
    220{
    221	void __iomem *io_base;
    222
    223	if (flipper_irq_host && flipper_irq_host->host_data) {
    224		io_base = flipper_irq_host->host_data;
    225		out_8(io_base + FLIPPER_RESET, 0x00);
    226	}
    227}
    228
    229/*
    230 * Returns non-zero if the reset button is pressed.
    231 */
    232int flipper_is_reset_button_pressed(void)
    233{
    234	void __iomem *io_base;
    235	u32 icr;
    236
    237	if (flipper_irq_host && flipper_irq_host->host_data) {
    238		io_base = flipper_irq_host->host_data;
    239		icr = in_be32(io_base + FLIPPER_ICR);
    240		return !(icr & FLIPPER_ICR_RSS);
    241	}
    242	return 0;
    243}
    244