Date:2013-01-14 07:55:51 (11 years 2 months ago)
Author:Werner Almesberger
Commit:09bf9c23ab8938b31af7bdff7390a7f28e19d53d
Message:ubb-patgen/: add DMA-based pattern transfer (WIP)

Works for some patterns but seems to have issues at the edge of
transfers. Clock selection also needs more work.
Files: ubb-patgen/ubb-patgen.c (8 diffs)

Change Details

ubb-patgen/ubb-patgen.c
1414#include <stdlib.h>
1515#include <stdio.h>
1616#include <unistd.h>
17#include <string.h>
1718#include <math.h>
1819#include <time.h>
20#include <assert.h>
1921
2022#include <ubb/ubb.h>
23#include <ubb/regs4740.h>
2124#include <ubb/mmcclk.h>
25#include <ubb/physmem.h>
26
27
28#define DMA 5
2229
2330
2431/* ----- List available bus clock frequencies ------------------------------ */
...... 
122129}
123130
124131
132/* ----- DMA the pattern --------------------------------------------------- */
133
134
135static uint32_t old_dmac;
136
137
138static void dma_stop(void)
139{
140    DCS(DMA) = (1 << 3) | (1 << 2); /* halt DMA channel */
141    DCS(DMA) = 0; /* reset DMA channel */
142}
143
144
145static void dma_init(void)
146{
147    old_dmac = DMAC;
148
149    DMAC = 1; /* activate the DMA controller (in case it's off) */
150    dma_stop();
151
152    DCM(DMA) =
153        (1 << 23) | /* source address increment */
154        (4 << 8); /* transfer size is 32 bytes */
155    DRT(DMA) = 26; /* MSC transmit-fifo-empty transfer request */
156}
157
158
159static void dma_cleanup(void)
160{
161    DMAC = old_dmac;
162    dma_stop();
163}
164
165
166static void dma_setup(unsigned long buf, int nibbles)
167{
168    assert(!(nibbles & 63));
169
170    DCS(DMA) = 1 << 31; /* no-descriptor transfer */
171    DSA(DMA) = buf; /* source */
172    DTA(DMA) = REG_PADDR(MSC_TXFIFO); /* MUST set this each time */
173    DTC(DMA) = nibbles >> 6; /* 32 bytes per transfer */
174}
175
176
177static void mmc_buffer(const struct mmcclk *clk,
178    unsigned long buf, int nibbles)
179{
180    MSC_STRPCL = 1 << 3; /* reset the MSC */
181
182    while (MSC_STAT & (1 << 15)); /* wait until reset finishes */
183
184    dma_setup(buf, nibbles);
185
186    MSC_CLKRT = clk->clkrt; /* cleared by MSC reset */
187    MSC_STRPCL = 2; /* start the bus clock */
188    MSC_RESTO = 0xffff; /* maximum response time-out */
189
190    MSC_CMDAT =
191        (2 << 9) | /* 4 bit bus */
192        (1 << 8) | /* DMA */
193        (1 << 4) | /* write */
194        (1 << 3) | /* with data transfer */
195        1; /* R1 response */
196
197        MSC_STRPCL = 4; /* START_OP */
198
199    DCS(DMA) =
200        (1 << 31) | /* no descriptor */
201        1; /* enable transfer */
202
203    usleep(100);
204
205    sleep(1);
206
207    printf("MSC_STAT 0x%x\n", MSC_STAT);
208}
209
210
211static void send_buffer(const struct mmcclk *clk,
212    const uint8_t *buf, int nibbles)
213{
214    unsigned long phys;
215
216    phys = physmem_xlat((void *) buf);
217    mmc_buffer(clk, phys, nibbles);
218}
219
220
221static int dma_pattern(const struct mmcclk *clk,
222    const char *pattern, uint32_t mask)
223{
224    int n = strlen(pattern);
225    int rounded = (n+63) & ~63;
226    uint8_t *buf = physmem_malloc(rounded >> 1);
227    uint8_t *tmp = physmem_malloc(32);
228    int i;
229
230    if (!n)
231        return 1;
232
233    memset(buf, 0, rounded);
234    for (i = 0; i != rounded; i++) {
235        char ch[2] = { pattern[i < n ? i : n-1], 0 };
236        char *end;
237
238        buf[i >> 1] |= strtoul(ch, &end, 16) << 4*(~i & 1);
239        if (*end)
240            return 0;
241    }
242
243    dma_init();
244
245    PDDATC = ~((buf[0] >> 4) << 10) & mask;
246    PDDATS = (buf[0] >> 4) << 10;
247    PDDIRS = mask;
248
249    memset(tmp, (buf[0] >> 4)*0x11, 64);
250
251    send_buffer(clk, tmp, 64);
252
253    PDFUNS = mask;
254
255    send_buffer(clk, buf, rounded);
256
257    PDDATC = ~((buf[(rounded >> 1)-1] & 0xf) << 10) & mask;
258    PDDATS = (buf[(rounded >> 1)-1] & 0xf) << 10;
259
260    PDFUNC = mask;
261
262    dma_cleanup();
263
264    return 1;
265}
266
267
125268/* ----- Command-line processing ------------------------------------------- */
126269
127270
...... 
174317{
175318        fprintf(stderr,
176319"usage: %s\n"
177"usage: %s [-b freq_hz] [-c] [-q] active_s\n\n"
320"usage: %s [-b freq_hz] [-f freq_hz] [-c] [-q] [pattern] active_s\n\n"
178321" -b freq_hz set bus clock to the specified frequency (default: 1 MHz)\n"
179322" -c output bus clock on CLK\n"
323" -f freq_hz set pattern rate (default: same as bus clock)\n"
180324" -q quiet. Don't report clock differences.\n\n"
181" active_s keep running that many seconds after setting the clock\n\n"
325" active_s keep running that many seconds after setting the clock\n"
326" pattern send the specified pattern on DAT0 through DAT3\n\n"
182327"Frequency: the frequency in Hz, optionally followed by \"M\" or \"k\",\n"
183328" optionally followed by \"Hz\", optionally followed by \"+\" or \"-\".\n"
184329" \"+\" selects a frequency >= the specified one, \"-\" one <=.\n"
185330" Without +/-, the closest available frequency is selected.\n"
331"Pattern: hex digits corresponding to 1 for DAT0, 2 for DAT1, etc.\n"
186332    , name, name);
187333    exit(1);
188334}
...... 
191337int main(int argc, char **argv)
192338{
193339    struct mmcclk clk;
194    int bus_hz = 1000000, clkout = 0, rel = 0;
340    int bus_hz = 0, clkout = 0, bus_rel = 0;
341    int pattern_hz = 0, pattern_rel = 0;
342    const char *pattern = NULL;
195343    int quiet = 0;
196344    double active_s;
197345    struct timespec active_ns;
...... 
201349    while ((c = getopt(argc, argv, "b:cq")) != EOF)
202350        switch (c) {
203351        case 'b':
204            if (!frequency(optarg, &bus_hz, &rel))
352            if (!frequency(optarg, &bus_hz, &bus_rel))
353                usage(*argv);
354            break;
355        case 'f':
356            if (!frequency(optarg, &pattern_hz, &pattern_rel))
205357                usage(*argv);
206358            break;
207359        case 'c':
...... 
221373        ubb_open(UBB_ALL);
222374        show_frequencies();
223375        return 1;
376    case 2:
377        pattern = argv[optind];
378        /* fall through */
224379    case 1:
225        active_s = strtod(argv[optind], &end);
380        active_s = strtod(argv[argc-1], &end);
226381        if (*end)
227382            usage(*argv);
228383        active_ns.tv_sec = (int) active_s;
...... 
234389
235390    ubb_open(UBB_ALL);
236391
237    if (!select_freq(&clk, bus_hz, rel)) {
392    PDFUNS = UBB_CMD;
393
394    if (!bus_hz)
395        bus_hz = 1000000;
396
397    if (!select_freq(&clk, bus_hz, bus_rel)) {
238398        fprintf(stderr, "no suitable frequency found\n");
239399        exit(1);
240400    }
...... 
254414        PDFUNS = UBB_CLK;
255415    mmcclk_start(&clk);
256416
417    if (pattern)
418        if (!dma_pattern(&clk, pattern,
419            UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3))
420            usage(*argv);
421
257422    if (nanosleep(&active_ns, NULL))
258423        perror("nanosleep");
259424
260425    mmcclk_stop();
261426
262    ubb_close(0);
427    ubb_close(UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3);
263428
264429    return 0;
265430}

Archive Download the corresponding diff file

Branches:
master



interactive