Date:2011-04-24 04:26:42 (12 years 11 months ago)
Author:Werner Almesberger
Commit:b85ae154794efd591f662cf75f34bb9e809dd835
Message:video/video.c: pseudo-VGA output (test pattern only)

Files: video/video.c (1 diff)

Change Details

video/video.c
1/*
2 * video.c - Output CGA ? video
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
38#define DAT0 (1 << 10)
39#define DAT1 (1 << 11)
40#define DAT2 (1 << 12)
41#define DAT3 (1 << 13)
42#define CMD (1 << 8)
43#define CLK (1 << 9)
44
45#define R DAT2
46#define G DAT0
47#define B DAT1
48#define HSYNC CMD
49#define VSYNC DAT3
50
51#define TIMER 7
52
53
54#define PAGE_SIZE 4096
55#define SOC_BASE 0x10000000
56#define DEFAULT_COUNT (1000*1000)
57
58
59/* ----- Ben hardware ------------------------------------------------------ */
60
61
62static volatile uint32_t *icmr, *icmsr, *icmcr;
63static uint32_t old_icmr;
64
65static volatile uint32_t *clkgr;
66static uint32_t old_clkgr;
67
68static volatile uint32_t *pdpin, *pddats, *pddatc;
69static volatile uint32_t *pddirs, *pddirc;
70
71static volatile uint32_t *tssr, *tscr;
72static volatile uint32_t *tesr, *tecr;
73static volatile uint32_t *tcsr, *tdfr, *tcnt;
74
75
76static void disable_interrupts(void)
77{
78    /*
79     * @@@ Race condition alert ! If we get interrupted/preempted between
80     * reading ICMR and masking all interrupts, and the code that runs
81     * between these two operations changes ICMR, then we may set an
82     * incorrect mask when restoring interrupts, which may hang the system.
83     */
84
85    old_icmr = *icmr;
86    *icmsr = 0xffffffff;
87}
88
89
90static void enable_interrupts(void)
91{
92    *icmcr = ~old_icmr;
93}
94
95
96/*
97 * @@@ Disabling the LCD clock will halng operations that depend on the LCD
98 * subsystem to advance. This includes the screen saver.
99 */
100
101static void disable_lcd(void)
102{
103    old_clkgr = *clkgr;
104    *clkgr = old_clkgr | 1 << 10;
105}
106
107
108static void enable_lcd(void)
109{
110    *clkgr = old_clkgr;
111}
112
113
114static void get_timer(void)
115{
116    *tscr = 1 << TIMER; /* enable clock */
117    *tcsr = 1; /* count at PCLK/1 */
118    *tdfr = 0xffff; /* count to 0xffff */
119    *tesr = 1 << TIMER;
120}
121
122
123static void release_timer(void)
124{
125    *tecr = 1 << TIMER;
126    *tssr = 1 << TIMER;
127}
128
129
130static void ben_setup(void)
131{
132    volatile void *base;
133    int fd;
134
135    fd = open("/dev/mem", O_RDWR | O_SYNC);
136    if (fd < 0) {
137        perror("/dev/mem");
138        exit(1);
139    }
140    base = mmap(NULL, PAGE_SIZE*3*16, PROT_READ | PROT_WRITE, MAP_SHARED,
141        fd, SOC_BASE);
142    if (base == MAP_FAILED) {
143        perror("mmap");
144        exit(1);
145    }
146
147    icmr = base+0x1004;
148    icmsr = base+0x1008;
149    icmcr = base+0x100c;
150
151    clkgr = base+0x20;
152
153    pdpin = base+0x10300;
154    pddats = base+0x10314;
155    pddatc = base+0x10318;
156
157    pddirs = base+0x10364;
158    pddirc = base+0x10368;
159
160    tssr = base+0x202c;
161    tscr = base+0x203c;
162
163    tesr = base+0x2014;
164    tecr = base+0x2018;
165
166    tcsr = base+0x204c+0x10*TIMER;
167    tdfr = base+0x2040+0x10*TIMER;
168    tcnt = base+0x2048+0x10*TIMER;
169
170    /*
171     * Ironically, switching the LCD clock on and off many times only
172     * increases the risk of a hang. Therefore, we leave stop it during
173     * all the measurements and only enable it again at the end.
174     */
175    disable_lcd();
176    get_timer();
177}
178
179
180static void cleanup(void)
181{
182    release_timer();
183    enable_lcd();
184}
185
186
187/* ----- Interface --------------------------------------------------------- */
188
189
190void setup(void)
191{
192    mlockall(MCL_CURRENT | MCL_FUTURE);
193    ben_setup();
194    *pddirs = R | G | B | HSYNC | VSYNC;
195}
196
197
198static uint32_t pick(int set, int bit, uint32_t val)
199{
200    return set == bit ? val >> 8 : 0;
201}
202
203
204static uint32_t pattern(int r, int g, int b, int hsync, int vsync, int set)
205{
206    return pick(set, r, R) | pick(set, g, G) | pick(set, b, B) |
207        pick(set, hsync, HSYNC) | pick(set, vsync, VSYNC);
208}
209
210
211#define BURST 32
212
213#define PREFETCH_HSYNC 160
214#define PREFETCH_HFRONT (160-PREFETCH_HSYNC)
215#define DELAY_HFRONT 30
216#define DELAY_HBACK 40
217//#define DELAY_VSYNC 3500
218//#define DELAY_VFRONT 56000
219//#define DELAY_VBACK 28000
220#define DELAY_VFRONT 1500
221#define DELAY_LINE 1800
222#define DELAY_HSYNC 210
223
224
225static inline void prefetch(const uint8_t *prefetch, int words)
226{
227    volatile const uint8_t *p = prefetch;
228
229    while (p != prefetch+words) {
230        (void) *p;
231        p += BURST;
232    }
233}
234
235
236static void until(uint16_t cycles)
237{
238    while ((*tcnt & 0xffff) < cycles);
239}
240
241#define US(us) ((uint16_t) ((us)*112))
242
243static void line(const uint8_t *line, const uint8_t *fetch)
244{
245    const uint8_t *p = line;
246//volatile uint8_t pat = R | B | G;
247    /* HSYNC */
248    *tcnt = 0;
249    *pddatc = HSYNC;
250// prefetch(fetch, PREFETCH_HSYNC);
251    prefetch(fetch, 160);
252    until(US(3.77));
253// *tcnt = 0;
254    *pddats = HSYNC;
255
256    /* Front porch */
257// prefetch(fetch+PREFETCH_HSYNC, PREFETCH_HFRONT);
258// until(US(3.77+1.79-3.77));
259    until(US(3.77+1.79));
260
261    while (p != line+320) {
262        *pddats = *p++ << 8;//pat; //R | G | B; //*p++;
263        *pddatc = *p++ << 8;//pat;//R | G | B; // *p++;
264    }
265
266    /* Back porch */
267// until(US(31.77-3.77));
268    until(US(31.77));
269    until(US(36));
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(US(31.77));
281    until(US(36));
282    }
283}
284
285
286static void frame(const uint8_t *f)
287{
288    const uint8_t *p;
289
290    /* VSYNC */
291    *pddatc = VSYNC;
292    hdelay(2);
293    *pddats = VSYNC;
294
295    /* Front porch */
296    *tcnt = 0;
297    *pddatc = HSYNC;
298// prefetch(f, PREFETCH_HSYNC);
299    until(US(3.77));
300// *tcnt = 0;
301    *pddats = HSYNC;
302
303// prefetch(f+PREFETCH_HSYNC, PREFETCH_HFRONT);
304    prefetch(f, 160);
305// until(US(31.77-3.77));
306    until(US(31.77));
307    until(US(36));
308    hdelay(31);
309
310    for (p = f; p != f+240*320; p += 320) {
311        line(p, p+160);
312        line(p, p+320);
313    }
314
315    /* Back porch */
316    hdelay(14);
317}
318
319
320static void tricolor(uint32_t *f)
321{
322    int i;
323
324    for (i = 0; i != 320*240/3; i++) {
325        f[i & ~1] = R;
326        f[i | 1] = G | B;
327    }
328    for (; i != 320*240*2/3; i++) {
329        f[i & ~1] = G;
330        f[i | 1] = R | B;
331    }
332
333    for (; i != 320*240; i++) {
334        f[i & ~1] = B;
335        f[i | 1] = R | G;
336    }
337}
338
339
340static void grid(uint8_t *f)
341{
342    static uint32_t col[8] = {
343        R | G | B,
344        R,
345        R | G,
346        G,
347        G | B,
348        B,
349        R | B,
350        R | G | B,
351    };
352    int i, x, y;
353
354    for (i = 0; i != 8; i++) {
355        x = i*40+20;
356        for (y = 0; y != 240; y++) {
357            f[y*320+x] = f[y*320+x+1] = col[i] >> 8;
358        }
359    }
360}
361
362
363static void session(int n)
364{
365    uint8_t f[320*(240+1)];
366    int i;
367
368    memset(f, 0, sizeof(f));
369    grid(f);
370
371    disable_interrupts();
372
373    for (i = 0; i != n; i++)
374        frame(f);
375
376    enable_interrupts();
377}
378
379
380int main(int argc, char **argv)
381{
382    setup();
383    session(atoi(argv[1]));
384    cleanup();
385    return 0;
386}

Archive Download the corresponding diff file

Branches:
master



interactive