1 /* $NetBSD: vga_subr.c,v 1.26 2023/05/06 21:34:40 andvar Exp $ */
2 
3 /*
4  * Copyright (c) 1998
5  *        Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: vga_subr.c,v 1.26 2023/05/06 21:34:40 andvar Exp $");
31 
32 /* for WSDISPLAY_BORDER_COLOR */
33 #include "opt_wsdisplay_border.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/queue.h>
39 #include <sys/bus.h>
40 
41 #include <dev/ic/mc6845reg.h>
42 #include <dev/ic/pcdisplay.h>
43 #include <dev/ic/pcdisplayvar.h>
44 #include <dev/ic/vgareg.h>
45 #include <dev/ic/vgavar.h>
46 
47 #include <dev/wscons/wsdisplayvar.h>
48 
49 static void fontram(struct vga_handle *);
50 static void textram(struct vga_handle *);
51 
52 static void
fontram(struct vga_handle * vh)53 fontram(struct vga_handle *vh)
54 {
55 
56           /* program sequencer to access character generator */
57 
58           vga_ts_write(vh, syncreset, 0x01);      /* synchronous reset */
59           vga_ts_write(vh, wrplmask, 0x04);       /* write to map 2 */
60           vga_ts_write(vh, memmode, 0x07);        /* sequential addressing */
61           vga_ts_write(vh, syncreset, 0x03);      /* clear synchronous reset */
62 
63           /* program graphics controller to access character generator */
64 
65           vga_gdc_write(vh, rdplanesel, 0x02);    /* select map 2 for CPU reads */
66           vga_gdc_write(vh, mode, 0x00);          /* disable odd-even addressing */
67           vga_gdc_write(vh, misc, 0x04);          /* map starts at 0xA000 */
68 }
69 
70 static void
textram(struct vga_handle * vh)71 textram(struct vga_handle *vh)
72 {
73 
74           /* program sequencer to access video ram */
75 
76           vga_ts_write(vh, syncreset, 0x01);      /* synchronous reset */
77           vga_ts_write(vh, wrplmask, 0x03);       /* write to map 0 & 1 */
78           vga_ts_write(vh, memmode, 0x03);        /* odd-even addressing */
79           vga_ts_write(vh, syncreset, 0x03);      /* clear synchronous reset */
80 
81           /* program graphics controller for text mode */
82 
83           vga_gdc_write(vh, rdplanesel, 0x00);    /* select map 0 for CPU reads */
84           vga_gdc_write(vh, mode, 0x10);                    /* enable odd-even addressing */
85           /* map starts at 0xb800 or 0xb000 (mono) */
86           vga_gdc_write(vh, misc, (vh->vh_mono ? 0x0a : 0x0e));
87 }
88 
89 #ifndef VGA_RASTERCONSOLE
90 void
vga_loadchars(struct vga_handle * vh,int fontset,int first,int num,int lpc,const char * data)91 vga_loadchars(struct vga_handle *vh, int fontset, int first, int num, int lpc,
92                 const char *data)
93 {
94           int offset, i, j, s;
95 
96           /* fontset number swizzle done in vga_setfontset() */
97           offset = (fontset << 13) | (first << 5);
98 
99           s = splhigh();
100           fontram(vh);
101 
102           for (i = 0; i < num; i++)
103                     for (j = 0; j < lpc; j++)
104                               bus_space_write_1(vh->vh_memt, vh->vh_allmemh,
105                                   offset + (i << 5) + j, data[i * lpc + j]);
106 
107           textram(vh);
108           splx(s);
109 }
110 
111 void
vga_readoutchars(struct vga_handle * vh,int fontset,int first,int num,int lpc,char * data)112 vga_readoutchars(struct vga_handle *vh, int fontset, int first, int num,
113                      int lpc, char *data)
114 {
115           int offset, i, j, s;
116 
117           /* fontset number swizzle done in vga_setfontset() */
118           offset = (fontset << 13) | (first << 5);
119 
120           s = splhigh();
121           fontram(vh);
122 
123           for (i = 0; i < num; i++)
124                     for (j = 0; j < lpc; j++)
125                               data[i * lpc + j] = bus_space_read_1(vh->vh_memt,
126                                   vh->vh_allmemh, offset + (i << 5) + j);
127 
128           textram(vh);
129           splx(s);
130 }
131 
132 #ifdef VGA_CONSOLE_ATI_BROKEN_FONTSEL
133 void
vga_copyfont01(struct vga_handle * vh)134 vga_copyfont01(struct vga_handle *vh)
135 {
136           int s;
137 
138           s = splhigh();
139           fontram(vh);
140 
141           bus_space_copy_region_1(vh->vh_memt, vh->vh_allmemh, 0,
142               vh->vh_allmemh, 1 << 13, 1 << 13);
143 
144           textram(vh);
145           splx(s);
146 }
147 #endif
148 
149 void
vga_setfontset(struct vga_handle * vh,int fontset1,int fontset2)150 vga_setfontset(struct vga_handle *vh, int fontset1, int fontset2)
151 {
152           uint8_t cmap;
153           static const uint8_t cmaptaba[] = {
154                     0x00, 0x10, 0x01, 0x11,
155                     0x02, 0x12, 0x03, 0x13
156           };
157           static const uint8_t cmaptabb[] = {
158                     0x00, 0x20, 0x04, 0x24,
159                     0x08, 0x28, 0x0c, 0x2c
160           };
161 
162           /* extended font if fontset1 != fontset2 */
163           cmap = cmaptaba[fontset1] | cmaptabb[fontset2];
164 
165           vga_ts_write(vh, fontsel, cmap);
166 }
167 
168 void
vga_setscreentype(struct vga_handle * vh,const struct wsscreen_descr * type)169 vga_setscreentype(struct vga_handle *vh, const struct wsscreen_descr *type)
170 {
171 
172           vga_6845_write(vh, maxrow, type->fontheight - 1);
173 
174           /* lo byte */
175           vga_6845_write(vh, vde, type->fontheight * type->nrows - 1);
176 
177 #ifndef PCDISPLAY_SOFTCURSOR
178           /* set cursor to last 2 lines */
179           vga_6845_write(vh, curstart, type->fontheight - 2);
180           vga_6845_write(vh, curend, type->fontheight - 1);
181 #endif
182           /*
183            * disable colour plane 3 if needed for font selection
184            */
185           if (type->capabilities & WSSCREEN_HILIT) {
186                     /*
187                      * these are the screens which don't support
188                      * 512-character fonts
189                      */
190                     vga_attr_write(vh, colplen, 0x0f);
191           } else
192                     vga_attr_write(vh, colplen, 0x07);
193 }
194 
195 #else /* !VGA_RASTERCONSOLE */
196 void
vga_load_builtinfont(struct vga_handle * vh,uint8_t * font,int firstchar,int numchars)197 vga_load_builtinfont(struct vga_handle *vh, uint8_t *font, int firstchar,
198           int numchars)
199 {
200           int i, s;
201 
202           s = splhigh();
203           fontram(vh);
204 
205           for (i = firstchar; i < firstchar + numchars; i++)
206                     bus_space_read_region_1(vh->vh_memt, vh->vh_allmemh, i * 32,
207                         font + i * 16, 16);
208 
209           textram(vh);
210           splx(s);
211 }
212 #endif /* !VGA_RASTERCONSOLE */
213 
214 /*
215  * vga_reset():
216  *        Reset VGA registers to put it into 80x25 text mode. (mode 3)
217  *        This function should be called from MD consinit() on ports
218  *        whose firmware does not use text mode at boot time.
219  */
220 void
vga_reset(struct vga_handle * vh,void (* md_initfunc)(struct vga_handle *))221 vga_reset(struct vga_handle *vh, void (*md_initfunc)(struct vga_handle *))
222 {
223           uint8_t reg;
224 
225           if (bus_space_map(vh->vh_iot, 0x3c0, 0x10, 0, &vh->vh_ioh_vga))
226                     return;
227 
228           reg = vga_raw_read(vh, VGA_MISC_DATAR);
229           vh->vh_mono = !(reg & 0x01);
230 
231           if (bus_space_map(vh->vh_iot, vh->vh_mono ? 0x3b0 : 0x3d0, 0x10,
232               0, &vh->vh_ioh_6845))
233                     goto out1;
234 
235           if (bus_space_map(vh->vh_memt, 0xa0000, 0x20000, 0, &vh->vh_allmemh))
236                     goto out2;
237 
238           if (bus_space_subregion(vh->vh_memt, vh->vh_allmemh,
239               vh->vh_mono ? 0x10000 : 0x18000, 0x8000, &vh->vh_memh))
240                     goto out3;
241 
242           /* check if VGA already in text mode. */
243           if ((vga_gdc_read(vh, misc) & 0x01) == 0)
244                     goto out3;
245 
246           /* initialize common VGA registers */
247           vga_initregs(vh);
248 
249           /* initialize chipset specific registers */
250           if (md_initfunc != NULL)
251                     (*md_initfunc)(vh);
252 
253           delay(10000);
254 
255           /* clear text buffer RAM */
256           bus_space_set_region_2(vh->vh_memt, vh->vh_memh, 0,
257               ((BG_BLACK | FG_LIGHTGREY) << 8) | ' ', 80 * 25 /*XXX*/);
258 
259  out3:
260           bus_space_unmap(vh->vh_memt, vh->vh_allmemh, 0x20000);
261  out2:
262           bus_space_unmap(vh->vh_iot, vh->vh_ioh_6845, 0x10);
263  out1:
264           bus_space_unmap(vh->vh_iot, vh->vh_ioh_vga, 0x10);
265 }
266 
267 /*
268  * values to initialize registers.
269  */
270 
271 /* miscellaneous output register */
272 #define VGA_MISCOUT 0x66
273 
274 /* sequencer registers */
275 static const uint8_t vga_ts[] = {
276           0x03,     /* 00: reset */
277           0x00,     /* 01: clocking mode */
278           0x03,     /* 02: map mask */
279           0x00,     /* 03: character map select */
280           0x02      /* 04: memory mode */
281 };
282 
283 /* CRT controller registers */
284 static const uint8_t vga_crtc[] = {
285           0x5f,     /* 00: horizontal total */
286           0x4f,     /* 01: horizontal display-enable end */
287           0x50,     /* 02: start horizontal blanking */
288           0x82,     /* 03: display skew control / end horizontal blanking */
289           0x55,     /* 04: start horizontal retrace pulse */
290           0x81,     /* 05: horizontal retrace delay / end horizontal retrace */
291           0xbf,     /* 06: vertical total */
292           0x1f,     /* 07: overflow register */
293           0x00,     /* 08: preset row scan */
294           0x4f,     /* 09: overflow / maximum scan line */
295           0x0d,     /* 0A: cursor off / cursor start */
296           0x0e,     /* 0B: cursor skew / cursor end */
297           0x00,     /* 0C: start regenerative buffer address high */
298           0x00,     /* 0D: start regenerative buffer address low */
299           0x00,     /* 0E: cursor location high */
300           0x00,     /* 0F: cursor location low */
301           0x9c,     /* 10: vertical retrace start */
302           0x8e,     /* 11: vertical interrupt / vertical retrace end */
303           0x8f,     /* 12: vertical display enable end */
304           0x28,     /* 13: logical line width */
305           0x00,     /* 14: underline location */
306           0x96,     /* 15: start vertical blanking */
307           0xb9,     /* 16: end vertical blanking */
308           0xa3,     /* 17: CRT mode control */
309           0xff      /* 18: line compare */
310 };
311 
312 /* graphics controller registers */
313 static const uint8_t vga_gdc[] = {
314           0x00,     /* 00: set/reset map */
315           0x00,     /* 01: enable set/reset */
316           0x00,     /* 02: color compare */
317           0x00,     /* 03: data rotate */
318           0x00,     /* 04: read map select */
319           0x10,     /* 05: graphics mode */
320           0x0e,     /* 06: miscellaneous */
321           0x00,     /* 07: color don't care */
322           0xff      /* 08: bit mask */
323 };
324 
325 /* attribute controller registers */
326 static const uint8_t vga_atc[] = {
327           0x00,     /* 00: internal palette  0 */
328           0x01,     /* 01: internal palette  1 */
329           0x02,     /* 02: internal palette  2 */
330           0x03,     /* 03: internal palette  3 */
331           0x04,     /* 04: internal palette  4 */
332           0x05,     /* 05: internal palette  5 */
333           0x14,     /* 06: internal palette  6 */
334           0x07,     /* 07: internal palette  7 */
335           0x38,     /* 08: internal palette  8 */
336           0x39,     /* 09: internal palette  9 */
337           0x3a,     /* 0A: internal palette 10 */
338           0x3b,     /* 0B: internal palette 11 */
339           0x3c,     /* 0C: internal palette 12 */
340           0x3d,     /* 0D: internal palette 13 */
341           0x3e,     /* 0E: internal palette 14 */
342           0x3f,     /* 0F: internal palette 15 */
343           0x0c,     /* 10: attribute mode control */
344           WSDISPLAY_BORDER_COLOR,       /* 11: overscan color */
345           0x0f,     /* 12: color plane enable */
346           0x08,     /* 13: horizontal PEL panning */
347           0x00      /* 14: color select */
348 };
349 
350 /* video DAC palette registers */
351 /* XXX only set up 16 colors used by internal palette in ATC registers */
352 static const uint8_t vga_dacpal[] = {
353           /* R     G     B */
354           0x00, 0x00, 0x00,   /* BLACK        */
355           0x00, 0x00, 0x2a,   /* BLUE           */
356           0x00, 0x2a, 0x00,   /* GREEN        */
357           0x00, 0x2a, 0x2a,   /* CYAN         */
358           0x2a, 0x00, 0x00,   /* RED          */
359           0x2a, 0x00, 0x2a,   /* MAGENTA      */
360           0x2a, 0x15, 0x00,   /* BROWN        */
361           0x2a, 0x2a, 0x2a,   /* LIGHTGREY    */
362           0x15, 0x15, 0x15,   /* DARKGREY     */
363           0x15, 0x15, 0x3f,   /* LIGHTBLUE    */
364           0x15, 0x3f, 0x15,   /* LIGHTGREEN   */
365           0x15, 0x3f, 0x3f,   /* LIGHTCYAN    */
366           0x3f, 0x15, 0x15,   /* LIGHTRED     */
367           0x3f, 0x15, 0x3f,   /* LIGHTMAGENTA */
368           0x3f, 0x3f, 0x15,   /* YELLOW       */
369           0x3f, 0x3f, 0x3f    /* WHITE        */
370 };
371 
372 void
vga_initregs(struct vga_handle * vh)373 vga_initregs(struct vga_handle *vh)
374 {
375           int i;
376 
377           /* disable video */
378           vga_ts_write(vh, mode, vga_ts[1] | VGA_TS_MODE_BLANK);
379 
380           /* synchronous reset */
381           vga_ts_write(vh, syncreset, 0x01);
382           /* set TS registers */
383           for (i = 2; i < VGA_TS_NREGS; i++)
384                     _vga_ts_write(vh, i, vga_ts[i]);
385           /* clear synchronous reset */
386           vga_ts_write(vh, syncreset, 0x03);
387 
388           /* unprotect CRTC registers */
389           vga_6845_write(vh, vsynce, vga_6845_read(vh, vsynce) & ~0x80);
390           /* set CRTC registers */
391           for (i = 0; i < MC6845_NREGS; i++)
392                     _vga_6845_write(vh, i, vga_crtc[i]);
393 
394           /* set GDC registers */
395           for (i = 0; i < VGA_GDC_NREGS; i++)
396                     _vga_gdc_write(vh, i, vga_gdc[i]);
397 
398           /* set ATC registers */
399           for (i = 0; i < VGA_ATC_NREGS; i++)
400                     _vga_attr_write(vh, i, vga_atc[i]);
401 
402           /* set DAC palette */
403           if (!vh->vh_mono) {
404                     for (i = 0; i < 16; i++) {
405                               vga_raw_write(vh,
406                                   VGA_DAC_ADDRW, vga_atc[i]);
407                               vga_raw_write(vh,
408                                   VGA_DAC_PALETTE, vga_dacpal[i * 3 + 0]);
409                               vga_raw_write(vh,
410                                   VGA_DAC_PALETTE, vga_dacpal[i * 3 + 1]);
411                               vga_raw_write(vh,
412                                   VGA_DAC_PALETTE, vga_dacpal[i * 3 + 2]);
413                     }
414           }
415 
416           /* set misc output register */
417           vga_raw_write(vh,
418               VGA_MISC_DATAW, VGA_MISCOUT | (vh->vh_mono ? 0 : 0x01));
419 
420           /* reenable video */
421           vga_ts_write(vh, mode, vga_ts[1] & ~VGA_TS_MODE_BLANK);
422 }
423