vidc20config.c revision 1.27 1 1.27 bjh21 /* $NetBSD: vidc20config.c,v 1.27 2006/08/19 16:57:06 bjh21 Exp $ */
2 1.1 reinoud
3 1.1 reinoud /*
4 1.1 reinoud * Copyright (c) 2001 Reinoud Zandijk
5 1.1 reinoud * Copyright (c) 1996 Mark Brinicombe
6 1.1 reinoud * Copyright (c) 1996 Robert Black
7 1.1 reinoud * Copyright (c) 1994-1995 Melvyn Tang-Richardson
8 1.1 reinoud * Copyright (c) 1994-1995 RiscBSD kernel team
9 1.1 reinoud * All rights reserved.
10 1.1 reinoud *
11 1.1 reinoud * Redistribution and use in source and binary forms, with or without
12 1.1 reinoud * modification, are permitted provided that the following conditions
13 1.1 reinoud * are met:
14 1.1 reinoud * 1. Redistributions of source code must retain the above copyright
15 1.1 reinoud * notice, this list of conditions and the following disclaimer.
16 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 reinoud * notice, this list of conditions and the following disclaimer in the
18 1.1 reinoud * documentation and/or other materials provided with the distribution.
19 1.1 reinoud * 3. All advertising materials mentioning features or use of this software
20 1.1 reinoud * must display the following acknowledgement:
21 1.1 reinoud * This product includes software developed by the RiscBSD kernel team
22 1.1 reinoud * 4. The name of the company nor the name of the author may be used to
23 1.1 reinoud * endorse or promote products derived from this software without specific
24 1.1 reinoud * prior written permission.
25 1.1 reinoud *
26 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE RISCBSD TEAM ``AS IS'' AND ANY EXPRESS
27 1.1 reinoud * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 1.1 reinoud * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 1.1 reinoud * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
30 1.1 reinoud * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 reinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 reinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 reinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 reinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 reinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36 1.1 reinoud * THE POSSIBILITY OF SUCH DAMAGE.
37 1.1 reinoud *
38 1.1 reinoud * NetBSD kernel project
39 1.1 reinoud *
40 1.1 reinoud * vidcvideo.c
41 1.1 reinoud *
42 1.1 reinoud * This file is the lower basis of the wscons driver for VIDC based ARM machines.
43 1.1 reinoud * It features the initialisation and all VIDC writing and keeps in internal state
44 1.1 reinoud * copy.
45 1.1 reinoud * Its currenly set up as a library file and not as a device; it could be named
46 1.1 reinoud * vidcvideo0 eventually.
47 1.1 reinoud */
48 1.1 reinoud
49 1.1 reinoud #include <sys/cdefs.h>
50 1.7 bjh21
51 1.27 bjh21 __KERNEL_RCSID(0, "$NetBSD: vidc20config.c,v 1.27 2006/08/19 16:57:06 bjh21 Exp $");
52 1.7 bjh21
53 1.1 reinoud #include <sys/types.h>
54 1.1 reinoud #include <sys/param.h>
55 1.1 reinoud #include <arm/iomd/vidc.h>
56 1.3 thorpej #include <arm/arm32/katelib.h>
57 1.1 reinoud #include <machine/bootconfig.h>
58 1.4 thorpej #include <machine/intr.h>
59 1.1 reinoud
60 1.1 reinoud #include <sys/systm.h>
61 1.1 reinoud #include <sys/device.h>
62 1.1 reinoud #include <uvm/uvm_extern.h>
63 1.1 reinoud
64 1.1 reinoud #include <arm/iomd/iomdreg.h>
65 1.1 reinoud #include <arm/iomd/iomdvar.h>
66 1.1 reinoud #include <arm/iomd/vidc20config.h>
67 1.1 reinoud
68 1.9 reinoud
69 1.1 reinoud /*
70 1.1 reinoud * A structure containing ALL the information required to restore
71 1.1 reinoud * the VIDC20 to any given state. ALL vidc transactions should
72 1.1 reinoud * go through these procedures, which record the vidc's state.
73 1.1 reinoud * it may be an idea to set the permissions of the vidc base address
74 1.1 reinoud * so we get a fault, so the fault routine can record the state but
75 1.1 reinoud * I guess that's not really necessary for the time being, since we
76 1.1 reinoud * can make the kernel more secure later on. Also, it is possible
77 1.1 reinoud * to write a routine to allow 'reading' of the vidc registers.
78 1.1 reinoud */
79 1.1 reinoud
80 1.1 reinoud static struct vidc_state vidc_lookup = {
81 1.1 reinoud { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
82 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
83 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
84 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
85 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
86 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
87 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
88 1.1 reinoud 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
89 1.1 reinoud },
90 1.1 reinoud
91 1.1 reinoud VIDC_PALREG,
92 1.1 reinoud VIDC_BCOL,
93 1.1 reinoud VIDC_CP1 ,
94 1.1 reinoud VIDC_CP2,
95 1.1 reinoud VIDC_CP3,
96 1.1 reinoud VIDC_HCR,
97 1.1 reinoud VIDC_HSWR,
98 1.1 reinoud VIDC_HBSR,
99 1.1 reinoud VIDC_HDSR,
100 1.1 reinoud VIDC_HDER,
101 1.1 reinoud VIDC_HBER,
102 1.1 reinoud VIDC_HCSR,
103 1.1 reinoud VIDC_HIR,
104 1.1 reinoud VIDC_VCR,
105 1.1 reinoud VIDC_VSWR,
106 1.1 reinoud VIDC_VBSR,
107 1.1 reinoud VIDC_VDSR,
108 1.1 reinoud VIDC_VDER,
109 1.1 reinoud VIDC_VBER,
110 1.1 reinoud VIDC_VCSR,
111 1.1 reinoud VIDC_VCER,
112 1.1 reinoud VIDC_EREG,
113 1.1 reinoud VIDC_FSYNREG,
114 1.1 reinoud VIDC_CONREG,
115 1.1 reinoud VIDC_DCTL
116 1.1 reinoud };
117 1.1 reinoud
118 1.1 reinoud struct vidc_state vidc_current[1];
119 1.1 reinoud
120 1.1 reinoud
121 1.1 reinoud /*
122 1.1 reinoud * XXX global display variables XXX ... should be a structure
123 1.1 reinoud */
124 1.1 reinoud static int cold_init = 0; /* flags initialisation */
125 1.1 reinoud extern videomemory_t videomemory;
126 1.1 reinoud
127 1.25 bjh21 static struct vidc_mode vidc_currentmode;
128 1.1 reinoud
129 1.1 reinoud unsigned int dispstart;
130 1.1 reinoud unsigned int dispsize;
131 1.1 reinoud unsigned int dispbase;
132 1.1 reinoud unsigned int dispend;
133 1.1 reinoud unsigned int ptov;
134 1.1 reinoud unsigned int vmem_base;
135 1.1 reinoud unsigned int phys_base;
136 1.1 reinoud unsigned int transfersize;
137 1.1 reinoud
138 1.1 reinoud
139 1.1 reinoud /* cursor stuff */
140 1.1 reinoud char *cursor_normal;
141 1.1 reinoud char *cursor_transparent;
142 1.9 reinoud int p_cursor_normal;
143 1.9 reinoud int p_cursor_transparent;
144 1.9 reinoud int cursor_width;
145 1.9 reinoud int cursor_height;
146 1.1 reinoud
147 1.1 reinoud
148 1.1 reinoud /*
149 1.1 reinoud * VIDC mode definitions
150 1.1 reinoud * generated from RISC OS mode definition file by an `awk' script
151 1.1 reinoud */
152 1.25 bjh21 extern const struct videomode vidc_videomode_list[];
153 1.25 bjh21 extern const int vidc_videomode_count;
154 1.1 reinoud
155 1.1 reinoud
156 1.1 reinoud /*
157 1.1 reinoud * configuration printing
158 1.1 reinoud *
159 1.1 reinoud */
160 1.1 reinoud
161 1.1 reinoud void
162 1.1 reinoud vidcvideo_printdetails(void)
163 1.1 reinoud {
164 1.1 reinoud printf(": refclk=%dMHz %dKB %s ", (vidc_fref / 1000000),
165 1.1 reinoud videomemory.vidm_size / 1024,
166 1.1 reinoud (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM) ? "VRAM" : "DRAM");
167 1.1 reinoud }
168 1.1 reinoud
169 1.9 reinoud
170 1.1 reinoud /*
171 1.1 reinoud * Common functions to directly access VIDC registers
172 1.1 reinoud */
173 1.1 reinoud int
174 1.21 bjh21 vidcvideo_write(u_int reg, int value)
175 1.1 reinoud {
176 1.1 reinoud int counter;
177 1.1 reinoud
178 1.1 reinoud int *current;
179 1.1 reinoud int *tab;
180 1.1 reinoud
181 1.1 reinoud tab = (int *)&vidc_lookup;
182 1.1 reinoud current = (int *)vidc_current;
183 1.1 reinoud
184 1.1 reinoud
185 1.1 reinoud /*
186 1.1 reinoud * OK, the VIDC_PALETTE register is handled differently
187 1.1 reinoud * to the others on the VIDC, so take that into account here
188 1.1 reinoud */
189 1.21 bjh21 if (reg == VIDC_PALREG) {
190 1.1 reinoud vidc_current->palreg = 0;
191 1.1 reinoud WriteWord(vidc_base, reg | value);
192 1.1 reinoud return 0;
193 1.1 reinoud }
194 1.1 reinoud
195 1.21 bjh21 if (reg == VIDC_PALETTE) {
196 1.1 reinoud WriteWord(vidc_base, reg | value);
197 1.1 reinoud vidc_current->palette[vidc_current->palreg] = value;
198 1.1 reinoud vidc_current->palreg++;
199 1.1 reinoud vidc_current->palreg = vidc_current->palreg & 0xff;
200 1.1 reinoud return 0;
201 1.1 reinoud }
202 1.1 reinoud
203 1.1 reinoud /*
204 1.1 reinoud * Undefine SAFER if you wish to speed things up (a little)
205 1.1 reinoud * although this means the function will assume things abou
206 1.1 reinoud * the structure of vidc_state. i.e. the first 256 words are
207 1.1 reinoud * the palette array
208 1.1 reinoud */
209 1.1 reinoud
210 1.1 reinoud #define SAFER
211 1.1 reinoud
212 1.1 reinoud #ifdef SAFER
213 1.1 reinoud #define INITVALUE 0
214 1.1 reinoud #else
215 1.1 reinoud #define INITVALUE 256
216 1.1 reinoud #endif
217 1.1 reinoud
218 1.21 bjh21 for (counter = INITVALUE;
219 1.21 bjh21 counter <= sizeof(struct vidc_state);
220 1.21 bjh21 counter++) {
221 1.21 bjh21 if (reg == tab[counter]) {
222 1.1 reinoud WriteWord ( vidc_base, reg | value );
223 1.1 reinoud current[counter] = value;
224 1.1 reinoud return 0;
225 1.1 reinoud }
226 1.1 reinoud }
227 1.1 reinoud return -1;
228 1.1 reinoud }
229 1.1 reinoud
230 1.1 reinoud
231 1.1 reinoud void
232 1.21 bjh21 vidcvideo_setpalette(struct vidc_state *vidc)
233 1.1 reinoud {
234 1.1 reinoud int counter = 0;
235 1.1 reinoud
236 1.1 reinoud vidcvideo_write(VIDC_PALREG, 0x00000000);
237 1.15 reinoud for (counter = 0; counter <= 255; counter++)
238 1.1 reinoud vidcvideo_write(VIDC_PALETTE, vidc->palette[counter]);
239 1.1 reinoud }
240 1.1 reinoud
241 1.1 reinoud
242 1.1 reinoud void
243 1.21 bjh21 vidcvideo_setstate(struct vidc_state *vidc)
244 1.1 reinoud {
245 1.9 reinoud vidcvideo_write ( VIDC_PALREG, vidc->palreg );
246 1.1 reinoud vidcvideo_write ( VIDC_BCOL, vidc->bcol );
247 1.1 reinoud vidcvideo_write ( VIDC_CP1, vidc->cp1 );
248 1.1 reinoud vidcvideo_write ( VIDC_CP2, vidc->cp2 );
249 1.1 reinoud vidcvideo_write ( VIDC_CP3, vidc->cp3 );
250 1.1 reinoud vidcvideo_write ( VIDC_HCR, vidc->hcr );
251 1.1 reinoud vidcvideo_write ( VIDC_HSWR, vidc->hswr );
252 1.1 reinoud vidcvideo_write ( VIDC_HBSR, vidc->hbsr );
253 1.1 reinoud vidcvideo_write ( VIDC_HDSR, vidc->hdsr );
254 1.1 reinoud vidcvideo_write ( VIDC_HDER, vidc->hder );
255 1.1 reinoud vidcvideo_write ( VIDC_HBER, vidc->hber );
256 1.1 reinoud vidcvideo_write ( VIDC_HCSR, vidc->hcsr );
257 1.1 reinoud vidcvideo_write ( VIDC_HIR, vidc->hir );
258 1.1 reinoud vidcvideo_write ( VIDC_VCR, vidc->vcr );
259 1.1 reinoud vidcvideo_write ( VIDC_VSWR, vidc->vswr );
260 1.1 reinoud vidcvideo_write ( VIDC_VBSR, vidc->vbsr );
261 1.1 reinoud vidcvideo_write ( VIDC_VDSR, vidc->vdsr );
262 1.1 reinoud vidcvideo_write ( VIDC_VDER, vidc->vder );
263 1.1 reinoud vidcvideo_write ( VIDC_VBER, vidc->vber );
264 1.1 reinoud vidcvideo_write ( VIDC_VCSR, vidc->vcsr );
265 1.1 reinoud vidcvideo_write ( VIDC_VCER, vidc->vcer );
266 1.1 reinoud /*
267 1.1 reinoud * Right, dunno what to set these to yet, but let's keep RiscOS's
268 1.1 reinoud * ones for now, until the time is right to finish this code
269 1.1 reinoud */
270 1.1 reinoud
271 1.1 reinoud /* vidcvideo_write ( VIDC_EREG, vidc->ereg ); */
272 1.1 reinoud /* vidcvideo_write ( VIDC_FSYNREG, vidc->fsynreg ); */
273 1.1 reinoud /* vidcvideo_write ( VIDC_CONREG, vidc->conreg ); */
274 1.1 reinoud /* vidcvideo_write ( VIDC_DCTL, vidc->dctl ); */
275 1.1 reinoud
276 1.15 reinoud vidcvideo_setpalette(vidc);
277 1.1 reinoud }
278 1.1 reinoud
279 1.1 reinoud
280 1.1 reinoud void
281 1.21 bjh21 vidcvideo_getstate(struct vidc_state *vidc)
282 1.1 reinoud {
283 1.21 bjh21
284 1.1 reinoud *vidc = *vidc_current;
285 1.1 reinoud }
286 1.1 reinoud
287 1.1 reinoud
288 1.1 reinoud void
289 1.21 bjh21 vidcvideo_getmode(struct vidc_mode *mode)
290 1.1 reinoud {
291 1.21 bjh21
292 1.25 bjh21 *mode = vidc_currentmode;
293 1.1 reinoud }
294 1.1 reinoud
295 1.1 reinoud
296 1.1 reinoud static int
297 1.1 reinoud vidcvideo_coldinit(void)
298 1.1 reinoud {
299 1.26 bjh21 struct videomode const *modes;
300 1.27 bjh21 unsigned besterror;
301 1.26 bjh21 int count;
302 1.23 bjh21 int i;
303 1.24 bjh21 unsigned framerate;
304 1.1 reinoud
305 1.1 reinoud /* Blank out the cursor */
306 1.1 reinoud
307 1.1 reinoud vidcvideo_write(VIDC_CP1, 0x0);
308 1.1 reinoud vidcvideo_write(VIDC_CP2, 0x0);
309 1.1 reinoud vidcvideo_write(VIDC_CP3, 0x0);
310 1.1 reinoud
311 1.1 reinoud dispbase = vmem_base = dispstart = videomemory.vidm_vbase;
312 1.1 reinoud phys_base = videomemory.vidm_pbase;
313 1.1 reinoud
314 1.1 reinoud /* Nut - should be using videomemory.vidm_size - mark */
315 1.1 reinoud if (videomemory.vidm_type == VIDEOMEM_TYPE_DRAM) {
316 1.1 reinoud dispsize = videomemory.vidm_size;
317 1.1 reinoud transfersize = 16;
318 1.1 reinoud } else {
319 1.16 thorpej dispsize = bootconfig.vram[0].pages * PAGE_SIZE;
320 1.1 reinoud transfersize = dispsize >> 10;
321 1.21 bjh21 }
322 1.1 reinoud
323 1.1 reinoud ptov = dispbase - phys_base;
324 1.1 reinoud
325 1.1 reinoud dispend = dispstart+dispsize;
326 1.1 reinoud
327 1.26 bjh21 if (vidc_videomode_count > 0) {
328 1.26 bjh21 modes = vidc_videomode_list;
329 1.26 bjh21 count = vidc_videomode_count;
330 1.26 bjh21 } else {
331 1.26 bjh21 modes = videomode_list;
332 1.26 bjh21 count = videomode_count;
333 1.26 bjh21 }
334 1.26 bjh21
335 1.1 reinoud /* try to find the current mode from the bootloader in my table */
336 1.26 bjh21 vidc_currentmode.timings = modes[0];
337 1.27 bjh21 besterror = 1000000;
338 1.26 bjh21 for (i = 0; i < count; i++) {
339 1.24 bjh21 /*
340 1.24 bjh21 * We jump through a few hoops here to ensure that we
341 1.24 bjh21 * round roughly to the nearest integer without too
342 1.24 bjh21 * much danger of overflow.
343 1.24 bjh21 */
344 1.26 bjh21 framerate = (modes[i].dot_clock * 1000 /
345 1.26 bjh21 modes[i].htotal * 2 / modes[i].vtotal + 1) / 2;
346 1.26 bjh21 if (modes[i].hdisplay == bootconfig.width + 1
347 1.26 bjh21 && modes[i].vdisplay == bootconfig.height + 1
348 1.27 bjh21 && abs(framerate - bootconfig.framerate) < besterror) {
349 1.26 bjh21 vidc_currentmode.timings = modes[i];
350 1.27 bjh21 besterror = abs(framerate - bootconfig.framerate);
351 1.1 reinoud }
352 1.1 reinoud }
353 1.1 reinoud
354 1.25 bjh21 vidc_currentmode.log2_bpp = bootconfig.log2_bpp;
355 1.1 reinoud
356 1.1 reinoud dispstart = dispbase;
357 1.1 reinoud dispend = dispstart+dispsize;
358 1.1 reinoud
359 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
360 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
361 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
362 1.1 reinoud return 0;
363 1.1 reinoud }
364 1.1 reinoud
365 1.1 reinoud
366 1.1 reinoud /* simple function to abstract vidc variables ; returns virt start address of screen */
367 1.1 reinoud /* XXX asumption that video memory is mapped in twice */
368 1.21 bjh21 void *vidcvideo_hwscroll(int bytes)
369 1.21 bjh21 {
370 1.21 bjh21
371 1.1 reinoud dispstart += bytes;
372 1.1 reinoud if (dispstart >= dispbase + dispsize) dispstart -= dispsize;
373 1.1 reinoud if (dispstart < dispbase) dispstart += dispsize;
374 1.1 reinoud dispend = dispstart+dispsize;
375 1.1 reinoud
376 1.1 reinoud /* return the start of the bit map of the screen (left top) */
377 1.21 bjh21 return (void *)dispstart;
378 1.1 reinoud }
379 1.1 reinoud
380 1.1 reinoud
381 1.1 reinoud /* reset the HW scroll to be at the start for the benefit of f.e. X */
382 1.21 bjh21 void *vidcvideo_hwscroll_reset(void)
383 1.21 bjh21 {
384 1.21 bjh21 void *cookie = (void *)dispstart;
385 1.1 reinoud
386 1.1 reinoud dispstart = dispbase;
387 1.1 reinoud dispend = dispstart + dispsize;
388 1.1 reinoud return cookie;
389 1.1 reinoud }
390 1.1 reinoud
391 1.1 reinoud
392 1.1 reinoud /* put HW scroll back to where it was */
393 1.21 bjh21 void *vidcvideo_hwscroll_back(void *cookie)
394 1.21 bjh21 {
395 1.21 bjh21
396 1.21 bjh21 dispstart = (int)cookie;
397 1.1 reinoud dispend = dispstart + dispsize;
398 1.1 reinoud return cookie;
399 1.1 reinoud }
400 1.1 reinoud
401 1.1 reinoud
402 1.9 reinoud /* this function is to be called perferably at vsync */
403 1.21 bjh21 void vidcvideo_progr_scroll(void)
404 1.21 bjh21 {
405 1.21 bjh21
406 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
407 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
408 1.1 reinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
409 1.1 reinoud }
410 1.1 reinoud
411 1.1 reinoud
412 1.1 reinoud /*
413 1.1 reinoud * Select a new mode by reprogramming the VIDC chip
414 1.1 reinoud * XXX this part is known not to work for 32bpp
415 1.1 reinoud */
416 1.1 reinoud
417 1.1 reinoud struct vidc_mode newmode;
418 1.1 reinoud
419 1.1 reinoud static const int bpp_mask_table[] = {
420 1.1 reinoud 0, /* 1bpp */
421 1.1 reinoud 1, /* 2bpp */
422 1.1 reinoud 2, /* 4bpp */
423 1.1 reinoud 3, /* 8bpp */
424 1.1 reinoud 4, /* 16bpp */
425 1.1 reinoud 6 /* 32bpp */
426 1.1 reinoud };
427 1.1 reinoud
428 1.1 reinoud
429 1.1 reinoud void
430 1.1 reinoud vidcvideo_setmode(struct vidc_mode *mode)
431 1.1 reinoud {
432 1.23 bjh21 struct videomode *vm;
433 1.1 reinoud int bpp_mask;
434 1.1 reinoud int ereg;
435 1.5 bjh21 int best_r, best_v;
436 1.5 bjh21 int least_error;
437 1.5 bjh21 int r, v, f;
438 1.1 reinoud
439 1.1 reinoud /*
440 1.21 bjh21 * Find out what bit mask we need to or with the vidc20
441 1.21 bjh21 * control register in order to generate the desired number of
442 1.21 bjh21 * bits per pixel. log_bpp is log base 2 of the number of
443 1.21 bjh21 * bits per pixel.
444 1.1 reinoud */
445 1.1 reinoud
446 1.1 reinoud bpp_mask = bpp_mask_table[mode->log2_bpp];
447 1.1 reinoud
448 1.25 bjh21 vidc_currentmode = *mode;
449 1.25 bjh21 vm = &vidc_currentmode.timings;
450 1.1 reinoud
451 1.5 bjh21 least_error = INT_MAX;
452 1.5 bjh21 best_r = 0; best_v = 0;
453 1.5 bjh21
454 1.5 bjh21 for (v = 63; v > 0; v--) {
455 1.5 bjh21 for (r = 63; r > 0; r--) {
456 1.5 bjh21 f = ((v * vidc_fref) /1000) / r;
457 1.23 bjh21 if (least_error >= abs(f - vm->dot_clock)) {
458 1.23 bjh21 least_error = abs(f - vm->dot_clock);
459 1.5 bjh21 best_r = r;
460 1.5 bjh21 best_v = v;
461 1.1 reinoud }
462 1.1 reinoud }
463 1.5 bjh21 }
464 1.1 reinoud
465 1.5 bjh21 if (best_r > 63) best_r=63;
466 1.5 bjh21 if (best_v > 63) best_v=63;
467 1.5 bjh21 if (best_r < 1) best_r= 1;
468 1.5 bjh21 if (best_v < 1) best_v= 1;
469 1.1 reinoud
470 1.2 reinoud vidcvideo_write(VIDC_FSYNREG, (best_v-1)<<8 | (best_r-1)<<0);
471 1.1 reinoud
472 1.23 bjh21 /*
473 1.23 bjh21 * The translation from struct videomode to VIDC timings is made
474 1.23 bjh21 * fun by the fact that the VIDC counts from the start of the sync
475 1.23 bjh21 * pulse while struct videomode counts from the start of the display.
476 1.23 bjh21 */
477 1.23 bjh21 vidcvideo_write(VIDC_HSWR, (vm->hsync_end - vm->hsync_start - 8) & ~1);
478 1.23 bjh21 vidcvideo_write(VIDC_HBSR, (vm->htotal - vm->hsync_start - 12) & ~1);
479 1.23 bjh21 vidcvideo_write(VIDC_HDSR, (vm->htotal - vm->hsync_start - 18) & ~1);
480 1.23 bjh21 vidcvideo_write(VIDC_HDER,
481 1.23 bjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 18) & ~1);
482 1.23 bjh21 vidcvideo_write(VIDC_HBER,
483 1.23 bjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 12) & ~1);
484 1.23 bjh21 vidcvideo_write(VIDC_HCR, (vm->htotal - 8) & ~3);
485 1.23 bjh21
486 1.23 bjh21 vidcvideo_write(VIDC_VSWR, vm->vsync_end - vm->vsync_start - 1);
487 1.23 bjh21 vidcvideo_write(VIDC_VBSR, vm->vtotal - vm->vsync_start - 1);
488 1.23 bjh21 vidcvideo_write(VIDC_VDSR, vm->vtotal - vm->vsync_start - 1);
489 1.23 bjh21 vidcvideo_write(VIDC_VDER,
490 1.23 bjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1);
491 1.23 bjh21 vidcvideo_write(VIDC_VBER,
492 1.23 bjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1);
493 1.23 bjh21 /* XXX VIDC20 data sheet say to subtract 2 */
494 1.23 bjh21 vidcvideo_write(VIDC_VCR, vm->vtotal - 1);
495 1.23 bjh21
496 1.23 bjh21 IOMD_WRITE_WORD(IOMD_FSIZE, vm->vdisplay - 1);
497 1.1 reinoud
498 1.1 reinoud if (dispsize <= 1024*1024)
499 1.23 bjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 1<<16 | 1<<12);
500 1.1 reinoud else
501 1.23 bjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 3<<16 | 1<<12);
502 1.1 reinoud
503 1.1 reinoud ereg = 1<<12;
504 1.23 bjh21 if (vm->flags & VID_NHSYNC)
505 1.1 reinoud ereg |= 1<<16;
506 1.23 bjh21 if (vm->flags & VID_NVSYNC)
507 1.1 reinoud ereg |= 1<<18;
508 1.1 reinoud vidcvideo_write(VIDC_EREG, ereg);
509 1.1 reinoud if (dispsize > 1024*1024) {
510 1.23 bjh21 if (vm->hdisplay >= 800)
511 1.1 reinoud vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
512 1.1 reinoud else
513 1.1 reinoud vidcvideo_write(VIDC_CONREG, 6<<8 | bpp_mask<<5);
514 1.1 reinoud } else {
515 1.1 reinoud vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
516 1.1 reinoud }
517 1.1 reinoud }
518 1.1 reinoud
519 1.1 reinoud
520 1.7 bjh21 #if 0
521 1.1 reinoud /* not used for now */
522 1.1 reinoud void
523 1.1 reinoud vidcvideo_set_display_base(base)
524 1.1 reinoud u_int base;
525 1.1 reinoud {
526 1.1 reinoud dispstart = dispstart-dispbase + base;
527 1.1 reinoud dispbase = vmem_base = base;
528 1.1 reinoud dispend = base + dispsize;
529 1.1 reinoud ptov = dispbase - phys_base;
530 1.1 reinoud }
531 1.7 bjh21 #endif
532 1.1 reinoud
533 1.1 reinoud
534 1.1 reinoud /*
535 1.1 reinoud * Main initialisation routine for now
536 1.1 reinoud */
537 1.1 reinoud
538 1.1 reinoud static int cursor_init = 0;
539 1.1 reinoud
540 1.1 reinoud int
541 1.1 reinoud vidcvideo_init(void)
542 1.1 reinoud {
543 1.1 reinoud vidcvideo_coldinit();
544 1.1 reinoud if (cold_init && (cursor_init == 0))
545 1.1 reinoud /* vidcvideo_flash_go() */;
546 1.1 reinoud
547 1.1 reinoud /* setting a mode goes wrong in 32 bpp ... 8 and 16 seem OK */
548 1.25 bjh21 vidcvideo_setmode(&vidc_currentmode);
549 1.1 reinoud vidcvideo_blank(0); /* display on */
550 1.1 reinoud
551 1.12 bjh21 vidcvideo_stdpalette();
552 1.1 reinoud
553 1.1 reinoud if (cold_init == 0) {
554 1.1 reinoud vidcvideo_write(VIDC_CP1, 0x0);
555 1.1 reinoud vidcvideo_write(VIDC_CP2, 0x0);
556 1.1 reinoud vidcvideo_write(VIDC_CP3, 0x0);
557 1.21 bjh21 } else
558 1.1 reinoud vidcvideo_cursor_init(CURSOR_MAX_WIDTH, CURSOR_MAX_HEIGHT);
559 1.1 reinoud
560 1.21 bjh21 cold_init = 1;
561 1.1 reinoud return 0;
562 1.1 reinoud }
563 1.1 reinoud
564 1.1 reinoud
565 1.1 reinoud /* reinitialise the vidcvideo */
566 1.1 reinoud void
567 1.1 reinoud vidcvideo_reinit()
568 1.1 reinoud {
569 1.21 bjh21
570 1.1 reinoud vidcvideo_coldinit();
571 1.25 bjh21 vidcvideo_setmode(&vidc_currentmode);
572 1.1 reinoud }
573 1.1 reinoud
574 1.1 reinoud
575 1.1 reinoud int
576 1.1 reinoud vidcvideo_cursor_init(int width, int height)
577 1.1 reinoud {
578 1.1 reinoud static char *cursor_data = NULL;
579 1.1 reinoud int counter;
580 1.1 reinoud int line;
581 1.1 reinoud paddr_t pa;
582 1.1 reinoud
583 1.1 reinoud cursor_width = width;
584 1.1 reinoud cursor_height = height;
585 1.1 reinoud
586 1.1 reinoud if (!cursor_data) {
587 1.1 reinoud /* Allocate cursor memory first time round */
588 1.19 yamt cursor_data = (char *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
589 1.19 yamt UVM_KMF_WIRED | UVM_KMF_ZERO);
590 1.1 reinoud if (!cursor_data)
591 1.14 provos panic("Cannot allocate memory for hardware cursor");
592 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_data, &pa);
593 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT, pa);
594 1.1 reinoud }
595 1.1 reinoud
596 1.1 reinoud /* Blank the cursor while initialising it's sprite */
597 1.1 reinoud
598 1.1 reinoud vidcvideo_write ( VIDC_CP1, 0x0 );
599 1.1 reinoud vidcvideo_write ( VIDC_CP2, 0x0 );
600 1.1 reinoud vidcvideo_write ( VIDC_CP3, 0x0 );
601 1.1 reinoud
602 1.1 reinoud cursor_normal = cursor_data;
603 1.1 reinoud cursor_transparent = cursor_data + (height * width);
604 1.1 reinoud
605 1.1 reinoud cursor_transparent += 32; /* ALIGN */
606 1.1 reinoud cursor_transparent = (char *)((int)cursor_transparent & (~31) );
607 1.1 reinoud
608 1.21 bjh21 for ( line = 0; line<height; ++line ) {
609 1.21 bjh21 for ( counter=0; counter<width/4;counter++ )
610 1.21 bjh21 cursor_normal[line * width + counter]=0x55; /* why 0x55 ? */
611 1.21 bjh21 for ( ; counter<8; counter++ )
612 1.21 bjh21 cursor_normal[line * width + counter]=0;
613 1.1 reinoud }
614 1.1 reinoud
615 1.21 bjh21 for ( line = 0; line<height; ++line ) {
616 1.21 bjh21 for ( counter=0; counter<width/4;counter++ )
617 1.21 bjh21 cursor_transparent[line * width + counter]=0x00;
618 1.21 bjh21 for ( ; counter<8; counter++ )
619 1.21 bjh21 cursor_transparent[line * width + counter]=0;
620 1.1 reinoud }
621 1.1 reinoud
622 1.1 reinoud
623 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_normal,
624 1.17 matt (void *)&p_cursor_normal);
625 1.1 reinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_transparent,
626 1.17 matt (void *)&p_cursor_transparent);
627 1.1 reinoud
628 1.21 bjh21 memset(cursor_normal, 0x55, width*height); /* white? */
629 1.21 bjh21 memset(cursor_transparent, 0x00, width*height);/* to see the diffence */
630 1.1 reinoud
631 1.1 reinoud /* Ok, now program the cursor; should be blank */
632 1.1 reinoud vidcvideo_enablecursor(0);
633 1.1 reinoud
634 1.1 reinoud return 0;
635 1.1 reinoud }
636 1.1 reinoud
637 1.1 reinoud
638 1.1 reinoud void
639 1.21 bjh21 vidcvideo_updatecursor(int xcur, int ycur)
640 1.1 reinoud {
641 1.25 bjh21 int frontporch = vidc_currentmode.timings.htotal -
642 1.25 bjh21 vidc_currentmode.timings.hsync_start;
643 1.25 bjh21 int topporch = vidc_currentmode.timings.vtotal -
644 1.25 bjh21 vidc_currentmode.timings.vsync_start;
645 1.1 reinoud
646 1.1 reinoud vidcvideo_write(VIDC_HCSR, frontporch -17 + xcur);
647 1.21 bjh21 vidcvideo_write(VIDC_VCSR, topporch -2 + (ycur+1)-2 + 3 -
648 1.21 bjh21 cursor_height);
649 1.1 reinoud vidcvideo_write(VIDC_VCER, topporch -2 + (ycur+3)+2 + 3 );
650 1.1 reinoud }
651 1.1 reinoud
652 1.1 reinoud
653 1.1 reinoud void
654 1.21 bjh21 vidcvideo_enablecursor(int on)
655 1.1 reinoud {
656 1.21 bjh21
657 1.21 bjh21 if (on)
658 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_normal);
659 1.21 bjh21 else
660 1.1 reinoud IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_transparent);
661 1.1 reinoud vidcvideo_write ( VIDC_CP1, 0xffffff ); /* enable */
662 1.1 reinoud }
663 1.1 reinoud
664 1.11 bjh21
665 1.12 bjh21 void
666 1.12 bjh21 vidcvideo_stdpalette()
667 1.11 bjh21 {
668 1.12 bjh21 int i;
669 1.11 bjh21
670 1.25 bjh21 switch (vidc_currentmode.log2_bpp) {
671 1.12 bjh21 case 0: /* 1 bpp */
672 1.12 bjh21 case 1: /* 2 bpp */
673 1.12 bjh21 case 2: /* 4 bpp */
674 1.12 bjh21 case 3: /* 8 bpp */
675 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
676 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 0));
677 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 0));
678 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 0));
679 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 0));
680 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 255));
681 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 255));
682 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 255));
683 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
684 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 128));
685 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 128));
686 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 255, 128));
687 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 128));
688 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 255));
689 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 255));
690 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
691 1.12 bjh21 break;
692 1.12 bjh21 case 4: /* 16 bpp */
693 1.12 bjh21 /*
694 1.12 bjh21 * The use of the palette in 16-bit modes is quite
695 1.12 bjh21 * fun. Comments in linux/drivers/video/acornfb.c
696 1.12 bjh21 * imply that it goes something like this:
697 1.12 bjh21 *
698 1.12 bjh21 * red = LUT[pixel[7:0]].red
699 1.12 bjh21 * green = LUT[pixel[11:4]].green
700 1.12 bjh21 * blue = LUT[pixel[15:8]].blue
701 1.12 bjh21 *
702 1.13 bjh21 * We use 6:5:5 R:G:B cos that's what Xarm32VIDC wants.
703 1.12 bjh21 */
704 1.13 bjh21 #define RBITS 6
705 1.13 bjh21 #define GBITS 5
706 1.13 bjh21 #define BBITS 5
707 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
708 1.12 bjh21 for (i = 0; i < 256; i++) {
709 1.13 bjh21 int r, g, b;
710 1.12 bjh21
711 1.13 bjh21 r = i & ((1 << RBITS) - 1);
712 1.13 bjh21 g = (i >> (RBITS - 4)) & ((1 << GBITS) - 1);
713 1.13 bjh21 b = (i >> (RBITS + GBITS - 8)) & ((1 << BBITS) - 1);
714 1.12 bjh21 vidcvideo_write(VIDC_PALETTE,
715 1.13 bjh21 VIDC_COL(r << (8 - RBITS) | r >> (2 * RBITS - 8),
716 1.13 bjh21 g << (8 - GBITS) | g >> (2 * GBITS - 8),
717 1.13 bjh21 b << (8 - BBITS) | b >> (2 * BBITS - 8)));
718 1.12 bjh21 }
719 1.12 bjh21 break;
720 1.12 bjh21 case 5: /* 32 bpp */
721 1.12 bjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
722 1.12 bjh21 for (i = 0; i < 256; i++)
723 1.12 bjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(i, i, i));
724 1.12 bjh21 break;
725 1.12 bjh21 }
726 1.11 bjh21 }
727 1.1 reinoud
728 1.1 reinoud int
729 1.21 bjh21 vidcvideo_blank(int video_off)
730 1.1 reinoud {
731 1.1 reinoud int ereg;
732 1.1 reinoud
733 1.1 reinoud ereg = 1<<12;
734 1.25 bjh21 if (vidc_currentmode.timings.flags & VID_NHSYNC)
735 1.1 reinoud ereg |= 1<<16;
736 1.25 bjh21 if (vidc_currentmode.timings.flags & VID_NVSYNC)
737 1.1 reinoud ereg |= 1<<18;
738 1.1 reinoud
739 1.21 bjh21 if (!video_off)
740 1.1 reinoud vidcvideo_write(VIDC_EREG, ereg);
741 1.21 bjh21 else
742 1.1 reinoud vidcvideo_write(VIDC_EREG, 0);
743 1.1 reinoud return 0;
744 1.1 reinoud }
745 1.1 reinoud
746 1.1 reinoud /* end of vidc20config.c */
747