root/arch/unicore32/kernel/dma.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. puv3_request_dma
  2. puv3_free_dma
  3. dma_irq_handler
  4. dma_err_handler
  5. puv3_init_dma

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/arch/unicore32/kernel/dma.c
   4  *
   5  * Code specific to PKUnity SoC and UniCore ISA
   6  *
   7  *      Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
   8  *      Copyright (C) 2001-2010 Guan Xuetao
   9  */
  10 
  11 #include <linux/module.h>
  12 #include <linux/init.h>
  13 #include <linux/kernel.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/errno.h>
  16 #include <linux/io.h>
  17 
  18 #include <asm/irq.h>
  19 #include <mach/hardware.h>
  20 #include <mach/dma.h>
  21 
  22 struct dma_channel {
  23         char *name;
  24         puv3_dma_prio prio;
  25         void (*irq_handler)(int, void *);
  26         void (*err_handler)(int, void *);
  27         void *data;
  28 };
  29 
  30 static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
  31 
  32 int puv3_request_dma(char *name, puv3_dma_prio prio,
  33                          void (*irq_handler)(int, void *),
  34                          void (*err_handler)(int, void *),
  35                          void *data)
  36 {
  37         unsigned long flags;
  38         int i, found = 0;
  39 
  40         /* basic sanity checks */
  41         if (!name)
  42                 return -EINVAL;
  43 
  44         local_irq_save(flags);
  45 
  46         do {
  47                 /* try grabbing a DMA channel with the requested priority */
  48                 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
  49                         if ((dma_channels[i].prio == prio) &&
  50                             !dma_channels[i].name) {
  51                                 found = 1;
  52                                 break;
  53                         }
  54                 }
  55                 /* if requested prio group is full, try a hier priority */
  56         } while (!found && prio--);
  57 
  58         if (found) {
  59                 dma_channels[i].name = name;
  60                 dma_channels[i].irq_handler = irq_handler;
  61                 dma_channels[i].err_handler = err_handler;
  62                 dma_channels[i].data = data;
  63         } else {
  64                 printk(KERN_WARNING "No more available DMA channels for %s\n",
  65                                 name);
  66                 i = -ENODEV;
  67         }
  68 
  69         local_irq_restore(flags);
  70         return i;
  71 }
  72 EXPORT_SYMBOL(puv3_request_dma);
  73 
  74 void puv3_free_dma(int dma_ch)
  75 {
  76         unsigned long flags;
  77 
  78         if (!dma_channels[dma_ch].name) {
  79                 printk(KERN_CRIT
  80                         "%s: trying to free channel %d which is already freed\n",
  81                         __func__, dma_ch);
  82                 return;
  83         }
  84 
  85         local_irq_save(flags);
  86         dma_channels[dma_ch].name = NULL;
  87         dma_channels[dma_ch].err_handler = NULL;
  88         local_irq_restore(flags);
  89 }
  90 EXPORT_SYMBOL(puv3_free_dma);
  91 
  92 static irqreturn_t dma_irq_handler(int irq, void *dev_id)
  93 {
  94         int i, dint;
  95 
  96         dint = readl(DMAC_ITCSR);
  97         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
  98                 if (dint & DMAC_CHANNEL(i)) {
  99                         struct dma_channel *channel = &dma_channels[i];
 100 
 101                         /* Clear TC interrupt of channel i */
 102                         writel(DMAC_CHANNEL(i), DMAC_ITCCR);
 103                         writel(0, DMAC_ITCCR);
 104 
 105                         if (channel->name && channel->irq_handler) {
 106                                 channel->irq_handler(i, channel->data);
 107                         } else {
 108                                 /*
 109                                  * IRQ for an unregistered DMA channel:
 110                                  * let's clear the interrupts and disable it.
 111                                  */
 112                                 printk(KERN_WARNING "spurious IRQ for"
 113                                                 " DMA channel %d\n", i);
 114                         }
 115                 }
 116         }
 117         return IRQ_HANDLED;
 118 }
 119 
 120 static irqreturn_t dma_err_handler(int irq, void *dev_id)
 121 {
 122         int i, dint;
 123 
 124         dint = readl(DMAC_IESR);
 125         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 126                 if (dint & DMAC_CHANNEL(i)) {
 127                         struct dma_channel *channel = &dma_channels[i];
 128 
 129                         /* Clear Err interrupt of channel i */
 130                         writel(DMAC_CHANNEL(i), DMAC_IECR);
 131                         writel(0, DMAC_IECR);
 132 
 133                         if (channel->name && channel->err_handler) {
 134                                 channel->err_handler(i, channel->data);
 135                         } else {
 136                                 /*
 137                                  * IRQ for an unregistered DMA channel:
 138                                  * let's clear the interrupts and disable it.
 139                                  */
 140                                 printk(KERN_WARNING "spurious IRQ for"
 141                                                 " DMA channel %d\n", i);
 142                         }
 143                 }
 144         }
 145         return IRQ_HANDLED;
 146 }
 147 
 148 int __init puv3_init_dma(void)
 149 {
 150         int i, ret;
 151 
 152         /* dma channel priorities on v8 processors:
 153          * ch 0 - 1  <--> (0) DMA_PRIO_HIGH
 154          * ch 2 - 3  <--> (1) DMA_PRIO_MEDIUM
 155          * ch 4 - 5  <--> (2) DMA_PRIO_LOW
 156          */
 157         for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 158                 puv3_stop_dma(i);
 159                 dma_channels[i].name = NULL;
 160                 dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
 161         }
 162 
 163         ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
 164         if (ret) {
 165                 printk(KERN_CRIT "Can't register IRQ for DMA\n");
 166                 return ret;
 167         }
 168 
 169         ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
 170         if (ret) {
 171                 printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
 172                 free_irq(IRQ_DMA, "DMA");
 173                 return ret;
 174         }
 175 
 176         return 0;
 177 }
 178 
 179 postcore_initcall(puv3_init_dma);

/* [<][>][^][v][top][bottom][index][help] */