Date:2011-04-24 07:56:56 (12 years 11 months ago)
Author:Werner Almesberger
Commit:3b7a7caec16eef092f149fef83b03832d11df0eb
Message:renamed "video" to ubb-vga

Files: ubb-vga/Makefile (1 diff)
ubb-vga/README (1 diff)
ubb-vga/ubb-vga.c (1 diff)
ubb-vga/ubb-vga.pro (1 diff)
ubb-vga/ubb-vga.sch (1 diff)
video/Makefile (1 diff)
video/README (1 diff)
video/ubb-vga.pro (1 diff)
video/ubb-vga.sch (1 diff)
video/video.c (1 diff)

Change Details

ubb-vga/Makefile
1#CC=mipsel-openwrt-linux-uclibc-gcc
2CC=mipsel-linux-gcc
3
4CFLAGS=-Wall -g -O9 -march=mips32
5
6.PHONY: all asm sch clean spotless
7
8all: ubb-vga
9
10asm: ubb-vga.c
11        $(CC) $(CFLAGS) -S $<
12
13sch:
14        eeschema `pwd`/ubb-vga.sch
15
16clean:
17        rm -f ubb-vga
18
19spotless: clean
ubb-vga/README
1Sources
2-------
3
4Timing and the idea for the voltage divider is from:
5http://faculty.lasierra.edu/~ehwang/public/mypublications/VGA Monitor Controller.pdf
6
7More timing parameters:
8http://tinyvga.com/vga-timing/640x480@60Hz
9
10
11Signal 8:10 VGA
12------- ------- ---
13R DAT2 1
14VSYNC DAT3 14
15HSYNC CMD 13
16G DAT0 2
17B DAT1 3
18GND GND 5
19
20http://en.wikipedia.org/wiki/VGA_connector
21
22
23Timing
24------
25
26Since the Ingenic CPUs take about 8.5 PCLK cycles for a GPIO set or clear,
27and we can only set or clear a set of signals in GPIO operation, but not
28set some and clear others, we cannot have a real 320 horizontal pixels.
29
30Instead, set and clear operations alternate. This means that the best-case
31resolution is equivalent to 320 pixels (if the original pixel boundaries
32coincide with the set/clear phases), but it can be as low as 160 pixels if
33the boundaries don't match.
34
35Furthermore, timing is still a bit too tight. We therefore use a pixel
36clock that's about 10% slower than the original. Luckily, most monitors
37don't mind.
ubb-vga/ubb-vga.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
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
59static uint8_t thres = 63;
60
61
62/* ----- Ben hardware ------------------------------------------------------ */
63
64
65static volatile uint32_t *icmr, *icmsr, *icmcr;
66static uint32_t old_icmr;
67
68static volatile uint32_t *clkgr;
69static uint32_t old_clkgr;
70
71static volatile uint32_t *pdpin, *pddats, *pddatc;
72static volatile uint32_t *pddirs, *pddirc;
73
74static volatile uint32_t *tssr, *tscr;
75static volatile uint32_t *tesr, *tecr;
76static volatile uint32_t *tcsr, *tdfr, *tcnt;
77
78
79static void disable_interrupts(void)
80{
81    /*
82     * @@@ Race condition alert ! If we get interrupted/preempted between
83     * reading ICMR and masking all interrupts, and the code that runs
84     * between these two operations changes ICMR, then we may set an
85     * incorrect mask when restoring interrupts, which may hang the system.
86     */
87
88    old_icmr = *icmr;
89    *icmsr = 0xffffffff;
90}
91
92
93static void enable_interrupts(void)
94{
95    *icmcr = ~old_icmr;
96}
97
98
99/*
100 * @@@ Disabling the LCD clock will halng operations that depend on the LCD
101 * subsystem to advance. This includes the screen saver.
102 */
103
104static void disable_lcd(void)
105{
106    old_clkgr = *clkgr;
107    *clkgr = old_clkgr | 1 << 10;
108}
109
110
111static void enable_lcd(void)
112{
113    *clkgr = old_clkgr;
114}
115
116
117static void get_timer(void)
118{
119    *tscr = 1 << TIMER; /* enable clock */
120    *tcsr = 1; /* count at PCLK/1 */
121    *tdfr = 0xffff; /* count to 0xffff */
122    *tesr = 1 << TIMER;
123}
124
125
126static void release_timer(void)
127{
128    *tecr = 1 << TIMER;
129    *tssr = 1 << TIMER;
130}
131
132
133static void *map(off_t addr, size_t size)
134{
135    int fd;
136    void *mem;
137
138    fd = open("/dev/mem", O_RDWR | O_SYNC);
139    if (fd < 0) {
140        perror("/dev/mem");
141        exit(1);
142    }
143    mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr);
144    if (mem == MAP_FAILED) {
145        perror("mmap");
146        exit(1);
147    }
148
149    return mem;
150}
151
152
153static void ben_setup(void)
154{
155    volatile void *base;
156
157    base = map(SOC_BASE, PAGE_SIZE*3*16);
158
159    icmr = base+0x1004;
160    icmsr = base+0x1008;
161    icmcr = base+0x100c;
162
163    clkgr = base+0x20;
164
165    pdpin = base+0x10300;
166    pddats = base+0x10314;
167    pddatc = base+0x10318;
168
169    pddirs = base+0x10364;
170    pddirc = base+0x10368;
171
172    tssr = base+0x202c;
173    tscr = base+0x203c;
174
175    tesr = base+0x2014;
176    tecr = base+0x2018;
177
178    tcsr = base+0x204c+0x10*TIMER;
179    tdfr = base+0x2040+0x10*TIMER;
180    tcnt = base+0x2048+0x10*TIMER;
181
182    /*
183     * Ironically, switching the LCD clock on and off many times only
184     * increases the risk of a hang. Therefore, we leave stop it during
185     * all the measurements and only enable it again at the end.
186     */
187    disable_lcd();
188    get_timer();
189}
190
191
192static void cleanup(void)
193{
194    release_timer();
195    enable_lcd();
196}
197
198
199/* ----- Interface --------------------------------------------------------- */
200
201
202void setup(void)
203{
204    mlockall(MCL_CURRENT | MCL_FUTURE);
205    ben_setup();
206    *pddirs = R | G | B | HSYNC | VSYNC;
207}
208
209
210static uint32_t pick(int set, int bit, uint32_t val)
211{
212    return set == bit ? val >> 8 : 0;
213}
214
215
216static uint32_t pattern(int set, int r, int g, int b)
217{
218    return pick(set, r, R) | pick(set, g, G) | pick(set, b, B);
219}
220
221
222#define BURST 32
223
224#define PREFETCH_HSYNC 160
225#define PREFETCH_HFRONT (160-PREFETCH_HSYNC)
226#define DELAY_HFRONT 30
227#define DELAY_HBACK 40
228//#define DELAY_VSYNC 3500
229//#define DELAY_VFRONT 56000
230//#define DELAY_VBACK 28000
231#define DELAY_VFRONT 1500
232#define DELAY_LINE 1800
233#define DELAY_HSYNC 210
234
235
236static inline void prefetch(const uint8_t *prefetch, int words)
237{
238    volatile const uint8_t *p = prefetch;
239
240    while (p != prefetch+words) {
241        (void) *p;
242        p += BURST;
243    }
244}
245
246
247static void until(uint16_t cycles)
248{
249    while ((*tcnt & 0xffff) < cycles);
250}
251
252#define US(us) ((uint16_t) ((us)*112))
253
254static void line(const uint8_t *line, const uint8_t *fetch)
255{
256    const uint8_t *p = line;
257//volatile uint8_t pat = R | B | G;
258    /* HSYNC */
259    *tcnt = 0;
260    *pddatc = HSYNC;
261// prefetch(fetch, PREFETCH_HSYNC);
262    prefetch(fetch, 160);
263    until(US(3.77));
264// *tcnt = 0;
265    *pddats = HSYNC;
266
267    /* Front porch */
268// prefetch(fetch+PREFETCH_HSYNC, PREFETCH_HFRONT);
269// until(US(3.77+1.79-3.77));
270    until(US(3.77+1.79));
271
272    while (p != line+320) {
273        *pddats = *p++ << 8;//pat; //R | G | B; //*p++;
274        *pddatc = *p++ << 8;//pat;//R | G | B; // *p++;
275    }
276
277    /* Back porch */
278// until(US(31.77-3.77));
279    until(US(31.77));
280    until(US(36));
281}
282
283
284static void hdelay(int cycles)
285{
286    while (cycles--) {
287        *tcnt = 0;
288        *pddatc = HSYNC;
289        until(US(3.77));
290        *pddats = HSYNC;
291        until(US(31.77));
292    until(US(36));
293    }
294}
295
296
297static void frame(const uint8_t *f)
298{
299    const uint8_t *p;
300
301    /* VSYNC */
302    *pddatc = VSYNC;
303    hdelay(2);
304    *pddats = VSYNC;
305
306    /* Front porch */
307    *tcnt = 0;
308    *pddatc = HSYNC;
309// prefetch(f, PREFETCH_HSYNC);
310    until(US(3.77));
311// *tcnt = 0;
312    *pddats = HSYNC;
313
314// prefetch(f+PREFETCH_HSYNC, PREFETCH_HFRONT);
315    prefetch(f, 160);
316// until(US(31.77-3.77));
317    until(US(31.77));
318    until(US(36));
319    hdelay(31);
320
321    for (p = f; p != f+240*320; p += 320) {
322        line(p, p+160);
323        line(p, p+320);
324    }
325
326    /* Back porch */
327    hdelay(14);
328}
329
330
331static void tricolor(uint32_t *f)
332{
333    int i;
334
335    for (i = 0; i != 320*240/3; i++) {
336        f[i & ~1] = R;
337        f[i | 1] = G | B;
338    }
339    for (; i != 320*240*2/3; i++) {
340        f[i & ~1] = G;
341        f[i | 1] = R | B;
342    }
343
344    for (; i != 320*240; i++) {
345        f[i & ~1] = B;
346        f[i | 1] = R | G;
347    }
348}
349
350
351static void grid(uint8_t *f)
352{
353    static uint32_t col[8] = {
354        R | G | B,
355        R,
356        R | G,
357        G,
358        G | B,
359        B,
360        R | B,
361        R | G | B,
362    };
363    int i, x, y;
364
365    for (i = 0; i != 8; i++) {
366        x = i*40+20;
367        for (y = 0; y != 240; y++) {
368            f[y*320+x] = f[y*320+x+1] = col[i] >> 8;
369        }
370    }
371}
372
373
374static void grab(uint8_t *f)
375{
376    uint32_t *fb = map(0x01d00000, 4*320*240);
377    int x, y;
378    uint32_t pix;
379
380    for (y = 0; y != 240; y++)
381        for (x = 0; x != 320; x++) {
382            pix = *fb++;
383            *f++ = pattern(!(x & 1),
384                ((pix >> 16) & 255) >= thres,
385                ((pix >> 8) & 255) >= thres,
386                (pix & 255) >= thres);
387        }
388}
389
390
391static void session(int n)
392{
393    uint8_t f[320*(240+1)];
394    int i;
395
396    memset(f, 0, sizeof(f));
397    grab(f);
398// grid(f);
399
400    disable_interrupts();
401
402    for (i = 0; i != n; i++)
403        frame(f);
404
405    enable_interrupts();
406}
407
408
409int main(int argc, char **argv)
410{
411    thres = atoi(argv[2]);
412    setup();
413    session(atoi(argv[1]));
414    cleanup();
415    return 0;
416}
ubb-vga/ubb-vga.pro
1update=Sun Apr 24 01:38:18 2011
2last_client=eeschema
3[eeschema]
4version=1
5LibDir=
6NetFmt=1
7HPGLSpd=20
8HPGLDm=15
9HPGLNum=1
10offX_A4=0
11offY_A4=0
12offX_A3=0
13offY_A3=0
14offX_A2=0
15offY_A2=0
16offX_A1=0
17offY_A1=0
18offX_A0=0
19offY_A0=0
20offX_A=0
21offY_A=0
22offX_B=0
23offY_B=0
24offX_C=0
25offY_C=0
26offX_D=0
27offY_D=0
28offX_E=0
29offY_E=0
30RptD_X=0
31RptD_Y=100
32RptLab=1
33LabSize=60
34PrintMonochrome=1
35ShowSheetReferenceAndTitleBlock=1
36[eeschema/libraries]
37LibName1=power
38LibName2=device
39LibName3=../../kicad-libs/components/8_10-card
40LibName4=../../kicad-libs/components/vga
ubb-vga/ubb-vga.sch
1EESchema Schematic File Version 2 date Sun Apr 24 02:16:48 2011
2LIBS:power
3LIBS:device
4LIBS:8_10-card
5LIBS:vga
6LIBS:ubb-vga-cache
7EELAYER 24 0
8EELAYER END
9$Descr A4 11700 8267
10Sheet 1 1
11Title "UBB VGA Adapter"
12Date "24 apr 2011"
13Rev "20110424"
14Comp "Werner Almesberger"
15Comment1 ""
16Comment2 ""
17Comment3 ""
18Comment4 ""
19$EndDescr
20Text Label 8200 3300 0 60 ~ 0
21VSYNC
22Text Label 8200 3400 0 60 ~ 0
23HSYNC
24Text Label 2100 3800 0 60 ~ 0
25VSYNC
26Text Label 2100 3600 0 60 ~ 0
27HSYNC
28Text Label 8200 3900 0 60 ~ 0
29B
30Text Label 8200 3800 0 60 ~ 0
31G
32Text Label 8200 3200 0 60 ~ 0
33R
34Wire Wire Line
35    2550 3800 1800 3800
36Wire Wire Line
37    1800 3800 1800 2550
38Wire Wire Line
39    1800 2550 5150 2550
40Wire Wire Line
41    5150 3300 5150 2550
42Wire Wire Line
43    8850 3300 5150 3300
44Wire Wire Line
45    3750 3600 4750 3600
46Wire Wire Line
47    4750 3600 4750 4000
48Wire Wire Line
49    4750 4000 7000 4000
50Wire Wire Line
51    7000 4000 7200 4000
52Wire Wire Line
53    7200 3800 6650 3800
54Wire Wire Line
55    6650 3800 4850 3800
56Connection ~ 3950 4000
57Wire Wire Line
58    3750 4000 3950 4000
59Connection ~ 7000 4000
60Connection ~ 6300 3200
61Wire Wire Line
62    6650 3800 6650 4200
63Wire Wire Line
64    7000 4600 7000 4800
65Wire Wire Line
66    6300 4800 6300 4600
67Wire Wire Line
68    8850 3800 7700 3800
69Wire Wire Line
70    8850 3700 8650 3700
71Wire Wire Line
72    8650 3700 8650 4300
73Wire Wire Line
74    7700 4000 7900 4000
75Wire Wire Line
76    7900 4000 7900 3900
77Wire Wire Line
78    7900 3900 8850 3900
79Wire Wire Line
80    8850 3200 7700 3200
81Wire Wire Line
82    6650 4600 6650 4800
83Wire Wire Line
84    7000 4000 7000 4200
85Wire Wire Line
86    6300 3200 6300 4200
87Connection ~ 6650 3800
88Wire Wire Line
89    3750 3900 3950 3900
90Wire Wire Line
91    3950 3900 3950 4000
92Wire Wire Line
93    3950 4000 3950 4200
94Wire Wire Line
95    3750 3200 6300 3200
96Wire Wire Line
97    6300 3200 7200 3200
98Wire Wire Line
99    3750 3400 4850 3400
100Wire Wire Line
101    4850 3400 4850 3800
102Wire Wire Line
103    8850 3400 5050 3400
104Wire Wire Line
105    5050 3400 5050 2650
106Wire Wire Line
107    5050 2650 1900 2650
108Wire Wire Line
109    1900 2650 1900 3600
110Wire Wire Line
111    1900 3600 2550 3600
112NoConn ~ 2550 3200
113NoConn ~ 2550 3400
114NoConn ~ 2550 4000
115Text Label 3950 3600 0 60 ~ 0
116BLUE
117Text Label 3950 3400 0 60 ~ 0
118GREEN
119Text Label 3950 3200 0 60 ~ 0
120RED
121NoConn ~ 3750 3800
122NoConn ~ 3750 3700
123NoConn ~ 3750 3500
124NoConn ~ 3750 3300
125NoConn ~ 3750 3100
126$Comp
127L GND #PWR1
128U 1 1 4DB3B0C4
129P 3950 4200
130F 0 "#PWR1" H 3950 4200 30 0001 C CNN
131F 1 "GND" H 3950 4130 30 0001 C CNN
132    1 3950 4200
133    1 0 0 -1
134$EndComp
135$Comp
136L GND #PWR4
137U 1 1 4DB3B04B
138P 7000 4800
139F 0 "#PWR4" H 7000 4800 30 0001 C CNN
140F 1 "GND" H 7000 4730 30 0001 C CNN
141    1 7000 4800
142    1 0 0 -1
143$EndComp
144$Comp
145L GND #PWR3
146U 1 1 4DB3B04A
147P 6650 4800
148F 0 "#PWR3" H 6650 4800 30 0001 C CNN
149F 1 "GND" H 6650 4730 30 0001 C CNN
150    1 6650 4800
151    1 0 0 -1
152$EndComp
153$Comp
154L GND #PWR2
155U 1 1 4DB3B048
156P 6300 4800
157F 0 "#PWR2" H 6300 4800 30 0001 C CNN
158F 1 "GND" H 6300 4730 30 0001 C CNN
159    1 6300 4800
160    1 0 0 -1
161$EndComp
162$Comp
163L GND #PWR5
164U 1 1 4DB3AFED
165P 8650 4300
166F 0 "#PWR5" H 8650 4300 30 0001 C CNN
167F 1 "GND" H 8650 4230 30 0001 C CNN
168    1 8650 4300
169    1 0 0 -1
170$EndComp
171NoConn ~ 8850 3600
172NoConn ~ 8850 3500
173$Comp
174L DIODE D1
175U 1 1 4DB3AF61
176P 6300 4400
177F 0 "D1" H 6300 4500 40 0000 C CNN
178F 1 "1N4148" H 6300 4300 40 0000 C CNN
179    1 6300 4400
180    0 -1 1 0
181$EndComp
182$Comp
183L DIODE D2
184U 1 1 4DB3AF5F
185P 6650 4400
186F 0 "D2" H 6650 4500 40 0000 C CNN
187F 1 "1N4148" H 6650 4300 40 0000 C CNN
188    1 6650 4400
189    0 -1 1 0
190$EndComp
191$Comp
192L DIODE D3
193U 1 1 4DB3AF5B
194P 7000 4400
195F 0 "D3" H 7000 4500 40 0000 C CNN
196F 1 "1N4148" H 7000 4300 40 0000 C CNN
197    1 7000 4400
198    0 -1 1 0
199$EndComp
200$Comp
201L R R3
202U 1 1 4DB3AF4D
203P 7450 4000
204F 0 "R3" V 7530 4000 50 0000 C CNN
205F 1 "1k" V 7450 4000 50 0000 C CNN
206    1 7450 4000
207    0 -1 -1 0
208$EndComp
209$Comp
210L R R2
211U 1 1 4DB3AF4B
212P 7450 3800
213F 0 "R2" V 7530 3800 50 0000 C CNN
214F 1 "1k" V 7450 3800 50 0000 C CNN
215    1 7450 3800
216    0 -1 -1 0
217$EndComp
218$Comp
219L R R1
220U 1 1 4DB3AF49
221P 7450 3200
222F 0 "R1" V 7530 3200 50 0000 C CNN
223F 1 "1k" V 7450 3200 50 0000 C CNN
224    1 7450 3200
225    0 -1 -1 0
226$EndComp
227$Comp
228L 8:10-CARD P1
229U 1 1 4DB3AF38
230P 9150 3500
231F 0 "P1" H 8950 4050 60 0000 C CNN
232F 1 "UBB" H 9200 2900 60 0000 C CNN
233    1 9150 3500
234    1 0 0 -1
235$EndComp
236$Comp
237L VGA J1
238U 1 1 4DB3AF2A
239P 3150 3550
240F 0 "J1" H 3350 2850 60 0000 C CNN
241F 1 "VGA" H 3150 4300 60 0000 C CNN
242    1 3150 3550
243    -1 0 0 1
244$EndComp
245$EndSCHEMATC
video/Makefile
1#CC=mipsel-openwrt-linux-uclibc-gcc
2CC=mipsel-linux-gcc
3
4CFLAGS=-Wall -g -O9 -march=mips32
5
6.PHONY: all asm sch clean spotless
7
8all: video
9
10asm: video.c
11        $(CC) $(CFLAGS) -S $<
12
13sch:
14        eeschema `pwd`/ubb-vga.sch
15
16clean:
17        rm -f video
18
19spotless: clean
video/README
1Sources
2
3Timing and the idea for the voltage divider is from:
4http://faculty.lasierra.edu/~ehwang/public/mypublications/VGA Monitor Controller.pdf
5
6More timing parameters:
7http://tinyvga.com/vga-timing/640x480@60Hz
8
9
10Signal 8:10 VGA
11R DAT2 1
12VSYNC DAT3 14
13HSYNC CMD 13
14G DAT0 2
15B DAT1 3
16GND GND 5
17
18http://en.wikipedia.org/wiki/VGA_connector
19
20
21Timing
22
23Since the Ingenic CPUs take about 8.5 PCLK cycles for a GPIO set or clear,
24and we can only set or clear a set of signals in GPIO operation, but not
25set some and clear others, we cannot have a real 320 horizontal pixels.
26
27Instead, set and clear operations alternate. This means that the best-case
28resolution is equivalent to 320 pixels (if the original pixel boundaries
29coincide with the set/clear phases), but it can be as low as 160 pixels if
30the boundaries don't match.
31
32Furthermore, timing is still a bit too tight. We therefore use a pixel
33clock that's about 10% slower than the original. Luckily, most monitors
34don't mind.
video/ubb-vga.pro
1update=Sun Apr 24 01:38:18 2011
2last_client=eeschema
3[eeschema]
4version=1
5LibDir=
6NetFmt=1
7HPGLSpd=20
8HPGLDm=15
9HPGLNum=1
10offX_A4=0
11offY_A4=0
12offX_A3=0
13offY_A3=0
14offX_A2=0
15offY_A2=0
16offX_A1=0
17offY_A1=0
18offX_A0=0
19offY_A0=0
20offX_A=0
21offY_A=0
22offX_B=0
23offY_B=0
24offX_C=0
25offY_C=0
26offX_D=0
27offY_D=0
28offX_E=0
29offY_E=0
30RptD_X=0
31RptD_Y=100
32RptLab=1
33LabSize=60
34PrintMonochrome=1
35ShowSheetReferenceAndTitleBlock=1
36[eeschema/libraries]
37LibName1=power
38LibName2=device
39LibName3=../../kicad-libs/components/8_10-card
40LibName4=../../kicad-libs/components/vga
video/ubb-vga.sch
1EESchema Schematic File Version 2 date Sun Apr 24 02:16:48 2011
2LIBS:power
3LIBS:device
4LIBS:8_10-card
5LIBS:vga
6LIBS:ubb-vga-cache
7EELAYER 24 0
8EELAYER END
9$Descr A4 11700 8267
10Sheet 1 1
11Title "UBB VGA Adapter"
12Date "24 apr 2011"
13Rev "20110424"
14Comp "Werner Almesberger"
15Comment1 ""
16Comment2 ""
17Comment3 ""
18Comment4 ""
19$EndDescr
20Text Label 8200 3300 0 60 ~ 0
21VSYNC
22Text Label 8200 3400 0 60 ~ 0
23HSYNC
24Text Label 2100 3800 0 60 ~ 0
25VSYNC
26Text Label 2100 3600 0 60 ~ 0
27HSYNC
28Text Label 8200 3900 0 60 ~ 0
29B
30Text Label 8200 3800 0 60 ~ 0
31G
32Text Label 8200 3200 0 60 ~ 0
33R
34Wire Wire Line
35    2550 3800 1800 3800
36Wire Wire Line
37    1800 3800 1800 2550
38Wire Wire Line
39    1800 2550 5150 2550
40Wire Wire Line
41    5150 3300 5150 2550
42Wire Wire Line
43    8850 3300 5150 3300
44Wire Wire Line
45    3750 3600 4750 3600
46Wire Wire Line
47    4750 3600 4750 4000
48Wire Wire Line
49    4750 4000 7000 4000
50Wire Wire Line
51    7000 4000 7200 4000
52Wire Wire Line
53    7200 3800 6650 3800
54Wire Wire Line
55    6650 3800 4850 3800
56Connection ~ 3950 4000
57Wire Wire Line
58    3750 4000 3950 4000
59Connection ~ 7000 4000
60Connection ~ 6300 3200
61Wire Wire Line
62    6650 3800 6650 4200
63Wire Wire Line
64    7000 4600 7000 4800
65Wire Wire Line
66    6300 4800 6300 4600
67Wire Wire Line
68    8850 3800 7700 3800
69Wire Wire Line
70    8850 3700 8650 3700
71Wire Wire Line
72    8650 3700 8650 4300
73Wire Wire Line
74    7700 4000 7900 4000
75Wire Wire Line
76    7900 4000 7900 3900
77Wire Wire Line
78    7900 3900 8850 3900
79Wire Wire Line
80    8850 3200 7700 3200
81Wire Wire Line
82    6650 4600 6650 4800
83Wire Wire Line
84    7000 4000 7000 4200
85Wire Wire Line
86    6300 3200 6300 4200
87Connection ~ 6650 3800
88Wire Wire Line
89    3750 3900 3950 3900
90Wire Wire Line
91    3950 3900 3950 4000
92Wire Wire Line
93    3950 4000 3950 4200
94Wire Wire Line
95    3750 3200 6300 3200
96Wire Wire Line
97    6300 3200 7200 3200
98Wire Wire Line
99    3750 3400 4850 3400
100Wire Wire Line
101    4850 3400 4850 3800
102Wire Wire Line
103    8850 3400 5050 3400
104Wire Wire Line
105    5050 3400 5050 2650
106Wire Wire Line
107    5050 2650 1900 2650
108Wire Wire Line
109    1900 2650 1900 3600
110Wire Wire Line
111    1900 3600 2550 3600
112NoConn ~ 2550 3200
113NoConn ~ 2550 3400
114NoConn ~ 2550 4000
115Text Label 3950 3600 0 60 ~ 0
116BLUE
117Text Label 3950 3400 0 60 ~ 0
118GREEN
119Text Label 3950 3200 0 60 ~ 0
120RED
121NoConn ~ 3750 3800
122NoConn ~ 3750 3700
123NoConn ~ 3750 3500
124NoConn ~ 3750 3300
125NoConn ~ 3750 3100
126$Comp
127L GND #PWR1
128U 1 1 4DB3B0C4
129P 3950 4200
130F 0 "#PWR1" H 3950 4200 30 0001 C CNN
131F 1 "GND" H 3950 4130 30 0001 C CNN
132    1 3950 4200
133    1 0 0 -1
134$EndComp
135$Comp
136L GND #PWR4
137U 1 1 4DB3B04B
138P 7000 4800
139F 0 "#PWR4" H 7000 4800 30 0001 C CNN
140F 1 "GND" H 7000 4730 30 0001 C CNN
141    1 7000 4800
142    1 0 0 -1
143$EndComp
144$Comp
145L GND #PWR3
146U 1 1 4DB3B04A
147P 6650 4800
148F 0 "#PWR3" H 6650 4800 30 0001 C CNN
149F 1 "GND" H 6650 4730 30 0001 C CNN
150    1 6650 4800
151    1 0 0 -1
152$EndComp
153$Comp
154L GND #PWR2
155U 1 1 4DB3B048
156P 6300 4800
157F 0 "#PWR2" H 6300 4800 30 0001 C CNN
158F 1 "GND" H 6300 4730 30 0001 C CNN
159    1 6300 4800
160    1 0 0 -1
161$EndComp
162$Comp
163L GND #PWR5
164U 1 1 4DB3AFED
165P 8650 4300
166F 0 "#PWR5" H 8650 4300 30 0001 C CNN
167F 1 "GND" H 8650 4230 30 0001 C CNN
168    1 8650 4300
169    1 0 0 -1
170$EndComp
171NoConn ~ 8850 3600
172NoConn ~ 8850 3500
173$Comp
174L DIODE D1
175U 1 1 4DB3AF61
176P 6300 4400
177F 0 "D1" H 6300 4500 40 0000 C CNN
178F 1 "1N4148" H 6300 4300 40 0000 C CNN
179    1 6300 4400
180    0 -1 1 0
181$EndComp
182$Comp
183L DIODE D2
184U 1 1 4DB3AF5F
185P 6650 4400
186F 0 "D2" H 6650 4500 40 0000 C CNN
187F 1 "1N4148" H 6650 4300 40 0000 C CNN
188    1 6650 4400
189    0 -1 1 0
190$EndComp
191$Comp
192L DIODE D3
193U 1 1 4DB3AF5B
194P 7000 4400
195F 0 "D3" H 7000 4500 40 0000 C CNN
196F 1 "1N4148" H 7000 4300 40 0000 C CNN
197    1 7000 4400
198    0 -1 1 0
199$EndComp
200$Comp
201L R R3
202U 1 1 4DB3AF4D
203P 7450 4000
204F 0 "R3" V 7530 4000 50 0000 C CNN
205F 1 "1k" V 7450 4000 50 0000 C CNN
206    1 7450 4000
207    0 -1 -1 0
208$EndComp
209$Comp
210L R R2
211U 1 1 4DB3AF4B
212P 7450 3800
213F 0 "R2" V 7530 3800 50 0000 C CNN
214F 1 "1k" V 7450 3800 50 0000 C CNN
215    1 7450 3800
216    0 -1 -1 0
217$EndComp
218$Comp
219L R R1
220U 1 1 4DB3AF49
221P 7450 3200
222F 0 "R1" V 7530 3200 50 0000 C CNN
223F 1 "1k" V 7450 3200 50 0000 C CNN
224    1 7450 3200
225    0 -1 -1 0
226$EndComp
227$Comp
228L 8:10-CARD P1
229U 1 1 4DB3AF38
230P 9150 3500
231F 0 "P1" H 8950 4050 60 0000 C CNN
232F 1 "UBB" H 9200 2900 60 0000 C CNN
233    1 9150 3500
234    1 0 0 -1
235$EndComp
236$Comp
237L VGA J1
238U 1 1 4DB3AF2A
239P 3150 3550
240F 0 "J1" H 3350 2850 60 0000 C CNN
241F 1 "VGA" H 3150 4300 60 0000 C CNN
242    1 3150 3550
243    -1 0 0 1
244$EndComp
245$EndSCHEMATC
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
59static uint8_t thres = 63;
60
61
62/* ----- Ben hardware ------------------------------------------------------ */
63
64
65static volatile uint32_t *icmr, *icmsr, *icmcr;
66static uint32_t old_icmr;
67
68static volatile uint32_t *clkgr;
69static uint32_t old_clkgr;
70
71static volatile uint32_t *pdpin, *pddats, *pddatc;
72static volatile uint32_t *pddirs, *pddirc;
73
74static volatile uint32_t *tssr, *tscr;
75static volatile uint32_t *tesr, *tecr;
76static volatile uint32_t *tcsr, *tdfr, *tcnt;
77
78
79static void disable_interrupts(void)
80{
81    /*
82     * @@@ Race condition alert ! If we get interrupted/preempted between
83     * reading ICMR and masking all interrupts, and the code that runs
84     * between these two operations changes ICMR, then we may set an
85     * incorrect mask when restoring interrupts, which may hang the system.
86     */
87
88    old_icmr = *icmr;
89    *icmsr = 0xffffffff;
90}
91
92
93static void enable_interrupts(void)
94{
95    *icmcr = ~old_icmr;
96}
97
98
99/*
100 * @@@ Disabling the LCD clock will halng operations that depend on the LCD
101 * subsystem to advance. This includes the screen saver.
102 */
103
104static void disable_lcd(void)
105{
106    old_clkgr = *clkgr;
107    *clkgr = old_clkgr | 1 << 10;
108}
109
110
111static void enable_lcd(void)
112{
113    *clkgr = old_clkgr;
114}
115
116
117static void get_timer(void)
118{
119    *tscr = 1 << TIMER; /* enable clock */
120    *tcsr = 1; /* count at PCLK/1 */
121    *tdfr = 0xffff; /* count to 0xffff */
122    *tesr = 1 << TIMER;
123}
124
125
126static void release_timer(void)
127{
128    *tecr = 1 << TIMER;
129    *tssr = 1 << TIMER;
130}
131
132
133static void *map(off_t addr, size_t size)
134{
135    int fd;
136    void *mem;
137
138    fd = open("/dev/mem", O_RDWR | O_SYNC);
139    if (fd < 0) {
140        perror("/dev/mem");
141        exit(1);
142    }
143    mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr);
144    if (mem == MAP_FAILED) {
145        perror("mmap");
146        exit(1);
147    }
148
149    return mem;
150}
151
152
153static void ben_setup(void)
154{
155    volatile void *base;
156
157    base = map(SOC_BASE, PAGE_SIZE*3*16);
158
159    icmr = base+0x1004;
160    icmsr = base+0x1008;
161    icmcr = base+0x100c;
162
163    clkgr = base+0x20;
164
165    pdpin = base+0x10300;
166    pddats = base+0x10314;
167    pddatc = base+0x10318;
168
169    pddirs = base+0x10364;
170    pddirc = base+0x10368;
171
172    tssr = base+0x202c;
173    tscr = base+0x203c;
174
175    tesr = base+0x2014;
176    tecr = base+0x2018;
177
178    tcsr = base+0x204c+0x10*TIMER;
179    tdfr = base+0x2040+0x10*TIMER;
180    tcnt = base+0x2048+0x10*TIMER;
181
182    /*
183     * Ironically, switching the LCD clock on and off many times only
184     * increases the risk of a hang. Therefore, we leave stop it during
185     * all the measurements and only enable it again at the end.
186     */
187    disable_lcd();
188    get_timer();
189}
190
191
192static void cleanup(void)
193{
194    release_timer();
195    enable_lcd();
196}
197
198
199/* ----- Interface --------------------------------------------------------- */
200
201
202void setup(void)
203{
204    mlockall(MCL_CURRENT | MCL_FUTURE);
205    ben_setup();
206    *pddirs = R | G | B | HSYNC | VSYNC;
207}
208
209
210static uint32_t pick(int set, int bit, uint32_t val)
211{
212    return set == bit ? val >> 8 : 0;
213}
214
215
216static uint32_t pattern(int set, int r, int g, int b)
217{
218    return pick(set, r, R) | pick(set, g, G) | pick(set, b, B);
219}
220
221
222#define BURST 32
223
224#define PREFETCH_HSYNC 160
225#define PREFETCH_HFRONT (160-PREFETCH_HSYNC)
226#define DELAY_HFRONT 30
227#define DELAY_HBACK 40
228//#define DELAY_VSYNC 3500
229//#define DELAY_VFRONT 56000
230//#define DELAY_VBACK 28000
231#define DELAY_VFRONT 1500
232#define DELAY_LINE 1800
233#define DELAY_HSYNC 210
234
235
236static inline void prefetch(const uint8_t *prefetch, int words)
237{
238    volatile const uint8_t *p = prefetch;
239
240    while (p != prefetch+words) {
241        (void) *p;
242        p += BURST;
243    }
244}
245
246
247static void until(uint16_t cycles)
248{
249    while ((*tcnt & 0xffff) < cycles);
250}
251
252#define US(us) ((uint16_t) ((us)*112))
253
254static void line(const uint8_t *line, const uint8_t *fetch)
255{
256    const uint8_t *p = line;
257//volatile uint8_t pat = R | B | G;
258    /* HSYNC */
259    *tcnt = 0;
260    *pddatc = HSYNC;
261// prefetch(fetch, PREFETCH_HSYNC);
262    prefetch(fetch, 160);
263    until(US(3.77));
264// *tcnt = 0;
265    *pddats = HSYNC;
266
267    /* Front porch */
268// prefetch(fetch+PREFETCH_HSYNC, PREFETCH_HFRONT);
269// until(US(3.77+1.79-3.77));
270    until(US(3.77+1.79));
271
272    while (p != line+320) {
273        *pddats = *p++ << 8;//pat; //R | G | B; //*p++;
274        *pddatc = *p++ << 8;//pat;//R | G | B; // *p++;
275    }
276
277    /* Back porch */
278// until(US(31.77-3.77));
279    until(US(31.77));
280    until(US(36));
281}
282
283
284static void hdelay(int cycles)
285{
286    while (cycles--) {
287        *tcnt = 0;
288        *pddatc = HSYNC;
289        until(US(3.77));
290        *pddats = HSYNC;
291        until(US(31.77));
292    until(US(36));
293    }
294}
295
296
297static void frame(const uint8_t *f)
298{
299    const uint8_t *p;
300
301    /* VSYNC */
302    *pddatc = VSYNC;
303    hdelay(2);
304    *pddats = VSYNC;
305
306    /* Front porch */
307    *tcnt = 0;
308    *pddatc = HSYNC;
309// prefetch(f, PREFETCH_HSYNC);
310    until(US(3.77));
311// *tcnt = 0;
312    *pddats = HSYNC;
313
314// prefetch(f+PREFETCH_HSYNC, PREFETCH_HFRONT);
315    prefetch(f, 160);
316// until(US(31.77-3.77));
317    until(US(31.77));
318    until(US(36));
319    hdelay(31);
320
321    for (p = f; p != f+240*320; p += 320) {
322        line(p, p+160);
323        line(p, p+320);
324    }
325
326    /* Back porch */
327    hdelay(14);
328}
329
330
331static void tricolor(uint32_t *f)
332{
333    int i;
334
335    for (i = 0; i != 320*240/3; i++) {
336        f[i & ~1] = R;
337        f[i | 1] = G | B;
338    }
339    for (; i != 320*240*2/3; i++) {
340        f[i & ~1] = G;
341        f[i | 1] = R | B;
342    }
343
344    for (; i != 320*240; i++) {
345        f[i & ~1] = B;
346        f[i | 1] = R | G;
347    }
348}
349
350
351static void grid(uint8_t *f)
352{
353    static uint32_t col[8] = {
354        R | G | B,
355        R,
356        R | G,
357        G,
358        G | B,
359        B,
360        R | B,
361        R | G | B,
362    };
363    int i, x, y;
364
365    for (i = 0; i != 8; i++) {
366        x = i*40+20;
367        for (y = 0; y != 240; y++) {
368            f[y*320+x] = f[y*320+x+1] = col[i] >> 8;
369        }
370    }
371}
372
373
374static void grab(uint8_t *f)
375{
376    uint32_t *fb = map(0x01d00000, 4*320*240);
377    int x, y;
378    uint32_t pix;
379
380    for (y = 0; y != 240; y++)
381        for (x = 0; x != 320; x++) {
382            pix = *fb++;
383            *f++ = pattern(!(x & 1),
384                ((pix >> 16) & 255) >= thres,
385                ((pix >> 8) & 255) >= thres,
386                (pix & 255) >= thres);
387        }
388}
389
390
391static void session(int n)
392{
393    uint8_t f[320*(240+1)];
394    int i;
395
396    memset(f, 0, sizeof(f));
397    grab(f);
398// grid(f);
399
400    disable_interrupts();
401
402    for (i = 0; i != n; i++)
403        frame(f);
404
405    enable_interrupts();
406}
407
408
409int main(int argc, char **argv)
410{
411    thres = atoi(argv[2]);
412    setup();
413    session(atoi(argv[1]));
414    cleanup();
415    return 0;
416}

Archive Download the corresponding diff file

Branches:
master



interactive