^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Apple Peripheral System Controller (PSC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * The PSC is used on the AV Macs to control IO functions not handled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * by the VIAs (Ethernet, DSP, SCC).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * TO DO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * persisant interrupt conditions in those registers and I have no idea what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * they are. Granted it doesn't affect since we're not enabling any interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * on those levels at the moment, but it would be nice to know. I have a feeling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * they aren't actually interrupt lines but data lines (to the DSP?)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/macintosh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/macints.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/mac_psc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DEBUG_PSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) volatile __u8 *psc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) EXPORT_SYMBOL_GPL(psc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Debugging dump, used in various places to see what's going on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static void psc_debug_dump(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (!psc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) for (i = 0x30 ; i < 0x70 ; i += 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) printk(KERN_DEBUG "PSC #%d: IFR = 0x%02X IER = 0x%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) i >> 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) (int) psc_read_byte(pIFRbase + i),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) (int) psc_read_byte(pIERbase + i));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Try to kill all DMA channels on the PSC. Not sure how this his
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * supposed to work; this is code lifted from macmace.c and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * expanded to cover what I think are the other 7 channels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static __init void psc_dma_die_die_die(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) for (i = 0 ; i < 9 ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Initialize the PSC. For now this just involves shutting down all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * interrupt sources using the IERs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) void __init psc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (macintosh_config->ident != MAC_MODEL_C660
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) && macintosh_config->ident != MAC_MODEL_Q840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) psc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * The PSC is always at the same spot, but using psc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * keeps things consistent with the psc_xxxx functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) psc = (void *) PSC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) pr_debug("PSC detected at %p\n", psc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) psc_dma_die_die_die();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #ifdef DEBUG_PSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) psc_debug_dump();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Mask and clear all possible interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) for (i = 0x30 ; i < 0x70 ; i += 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) psc_write_byte(pIERbase + i, 0x0F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) psc_write_byte(pIFRbase + i, 0x0F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * PSC interrupt handler. It's a lot like the VIA interrupt handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void psc_irq(struct irq_desc *desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) unsigned int irq = irq_desc_get_irq(desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) int pIFR = pIFRbase + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int pIER = pIERbase + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) int irq_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned char irq_bit, events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!events)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) irq_num = irq << 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) irq_bit = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (events & irq_bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) psc_write_byte(pIFR, irq_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) generic_handle_irq(irq_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) irq_num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) irq_bit <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) } while (events >= irq_bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) void __init psc_register_interrupts(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) irq_set_chained_handler_and_data(IRQ_AUTO_3, psc_irq, (void *)0x30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) irq_set_chained_handler_and_data(IRQ_AUTO_4, psc_irq, (void *)0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) irq_set_chained_handler_and_data(IRQ_AUTO_5, psc_irq, (void *)0x50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) irq_set_chained_handler_and_data(IRQ_AUTO_6, psc_irq, (void *)0x60);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) void psc_irq_enable(int irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int irq_src = IRQ_SRC(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) int irq_idx = IRQ_IDX(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int pIER = pIERbase + (irq_src << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) psc_write_byte(pIER, (1 << irq_idx) | 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) void psc_irq_disable(int irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int irq_src = IRQ_SRC(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int irq_idx = IRQ_IDX(irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int pIER = pIERbase + (irq_src << 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) psc_write_byte(pIER, 1 << irq_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }