Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * SH7760 DMABRG IRQ handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <asm/dma.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <asm/dmabrg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  * The DMABRG is a special DMA unit within the SH7760. It does transfers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  * from USB-SRAM/Audio units to main memory (and also the LCDC; but that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * part is sensibly placed  in the LCDC  registers and requires no irqs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * It has 3 IRQ lines which trigger 10 events, and works independently
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * from the traditional SH DMAC (although it blocks usage of DMAC 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * BRGIRQID   | component | dir | meaning      | source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * -----------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  *     0      | USB-DMA   | ... | xfer done    | DMABRGI1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *     1      | USB-UAE   | ... | USB addr err.| DMABRGI0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  *     2      | HAC0/SSI0 | play| all done     | DMABRGI1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  *     3      | HAC0/SSI0 | play| half done    | DMABRGI2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *     4      | HAC0/SSI0 | rec | all done     | DMABRGI1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  *     5      | HAC0/SSI0 | rec | half done    | DMABRGI2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  *     6      | HAC1/SSI1 | play| all done     | DMABRGI1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  *     7      | HAC1/SSI1 | play| half done    | DMABRGI2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  *     8      | HAC1/SSI1 | rec | all done     | DMABRGI1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  *     9      | HAC1/SSI1 | rec | half done    | DMABRGI2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  * all can be enabled/disabled in the DMABRGCR register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  * as well as checked if they occurred.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  * DMABRGI0 services  USB  DMA  Address  errors,  but it still must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * enabled/acked in the DMABRGCR register.  USB-DMA complete indicator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * is grouped together with the audio buffer end indicators, too bad...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * DMABRGCR:	Bits 31-24: audio-dma ENABLE flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  *		Bits 23-16: audio-dma STATUS flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  *		Bits  9-8:  USB error/xfer ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  *		Bits  1-0:  USB error/xfer STATUS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  *	Ack an IRQ by writing 0 to the STATUS flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  *	Mask IRQ by writing 0 to ENABLE flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  * Usage is almost like with any other IRQ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50)  *  dmabrg_request_irq(BRGIRQID, handler, data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)  *  dmabrg_free_irq(BRGIRQID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)  * handler prototype:  void brgirqhandler(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #define DMARSRA		0xfe090000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) #define DMAOR		0xffa00040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) #define DMACHCR0	0xffa0000c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #define DMABRGCR	0xfe3c0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #define DMAOR_BRG	0x0000c000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #define DMAOR_DMEN	0x00000001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) #define DMABRGI0	68
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) #define DMABRGI1	69
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) #define DMABRGI2	70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) struct dmabrg_handler {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	void (*handler)(void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) } *dmabrg_handlers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) static inline void dmabrg_call_handler(int i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	dmabrg_handlers[i].handler(dmabrg_handlers[i].data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79)  * main DMABRG irq handler. It acks irqs and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80)  * handles every set and unmasked bit sequentially.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81)  * No locking and no validity checks; it should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82)  * as fast as possible (audio!)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) static irqreturn_t dmabrg_irq(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	unsigned long dcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	dcr = __raw_readl(DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	__raw_writel(dcr & ~0x00ff0003, DMABRGCR);	/* ack all */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	dcr &= dcr >> 8;	/* ignore masked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	/* USB stuff, get it out of the way first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	if (dcr & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		dmabrg_call_handler(DMABRGIRQ_USBDMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	if (dcr & 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		dmabrg_call_handler(DMABRGIRQ_USBDMAERR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	/* Audio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	dcr >>= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	while (dcr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		i = __ffs(dcr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		dcr &= dcr - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		dmabrg_call_handler(i + DMABRGIRQ_A0TXF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static void dmabrg_disable_irq(unsigned int dmairq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	unsigned long dcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	dcr = __raw_readl(DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	__raw_writel(dcr, DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static void dmabrg_enable_irq(unsigned int dmairq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	unsigned long dcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	dcr = __raw_readl(DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	__raw_writel(dcr, DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		       void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	if ((dmairq > 9) || !handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	if (dmabrg_handlers[dmairq].handler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	dmabrg_handlers[dmairq].handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	dmabrg_handlers[dmairq].data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	dmabrg_enable_irq(dmairq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) EXPORT_SYMBOL_GPL(dmabrg_request_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) void dmabrg_free_irq(unsigned int dmairq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	if (likely(dmairq < 10)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		dmabrg_disable_irq(dmairq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		dmabrg_handlers[dmairq].handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		dmabrg_handlers[dmairq].data = NULL;
^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) EXPORT_SYMBOL_GPL(dmabrg_free_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int __init dmabrg_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	unsigned long or;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	dmabrg_handlers = kcalloc(10, sizeof(struct dmabrg_handler),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 				  GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	if (!dmabrg_handlers)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #ifdef CONFIG_SH_DMA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	/* request DMAC channel 0 before anyone else can get it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	ret = request_dma(0, "DMAC 0 (DMABRG)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	__raw_writel(0, DMABRGCR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	__raw_writel(0, DMACHCR0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	__raw_writel(0x94000000, DMARSRA);	/* enable DMABRG in DMAC 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	/* enable DMABRG mode, enable the DMAC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	or = __raw_readl(DMAOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	__raw_writel(or | DMAOR_BRG | DMAOR_DMEN, DMAOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	ret = request_irq(DMABRGI0, dmabrg_irq, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			"DMABRG USB address error", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		goto out0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	ret = request_irq(DMABRGI1, dmabrg_irq, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			"DMABRG Transfer End", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		goto out1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	ret = request_irq(DMABRGI2, dmabrg_irq, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 			"DMABRG Transfer Half", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	free_irq(DMABRGI1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) out1:	free_irq(DMABRGI0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) out0:	kfree(dmabrg_handlers);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) subsys_initcall(dmabrg_init);