~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sh/drivers/dma/dmabrg.c

Version: ~ [ linux-5.2-rc5 ] ~ [ linux-5.1.12 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.53 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.128 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.182 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.182 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.68 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp