^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * linux/arch/m68k/amiga/cia.c - CIA support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1996 Roman Zippel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * The concept of some functions bases on the original Amiga OS function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * License. See the file COPYING in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel_stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/amigahw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/amigaints.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct ciabase {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) volatile struct CIA *cia;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned char icr_mask, icr_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned short int_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int handler_irq, cia_irq, server_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) } ciaa_base = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) .cia = &ciaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) .int_mask = IF_PORTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .handler_irq = IRQ_AMIGA_PORTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .cia_irq = IRQ_AMIGA_CIAA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .name = "CIAA"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }, ciab_base = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .cia = &ciab,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .int_mask = IF_EXTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .handler_irq = IRQ_AMIGA_EXTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .cia_irq = IRQ_AMIGA_CIAB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .name = "CIAB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Cause or clear CIA interrupts, return old interrupt status.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned char old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) old = (base->icr_data |= base->cia->icr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (mask & CIA_ICR_SETCLR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) base->icr_data |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) base->icr_data &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (base->icr_data & base->icr_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) amiga_custom.intreq = IF_SETCLR | base->int_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return old & base->icr_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * Enable or disable CIA interrupts, return old interrupt mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) unsigned char old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) old = base->icr_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) base->icr_data |= base->cia->icr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) base->cia->icr = mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (mask & CIA_ICR_SETCLR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) base->icr_mask |= mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) base->icr_mask &= ~mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) base->icr_mask &= CIA_ICR_ALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (base->icr_data & base->icr_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) amiga_custom.intreq = IF_SETCLR | base->int_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static irqreturn_t cia_handler(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct ciabase *base = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int mach_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) unsigned char ints;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Interrupts get disabled while the timer irq flag is cleared and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * the timer interrupt serviced.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) mach_irq = base->cia_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ints = cia_set_irq(base, CIA_ICR_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) amiga_custom.intreq = base->int_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (ints & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) generic_handle_irq(mach_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) mach_irq++, ints >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) for (; ints; mach_irq++, ints >>= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (ints & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) generic_handle_irq(mach_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return IRQ_HANDLED;
^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) static void cia_irq_enable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned char mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (irq >= IRQ_AMIGA_CIAB) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) mask = 1 << (irq - IRQ_AMIGA_CIAB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) cia_set_irq(&ciab_base, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) mask = 1 << (irq - IRQ_AMIGA_CIAA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) cia_set_irq(&ciaa_base, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static void cia_irq_disable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned int irq = data->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (irq >= IRQ_AMIGA_CIAB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static struct irq_chip cia_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .name = "cia",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .irq_enable = cia_irq_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .irq_disable = cia_irq_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) };
^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) * Override auto irq 2 & 6 and use them as general chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * for external interrupts, we link the CIA interrupt sources
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * into this chain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static void auto_irq_enable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) switch (data->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) case IRQ_AUTO_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) amiga_custom.intena = IF_SETCLR | IF_PORTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case IRQ_AUTO_6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) amiga_custom.intena = IF_SETCLR | IF_EXTER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static void auto_irq_disable(struct irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) switch (data->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) case IRQ_AUTO_2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) amiga_custom.intena = IF_PORTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case IRQ_AUTO_6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) amiga_custom.intena = IF_EXTER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static struct irq_chip auto_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .name = "auto",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .irq_enable = auto_irq_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .irq_disable = auto_irq_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) void __init cia_init_IRQ(struct ciabase *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) m68k_setup_irq_controller(&cia_irq_chip, handle_simple_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) base->cia_irq, CIA_IRQS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* clear any pending interrupt and turn off all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) cia_set_irq(base, CIA_ICR_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) cia_able_irq(base, CIA_ICR_ALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* override auto int and install CIA handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) m68k_setup_irq_controller(&auto_irq_chip, handle_simple_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) base->handler_irq, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) m68k_irq_startup_irq(base->handler_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (request_irq(base->handler_irq, cia_handler, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) base->name, base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) pr_err("Couldn't register %s interrupt\n", base->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }