Linux Audio

Check our new training course

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