root/arch/powerpc/platforms/embedded6xx/flipper-pic.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flipper_pic_mask_and_ack
  2. flipper_pic_ack
  3. flipper_pic_mask
  4. flipper_pic_unmask
  5. flipper_pic_map
  6. __flipper_quiesce
  7. flipper_pic_init
  8. flipper_pic_get_irq
  9. flipper_pic_probe
  10. flipper_quiesce
  11. flipper_platform_reset
  12. flipper_is_reset_button_pressed

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

/* [<][>][^][v][top][bottom][index][help] */