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