Root/ubb-vga/ubb-vga-old.c

1/*
2 * ubb-vga.c - Output video on UBB with more or less VGA timing
3 *
4 * Written 2011 by Werner Almesberger
5 * Copyright 2011 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * WARNING: this program does very nasty things to the Ben and it doesn't
15 * like company. In particular, it resents:
16 *
17 * - the MMC driver - disable it with
18 * echo jz4740-mmc.0 >/sys/bus/platform/drivers/jz4740-mmc/unbind
19 * - the AT86RF230/1 kernel driver - use a kernel that doesn't have it
20 * - anything that accesses the screen - kill GUI, X server, etc.
21 * - the screen blanker - either disable it or make sure the screen stays
22 * dark, e.g., with
23 * echo 1 >/sys/devices/platform/jz4740-fb/graphics/fb0/blank
24 * - probably a fair number of other daemons and things as well - best to
25 * kill them all.
26 */
27
28
29#include <stdint.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <unistd.h>
33#include <string.h>
34#include <fcntl.h>
35#include <sys/mman.h>
36
37
38static uint8_t thres = 63;
39
40
41/* ----- I/O pin assignment ------------------------------------------------ */
42
43
44#define DAT0 (1 << 10)
45#define DAT1 (1 << 11)
46#define DAT2 (1 << 12)
47#define DAT3 (1 << 13)
48#define CMD (1 << 8)
49#define CLK (1 << 9)
50
51#define R DAT3
52#define G DAT0
53#define B DAT1
54#define HSYNC CMD
55#define VSYNC CLK
56
57
58/* ----- Ben hardware ------------------------------------------------------ */
59
60
61#define TIMER 7
62
63
64#define PAGE_SIZE 4096
65#define SOC_BASE 0x10000000
66
67
68static volatile uint32_t *icmr, *icmsr, *icmcr;
69static uint32_t old_icmr;
70
71static volatile uint32_t *clkgr;
72static uint32_t old_clkgr;
73
74static volatile uint32_t *pdpin, *pddats, *pddatc;
75static volatile uint32_t *pddirs, *pddirc;
76static volatile uint32_t *pdfuns, *pdfunc;
77
78static volatile uint32_t *tssr, *tscr;
79static volatile uint32_t *tesr, *tecr;
80static volatile uint32_t *tcsr, *tdfr, *tcnt;
81
82
83static void disable_interrupts(void)
84{
85    /*
86     * @@@ Race condition alert ! If we get interrupted/preempted between
87     * reading ICMR and masking all interrupts, and the code that runs
88     * between these two operations changes ICMR, then we may set an
89     * incorrect mask when restoring interrupts, which may hang the system.
90     */
91
92    old_icmr = *icmr;
93    *icmsr = 0xffffffff;
94}
95
96
97static void enable_interrupts(void)
98{
99    *icmcr = ~old_icmr;
100}
101
102
103/*
104 * @@@ Disabling the LCD clock will hang operations that depend on the LCD
105 * subsystem to advance. This includes the screen saver.
106 */
107
108static void disable_lcd(void)
109{
110    old_clkgr = *clkgr;
111    *clkgr = old_clkgr | 1 << 10;
112}
113
114
115static void enable_lcd(void)
116{
117    *clkgr = old_clkgr;
118}
119
120
121static void get_timer(void)
122{
123    *tscr = 1 << TIMER; /* enable clock */
124    *tcsr = 1; /* count at PCLK/1 */
125    *tdfr = 0xffff; /* count to 0xffff */
126    *tesr = 1 << TIMER;
127}
128
129
130static void release_timer(void)
131{
132    *tecr = 1 << TIMER;
133    *tssr = 1 << TIMER;
134}
135
136
137static void *map(off_t addr, size_t size)
138{
139    int fd;
140    void *mem;
141
142    fd = open("/dev/mem", O_RDWR | O_SYNC);
143    if (fd < 0) {
144        perror("/dev/mem");
145        exit(1);
146    }
147    mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr);
148    if (mem == MAP_FAILED) {
149        perror("mmap");
150        exit(1);
151    }
152
153    return mem;
154}
155
156
157static void ben_setup(void)
158{
159    volatile void *base;
160
161    base = map(SOC_BASE, PAGE_SIZE*3*16);
162
163    icmr = base+0x1004;
164    icmsr = base+0x1008;
165    icmcr = base+0x100c;
166
167    clkgr = base+0x20;
168
169    pdpin = base+0x10300;
170    pddats = base+0x10314;
171    pddatc = base+0x10318;
172
173    pdfuns = base+0x10344;
174    pdfunc = base+0x10348;
175
176    pddirs = base+0x10364;
177    pddirc = base+0x10368;
178
179    tssr = base+0x202c;
180    tscr = base+0x203c;
181
182    tesr = base+0x2014;
183    tecr = base+0x2018;
184
185    tcsr = base+0x204c+0x10*TIMER;
186    tdfr = base+0x2040+0x10*TIMER;
187    tcnt = base+0x2048+0x10*TIMER;
188
189    /*
190     * Ironically, switching the LCD clock on and off many times only
191     * increases the risk of a hang. Therefore, we leave stop it during
192     * all the measurements and only enable it again at the end.
193     */
194    disable_lcd();
195    get_timer();
196}
197
198
199static void cleanup(void)
200{
201    release_timer();
202    enable_lcd();
203}
204
205
206
207/* ----- Prefetch and delay logic ------------------------------------------ */
208
209
210#define BURST 32 /* bytes */
211
212
213static inline void prefetch(const uint8_t *prefetch, int words)
214{
215    volatile const uint8_t *p = prefetch;
216
217    while (p != prefetch+words) {
218        (void) *p;
219        p += BURST;
220    }
221}
222
223
224#define US(us) ((uint16_t) ((us)*112))
225
226
227static void until(uint16_t cycles)
228{
229    while ((*tcnt & 0xffff) < cycles);
230}
231
232
233/* ----- Frame buffer output ----------------------------------------------- */
234
235
236static int line_pairs = 160; /* set/clear pairs */
237static int line_cycles = US(36); /* nominally 31.77 us, but we're too slow */
238
239
240void setup(void)
241{
242    mlockall(MCL_CURRENT | MCL_FUTURE);
243    ben_setup();
244    *pdfunc = R | G | B | HSYNC | VSYNC;
245    *pddirs = R | G | B | HSYNC | VSYNC;
246}
247
248
249static void line(const uint8_t *line, const uint8_t *fetch)
250{
251    const uint8_t *p = line;
252
253    /* HSYNC */
254    *tcnt = 0;
255    *pddatc = HSYNC;
256    prefetch(fetch, line_pairs);
257    until(US(3.77));
258    *pddats = HSYNC;
259
260    /* Front porch */
261    until(US(3.77+1.79));
262
263    while (p != line+2*line_pairs) {
264        *pddats = *p++ << 8;
265        *pddatc = *p++ << 8;
266    }
267
268    /* Back porch */
269    until(line_cycles);
270}
271
272
273static void hdelay(int cycles)
274{
275    while (cycles--) {
276        *tcnt = 0;
277        *pddatc = HSYNC;
278        until(US(3.77));
279        *pddats = HSYNC;
280        until(line_cycles);
281    }
282}
283
284
285static void frame(const uint8_t *f)
286{
287    const uint8_t *p;
288
289    /* VSYNC */
290    *pddatc = VSYNC;
291    hdelay(2);
292    *pddats = VSYNC;
293
294    /* Front porch */
295    *tcnt = 0;
296    *pddatc = HSYNC;
297    until(US(3.77));
298    *pddats = HSYNC;
299
300    prefetch(f, line_pairs);
301    until(line_cycles);
302    hdelay(31);
303
304    for (p = f; p != f+240*2*line_pairs; p += 2*line_pairs) {
305        line(p, p+line_pairs);
306        line(p, p+2*line_pairs);
307    }
308
309    /* Back porch */
310    hdelay(14);
311}
312
313
314/* ----- Frame buffer image generation ------------------------------------- */
315
316
317static uint32_t pick(int set, int bit, uint32_t val)
318{
319    return set == bit ? val >> 8 : 0;
320}
321
322
323static uint32_t pattern(int set, int r, int g, int b)
324{
325    return pick(set, r, R) | pick(set, g, G) | pick(set, b, B);
326}
327
328
329static void tricolor(uint32_t *f)
330{
331    int pairs = 2*line_pairs*240;
332    int i;
333
334    for (i = 0; i != pairs/3; i++) {
335        f[i & ~1] = R;
336        f[i | 1] = G | B;
337    }
338    for (; i != pairs*2/3; i++) {
339        f[i & ~1] = G;
340        f[i | 1] = R | B;
341    }
342
343    for (; i != pairs; i++) {
344        f[i & ~1] = B;
345        f[i | 1] = R | G;
346    }
347}
348
349
350static void grid(uint8_t *f)
351{
352    static uint32_t col[8] = {
353        R | G | B,
354        R,
355        R | G,
356        G,
357        G | B,
358        B,
359        R | B,
360        R | G | B,
361    };
362    int i, x, y;
363
364    for (i = 0; i != 8; i++) {
365        x = i*line_pairs/4+line_pairs/8;
366        for (y = 0; y != 240; y++) {
367            uint8_t *p = f+y*2*line_pairs+x;
368            p[0] = p[1] = col[i] >> 8;
369        }
370    }
371}
372
373
374static void grab(uint8_t *f, int single)
375{
376    uint32_t *fb = map(0x01d00000, 4*320*240);
377    int x, y;
378    uint32_t pix;
379    uint8_t r, g, b;
380
381    for (y = 0; y != 240; y++)
382        for (x = 0; x != 320; x++) {
383            pix = *fb++;
384            r = pix >> 16;
385            g = pix >> 8;
386            b = pix;
387            if (single)
388                *f++ = pattern(!(x & 1),
389                    r >= thres, g >= thres, b >= thres);
390            else {
391                *f++ = pattern(1,
392                    r >= thres, g >= thres, b >= thres);
393                *f++ = pattern(0,
394                    r >= thres, g >= thres, b >= thres);
395            }
396        }
397}
398
399
400/* ----- Command-line parsing and main loop -------------------------------- */
401
402
403static void session(int frames, int single)
404{
405    uint8_t f[2*line_pairs*(240+1)];
406    int i;
407
408    memset(f, 0, sizeof(f));
409    grab(f, single);
410// grid(f);
411
412    disable_interrupts();
413
414    for (i = 0; i != frames; i++)
415        frame(f);
416
417    enable_interrupts();
418}
419
420
421static void usage(const char *name)
422{
423    fprintf(stderr,
424"usage: %s frames -d [threshold]\n\n"
425" frames number of frames to display\n"
426" threshold channel on/off threshold\n\n"
427" -d double the number of set/clear pairs\n"
428    , name);
429    exit(1);
430}
431
432
433int main(int argc, char *const *argv)
434{
435    int frames;
436    int single = 1;
437    int c;
438
439    while ((c = getopt(argc, argv, "d")) != EOF)
440        switch (c) {
441        case 'd':
442            single = 0;
443            line_pairs = 320;
444            line_cycles = US(36+26);
445            break;
446        default:
447            usage(*argv);
448        }
449
450    switch (argc-optind) {
451    case 2:
452        thres = atoi(argv[optind+1]);
453        /* fall through */
454    case 1:
455        frames = atoi(argv[optind]);
456        break;
457    default:
458        usage(*argv);
459    }
460
461    setup();
462    session(frames, single);
463    cleanup();
464
465    return 0;
466}
467

Archive Download this file

Branches:
master



interactive