root/arch/m68k/mac/oss.c

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

DEFINITIONS

This source file includes following definitions.
  1. oss_init
  2. oss_iopism_irq
  3. oss_scsi_irq
  4. oss_nubus_irq
  5. oss_iopscc_irq
  6. oss_register_interrupts
  7. oss_irq_enable
  8. oss_irq_disable

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *      Operating System Services (OSS) chip handling
   4  *      Written by Joshua M. Thompson (funaho@jurai.org)
   5  *
   6  *
   7  *      This chip is used in the IIfx in place of VIA #2. It acts like a fancy
   8  *      VIA chip with prorammable interrupt levels.
   9  *
  10  * 990502 (jmt) - Major rewrite for new interrupt architecture as well as some
  11  *                recent insights into OSS operational details.
  12  * 990610 (jmt) - Now taking full advantage of the OSS. Interrupts are mapped
  13  *                to mostly match the A/UX interrupt scheme supported on the
  14  *                VIA side. Also added support for enabling the ISM irq again
  15  *                since we now have a functional IOP manager.
  16  */
  17 
  18 #include <linux/types.h>
  19 #include <linux/kernel.h>
  20 #include <linux/mm.h>
  21 #include <linux/delay.h>
  22 #include <linux/init.h>
  23 #include <linux/irq.h>
  24 
  25 #include <asm/macintosh.h>
  26 #include <asm/macints.h>
  27 #include <asm/mac_via.h>
  28 #include <asm/mac_oss.h>
  29 
  30 int oss_present;
  31 volatile struct mac_oss *oss;
  32 
  33 /*
  34  * Initialize the OSS
  35  */
  36 
  37 void __init oss_init(void)
  38 {
  39         int i;
  40 
  41         if (macintosh_config->ident != MAC_MODEL_IIFX)
  42                 return;
  43 
  44         oss = (struct mac_oss *) OSS_BASE;
  45         pr_debug("OSS detected at %p", oss);
  46         oss_present = 1;
  47 
  48         /* Disable all interrupts. Unlike a VIA it looks like we    */
  49         /* do this by setting the source's interrupt level to zero. */
  50 
  51         for (i = 0; i < OSS_NUM_SOURCES; i++)
  52                 oss->irq_level[i] = 0;
  53 }
  54 
  55 /*
  56  * Handle OSS interrupts.
  57  * XXX how do you clear a pending IRQ? is it even necessary?
  58  */
  59 
  60 static void oss_iopism_irq(struct irq_desc *desc)
  61 {
  62         generic_handle_irq(IRQ_MAC_ADB);
  63 }
  64 
  65 static void oss_scsi_irq(struct irq_desc *desc)
  66 {
  67         generic_handle_irq(IRQ_MAC_SCSI);
  68 }
  69 
  70 static void oss_nubus_irq(struct irq_desc *desc)
  71 {
  72         u16 events, irq_bit;
  73         int irq_num;
  74 
  75         events = oss->irq_pending & OSS_IP_NUBUS;
  76         irq_num = NUBUS_SOURCE_BASE + 5;
  77         irq_bit = OSS_IP_NUBUS5;
  78         do {
  79                 if (events & irq_bit) {
  80                         events &= ~irq_bit;
  81                         generic_handle_irq(irq_num);
  82                 }
  83                 --irq_num;
  84                 irq_bit >>= 1;
  85         } while (events);
  86 }
  87 
  88 static void oss_iopscc_irq(struct irq_desc *desc)
  89 {
  90         generic_handle_irq(IRQ_MAC_SCC);
  91 }
  92 
  93 /*
  94  * Register the OSS and NuBus interrupt dispatchers.
  95  *
  96  * This IRQ mapping is laid out with two things in mind: first, we try to keep
  97  * things on their own levels to avoid having to do double-dispatches. Second,
  98  * the levels match as closely as possible the alternate IRQ mapping mode (aka
  99  * "A/UX mode") available on some VIA machines.
 100  */
 101 
 102 #define OSS_IRQLEV_IOPISM    IRQ_AUTO_1
 103 #define OSS_IRQLEV_SCSI      IRQ_AUTO_2
 104 #define OSS_IRQLEV_NUBUS     IRQ_AUTO_3
 105 #define OSS_IRQLEV_IOPSCC    IRQ_AUTO_4
 106 #define OSS_IRQLEV_VIA1      IRQ_AUTO_6
 107 
 108 void __init oss_register_interrupts(void)
 109 {
 110         irq_set_chained_handler(OSS_IRQLEV_IOPISM, oss_iopism_irq);
 111         irq_set_chained_handler(OSS_IRQLEV_SCSI,   oss_scsi_irq);
 112         irq_set_chained_handler(OSS_IRQLEV_NUBUS,  oss_nubus_irq);
 113         irq_set_chained_handler(OSS_IRQLEV_IOPSCC, oss_iopscc_irq);
 114         irq_set_chained_handler(OSS_IRQLEV_VIA1,   via1_irq);
 115 
 116         /* OSS_VIA1 gets enabled here because it has no machspec interrupt. */
 117         oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
 118 }
 119 
 120 /*
 121  * Enable an OSS interrupt
 122  *
 123  * It looks messy but it's rather straightforward. The switch() statement
 124  * just maps the machspec interrupt numbers to the right OSS interrupt
 125  * source (if the OSS handles that interrupt) and then sets the interrupt
 126  * level for that source to nonzero, thus enabling the interrupt.
 127  */
 128 
 129 void oss_irq_enable(int irq) {
 130         switch(irq) {
 131                 case IRQ_MAC_SCC:
 132                         oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC;
 133                         return;
 134                 case IRQ_MAC_ADB:
 135                         oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM;
 136                         return;
 137                 case IRQ_MAC_SCSI:
 138                         oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
 139                         return;
 140                 case IRQ_NUBUS_9:
 141                 case IRQ_NUBUS_A:
 142                 case IRQ_NUBUS_B:
 143                 case IRQ_NUBUS_C:
 144                 case IRQ_NUBUS_D:
 145                 case IRQ_NUBUS_E:
 146                         irq -= NUBUS_SOURCE_BASE;
 147                         oss->irq_level[irq] = OSS_IRQLEV_NUBUS;
 148                         return;
 149         }
 150 
 151         if (IRQ_SRC(irq) == 1)
 152                 via_irq_enable(irq);
 153 }
 154 
 155 /*
 156  * Disable an OSS interrupt
 157  *
 158  * Same as above except we set the source's interrupt level to zero,
 159  * to disable the interrupt.
 160  */
 161 
 162 void oss_irq_disable(int irq) {
 163         switch(irq) {
 164                 case IRQ_MAC_SCC:
 165                         oss->irq_level[OSS_IOPSCC] = 0;
 166                         return;
 167                 case IRQ_MAC_ADB:
 168                         oss->irq_level[OSS_IOPISM] = 0;
 169                         return;
 170                 case IRQ_MAC_SCSI:
 171                         oss->irq_level[OSS_SCSI] = 0;
 172                         return;
 173                 case IRQ_NUBUS_9:
 174                 case IRQ_NUBUS_A:
 175                 case IRQ_NUBUS_B:
 176                 case IRQ_NUBUS_C:
 177                 case IRQ_NUBUS_D:
 178                 case IRQ_NUBUS_E:
 179                         irq -= NUBUS_SOURCE_BASE;
 180                         oss->irq_level[irq] = 0;
 181                         return;
 182         }
 183 
 184         if (IRQ_SRC(irq) == 1)
 185                 via_irq_disable(irq);
 186 }

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