source: mainline/uspace/drv/audio/sb16/dma_controller.c@ 25f8e5d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 25f8e5d was b4857bc, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

b16: DMA controller fixes and increased debug verbosity.

Fix of by one size representation.
Size of 16bit channels is reported in 16 bit words not bytes.
Lower two bytes of address need to shifted by one for 16 bit transfers.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup drvaudiosb16
29 * @{
30 */
31/** @file
32 * @brief DMA memory management
33 */
34#include <assert.h>
35#include <errno.h>
36#include <ddi.h>
37#include <libarch/ddi.h>
38
39#include "ddf_log.h"
40#include "dma_controller.h"
41
42#define DMA_CONTROLLER_FIRST_BASE ((void*)0x0)
43typedef struct dma_controller_regs_first {
44 uint8_t channel_start0;
45 uint8_t channel_count0;
46 uint8_t channel_start1;
47 uint8_t channel_count1;
48 uint8_t channel_start2;
49 uint8_t channel_count2;
50 uint8_t channel_start3;
51 uint8_t channel_count3;
52
53 uint8_t command_status;
54#define DMA_STATUS_REQ(x) (1 << ((x % 4) + 4))
55#define DMA_STATUS_COMPLETE(x) (1 << (x % 4))
56/* http://wiki.osdev.org/DMA: The only bit that works is COND(bit 2) */
57#define DMA_COMMAND_COND (1 << 2) /* Disables DMA controller */
58
59 uint8_t request; /* Memory to memory transfers, NOT implemented on PCs*/
60 uint8_t single_mask;
61#define DMA_SINGLE_MASK_CHAN_SEL_MASK (0x3)
62#define DMA_SINGLE_MASK_CHAN_SEL_SHIFT (0)
63#define DMA_SINGLE_MASK_CHAN_TO_REG(x) \
64 (((x % 4) & DMA_SINGLE_MASK_CHAN_SEL_MASK) << DMA_SINGLE_MASK_CHAN_SEL_SHIFT)
65#define DMA_SINGLE_MASK_MASKED_FLAG (1 << 2)
66
67 uint8_t mode;
68#define DMA_MODE_CHAN_SELECT_MASK (0x3)
69#define DMA_MODE_CHAN_SELECT_SHIFT (0)
70#define DMA_MODE_CHAN_TO_REG(x) \
71 (((x % 4) & DMA_MODE_CHAN_SELECT_MASK) << DMA_MODE_CHAN_SELECT_SHIFT)
72#define DMA_MODE_CHAN_TRA_MASK (0x3)
73#define DMA_MODE_CHAN_TRA_SHIFT (2)
74#define DMA_MODE_CHAN_TRA_SELF_TEST (0)
75#define DMA_MODE_CHAN_TRA_WRITE (0x1)
76#define DMA_MODE_CHAN_TRA_READ (0x2)
77#define DMA_MODE_CHAN_AUTO_FLAG (1 << 4)
78#define DMA_MODE_CHAN_DOWN_FLAG (1 << 5)
79#define DMA_MODE_CHAN_MODE_MASK (0x3)
80#define DMA_MODE_CHAN_MODE_SHIFT (6)
81#define DMA_MODE_CHAN_MODE_DEMAND (0)
82#define DMA_MODE_CHAN_MODE_SINGLE (1)
83#define DMA_MODE_CHAN_MODE_BLOCK (2)
84#define DMA_MODE_CHAN_MODE_CASCADE (3)
85
86 uint8_t flip_flop;
87 uint8_t master_reset; /* Intermediate is not implemented on PCs */
88 uint8_t mask_reset;
89/* Master reset sets Flip-Flop low, clears status,sets all mask bits on */
90
91 uint8_t multi_mask;
92#define DMA_MULTI_MASK_CHAN(x) (1 << (x % 4))
93
94} dma_controller_regs_first_t;
95
96#define DMA_CONTROLLER_SECOND_BASE ((void*)0xc0)
97/* See dma_controller_regs_first_t for register values */
98typedef struct dma_controller_regs_second {
99 uint8_t channel_start4;
100 uint8_t reserved0;
101 uint8_t channel_count4;
102 uint8_t reserved1;
103 uint8_t channel_start5;
104 uint8_t reserved2;
105 uint8_t channel_count5;
106 uint8_t reserved3;
107 uint8_t channel_start6;
108 uint8_t reserved4;
109 uint8_t channel_count6;
110 uint8_t reserved5;
111 uint8_t channel_start7;
112 uint8_t reserved6;
113 uint8_t channel_count7;
114
115 uint8_t command_status;
116 uint8_t reserved8;
117 uint8_t request;
118 uint8_t reserved9;
119 uint8_t single_mask;
120 uint8_t reserveda;
121 uint8_t mode;
122 uint8_t reservedb;
123 uint8_t flip_flop;
124 uint8_t reservedc;
125 uint8_t master_reset_intermediate;
126 uint8_t reservedd;
127 uint8_t multi_mask;
128} dma_controller_regs_second_t;
129
130#define DMA_CONTROLLER_PAGE_BASE ((void*)0x81)
131typedef struct dma_page_regs {
132 uint8_t channel2;
133 uint8_t channel3;
134 uint8_t channel1;
135 uint8_t reserved0;
136 uint8_t reserved1;
137 uint8_t reserved2;
138 uint8_t channel0;
139 uint8_t reserved3;
140 uint8_t channel6;
141 uint8_t channel7;
142 uint8_t channel5;
143 uint8_t reserved4;
144 uint8_t reserved5;
145 uint8_t reserved6;
146 uint8_t channel4;
147} dma_page_regs_t;
148
149typedef struct dma_channel {
150 uint8_t *offset_reg_address;
151 uint8_t *size_reg_address;
152 uint8_t *page_reg_address;
153 uint8_t *single_mask_address;
154 uint8_t *mode_address;
155 uint8_t *flip_flop_address;
156} dma_channel_t;
157
158typedef struct dma_controller {
159 dma_channel_t channels[8];
160 dma_page_regs_t *page_table;
161 dma_controller_regs_first_t *first;
162 dma_controller_regs_second_t *second;
163 bool initialized;
164} dma_controller_t;
165
166
167/* http://zet.aluzina.org/index.php/8237_DMA_controller#DMA_Channel_Registers */
168static dma_controller_t controller_8237 = {
169 .channels = {
170 /* The first chip */
171 { (uint8_t*)0x00, (uint8_t*)0x01, (uint8_t*)0x87,
172 (uint8_t*)0x0a, (uint8_t*)0x0b, (uint8_t*)0x0c, },
173 { (uint8_t*)0x02, (uint8_t*)0x03, (uint8_t*)0x83,
174 (uint8_t*)0x0a, (uint8_t*)0x0b, (uint8_t*)0x0c, },
175 { (uint8_t*)0x04, (uint8_t*)0x05, (uint8_t*)0x81,
176 (uint8_t*)0x0a, (uint8_t*)0x0b, (uint8_t*)0x0c, },
177 { (uint8_t*)0x06, (uint8_t*)0x07, (uint8_t*)0x82,
178 (uint8_t*)0x0a, (uint8_t*)0x0b, (uint8_t*)0x0c, },
179
180 /* The second chip */
181 { (uint8_t*)0xc0, (uint8_t*)0xc2, (uint8_t*)0x8f,
182 (uint8_t*)0xd4, (uint8_t*)0xd6, (uint8_t*)0xd8, },
183 { (uint8_t*)0xc4, (uint8_t*)0xc6, (uint8_t*)0x8b,
184 (uint8_t*)0xd4, (uint8_t*)0xd6, (uint8_t*)0xd8, },
185 { (uint8_t*)0xc8, (uint8_t*)0xca, (uint8_t*)0x89,
186 (uint8_t*)0xd4, (uint8_t*)0xd6, (uint8_t*)0xd8, },
187 { (uint8_t*)0xcc, (uint8_t*)0xce, (uint8_t*)0x8a,
188 (uint8_t*)0xd4, (uint8_t*)0xd6, (uint8_t*)0xd8, }, },
189
190 .page_table = NULL,
191 .first = NULL,
192 .second = NULL,
193 .initialized = false,
194};
195
196static inline int dma_controller_init(dma_controller_t *controller)
197{
198 assert(controller);
199 int ret = pio_enable(DMA_CONTROLLER_PAGE_BASE, sizeof(dma_page_regs_t),
200 (void**)&controller->page_table);
201 if (ret != EOK)
202 return EIO;
203
204 ret = pio_enable(DMA_CONTROLLER_FIRST_BASE,
205 sizeof(dma_controller_regs_first_t),
206 (void**)&controller->first);
207 if (ret != EOK)
208 return EIO;
209
210 ret = pio_enable(DMA_CONTROLLER_SECOND_BASE,
211 sizeof(dma_controller_regs_second_t),
212 (void**)&controller->second);
213 if (ret != EOK)
214 return EIO;
215 controller->initialized = true;
216 return EOK;
217}
218/*----------------------------------------------------------------------------*/
219int dma_setup_channel(unsigned channel, uintptr_t pa, size_t size)
220{
221 if (channel == 0 || channel == 4)
222 return ENOTSUP;
223 if (channel > 7)
224 return ENOENT;
225
226 if (!controller_8237.initialized)
227 dma_controller_init(&controller_8237);
228
229 if (!controller_8237.initialized)
230 return EIO;
231
232 /* 16 bit transfers are a bit special */
233 ddf_log_debug("Unspoiled address and size: %p(%zu).\n", pa, size);
234 if (channel > 4) {
235 /* Size is the count of 16bit words */
236 assert(size % 2 == 0);
237 size /= 2;
238 /* Address is fun: lower 16bits need to be shifted by 1 */
239 pa = ((pa & 0xffff) >> 1) | (pa & 0xff0000);
240 }
241
242 const dma_channel_t dma_channel = controller_8237.channels[channel];
243
244 ddf_log_debug("Setting channel %u, to address %p(%zu).\n",
245 channel, pa, size);
246 /* Mask DMA request */
247 uint8_t value = DMA_SINGLE_MASK_CHAN_TO_REG(channel)
248 | DMA_SINGLE_MASK_MASKED_FLAG;
249 pio_write_8(dma_channel.single_mask_address, value);
250
251 /* Set address -- reset flip-flop*/
252 pio_write_8(dma_channel.flip_flop_address, 1);
253
254 /* Low byte */
255 value = pa & 0xff;
256 ddf_log_verbose("Writing address low byte: %hhx.\n", value);
257 pio_write_8(dma_channel.offset_reg_address, value);
258
259 /* High byte */
260 value = (pa >> 8) & 0xff;
261 ddf_log_verbose("Writing address high byte: %hhx.\n", value);
262 pio_write_8(dma_channel.offset_reg_address, value);
263
264 /* Page address - third byte */
265 value = (pa >> 16) & 0xff;
266 ddf_log_verbose("Writing address page byte: %hhx.\n", value);
267 pio_write_8(dma_channel.offset_reg_address, value);
268
269 /* Set size -- reset flip-flop */
270 pio_write_8(dma_channel.flip_flop_address, 1);
271
272 /* Low byte */
273 value = (size - 1) & 0xff;
274 ddf_log_verbose("Writing size low byte: %hhx.\n", value);
275 pio_write_8(dma_channel.offset_reg_address, value);
276
277 /* High byte */
278 value = ((size - 1) >> 8) & 0xff;
279 ddf_log_verbose("Writing size high byte: %hhx.\n", value);
280 pio_write_8(dma_channel.offset_reg_address, value);
281
282 /* Unmask DMA request */
283 value = DMA_SINGLE_MASK_CHAN_TO_REG(channel);
284 pio_write_8(dma_channel.single_mask_address, value);
285
286 return EOK;
287}
288/*----------------------------------------------------------------------------*/
289int dma_prepare_channel(
290 unsigned channel, bool write, bool auto_mode, transfer_mode_t mode)
291{
292 if (channel == 0 || channel == 4)
293 return ENOTSUP;
294 if (channel > 7)
295 return ENOENT;
296
297 if (!controller_8237.initialized)
298 return EIO;
299
300 dma_channel_t dma_channel = controller_8237.channels[channel];
301
302 /* Mask DMA request */
303 uint8_t value = DMA_SINGLE_MASK_CHAN_TO_REG(channel)
304 | DMA_SINGLE_MASK_MASKED_FLAG;
305 pio_write_8(dma_channel.single_mask_address, value);
306
307 /* Set DMA mode */
308 value = DMA_MODE_CHAN_TO_REG(channel)
309 | ((write ? DMA_MODE_CHAN_TRA_WRITE : DMA_MODE_CHAN_TRA_READ)
310 << DMA_MODE_CHAN_TRA_SHIFT)
311 | (auto_mode ? DMA_MODE_CHAN_AUTO_FLAG : 0)
312 | (mode << DMA_MODE_CHAN_MODE_SHIFT);
313 ddf_log_verbose("Setting mode: %hhx.\n", value);
314 pio_write_8(dma_channel.mode_address, value);
315
316 /* Unmask DMA request */
317 value = DMA_SINGLE_MASK_CHAN_TO_REG(channel);
318 pio_write_8(dma_channel.single_mask_address, value);
319
320 return EOK;
321}
322/**
323 * @}
324 */
Note: See TracBrowser for help on using the repository browser.