dma.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:3k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * arch/sh/kernel/dma.c
  3.  *
  4.  * Copyright (C) 2000 Takashi YOSHII
  5.  *
  6.  * PC like DMA API for SuperH's DMAC.
  7.  */
  8. #include <linux/config.h>
  9. #include <linux/init.h>
  10. #include <linux/irq.h>
  11. #include <linux/interrupt.h>
  12. #include <asm/signal.h>
  13. #include <asm/dma.h>
  14. static struct dma_info_t *dma_info[MAX_DMA_CHANNELS];
  15. static struct dma_info_t *autoinit_info[SH_MAX_DMA_CHANNELS] = {0};
  16. static spinlock_t  dma_spin_lock;
  17. static unsigned int calc_chcr(struct dma_info_t *info)
  18. {
  19. unsigned int chcr;
  20. chcr = ( info->mode & DMA_MODE_WRITE )? info->mode_write : info->mode_read;
  21. if( info->mode & DMA_AUTOINIT )
  22. chcr |= CHCR_IE;
  23. return chcr;
  24. }
  25. static __inline__ int ts_shift(unsigned long chcr)
  26. {
  27. return ((int[]){3,0,1,2,5,0,0,0})[(chcr>>4)&0x000007];
  28. }
  29. static void dma_tei(int irq, void *dev_id, struct pt_regs *regs)
  30. {
  31. int chan = irq - DMTE_IRQ[0];
  32. struct dma_info_t *info = autoinit_info[chan];
  33. if( info->mode & DMA_MODE_WRITE )
  34. ctrl_outl(info->mem_addr, SAR[info->chan]);
  35. else
  36. ctrl_outl(info->mem_addr, DAR[info->chan]);
  37. ctrl_outl(info->count>>ts_shift(calc_chcr(info)), DMATCR[info->chan]);
  38. ctrl_outl(ctrl_inl(CHCR[info->chan])&~CHCR_TE, CHCR[info->chan]);
  39. }
  40. static struct irqaction irq_tei = { dma_tei, SA_INTERRUPT, 0, "dma_tei", NULL, NULL};
  41. void setup_dma(unsigned int dmanr, struct dma_info_t *info)
  42. {
  43. make_ipr_irq(DMTE_IRQ[info->chan], DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
  44. setup_irq(DMTE_IRQ[info->chan], &irq_tei);
  45. dma_info[dmanr] = info;
  46. }
  47. unsigned long claim_dma_lock(void)
  48. {
  49. unsigned long flags;
  50. spin_lock_irqsave(&dma_spin_lock, flags);
  51. return flags;
  52. }
  53. void release_dma_lock(unsigned long flags)
  54. {
  55. spin_unlock_irqrestore(&dma_spin_lock, flags);
  56. }
  57. void enable_dma(unsigned int dmanr)
  58. {
  59. struct dma_info_t *info = dma_info[dmanr];
  60. ctrl_outl(calc_chcr(info)|CHCR_DE, CHCR[info->chan]);
  61. }
  62. void disable_dma(unsigned int dmanr)
  63. {
  64. struct dma_info_t *info = dma_info[dmanr];
  65. ctrl_outl(calc_chcr(info)&~CHCR_DE, CHCR[info->chan]);
  66. }
  67. void set_dma_mode(unsigned int dmanr, char mode)
  68. {
  69. struct dma_info_t *info = dma_info[dmanr];
  70. info->mode = mode;
  71. set_dma_addr(dmanr, info->mem_addr);
  72. set_dma_count(dmanr, info->count);
  73. autoinit_info[info->chan] = info;
  74. }
  75. void set_dma_addr(unsigned int dmanr, unsigned int a)
  76. {
  77. struct dma_info_t *info = dma_info[dmanr];
  78. unsigned long sar, dar;
  79. info->mem_addr = a;
  80. sar = (info->mode & DMA_MODE_WRITE)? info->mem_addr: info->dev_addr;
  81. dar = (info->mode & DMA_MODE_WRITE)? info->dev_addr: info->mem_addr;
  82. ctrl_outl(sar, SAR[info->chan]);
  83. ctrl_outl(dar, DAR[info->chan]);
  84. }
  85. void set_dma_count(unsigned int dmanr, unsigned int count)
  86. {
  87. struct dma_info_t *info = dma_info[dmanr];
  88. info->count = count;
  89. ctrl_outl(count>>ts_shift(calc_chcr(info)), DMATCR[info->chan]);
  90. }
  91. int get_dma_residue(unsigned int dmanr)
  92. {
  93. struct dma_info_t *info = dma_info[dmanr];
  94. return ctrl_inl(DMATCR[info->chan])<<ts_shift(calc_chcr(info));
  95. }
  96. #if defined(__SH4__)
  97. static void dma_err(int irq, void *dev_id, struct pt_regs *regs)
  98. {
  99. printk(KERN_WARNING "DMAE: DMAOR=%lxn",ctrl_inl(DMAOR));
  100. ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_NMIF, DMAOR);
  101. ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_AE, DMAOR);
  102. ctrl_outl(ctrl_inl(DMAOR)|DMAOR_DME, DMAOR);
  103. }
  104. static struct irqaction irq_err = { dma_err, SA_INTERRUPT, 0, "dma_err", NULL, NULL};
  105. #endif
  106. int __init init_dma(void)
  107. {
  108. #if defined(__SH4__)
  109. make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
  110. setup_irq(DMAE_IRQ, &irq_err);
  111. #endif
  112. ctrl_outl(DMAOR_DME, DMAOR);
  113. return 0;
  114. }
  115. module_init(init_dma);
  116. /**/