1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  */
8 #ifndef _DMA_H
9 #define _DMA_H
10 
11 
12 #define MAX_DMA_CHANNELS    8
13 
14 /* 8237 DMA controllers */
15 #define IO_DMA1_BASE            0x00        /* 8 bit slave DMA, channels 0..3 */
16 #define IO_DMA2_BASE            0xC0        /* 16 bit master DMA, ch 4(=slave input)..7 */
17 
18 /* DMA controller registers */
19 #define DMA1_CMD_REG            0x08        /* command register (w) */
20 #define DMA1_STAT_REG           0x08        /* status register (r) */
21 #define DMA1_REQ_REG            0x09        /* request register (w) */
22 #define DMA1_MASK_REG           0x0A        /* single-channel mask (w) */
23 #define DMA1_MODE_REG           0x0B        /* mode register (w) */
24 #define DMA1_CLEAR_FF_REG       0x0C        /* clear pointer flip-flop (w) */
25 #define DMA1_TEMP_REG           0x0D        /* Temporary Register (r) */
26 #define DMA1_RESET_REG          0x0D        /* Master Clear (w) */
27 #define DMA1_CLR_MASK_REG       0x0E        /* Clear Mask */
28 #define DMA1_MASK_ALL_REG       0x0F        /* all-channels mask (w) */
29 
30 #define DMA2_CMD_REG            0xD0        /* command register (w) */
31 #define DMA2_STAT_REG           0xD0        /* status register (r) */
32 #define DMA2_REQ_REG            0xD2        /* request register (w) */
33 #define DMA2_MASK_REG           0xD4        /* single-channel mask (w) */
34 #define DMA2_MODE_REG           0xD6        /* mode register (w) */
35 #define DMA2_CLEAR_FF_REG       0xD8        /* clear pointer flip-flop (w) */
36 #define DMA2_TEMP_REG           0xDA        /* Temporary Register (r) */
37 #define DMA2_RESET_REG          0xDA        /* Master Clear (w) */
38 #define DMA2_CLR_MASK_REG       0xDC        /* Clear Mask */
39 #define DMA2_MASK_ALL_REG       0xDE        /* all-channels mask (w) */
40 
41 #define DMA_ADDR_0              0x00        /* DMA address registers */
42 #define DMA_ADDR_1              0x02
43 #define DMA_ADDR_2              0x04
44 #define DMA_ADDR_3              0x06
45 #define DMA_ADDR_4              0xC0
46 #define DMA_ADDR_5              0xC4
47 #define DMA_ADDR_6              0xC8
48 #define DMA_ADDR_7              0xCC
49 
50 #define DMA_CNT_0               0x01        /* DMA count registers */
51 #define DMA_CNT_1               0x03
52 #define DMA_CNT_2               0x05
53 #define DMA_CNT_3               0x07
54 #define DMA_CNT_4               0xC2
55 #define DMA_CNT_5               0xC6
56 #define DMA_CNT_6               0xCA
57 #define DMA_CNT_7               0xCE
58 
59 #define DMA_PAGE_0              0x87        /* DMA page registers */
60 #define DMA_PAGE_1              0x83
61 #define DMA_PAGE_2              0x81
62 #define DMA_PAGE_3              0x82
63 #define DMA_PAGE_5              0x8B
64 #define DMA_PAGE_6              0x89
65 #define DMA_PAGE_7              0x8A
66 
67 #define DMA_MODE_READ           0x44        /* I/O to memory, no autoinit, increment, single mode */
68 #define DMA_MODE_WRITE          0x48        /* memory to I/O, no autoinit, increment, single mode */
69 #define DMA_MODE_CASCADE        0xC0        /* pass thru DREQ->HRQ, DACK<-HLDA only */
70 
71 /*
72  * 启用指定的DMA通道
73  */
EnableDma(unsigned int dmanr)74 static __inline__ void EnableDma(unsigned int dmanr)
75 {
76     if (dmanr<=3)
77         OUTB(dmanr,  DMA1_MASK_REG);
78     else
79         OUTB(dmanr & 3,  DMA2_MASK_REG);
80 }
81 
82 /*
83  * 禁用指定的DMA通道
84  */
DisableDma(unsigned int dmanr)85 static __inline__ void DisableDma(unsigned int dmanr)
86 {
87     if (dmanr<=3)
88         OUTB(dmanr | 4,  DMA1_MASK_REG);
89     else
90         OUTB((dmanr & 3) | 4,  DMA2_MASK_REG);
91 }
92 
93 /*
94  * 清空DMA 晶体计数器
95  */
ClearDmaFF(unsigned int dmanr)96 static __inline__ void ClearDmaFF(unsigned int dmanr)
97 {
98     if (dmanr<=3)
99         OUTB(0,  DMA1_CLEAR_FF_REG);
100     else
101         OUTB(0,  DMA2_CLEAR_FF_REG);
102 }
103 
104 /*
105  * 清空DMA 晶体计数器
106  */
SetDmaMode(unsigned int dmanr,char mode)107 static __inline__ void SetDmaMode(unsigned int dmanr, char mode)
108 {
109     if (dmanr<=3)
110         OUTB(mode | dmanr,  DMA1_MODE_REG);
111     else
112         OUTB(mode | (dmanr&3),  DMA2_MODE_REG);
113 }
114 
115 /*
116  *  设定DMA 页面寄存器
117  */
SetDmaPage(unsigned int dmanr,char pagenr)118 static __inline__ void SetDmaPage(unsigned int dmanr, char pagenr)
119 {
120     switch(dmanr) {
121         case 0:
122             OUTB(pagenr, DMA_PAGE_0);
123             break;
124         case 1:
125             OUTB(pagenr, DMA_PAGE_1);
126             break;
127         case 2:
128             OUTB(pagenr, DMA_PAGE_2);
129             break;
130         case 3:
131             OUTB(pagenr, DMA_PAGE_3);
132             break;
133         case 5:
134             OUTB(pagenr & 0xfe, DMA_PAGE_5);
135             break;
136         case 6:
137             OUTB(pagenr & 0xfe, DMA_PAGE_6);
138             break;
139         case 7:
140             OUTB(pagenr & 0xfe, DMA_PAGE_7);
141             break;
142     }
143 }
144 
145 
146 /*
147  * 设定DMA 传输高速缓冲区地址
148  */
SetDmaAddr(unsigned int dmanr,unsigned int a)149 static __inline__ void SetDmaAddr(unsigned int dmanr, unsigned int a)
150 {
151     SetDmaPage(dmanr, a>>16);
152     if (dmanr <= 3)  {
153         OUTB( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
154             OUTB( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
155     }  else  {
156         OUTB( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
157         OUTB( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
158     }
159 }
160 
161 
162 /*
163  * 设定DMA 传输块数
164  */
SetDmaCount(unsigned int dmanr,unsigned int count)165 static __inline__ void SetDmaCount(unsigned int dmanr, unsigned int count)
166 {
167         count--;
168     if (dmanr <= 3)  {
169         OUTB( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
170         OUTB( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
171         } else {
172         OUTB( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
173         OUTB( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
174         }
175 }
176 
177 
178 /*
179  *  获得DMA 传输剩余块数
180  */
GetDmaResidue(unsigned int dmanr)181 static __inline__ int GetDmaResidue(unsigned int dmanr)
182 {
183     unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
184                      : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
185 
186     /* using short to get 16-bit wrap around */
187     unsigned short count;
188     count = 1 + inb(io_port);
189     count += inb(io_port) << 8;
190     return (dmanr<=3)? count : (count<<1);
191 }
192 
193 #endif
194 
195