dmac_sam3.c
Go to the documentation of this file.
00001
00037 #include "dmac_sam3.h"
00038 #include <drv/irq_cm3.h>
00039
00040 #include <cpu/irq.h>
00041 #include <cpu/power.h>
00042
00043 #include <io/cm3.h>
00044
00045 #include <mware/event.h>
00046
00047 #include <string.h>
00048
00049 struct DmacCh
00050 {
00051     reg32_t *src;
00052     reg32_t *dst;
00053     reg32_t *desc;
00054     reg32_t *cfg;
00055     reg32_t *ctrla;
00056     reg32_t *ctrlb;
00057 };
00058
00059 #define DMAC_CHANNEL_CNT   6
00060 struct DmacCh dmac_ch[] =
00061 {
00062     {
00063         .src = &DMAC_SADDR0,
00064         .dst = &DMAC_DADDR0,
00065         .desc = &DMAC_DSCR0,
00066         .cfg = &DMAC_CFG0,
00067         .ctrla = &DMAC_CTRLA0,
00068         .ctrlb = &DMAC_CTRLB0,
00069     },
00070     {
00071         .src = &DMAC_SADDR1,
00072         .dst = &DMAC_DADDR1,
00073         .desc = &DMAC_DSCR1,
00074         .cfg = &DMAC_CFG1,
00075         .ctrla = &DMAC_CTRLA1,
00076         .ctrlb = &DMAC_CTRLB1,
00077     },
00078     {
00079         .src = &DMAC_SADDR2,
00080         .dst = &DMAC_DADDR2,
00081         .desc = &DMAC_DSCR2,
00082         .cfg = &DMAC_CFG2,
00083         .ctrla = &DMAC_CTRLA2,
00084         .ctrlb = &DMAC_CTRLB2,
00085     },
00086     {
00087         .src = &DMAC_SADDR3,
00088         .dst = &DMAC_DADDR3,
00089         .desc = &DMAC_DSCR3,
00090         .cfg = &DMAC_CFG3,
00091         .ctrla = &DMAC_CTRLA3,
00092         .ctrlb = &DMAC_CTRLB3,
00093     },
00094     {
00095         .src = &DMAC_SADDR4,
00096         .dst = &DMAC_DADDR4,
00097         .desc = &DMAC_DSCR4,
00098         .cfg = &DMAC_CFG4,
00099         .ctrla = &DMAC_CTRLA4,
00100         .ctrlb = &DMAC_CTRLB4,
00101     },
00102     {
00103         .src = &DMAC_SADDR5,
00104         .dst = &DMAC_DADDR5,
00105         .desc = &DMAC_DSCR5,
00106         .cfg = &DMAC_CFG5,
00107         .ctrla = &DMAC_CTRLA5,
00108         .ctrlb = &DMAC_CTRLB5,
00109     },
00110 };
00111
00112 /* We use event to signal the end of conversion */
00113 static Dmac dmac[DMAC_CHANNEL_CNT];
00114 static uint8_t dmac_ch_enabled;
00115
00116 void dmac_setLLITransfer(int ch, DmacDesc *lli, uint32_t cfg)
00117 {
00118     DMAC_CHDR = BV(ch);
00119     reg32_t reg = DMAC_EBCISR;
00120     (void)reg;
00121
00122     *dmac_ch[ch].cfg = cfg | DMAC_CFG_FIFOCFG_ALAP_CFG | (0x1 << DMAC_CFG_AHB_PROT_SHIFT);
00123     *dmac_ch[ch].desc = (uint32_t)lli;
00124 }
00125
00126 void dmac_setSources(int ch, uint32_t src, uint32_t dst)
00127 {
00128     DMAC_CHDR = BV(ch);
00129
00130     *dmac_ch[ch].src = src;
00131     *dmac_ch[ch].dst = dst;
00132     *dmac_ch[ch].desc = 0;
00133 }
00134
00135 void dmac_configureDmac(int ch, size_t transfer_size, uint32_t cfg, uint32_t ctrla, uint32_t ctrlb)
00136 {
00137     DMAC_CHDR = BV(ch);
00138
00139     *dmac_ch[ch].cfg = cfg | DMAC_CFG_FIFOCFG_ALAP_CFG | (0x1 << DMAC_CFG_AHB_PROT_SHIFT);
00140     *dmac_ch[ch].ctrla = ctrla | (transfer_size & DMAC_CTRLA_BTSIZE_MASK);
00141     *dmac_ch[ch].ctrlb = ctrlb & ~BV(DMAC_CTRLB_IEN);
00142 }
00143
00144 int dmac_start(int ch)
00145 {
00146     if (DMAC_CHSR & BV(ch))
00147     {
00148         dmac[ch].errors |= DMAC_ERR_CH_ALREDY_ON;
00149         return -1;
00150     }
00151     DMAC_CHER = BV(ch);
00152     dmac_ch_enabled |= BV(ch);
00153     return 0;
00154 }
00155
00156 void dmac_stop(int ch)
00157 {
00158     DMAC_CHDR = BV(ch);
00159     dmac_ch_enabled &= ~BV(ch);
00160 }
00161
00162 int dmac_error(int ch)
00163 {
00164     uint32_t err = ((DMAC_EBCISR & 0x3F0000) | dmac[ch].errors);
00165     dmac[ch].errors = 0;
00166     return err;
00167 }
00168
00169 static DECLARE_ISR(dmac_irq)
00170 {
00171     uint32_t status = DMAC_EBCISR;
00172     uint32_t irq_ch = (status & (((dmac_ch_enabled |
00173                                 (dmac_ch_enabled << DMAC_EBCIDR_ERR0) >> DMAC_EBCIDR_ERR0) |
00174                                 (dmac_ch_enabled << DMAC_EBCIDR_CBTC0) >> DMAC_EBCIDR_CBTC0) & 0xFF));
00175     if (irq_ch)
00176         for(int i = 0; i < 6; i++)
00177         {
00178             if (BV(i) & irq_ch)
00179                 if(dmac[i].handler)
00180                     dmac[i].handler(status);
00181         }
00182 }
00183
00184 bool dmac_enableCh(int ch, dmac_handler_t handler)
00185 {
00186     ASSERT(ch <= DMAC_CHANNEL_CNT);
00187
00188     dmac_ch_enabled |= BV(ch);
00189     if (handler)
00190     {
00191         dmac[ch].handler = handler;
00192         DMAC_EBCIER |= (BV(ch) << DMAC_EBCIER_BTC0) | (BV(ch) << DMAC_EBCIDR_CBTC0) | (BV(ch) << DMAC_EBCIDR_ERR0);
00193         kprintf("Init dmac ch[%08lx]\n", DMAC_EBCIMR);
00194     }
00195
00196     return true;
00197 }
00198
00199 void dmac_init(void)
00200 {
00201     dmac_ch_enabled = 0;
00202     memset(&dmac, 0, sizeof(dmac));
00203
00204     //init DMAC
00205     DMAC_EBCIDR = 0x3FFFFF;
00206     DMAC_CHDR = 0x1F;
00207
00208     pmc_periphEnable(DMAC_ID);
00209     DMAC_EN = BV(DMAC_EN_ENABLE);
00210
00211     sysirq_setHandler(INT_DMAC, dmac_irq);
00212 }