1*7b6cdeb9Sandvar /* $NetBSD: vidc20config.c,v 1.37 2024/05/18 19:04:45 andvar Exp $ */
27d4a1addSreinoud
37d4a1addSreinoud /*
47d4a1addSreinoud * Copyright (c) 2001 Reinoud Zandijk
57d4a1addSreinoud * Copyright (c) 1996 Mark Brinicombe
67d4a1addSreinoud * Copyright (c) 1996 Robert Black
77d4a1addSreinoud * Copyright (c) 1994-1995 Melvyn Tang-Richardson
87d4a1addSreinoud * Copyright (c) 1994-1995 RiscBSD kernel team
97d4a1addSreinoud * All rights reserved.
107d4a1addSreinoud *
117d4a1addSreinoud * Redistribution and use in source and binary forms, with or without
127d4a1addSreinoud * modification, are permitted provided that the following conditions
137d4a1addSreinoud * are met:
147d4a1addSreinoud * 1. Redistributions of source code must retain the above copyright
157d4a1addSreinoud * notice, this list of conditions and the following disclaimer.
167d4a1addSreinoud * 2. Redistributions in binary form must reproduce the above copyright
177d4a1addSreinoud * notice, this list of conditions and the following disclaimer in the
187d4a1addSreinoud * documentation and/or other materials provided with the distribution.
197d4a1addSreinoud * 3. All advertising materials mentioning features or use of this software
207d4a1addSreinoud * must display the following acknowledgement:
217d4a1addSreinoud * This product includes software developed by the RiscBSD kernel team
227d4a1addSreinoud * 4. The name of the company nor the name of the author may be used to
237d4a1addSreinoud * endorse or promote products derived from this software without specific
247d4a1addSreinoud * prior written permission.
257d4a1addSreinoud *
267d4a1addSreinoud * THIS SOFTWARE IS PROVIDED BY THE RISCBSD TEAM ``AS IS'' AND ANY EXPRESS
277d4a1addSreinoud * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
287d4a1addSreinoud * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297d4a1addSreinoud * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
307d4a1addSreinoud * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
317d4a1addSreinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
327d4a1addSreinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
337d4a1addSreinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
347d4a1addSreinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
357d4a1addSreinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
367d4a1addSreinoud * THE POSSIBILITY OF SUCH DAMAGE.
377d4a1addSreinoud *
387d4a1addSreinoud * NetBSD kernel project
397d4a1addSreinoud *
407d4a1addSreinoud * vidcvideo.c
417d4a1addSreinoud *
427d4a1addSreinoud * This file is the lower basis of the wscons driver for VIDC based ARM machines.
437d4a1addSreinoud * It features the initialisation and all VIDC writing and keeps in internal state
447d4a1addSreinoud * copy.
459f4a9600Sandvar * Its currently set up as a library file and not as a device; it could be named
467d4a1addSreinoud * vidcvideo0 eventually.
477d4a1addSreinoud */
487d4a1addSreinoud
497d4a1addSreinoud #include <sys/cdefs.h>
50c1f8e3aaSbjh21
51*7b6cdeb9Sandvar __KERNEL_RCSID(0, "$NetBSD: vidc20config.c,v 1.37 2024/05/18 19:04:45 andvar Exp $");
52c1f8e3aaSbjh21
537d4a1addSreinoud #include <sys/types.h>
547d4a1addSreinoud #include <sys/param.h>
557d4a1addSreinoud #include <arm/iomd/vidc.h>
567d4a1addSreinoud #include <machine/bootconfig.h>
5728466919Sthorpej #include <machine/intr.h>
587d4a1addSreinoud
597d4a1addSreinoud #include <sys/systm.h>
607d4a1addSreinoud #include <sys/device.h>
617d4a1addSreinoud #include <uvm/uvm_extern.h>
627d4a1addSreinoud
637d4a1addSreinoud #include <arm/iomd/iomdreg.h>
647d4a1addSreinoud #include <arm/iomd/iomdvar.h>
657d4a1addSreinoud #include <arm/iomd/vidc20config.h>
667d4a1addSreinoud
6701e40549Sskrll #define WriteWord(a, b) \
6801e40549Sskrll *((volatile unsigned int *)(a)) = (b)
6901e40549Sskrll
7001e40549Sskrll #define ReadWord(a) \
7101e40549Sskrll (*((volatile unsigned int *)(a)))
721a19ddabSreinoud
737d4a1addSreinoud /*
747d4a1addSreinoud * A structure containing ALL the information required to restore
757d4a1addSreinoud * the VIDC20 to any given state. ALL vidc transactions should
767d4a1addSreinoud * go through these procedures, which record the vidc's state.
777d4a1addSreinoud * it may be an idea to set the permissions of the vidc base address
787d4a1addSreinoud * so we get a fault, so the fault routine can record the state but
797d4a1addSreinoud * I guess that's not really necessary for the time being, since we
807d4a1addSreinoud * can make the kernel more secure later on. Also, it is possible
817d4a1addSreinoud * to write a routine to allow 'reading' of the vidc registers.
827d4a1addSreinoud */
837d4a1addSreinoud
847d4a1addSreinoud static struct vidc_state vidc_lookup = {
857d4a1addSreinoud { 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,
867d4a1addSreinoud 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,
877d4a1addSreinoud 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,
887d4a1addSreinoud 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,
897d4a1addSreinoud 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,
907d4a1addSreinoud 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,
917d4a1addSreinoud 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,
927d4a1addSreinoud 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
937d4a1addSreinoud },
947d4a1addSreinoud
957d4a1addSreinoud VIDC_PALREG,
967d4a1addSreinoud VIDC_BCOL,
977d4a1addSreinoud VIDC_CP1 ,
987d4a1addSreinoud VIDC_CP2,
997d4a1addSreinoud VIDC_CP3,
1007d4a1addSreinoud VIDC_HCR,
1017d4a1addSreinoud VIDC_HSWR,
1027d4a1addSreinoud VIDC_HBSR,
1037d4a1addSreinoud VIDC_HDSR,
1047d4a1addSreinoud VIDC_HDER,
1057d4a1addSreinoud VIDC_HBER,
1067d4a1addSreinoud VIDC_HCSR,
1077d4a1addSreinoud VIDC_HIR,
1087d4a1addSreinoud VIDC_VCR,
1097d4a1addSreinoud VIDC_VSWR,
1107d4a1addSreinoud VIDC_VBSR,
1117d4a1addSreinoud VIDC_VDSR,
1127d4a1addSreinoud VIDC_VDER,
1137d4a1addSreinoud VIDC_VBER,
1147d4a1addSreinoud VIDC_VCSR,
1157d4a1addSreinoud VIDC_VCER,
1167d4a1addSreinoud VIDC_EREG,
1177d4a1addSreinoud VIDC_FSYNREG,
1187d4a1addSreinoud VIDC_CONREG,
1197d4a1addSreinoud VIDC_DCTL
1207d4a1addSreinoud };
1217d4a1addSreinoud
1227d4a1addSreinoud struct vidc_state vidc_current[1];
1237d4a1addSreinoud
1247d4a1addSreinoud
1257d4a1addSreinoud /*
1267d4a1addSreinoud * XXX global display variables XXX ... should be a structure
1277d4a1addSreinoud */
1287d4a1addSreinoud static int cold_init = 0; /* flags initialisation */
1297d4a1addSreinoud extern videomemory_t videomemory;
1307d4a1addSreinoud
13172cec937Sbjh21 static struct vidc_mode vidc_currentmode;
1327d4a1addSreinoud
1337d4a1addSreinoud unsigned int dispstart;
1347d4a1addSreinoud unsigned int dispsize;
1357d4a1addSreinoud unsigned int dispbase;
1367d4a1addSreinoud unsigned int dispend;
1377d4a1addSreinoud unsigned int ptov;
1387d4a1addSreinoud unsigned int vmem_base;
1397d4a1addSreinoud unsigned int phys_base;
1407d4a1addSreinoud unsigned int transfersize;
1417d4a1addSreinoud
1427d4a1addSreinoud
1437d4a1addSreinoud /* cursor stuff */
1447d4a1addSreinoud char *cursor_normal;
1457d4a1addSreinoud char *cursor_transparent;
1467d4a1addSreinoud int p_cursor_normal;
1477d4a1addSreinoud int p_cursor_transparent;
1487d4a1addSreinoud int cursor_width;
1497d4a1addSreinoud int cursor_height;
1507d4a1addSreinoud
1517d4a1addSreinoud
1527d4a1addSreinoud /*
1537d4a1addSreinoud * VIDC mode definitions
1547d4a1addSreinoud * generated from RISC OS mode definition file by an `awk' script
1557d4a1addSreinoud */
15672cec937Sbjh21 extern const struct videomode vidc_videomode_list[];
15772cec937Sbjh21 extern const int vidc_videomode_count;
1587d4a1addSreinoud
1597d4a1addSreinoud
1607d4a1addSreinoud /*
1617d4a1addSreinoud * configuration printing
1627d4a1addSreinoud *
1637d4a1addSreinoud */
1647d4a1addSreinoud
1657d4a1addSreinoud void
vidcvideo_printdetails(void)1667d4a1addSreinoud vidcvideo_printdetails(void)
1677d4a1addSreinoud {
1687d4a1addSreinoud printf(": refclk=%dMHz %dKB %s ", (vidc_fref / 1000000),
1697d4a1addSreinoud videomemory.vidm_size / 1024,
1707d4a1addSreinoud (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM) ? "VRAM" : "DRAM");
1717d4a1addSreinoud }
1727d4a1addSreinoud
1731a19ddabSreinoud
1747d4a1addSreinoud /*
1757d4a1addSreinoud * Common functions to directly access VIDC registers
1767d4a1addSreinoud */
1777d4a1addSreinoud int
vidcvideo_write(u_int reg,int value)178758ec341Sbjh21 vidcvideo_write(u_int reg, int value)
1797d4a1addSreinoud {
1807d4a1addSreinoud int counter;
1817d4a1addSreinoud
1827d4a1addSreinoud int *current;
1837d4a1addSreinoud int *tab;
1847d4a1addSreinoud
1857d4a1addSreinoud tab = (int *)&vidc_lookup;
1867d4a1addSreinoud current = (int *)vidc_current;
1877d4a1addSreinoud
1887d4a1addSreinoud
1897d4a1addSreinoud /*
1907d4a1addSreinoud * OK, the VIDC_PALETTE register is handled differently
1917d4a1addSreinoud * to the others on the VIDC, so take that into account here
1927d4a1addSreinoud */
1937d4a1addSreinoud if (reg == VIDC_PALREG) {
1947d4a1addSreinoud vidc_current->palreg = 0;
1957d4a1addSreinoud WriteWord(vidc_base, reg | value);
1967d4a1addSreinoud return 0;
1977d4a1addSreinoud }
1987d4a1addSreinoud
1997d4a1addSreinoud if (reg == VIDC_PALETTE) {
2007d4a1addSreinoud WriteWord(vidc_base, reg | value);
2017d4a1addSreinoud vidc_current->palette[vidc_current->palreg] = value;
2027d4a1addSreinoud vidc_current->palreg++;
2037d4a1addSreinoud vidc_current->palreg = vidc_current->palreg & 0xff;
2047d4a1addSreinoud return 0;
2057d4a1addSreinoud }
2067d4a1addSreinoud
2077d4a1addSreinoud /*
2087d4a1addSreinoud * Undefine SAFER if you wish to speed things up (a little)
209*7b6cdeb9Sandvar * although this means the function will assume things about
2107d4a1addSreinoud * the structure of vidc_state. i.e. the first 256 words are
2117d4a1addSreinoud * the palette array
2127d4a1addSreinoud */
2137d4a1addSreinoud
2147d4a1addSreinoud #define SAFER
2157d4a1addSreinoud
2167d4a1addSreinoud #ifdef SAFER
2177d4a1addSreinoud #define INITVALUE 0
2187d4a1addSreinoud #else
2197d4a1addSreinoud #define INITVALUE 256
2207d4a1addSreinoud #endif
2217d4a1addSreinoud
222758ec341Sbjh21 for (counter = INITVALUE;
223758ec341Sbjh21 counter <= sizeof(struct vidc_state);
224758ec341Sbjh21 counter++) {
2257d4a1addSreinoud if (reg == tab[counter]) {
2267d4a1addSreinoud WriteWord ( vidc_base, reg | value );
2277d4a1addSreinoud current[counter] = value;
2287d4a1addSreinoud return 0;
2297d4a1addSreinoud }
2307d4a1addSreinoud }
2317d4a1addSreinoud return -1;
2327d4a1addSreinoud }
2337d4a1addSreinoud
2347d4a1addSreinoud
2357d4a1addSreinoud void
vidcvideo_setpalette(struct vidc_state * vidc)236758ec341Sbjh21 vidcvideo_setpalette(struct vidc_state *vidc)
2377d4a1addSreinoud {
2387d4a1addSreinoud int counter = 0;
2397d4a1addSreinoud
2407d4a1addSreinoud vidcvideo_write(VIDC_PALREG, 0x00000000);
2417ba11c51Sreinoud for (counter = 0; counter <= 255; counter++)
2427d4a1addSreinoud vidcvideo_write(VIDC_PALETTE, vidc->palette[counter]);
2437d4a1addSreinoud }
2447d4a1addSreinoud
2457d4a1addSreinoud
2467d4a1addSreinoud void
vidcvideo_setstate(struct vidc_state * vidc)247758ec341Sbjh21 vidcvideo_setstate(struct vidc_state *vidc)
2487d4a1addSreinoud {
2497d4a1addSreinoud vidcvideo_write ( VIDC_PALREG, vidc->palreg );
2507d4a1addSreinoud vidcvideo_write ( VIDC_BCOL, vidc->bcol );
2517d4a1addSreinoud vidcvideo_write ( VIDC_CP1, vidc->cp1 );
2527d4a1addSreinoud vidcvideo_write ( VIDC_CP2, vidc->cp2 );
2537d4a1addSreinoud vidcvideo_write ( VIDC_CP3, vidc->cp3 );
2547d4a1addSreinoud vidcvideo_write ( VIDC_HCR, vidc->hcr );
2557d4a1addSreinoud vidcvideo_write ( VIDC_HSWR, vidc->hswr );
2567d4a1addSreinoud vidcvideo_write ( VIDC_HBSR, vidc->hbsr );
2577d4a1addSreinoud vidcvideo_write ( VIDC_HDSR, vidc->hdsr );
2587d4a1addSreinoud vidcvideo_write ( VIDC_HDER, vidc->hder );
2597d4a1addSreinoud vidcvideo_write ( VIDC_HBER, vidc->hber );
2607d4a1addSreinoud vidcvideo_write ( VIDC_HCSR, vidc->hcsr );
2617d4a1addSreinoud vidcvideo_write ( VIDC_HIR, vidc->hir );
2627d4a1addSreinoud vidcvideo_write ( VIDC_VCR, vidc->vcr );
2637d4a1addSreinoud vidcvideo_write ( VIDC_VSWR, vidc->vswr );
2647d4a1addSreinoud vidcvideo_write ( VIDC_VBSR, vidc->vbsr );
2657d4a1addSreinoud vidcvideo_write ( VIDC_VDSR, vidc->vdsr );
2667d4a1addSreinoud vidcvideo_write ( VIDC_VDER, vidc->vder );
2677d4a1addSreinoud vidcvideo_write ( VIDC_VBER, vidc->vber );
2687d4a1addSreinoud vidcvideo_write ( VIDC_VCSR, vidc->vcsr );
2697d4a1addSreinoud vidcvideo_write ( VIDC_VCER, vidc->vcer );
2707d4a1addSreinoud /*
2717d4a1addSreinoud * Right, dunno what to set these to yet, but let's keep RiscOS's
2727d4a1addSreinoud * ones for now, until the time is right to finish this code
2737d4a1addSreinoud */
2747d4a1addSreinoud
2757d4a1addSreinoud /* vidcvideo_write ( VIDC_EREG, vidc->ereg ); */
2767d4a1addSreinoud /* vidcvideo_write ( VIDC_FSYNREG, vidc->fsynreg ); */
2777d4a1addSreinoud /* vidcvideo_write ( VIDC_CONREG, vidc->conreg ); */
2787d4a1addSreinoud /* vidcvideo_write ( VIDC_DCTL, vidc->dctl ); */
2797d4a1addSreinoud
2807ba11c51Sreinoud vidcvideo_setpalette(vidc);
2817d4a1addSreinoud }
2827d4a1addSreinoud
2837d4a1addSreinoud
2847d4a1addSreinoud void
vidcvideo_getstate(struct vidc_state * vidc)285758ec341Sbjh21 vidcvideo_getstate(struct vidc_state *vidc)
2867d4a1addSreinoud {
287758ec341Sbjh21
2887d4a1addSreinoud *vidc = *vidc_current;
2897d4a1addSreinoud }
2907d4a1addSreinoud
2917d4a1addSreinoud
2927d4a1addSreinoud void
vidcvideo_getmode(struct vidc_mode * mode)293758ec341Sbjh21 vidcvideo_getmode(struct vidc_mode *mode)
2947d4a1addSreinoud {
295758ec341Sbjh21
29672cec937Sbjh21 *mode = vidc_currentmode;
2977d4a1addSreinoud }
2987d4a1addSreinoud
2997d4a1addSreinoud
3007d4a1addSreinoud static int
vidcvideo_coldinit(void)3017d4a1addSreinoud vidcvideo_coldinit(void)
3027d4a1addSreinoud {
3039dc302feSbjh21 struct videomode const *modes;
30463030ccaSbjh21 unsigned besterror;
3059dc302feSbjh21 int count;
30628d9a9e3Sbjh21 int i;
3071e6fe5d0Sbjh21 unsigned framerate;
3087d4a1addSreinoud
3097d4a1addSreinoud /* Blank out the cursor */
3107d4a1addSreinoud
3117d4a1addSreinoud vidcvideo_write(VIDC_CP1, 0x0);
3127d4a1addSreinoud vidcvideo_write(VIDC_CP2, 0x0);
3137d4a1addSreinoud vidcvideo_write(VIDC_CP3, 0x0);
3147d4a1addSreinoud
3157d4a1addSreinoud dispbase = vmem_base = dispstart = videomemory.vidm_vbase;
3167d4a1addSreinoud phys_base = videomemory.vidm_pbase;
3177d4a1addSreinoud
3187d4a1addSreinoud /* Nut - should be using videomemory.vidm_size - mark */
3197d4a1addSreinoud if (videomemory.vidm_type == VIDEOMEM_TYPE_DRAM) {
3207d4a1addSreinoud dispsize = videomemory.vidm_size;
3217d4a1addSreinoud transfersize = 16;
3227d4a1addSreinoud } else {
32395281cabSthorpej dispsize = bootconfig.vram[0].pages * PAGE_SIZE;
3247d4a1addSreinoud transfersize = dispsize >> 10;
325758ec341Sbjh21 }
3267d4a1addSreinoud
3277d4a1addSreinoud ptov = dispbase - phys_base;
3287d4a1addSreinoud
3297d4a1addSreinoud dispend = dispstart+dispsize;
3307d4a1addSreinoud
3319dc302feSbjh21 if (vidc_videomode_count > 0) {
3329dc302feSbjh21 modes = vidc_videomode_list;
3339dc302feSbjh21 count = vidc_videomode_count;
3349dc302feSbjh21 } else {
3359dc302feSbjh21 modes = videomode_list;
3369dc302feSbjh21 count = videomode_count;
3379dc302feSbjh21 }
3389dc302feSbjh21
3397d4a1addSreinoud /* try to find the current mode from the bootloader in my table */
3409dc302feSbjh21 vidc_currentmode.timings = modes[0];
34163030ccaSbjh21 besterror = 1000000;
3429dc302feSbjh21 for (i = 0; i < count; i++) {
343a296cdc1Sbjh21 /* We don't support interlace or doublescan */
344a296cdc1Sbjh21 if (modes[i].flags & (VID_INTERLACE | VID_DBLSCAN))
345a296cdc1Sbjh21 continue;
3461e6fe5d0Sbjh21 /*
3471e6fe5d0Sbjh21 * We jump through a few hoops here to ensure that we
3481e6fe5d0Sbjh21 * round roughly to the nearest integer without too
3491e6fe5d0Sbjh21 * much danger of overflow.
3501e6fe5d0Sbjh21 */
3519dc302feSbjh21 framerate = (modes[i].dot_clock * 1000 /
3529dc302feSbjh21 modes[i].htotal * 2 / modes[i].vtotal + 1) / 2;
3539dc302feSbjh21 if (modes[i].hdisplay == bootconfig.width + 1
3549dc302feSbjh21 && modes[i].vdisplay == bootconfig.height + 1
35563030ccaSbjh21 && abs(framerate - bootconfig.framerate) < besterror) {
3569dc302feSbjh21 vidc_currentmode.timings = modes[i];
35763030ccaSbjh21 besterror = abs(framerate - bootconfig.framerate);
3587d4a1addSreinoud }
3597d4a1addSreinoud }
3607d4a1addSreinoud
36172cec937Sbjh21 vidc_currentmode.log2_bpp = bootconfig.log2_bpp;
3627d4a1addSreinoud
3637d4a1addSreinoud dispstart = dispbase;
3647d4a1addSreinoud dispend = dispstart+dispsize;
3657d4a1addSreinoud
3667d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
3677d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
3687d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
3697d4a1addSreinoud return 0;
3707d4a1addSreinoud }
3717d4a1addSreinoud
3727d4a1addSreinoud
3737d4a1addSreinoud /* simple function to abstract vidc variables ; returns virt start address of screen */
374a136e22aSandvar /* XXX assumption that video memory is mapped in twice */
vidcvideo_hwscroll(int bytes)375758ec341Sbjh21 void *vidcvideo_hwscroll(int bytes)
376758ec341Sbjh21 {
377758ec341Sbjh21
3787d4a1addSreinoud dispstart += bytes;
3797d4a1addSreinoud if (dispstart >= dispbase + dispsize) dispstart -= dispsize;
3807d4a1addSreinoud if (dispstart < dispbase) dispstart += dispsize;
3817d4a1addSreinoud dispend = dispstart+dispsize;
3827d4a1addSreinoud
3837d4a1addSreinoud /* return the start of the bit map of the screen (left top) */
3847d4a1addSreinoud return (void *)dispstart;
3857d4a1addSreinoud }
3867d4a1addSreinoud
3877d4a1addSreinoud
3887d4a1addSreinoud /* reset the HW scroll to be at the start for the benefit of f.e. X */
vidcvideo_hwscroll_reset(void)389758ec341Sbjh21 void *vidcvideo_hwscroll_reset(void)
390758ec341Sbjh21 {
3917d4a1addSreinoud void *cookie = (void *)dispstart;
3927d4a1addSreinoud
3937d4a1addSreinoud dispstart = dispbase;
3947d4a1addSreinoud dispend = dispstart + dispsize;
3957d4a1addSreinoud return cookie;
3967d4a1addSreinoud }
3977d4a1addSreinoud
3987d4a1addSreinoud
3997d4a1addSreinoud /* put HW scroll back to where it was */
vidcvideo_hwscroll_back(void * cookie)400758ec341Sbjh21 void *vidcvideo_hwscroll_back(void *cookie)
401758ec341Sbjh21 {
402758ec341Sbjh21
4037d4a1addSreinoud dispstart = (int)cookie;
4047d4a1addSreinoud dispend = dispstart + dispsize;
4057d4a1addSreinoud return cookie;
4067d4a1addSreinoud }
4077d4a1addSreinoud
4087d4a1addSreinoud
4099f4a9600Sandvar /* this function is to be called preferably at vsync */
vidcvideo_progr_scroll(void)410758ec341Sbjh21 void vidcvideo_progr_scroll(void)
411758ec341Sbjh21 {
412758ec341Sbjh21
4137d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDINIT, dispstart-ptov);
4147d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDSTART, dispstart-ptov);
4157d4a1addSreinoud IOMD_WRITE_WORD(IOMD_VIDEND, (dispend-transfersize)-ptov);
4167d4a1addSreinoud }
4177d4a1addSreinoud
4187d4a1addSreinoud
4197d4a1addSreinoud /*
4207d4a1addSreinoud * Select a new mode by reprogramming the VIDC chip
4217d4a1addSreinoud * XXX this part is known not to work for 32bpp
4227d4a1addSreinoud */
4237d4a1addSreinoud
4247d4a1addSreinoud struct vidc_mode newmode;
4257d4a1addSreinoud
4267d4a1addSreinoud static const int bpp_mask_table[] = {
4277d4a1addSreinoud 0, /* 1bpp */
4287d4a1addSreinoud 1, /* 2bpp */
4297d4a1addSreinoud 2, /* 4bpp */
4307d4a1addSreinoud 3, /* 8bpp */
4317d4a1addSreinoud 4, /* 16bpp */
4327d4a1addSreinoud 6 /* 32bpp */
4337d4a1addSreinoud };
4347d4a1addSreinoud
4357d4a1addSreinoud
4367d4a1addSreinoud void
vidcvideo_setmode(struct vidc_mode * mode)4377d4a1addSreinoud vidcvideo_setmode(struct vidc_mode *mode)
4387d4a1addSreinoud {
43928d9a9e3Sbjh21 struct videomode *vm;
4407d4a1addSreinoud int bpp_mask;
4417d4a1addSreinoud int ereg;
442eefdf030Sbjh21 int best_r, best_v;
443eefdf030Sbjh21 int least_error;
444eefdf030Sbjh21 int r, v, f;
4457d4a1addSreinoud
4467d4a1addSreinoud /*
447758ec341Sbjh21 * Find out what bit mask we need to or with the vidc20
448758ec341Sbjh21 * control register in order to generate the desired number of
449758ec341Sbjh21 * bits per pixel. log_bpp is log base 2 of the number of
450758ec341Sbjh21 * bits per pixel.
4517d4a1addSreinoud */
4527d4a1addSreinoud
4537d4a1addSreinoud bpp_mask = bpp_mask_table[mode->log2_bpp];
4547d4a1addSreinoud
45572cec937Sbjh21 vidc_currentmode = *mode;
45672cec937Sbjh21 vm = &vidc_currentmode.timings;
4577d4a1addSreinoud
458eefdf030Sbjh21 least_error = INT_MAX;
459eefdf030Sbjh21 best_r = 0; best_v = 0;
4607d4a1addSreinoud
461eefdf030Sbjh21 for (v = 63; v > 0; v--) {
4627d4a1addSreinoud for (r = 63; r > 0; r--) {
4637d4a1addSreinoud f = ((v * vidc_fref) /1000) / r;
46428d9a9e3Sbjh21 if (least_error >= abs(f - vm->dot_clock)) {
46528d9a9e3Sbjh21 least_error = abs(f - vm->dot_clock);
4667d4a1addSreinoud best_r = r;
4677d4a1addSreinoud best_v = v;
4687d4a1addSreinoud }
4697d4a1addSreinoud }
4707d4a1addSreinoud }
4717d4a1addSreinoud
4727d4a1addSreinoud if (best_r > 63) best_r=63;
4737d4a1addSreinoud if (best_v > 63) best_v=63;
4747d4a1addSreinoud if (best_r < 1) best_r= 1;
4757d4a1addSreinoud if (best_v < 1) best_v= 1;
4767d4a1addSreinoud
4777d4a1addSreinoud vidcvideo_write(VIDC_FSYNREG, (best_v-1)<<8 | (best_r-1)<<0);
478be3168abSreinoud
47928d9a9e3Sbjh21 /*
48028d9a9e3Sbjh21 * The translation from struct videomode to VIDC timings is made
48128d9a9e3Sbjh21 * fun by the fact that the VIDC counts from the start of the sync
48228d9a9e3Sbjh21 * pulse while struct videomode counts from the start of the display.
48328d9a9e3Sbjh21 */
48428d9a9e3Sbjh21 vidcvideo_write(VIDC_HSWR, (vm->hsync_end - vm->hsync_start - 8) & ~1);
48528d9a9e3Sbjh21 vidcvideo_write(VIDC_HBSR, (vm->htotal - vm->hsync_start - 12) & ~1);
48628d9a9e3Sbjh21 vidcvideo_write(VIDC_HDSR, (vm->htotal - vm->hsync_start - 18) & ~1);
48728d9a9e3Sbjh21 vidcvideo_write(VIDC_HDER,
48828d9a9e3Sbjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 18) & ~1);
48928d9a9e3Sbjh21 vidcvideo_write(VIDC_HBER,
49028d9a9e3Sbjh21 (vm->htotal - vm->hsync_start + vm->hdisplay - 12) & ~1);
49128d9a9e3Sbjh21 vidcvideo_write(VIDC_HCR, (vm->htotal - 8) & ~3);
4927d4a1addSreinoud
49328d9a9e3Sbjh21 vidcvideo_write(VIDC_VSWR, vm->vsync_end - vm->vsync_start - 1);
49428d9a9e3Sbjh21 vidcvideo_write(VIDC_VBSR, vm->vtotal - vm->vsync_start - 1);
49528d9a9e3Sbjh21 vidcvideo_write(VIDC_VDSR, vm->vtotal - vm->vsync_start - 1);
49628d9a9e3Sbjh21 vidcvideo_write(VIDC_VDER,
49728d9a9e3Sbjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1);
49828d9a9e3Sbjh21 vidcvideo_write(VIDC_VBER,
49928d9a9e3Sbjh21 vm->vtotal - vm->vsync_start + vm->vdisplay - 1);
50028d9a9e3Sbjh21 /* XXX VIDC20 data sheet say to subtract 2 */
50128d9a9e3Sbjh21 vidcvideo_write(VIDC_VCR, vm->vtotal - 1);
5027d4a1addSreinoud
503983692f3Sbjh21 IOMD_WRITE_WORD(IOMD_FSIZE, vm->vtotal - vm->vdisplay - 1);
5047d4a1addSreinoud
5057d4a1addSreinoud if (dispsize <= 1024*1024)
50628d9a9e3Sbjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 1<<16 | 1<<12);
5077d4a1addSreinoud else
50828d9a9e3Sbjh21 vidcvideo_write(VIDC_DCTL, vm->hdisplay>>2 | 3<<16 | 1<<12);
5097d4a1addSreinoud
5107d4a1addSreinoud ereg = 1<<12;
51128d9a9e3Sbjh21 if (vm->flags & VID_NHSYNC)
5127d4a1addSreinoud ereg |= 1<<16;
51328d9a9e3Sbjh21 if (vm->flags & VID_NVSYNC)
5147d4a1addSreinoud ereg |= 1<<18;
5157d4a1addSreinoud vidcvideo_write(VIDC_EREG, ereg);
5161aeaeb0eSbjh21
5171aeaeb0eSbjh21 /*
5181aeaeb0eSbjh21 * Set the video FIFO preload value and bit depth. Chapter 6
5191aeaeb0eSbjh21 * of the VIDC20 Data Sheet has full details of the FIFO
5201aeaeb0eSbjh21 * preload, but we don't do anything clever and just use the
5211aeaeb0eSbjh21 * largest possible value, which is 7 when the VIDC20 is in
5221aeaeb0eSbjh21 * 32-bit mode (0MB or 1MB VRAM) and 6 when it is in 64-bit
5231aeaeb0eSbjh21 * mode (2MB VRAM).
5241aeaeb0eSbjh21 */
5251aeaeb0eSbjh21 if (dispsize > 1024*1024)
5267d4a1addSreinoud vidcvideo_write(VIDC_CONREG, 6<<8 | bpp_mask<<5);
5271aeaeb0eSbjh21 else
5287d4a1addSreinoud vidcvideo_write(VIDC_CONREG, 7<<8 | bpp_mask<<5);
5297d4a1addSreinoud }
5307d4a1addSreinoud
5317d4a1addSreinoud
532c1f8e3aaSbjh21 #if 0
5337d4a1addSreinoud /* not used for now */
5347d4a1addSreinoud void
535454af1c0Sdsl vidcvideo_set_display_base(u_int base)
5367d4a1addSreinoud {
5377d4a1addSreinoud dispstart = dispstart-dispbase + base;
5387d4a1addSreinoud dispbase = vmem_base = base;
5397d4a1addSreinoud dispend = base + dispsize;
5407d4a1addSreinoud ptov = dispbase - phys_base;
5417d4a1addSreinoud }
542c1f8e3aaSbjh21 #endif
5437d4a1addSreinoud
5447d4a1addSreinoud
5457d4a1addSreinoud /*
5467d4a1addSreinoud * Main initialisation routine for now
5477d4a1addSreinoud */
5487d4a1addSreinoud
5497d4a1addSreinoud static int cursor_init = 0;
5507d4a1addSreinoud
5517d4a1addSreinoud int
vidcvideo_init(void)5527d4a1addSreinoud vidcvideo_init(void)
5537d4a1addSreinoud {
5547d4a1addSreinoud vidcvideo_coldinit();
5557d4a1addSreinoud if (cold_init && (cursor_init == 0))
5567d4a1addSreinoud /* vidcvideo_flash_go() */;
5577d4a1addSreinoud
5587d4a1addSreinoud /* setting a mode goes wrong in 32 bpp ... 8 and 16 seem OK */
55972cec937Sbjh21 vidcvideo_setmode(&vidc_currentmode);
5607d4a1addSreinoud vidcvideo_blank(0); /* display on */
5617d4a1addSreinoud
5621dda0b46Sbjh21 vidcvideo_stdpalette();
5637d4a1addSreinoud
5647d4a1addSreinoud if (cold_init == 0) {
5657d4a1addSreinoud vidcvideo_write(VIDC_CP1, 0x0);
5667d4a1addSreinoud vidcvideo_write(VIDC_CP2, 0x0);
5677d4a1addSreinoud vidcvideo_write(VIDC_CP3, 0x0);
568758ec341Sbjh21 } else
5697d4a1addSreinoud vidcvideo_cursor_init(CURSOR_MAX_WIDTH, CURSOR_MAX_HEIGHT);
5707d4a1addSreinoud
5717d4a1addSreinoud cold_init = 1;
5727d4a1addSreinoud return 0;
5737d4a1addSreinoud }
5747d4a1addSreinoud
5757d4a1addSreinoud
5767d4a1addSreinoud /* reinitialise the vidcvideo */
5777d4a1addSreinoud void
vidcvideo_reinit(void)578ebceae53Scegger vidcvideo_reinit(void)
5797d4a1addSreinoud {
580758ec341Sbjh21
5817d4a1addSreinoud vidcvideo_coldinit();
58272cec937Sbjh21 vidcvideo_setmode(&vidc_currentmode);
5837d4a1addSreinoud }
5847d4a1addSreinoud
5857d4a1addSreinoud
5867d4a1addSreinoud int
vidcvideo_cursor_init(int width,int height)5877d4a1addSreinoud vidcvideo_cursor_init(int width, int height)
5887d4a1addSreinoud {
5897d4a1addSreinoud static char *cursor_data = NULL;
5907d4a1addSreinoud int counter;
5917d4a1addSreinoud int line;
5927d4a1addSreinoud paddr_t pa;
5937d4a1addSreinoud
5947d4a1addSreinoud cursor_width = width;
5957d4a1addSreinoud cursor_height = height;
5967d4a1addSreinoud
5977d4a1addSreinoud if (!cursor_data) {
5987d4a1addSreinoud /* Allocate cursor memory first time round */
5996b2d8b66Syamt cursor_data = (char *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
6006b2d8b66Syamt UVM_KMF_WIRED | UVM_KMF_ZERO);
6017d4a1addSreinoud if (!cursor_data)
6020f09ed48Sprovos panic("Cannot allocate memory for hardware cursor");
6037d4a1addSreinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_data, &pa);
6047d4a1addSreinoud IOMD_WRITE_WORD(IOMD_CURSINIT, pa);
6057d4a1addSreinoud }
6067d4a1addSreinoud
607f0a7346dSsnj /* Blank the cursor while initialising its sprite */
6087d4a1addSreinoud
6097d4a1addSreinoud vidcvideo_write ( VIDC_CP1, 0x0 );
6107d4a1addSreinoud vidcvideo_write ( VIDC_CP2, 0x0 );
6117d4a1addSreinoud vidcvideo_write ( VIDC_CP3, 0x0 );
6127d4a1addSreinoud
6137d4a1addSreinoud cursor_normal = cursor_data;
6147d4a1addSreinoud cursor_transparent = cursor_data + (height * width);
6157d4a1addSreinoud
6167d4a1addSreinoud cursor_transparent += 32; /* ALIGN */
6177d4a1addSreinoud cursor_transparent = (char *)((int)cursor_transparent & (~31) );
6187d4a1addSreinoud
619758ec341Sbjh21 for ( line = 0; line<height; ++line ) {
6207d4a1addSreinoud for ( counter=0; counter<width/4;counter++ )
6217d4a1addSreinoud cursor_normal[line * width + counter]=0x55; /* why 0x55 ? */
6227d4a1addSreinoud for ( ; counter<8; counter++ )
6237d4a1addSreinoud cursor_normal[line * width + counter]=0;
6247d4a1addSreinoud }
6257d4a1addSreinoud
626758ec341Sbjh21 for ( line = 0; line<height; ++line ) {
6277d4a1addSreinoud for ( counter=0; counter<width/4;counter++ )
6287d4a1addSreinoud cursor_transparent[line * width + counter]=0x00;
6297d4a1addSreinoud for ( ; counter<8; counter++ )
6307d4a1addSreinoud cursor_transparent[line * width + counter]=0;
6317d4a1addSreinoud }
6327d4a1addSreinoud
6337d4a1addSreinoud
6347d4a1addSreinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_normal,
635b9d20d13Smatt (void *)&p_cursor_normal);
6367d4a1addSreinoud (void) pmap_extract(pmap_kernel(), (vaddr_t)cursor_transparent,
637b9d20d13Smatt (void *)&p_cursor_transparent);
6387d4a1addSreinoud
6397d4a1addSreinoud memset(cursor_normal, 0x55, width*height); /* white? */
6407d4a1addSreinoud memset(cursor_transparent, 0x00, width*height);/* to see the diffence */
6417d4a1addSreinoud
6427d4a1addSreinoud /* Ok, now program the cursor; should be blank */
6437d4a1addSreinoud vidcvideo_enablecursor(0);
6447d4a1addSreinoud
6457d4a1addSreinoud return 0;
6467d4a1addSreinoud }
6477d4a1addSreinoud
6487d4a1addSreinoud
6497d4a1addSreinoud void
vidcvideo_updatecursor(int xcur,int ycur)650758ec341Sbjh21 vidcvideo_updatecursor(int xcur, int ycur)
6517d4a1addSreinoud {
65272cec937Sbjh21 int frontporch = vidc_currentmode.timings.htotal -
65372cec937Sbjh21 vidc_currentmode.timings.hsync_start;
65472cec937Sbjh21 int topporch = vidc_currentmode.timings.vtotal -
65572cec937Sbjh21 vidc_currentmode.timings.vsync_start;
6567d4a1addSreinoud
6577d4a1addSreinoud vidcvideo_write(VIDC_HCSR, frontporch -17 + xcur);
658758ec341Sbjh21 vidcvideo_write(VIDC_VCSR, topporch -2 + (ycur+1)-2 + 3 -
659758ec341Sbjh21 cursor_height);
6607d4a1addSreinoud vidcvideo_write(VIDC_VCER, topporch -2 + (ycur+3)+2 + 3 );
6617d4a1addSreinoud }
6627d4a1addSreinoud
6637d4a1addSreinoud
6647d4a1addSreinoud void
vidcvideo_enablecursor(int on)665758ec341Sbjh21 vidcvideo_enablecursor(int on)
6667d4a1addSreinoud {
6677d4a1addSreinoud
668758ec341Sbjh21 if (on)
669758ec341Sbjh21 IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_normal);
670758ec341Sbjh21 else
671758ec341Sbjh21 IOMD_WRITE_WORD(IOMD_CURSINIT,p_cursor_transparent);
672758ec341Sbjh21 vidcvideo_write ( VIDC_CP1, 0xffffff ); /* enable */
6737d4a1addSreinoud }
6747d4a1addSreinoud
6757d4a1addSreinoud
6761dda0b46Sbjh21 void
vidcvideo_stdpalette(void)677ebceae53Scegger vidcvideo_stdpalette(void)
67805012290Sbjh21 {
6791dda0b46Sbjh21 int i;
6801dda0b46Sbjh21
68172cec937Sbjh21 switch (vidc_currentmode.log2_bpp) {
6821dda0b46Sbjh21 case 0: /* 1 bpp */
6831dda0b46Sbjh21 case 1: /* 2 bpp */
6841dda0b46Sbjh21 case 2: /* 4 bpp */
6851dda0b46Sbjh21 case 3: /* 8 bpp */
68605012290Sbjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
68705012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 0));
68805012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 0));
68905012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 0));
69005012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 0));
69105012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 0, 255));
69205012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 0, 255));
69305012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL( 0, 255, 255));
69405012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
69505012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 128));
69605012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 128));
69705012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 255, 128));
69805012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 128));
69905012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(128, 128, 255));
70005012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 128, 255));
70105012290Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(255, 255, 255));
7021dda0b46Sbjh21 break;
7031dda0b46Sbjh21 case 4: /* 16 bpp */
7041dda0b46Sbjh21 /*
7051dda0b46Sbjh21 * The use of the palette in 16-bit modes is quite
7061dda0b46Sbjh21 * fun. Comments in linux/drivers/video/acornfb.c
7071dda0b46Sbjh21 * imply that it goes something like this:
7081dda0b46Sbjh21 *
7091dda0b46Sbjh21 * red = LUT[pixel[7:0]].red
7101dda0b46Sbjh21 * green = LUT[pixel[11:4]].green
7111dda0b46Sbjh21 * blue = LUT[pixel[15:8]].blue
7121dda0b46Sbjh21 *
713a7f52777Sbjh21 * We use 6:5:5 R:G:B cos that's what Xarm32VIDC wants.
7141dda0b46Sbjh21 */
715a7f52777Sbjh21 #define RBITS 6
716a7f52777Sbjh21 #define GBITS 5
717a7f52777Sbjh21 #define BBITS 5
7181dda0b46Sbjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
7191dda0b46Sbjh21 for (i = 0; i < 256; i++) {
720a7f52777Sbjh21 int r, g, b;
72105012290Sbjh21
722a7f52777Sbjh21 r = i & ((1 << RBITS) - 1);
723a7f52777Sbjh21 g = (i >> (RBITS - 4)) & ((1 << GBITS) - 1);
724a7f52777Sbjh21 b = (i >> (RBITS + GBITS - 8)) & ((1 << BBITS) - 1);
7251dda0b46Sbjh21 vidcvideo_write(VIDC_PALETTE,
726a7f52777Sbjh21 VIDC_COL(r << (8 - RBITS) | r >> (2 * RBITS - 8),
727a7f52777Sbjh21 g << (8 - GBITS) | g >> (2 * GBITS - 8),
728a7f52777Sbjh21 b << (8 - BBITS) | b >> (2 * BBITS - 8)));
7291dda0b46Sbjh21 }
7301dda0b46Sbjh21 break;
7311dda0b46Sbjh21 case 5: /* 32 bpp */
7321dda0b46Sbjh21 vidcvideo_write(VIDC_PALREG, 0x00000000);
7331dda0b46Sbjh21 for (i = 0; i < 256; i++)
7341dda0b46Sbjh21 vidcvideo_write(VIDC_PALETTE, VIDC_COL(i, i, i));
7351dda0b46Sbjh21 break;
7361dda0b46Sbjh21 }
73705012290Sbjh21 }
73805012290Sbjh21
73905012290Sbjh21 int
vidcvideo_blank(int video_off)740758ec341Sbjh21 vidcvideo_blank(int video_off)
7417d4a1addSreinoud {
7427d4a1addSreinoud int ereg;
7437d4a1addSreinoud
7447d4a1addSreinoud ereg = 1<<12;
74572cec937Sbjh21 if (vidc_currentmode.timings.flags & VID_NHSYNC)
7467d4a1addSreinoud ereg |= 1<<16;
74772cec937Sbjh21 if (vidc_currentmode.timings.flags & VID_NVSYNC)
7487d4a1addSreinoud ereg |= 1<<18;
7497d4a1addSreinoud
750758ec341Sbjh21 if (!video_off)
7517d4a1addSreinoud vidcvideo_write(VIDC_EREG, ereg);
752758ec341Sbjh21 else
7537d4a1addSreinoud vidcvideo_write(VIDC_EREG, 0);
7547d4a1addSreinoud return 0;
7557d4a1addSreinoud }
7567d4a1addSreinoud
7577d4a1addSreinoud /* end of vidc20config.c */
758