1 /* $OpenBSD: sti.c,v 1.84 2024/08/17 08:45:22 miod Exp $ */
2
3 /*
4 * Copyright (c) 2000-2003 Michael Shalayeff
5 * 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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 /*
29 * TODO:
30 * call sti procs asynchronously;
31 * implement console scroll-back;
32 * X11 support on more models.
33 */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39
40 #include <uvm/uvm_extern.h>
41
42 #include <machine/bus.h>
43
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/wscons/wsconsio.h>
46
47 #include <dev/ic/stireg.h>
48 #include <dev/ic/stivar.h>
49
50 #include "sti.h"
51
52 struct cfdriver sti_cd = {
53 NULL, "sti", DV_DULL
54 };
55
56 int sti_pack_attr(void *, int, int, int, uint32_t *);
57 int sti_copycols(void *, int, int, int, int);
58 int sti_copyrows(void *, int, int, int);
59 int sti_cursor(void *, int, int, int);
60 int sti_erasecols(void *, int, int, int, uint32_t);
61 int sti_eraserows(void *, int, int, uint32_t);
62 int sti_mapchar(void *, int, u_int *);
63 int sti_putchar(void *, int, int, u_int, uint32_t);
64 void sti_unpack_attr(void *, uint32_t, int *, int *, int *);
65
66 struct wsdisplay_emulops sti_emulops = {
67 .cursor = sti_cursor,
68 .mapchar = sti_mapchar,
69 .putchar = sti_putchar,
70 .copycols = sti_copycols,
71 .erasecols = sti_erasecols,
72 .copyrows = sti_copyrows,
73 .eraserows = sti_eraserows,
74 .pack_attr = sti_pack_attr,
75 .unpack_attr = sti_unpack_attr
76 };
77
78 int sti_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
79 int *, uint32_t *);
80 void sti_free_screen(void *, void *);
81 int sti_ioctl(void *, u_long, caddr_t, int, struct proc *);
82 paddr_t sti_mmap(void *, off_t, int);
83 int sti_show_screen(void *, void *, int, void (*)(void *, int, int),
84 void *);
85
86 const struct wsdisplay_accessops sti_accessops = {
87 .ioctl = sti_ioctl,
88 .mmap = sti_mmap,
89 .alloc_screen = sti_alloc_screen,
90 .free_screen = sti_free_screen,
91 .show_screen = sti_show_screen
92 };
93
94 enum sti_bmove_funcs {
95 bmf_clear, bmf_copy, bmf_invert, bmf_underline
96 };
97
98 void sti_bmove(struct sti_screen *, int, int, int, int, int, int,
99 enum sti_bmove_funcs);
100 int sti_init(struct sti_screen *, int);
101 #define STI_TEXTMODE 0x01
102 #define STI_CLEARSCR 0x02
103 #define STI_FBMODE 0x04
104 int sti_inqcfg(struct sti_screen *, struct sti_inqconfout *);
105 int sti_setcment(struct sti_screen *, u_int, u_char, u_char, u_char);
106
107 struct sti_screen *
108 sti_attach_screen(struct sti_softc *, int);
109 void sti_describe_screen(struct sti_softc *, struct sti_screen *);
110 void sti_end_attach_screen(struct sti_softc *, struct sti_screen *, int);
111 int sti_fetchfonts(struct sti_screen *, struct sti_inqconfout *, u_int32_t,
112 u_int);
113 int32_t sti_gvid(void *, uint32_t, uint32_t *);
114 void sti_region_setup(struct sti_screen *);
115 int sti_rom_setup(struct sti_rom *, bus_space_tag_t, bus_space_tag_t,
116 bus_space_handle_t, bus_addr_t *, u_int);
117 int sti_screen_setup(struct sti_screen *, int);
118
119 int ngle_default_putcmap(struct sti_screen *, u_int, u_int);
120
121 void ngle_artist_setupfb(struct sti_screen *);
122 void ngle_elk_setupfb(struct sti_screen *);
123 void ngle_timber_setupfb(struct sti_screen *);
124 int ngle_putcmap(struct sti_screen *, u_int, u_int);
125
126 /*
127 * Helper macros to control whether the STI ROM is accessible on PCI
128 * devices.
129 */
130 #if NSTI_PCI > 0
131 #define STI_ENABLE_ROM(sc) \
132 do { \
133 if ((sc) != NULL && (sc)->sc_enable_rom != NULL) \
134 (*(sc)->sc_enable_rom)(sc); \
135 } while (0)
136 #define STI_DISABLE_ROM(sc) \
137 do { \
138 if ((sc) != NULL && (sc)->sc_disable_rom != NULL) \
139 (*(sc)->sc_disable_rom)(sc); \
140 } while (0)
141 #else
142 #define STI_ENABLE_ROM(sc) do { /* nothing */ } while (0)
143 #define STI_DISABLE_ROM(sc) do { /* nothing */ } while (0)
144 #endif
145
146 /* Macros to read larger than 8 bit values from byte roms */
147 #define parseshort(o) \
148 ((bus_space_read_1(memt, romh, (o) + 3) << 8) | \
149 (bus_space_read_1(memt, romh, (o) + 7)))
150 #define parseword(o) \
151 ((bus_space_read_1(memt, romh, (o) + 3) << 24) | \
152 (bus_space_read_1(memt, romh, (o) + 7) << 16) | \
153 (bus_space_read_1(memt, romh, (o) + 11) << 8) | \
154 (bus_space_read_1(memt, romh, (o) + 15)))
155
156 int
sti_attach_common(struct sti_softc * sc,bus_space_tag_t iot,bus_space_tag_t memt,bus_space_handle_t romh,u_int codebase)157 sti_attach_common(struct sti_softc *sc, bus_space_tag_t iot,
158 bus_space_tag_t memt, bus_space_handle_t romh, u_int codebase)
159 {
160 struct sti_rom *rom;
161 int rc;
162
163 rom = (struct sti_rom *)malloc(sizeof(*rom), M_DEVBUF,
164 M_NOWAIT | M_ZERO);
165 if (rom == NULL) {
166 printf("cannot allocate rom data\n");
167 return (ENOMEM);
168 }
169
170 rom->rom_softc = sc;
171 rc = sti_rom_setup(rom, iot, memt, romh, sc->bases, codebase);
172 if (rc != 0) {
173 free(rom, M_DEVBUF, sizeof *rom);
174 return (rc);
175 }
176
177 sc->sc_rom = rom;
178
179 sti_describe(sc);
180
181 sc->sc_scr = sti_attach_screen(sc,
182 sc->sc_flags & STI_CONSOLE ? 0 : STI_CLEARSCR);
183 if (sc->sc_scr == NULL)
184 rc = ENOMEM;
185
186 return (rc);
187 }
188
189 struct sti_screen *
sti_attach_screen(struct sti_softc * sc,int flags)190 sti_attach_screen(struct sti_softc *sc, int flags)
191 {
192 struct sti_screen *scr;
193 int rc;
194
195 scr = (struct sti_screen *)malloc(sizeof(*scr), M_DEVBUF,
196 M_NOWAIT | M_ZERO);
197 if (scr == NULL) {
198 printf("cannot allocate screen data\n");
199 return (NULL);
200 }
201
202 scr->scr_rom = sc->sc_rom;
203 rc = sti_screen_setup(scr, flags);
204 if (rc != 0) {
205 free(scr, M_DEVBUF, sizeof *scr);
206 return (NULL);
207 }
208
209 sti_describe_screen(sc, scr);
210
211 return (scr);
212 }
213
214 int
sti_rom_setup(struct sti_rom * rom,bus_space_tag_t iot,bus_space_tag_t memt,bus_space_handle_t romh,bus_addr_t * bases,u_int codebase)215 sti_rom_setup(struct sti_rom *rom, bus_space_tag_t iot, bus_space_tag_t memt,
216 bus_space_handle_t romh, bus_addr_t *bases, u_int codebase)
217 {
218 struct sti_dd *dd;
219 int size, i;
220 vaddr_t va;
221 paddr_t pa;
222
223 STI_ENABLE_ROM(rom->rom_softc);
224
225 rom->iot = iot;
226 rom->memt = memt;
227 rom->romh = romh;
228 rom->bases = bases;
229
230 /*
231 * Get ROM header and code function pointers.
232 */
233
234 dd = &rom->rom_dd;
235 rom->rom_devtype = bus_space_read_1(memt, romh, 3);
236 if (rom->rom_devtype == STI_DEVTYPE1) {
237 dd->dd_type = bus_space_read_1(memt, romh, 0x03);
238 dd->dd_nmon = bus_space_read_1(memt, romh, 0x07);
239 dd->dd_grrev = bus_space_read_1(memt, romh, 0x0b);
240 dd->dd_lrrev = bus_space_read_1(memt, romh, 0x0f);
241 dd->dd_grid[0] = parseword(0x10);
242 dd->dd_grid[1] = parseword(0x20);
243 dd->dd_fntaddr = parseword(0x30) & ~3;
244 dd->dd_maxst = parseword(0x40);
245 dd->dd_romend = parseword(0x50) & ~3;
246 dd->dd_reglst = parseword(0x60) & ~3;
247 dd->dd_maxreent = parseshort(0x70);
248 dd->dd_maxtimo = parseshort(0x78);
249 dd->dd_montbl = parseword(0x80) & ~3;
250 dd->dd_udaddr = parseword(0x90) & ~3;
251 dd->dd_stimemreq = parseword(0xa0);
252 dd->dd_udsize = parseword(0xb0);
253 dd->dd_pwruse = parseshort(0xc0);
254 dd->dd_bussup = bus_space_read_1(memt, romh, 0xcb);
255 dd->dd_ebussup = bus_space_read_1(memt, romh, 0xcf);
256 dd->dd_altcodet = bus_space_read_1(memt, romh, 0xd3);
257 dd->dd_eddst[0] = bus_space_read_1(memt, romh, 0xd7);
258 dd->dd_eddst[1] = bus_space_read_1(memt, romh, 0xdb);
259 dd->dd_eddst[2] = bus_space_read_1(memt, romh, 0xdf);
260 dd->dd_cfbaddr = parseword(0xe0) & ~3;
261
262 codebase <<= 2;
263 dd->dd_pacode[0x0] = parseword(codebase + 0x000) & ~3;
264 dd->dd_pacode[0x1] = parseword(codebase + 0x010) & ~3;
265 dd->dd_pacode[0x2] = parseword(codebase + 0x020) & ~3;
266 dd->dd_pacode[0x3] = parseword(codebase + 0x030) & ~3;
267 dd->dd_pacode[0x4] = parseword(codebase + 0x040) & ~3;
268 dd->dd_pacode[0x5] = parseword(codebase + 0x050) & ~3;
269 dd->dd_pacode[0x6] = parseword(codebase + 0x060) & ~3;
270 dd->dd_pacode[0x7] = parseword(codebase + 0x070) & ~3;
271 dd->dd_pacode[0x8] = parseword(codebase + 0x080) & ~3;
272 dd->dd_pacode[0x9] = parseword(codebase + 0x090) & ~3;
273 dd->dd_pacode[0xa] = parseword(codebase + 0x0a0) & ~3;
274 dd->dd_pacode[0xb] = parseword(codebase + 0x0b0) & ~3;
275 dd->dd_pacode[0xc] = parseword(codebase + 0x0c0) & ~3;
276 dd->dd_pacode[0xd] = parseword(codebase + 0x0d0) & ~3;
277 dd->dd_pacode[0xe] = parseword(codebase + 0x0e0) & ~3;
278 dd->dd_pacode[0xf] = parseword(codebase + 0x0f0) & ~3;
279 } else { /* STI_DEVTYPE4 */
280 bus_space_read_raw_region_4(memt, romh, 0, (u_int8_t *)dd,
281 sizeof(*dd));
282 /* fix pacode... */
283 bus_space_read_raw_region_4(memt, romh, codebase,
284 (u_int8_t *)dd->dd_pacode, sizeof(dd->dd_pacode));
285 }
286
287 STI_DISABLE_ROM(rom->rom_softc);
288
289 #ifdef STIDEBUG
290 printf("dd:\n"
291 "devtype=%x, rev=%x;%d, altt=%x, gid=%08x%08x, font=%x, mss=%x\n"
292 "end=%x, regions=%x, msto=%x, timo=%d, mont=%x, user=%x[%x]\n"
293 "memrq=%x, pwr=%d, bus=%x, ebus=%x, cfb=%x\n"
294 "code=",
295 dd->dd_type & 0xff, dd->dd_grrev, dd->dd_lrrev, dd->dd_altcodet,
296 dd->dd_grid[0], dd->dd_grid[1], dd->dd_fntaddr, dd->dd_maxst,
297 dd->dd_romend, dd->dd_reglst, dd->dd_maxreent, dd->dd_maxtimo,
298 dd->dd_montbl, dd->dd_udaddr, dd->dd_udsize, dd->dd_stimemreq,
299 dd->dd_pwruse, dd->dd_bussup, dd->dd_ebussup, dd->dd_cfbaddr);
300 printf("%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
301 dd->dd_pacode[0x0], dd->dd_pacode[0x1], dd->dd_pacode[0x2],
302 dd->dd_pacode[0x3], dd->dd_pacode[0x4], dd->dd_pacode[0x5],
303 dd->dd_pacode[0x6], dd->dd_pacode[0x7], dd->dd_pacode[0x8],
304 dd->dd_pacode[0x9], dd->dd_pacode[0xa], dd->dd_pacode[0xb],
305 dd->dd_pacode[0xc], dd->dd_pacode[0xd], dd->dd_pacode[0xe],
306 dd->dd_pacode[0xf]);
307 #endif
308
309 /*
310 * Take note that it will be necessary to enable the PCI ROM around
311 * some sti function calls if the MMAP (multiple map) bit is set in
312 * the bus support flags, which means the PCI ROM is only available
313 * through the PCI expansion ROM space and never through regular
314 * PCI BARs.
315 */
316 rom->rom_enable = dd->dd_bussup & STI_BUSSUPPORT_ROMMAP;
317
318 /*
319 * Figure out how much bytes we need for the STI code.
320 * Note there could be fewer than STI_END entries pointer
321 * entries populated, especially on older devices.
322 */
323
324 for (i = STI_END; dd->dd_pacode[i] == 0; i--)
325 ;
326 size = dd->dd_pacode[i] - dd->dd_pacode[STI_BEGIN];
327 if (rom->rom_devtype == STI_DEVTYPE1)
328 size = (size + 3) / 4;
329 if (size == 0) {
330 printf(": no code for the requested platform\n");
331 return (EINVAL);
332 }
333
334 if (!(rom->rom_code = km_alloc(round_page(size), &kv_any,
335 &kp_zero, &kd_waitok))) {
336 printf(": cannot allocate %u bytes for code\n", size);
337 return (ENOMEM);
338 }
339 #ifdef STIDEBUG
340 printf("code=%p[%x]\n", rom->rom_code, size);
341 #endif
342
343 /*
344 * Copy code into memory and make it executable.
345 */
346
347 STI_ENABLE_ROM(rom->rom_softc);
348
349 if (rom->rom_devtype == STI_DEVTYPE1) {
350 u_int8_t *p = rom->rom_code;
351 u_int32_t addr, eaddr;
352
353 for (addr = dd->dd_pacode[STI_BEGIN], eaddr = addr + size * 4;
354 addr < eaddr; addr += 4)
355 *p++ = bus_space_read_4(memt, romh, addr) & 0xff;
356 } else /* STI_DEVTYPE4 */
357 bus_space_read_raw_region_4(memt, romh,
358 dd->dd_pacode[STI_BEGIN], rom->rom_code, size);
359
360 STI_DISABLE_ROM(rom->rom_softc);
361
362 /*
363 * Remap the ROM code as executable. This happens to be the
364 * only place in the OpenBSD kernel where we need to do this.
365 * Since the kernel (deliberately) doesn't provide a
366 * high-level interface to map kernel memory as executable we
367 * use low-level pmap calls for this.
368 */
369 for (va = (vaddr_t)rom->rom_code;
370 va < (vaddr_t)rom->rom_code + round_page(size);
371 va += PAGE_SIZE) {
372 pmap_extract(pmap_kernel(), va, &pa);
373 pmap_kenter_pa(va, pa, PROT_READ | PROT_EXEC);
374 }
375 pmap_update(pmap_kernel());
376
377 /*
378 * Setup code function pointers.
379 */
380
381 #define O(i) \
382 (dd->dd_pacode[(i)] == 0 ? 0 : \
383 (rom->rom_code + (dd->dd_pacode[(i)] - dd->dd_pacode[0]) / \
384 (rom->rom_devtype == STI_DEVTYPE1? 4 : 1)))
385
386 rom->init = (sti_init_t)O(STI_INIT_GRAPH);
387 rom->unpmv = (sti_unpmv_t)O(STI_FONT_UNPMV);
388 rom->blkmv = (sti_blkmv_t)O(STI_BLOCK_MOVE);
389 rom->inqconf = (sti_inqconf_t)O(STI_INQ_CONF);
390 rom->scment = (sti_scment_t)O(STI_SCM_ENT);
391
392 #undef O
393
394 /*
395 * Set colormap entry is not implemented until 8.04, so force
396 * a NULL pointer here.
397 */
398 if (dd->dd_grrev < STI_REVISION(8,4)) {
399 rom->scment = NULL;
400 }
401
402 return (0);
403 }
404
405 /*
406 * Map all regions.
407 */
408 void
sti_region_setup(struct sti_screen * scr)409 sti_region_setup(struct sti_screen *scr)
410 {
411 struct sti_rom *rom = scr->scr_rom;
412 bus_space_tag_t memt = rom->memt;
413 bus_space_handle_t romh = rom->romh;
414 bus_addr_t *bases = rom->bases;
415 struct sti_dd *dd = &rom->rom_dd;
416 struct sti_cfg *cc = &scr->scr_cfg;
417 struct sti_region regions[STI_REGION_MAX], *r;
418 u_int regno, regcnt;
419 bus_addr_t addr;
420
421 #ifdef STIDEBUG
422 printf("stiregions @%p:\n", (void *)dd->dd_reglst);
423 #endif
424
425 /*
426 * Read the region information.
427 */
428
429 STI_ENABLE_ROM(rom->rom_softc);
430
431 if (rom->rom_devtype == STI_DEVTYPE1) {
432 for (regno = 0; regno < STI_REGION_MAX; regno++)
433 *(u_int *)(regions + regno) =
434 parseword(dd->dd_reglst + regno * 0x10);
435 } else {
436 bus_space_read_raw_region_4(memt, romh, dd->dd_reglst,
437 (u_int8_t *)regions, sizeof regions);
438 }
439
440 STI_DISABLE_ROM(rom->rom_softc);
441
442 /*
443 * Count them.
444 */
445
446 for (regcnt = 0, r = regions; regcnt < STI_REGION_MAX; regcnt++, r++)
447 if (r->last)
448 break;
449 regcnt++;
450
451 /*
452 * Map them.
453 */
454
455 for (regno = 0, r = regions; regno < regcnt; regno++, r++) {
456 if (r->length == 0)
457 continue;
458
459 /*
460 * Assume an existing mapping exists.
461 */
462 addr = bases[regno] + (r->offset << PGSHIFT);
463
464 #ifdef STIDEBUG
465 printf("%08x @ 0x%08lx%s%s%s%s\n",
466 r->length << PGSHIFT, addr, r->sys_only ? " sys" : "",
467 r->cache ? " cache" : "", r->btlb ? " btlb" : "",
468 r->last ? " last" : "");
469 #endif
470
471 /*
472 * Region #0 is always the rom, and it should have been
473 * mapped already.
474 * XXX This expects a 1:1 mapping...
475 */
476 if (regno == 0 && romh == bases[0]) {
477 cc->regions[0] = addr;
478 continue;
479 }
480
481 if (bus_space_map(memt, addr, r->length << PGSHIFT,
482 BUS_SPACE_MAP_LINEAR | (r->cache ?
483 BUS_SPACE_MAP_CACHEABLE : 0), &rom->regh[regno]) != 0) {
484 rom->regh[regno] = romh; /* XXX */
485 #ifdef STIDEBUG
486 printf("already mapped region\n");
487 #endif
488 } else {
489 addr = (bus_addr_t)
490 bus_space_vaddr(memt, rom->regh[regno]);
491 if (regno == 1) {
492 scr->fbaddr = addr;
493 scr->fblen = r->length << PGSHIFT;
494 }
495 }
496
497 cc->regions[regno] = addr;
498 }
499
500 #ifdef STIDEBUG
501 /*
502 * Make sure we'll trap accessing unmapped regions
503 */
504 for (regno = 0; regno < STI_REGION_MAX; regno++)
505 if (cc->regions[regno] == 0)
506 cc->regions[regno] = 0x81234567;
507 #endif
508 }
509
510 /*
511 * ``gvid'' callback routine.
512 *
513 * The FireGL-UX board is using this interface, and will revert to direct
514 * PDC calls if no gvid callback is set.
515 * Unfortunately, under OpenBSD it is not possible to invoke PDC directly
516 * from its physical address once the MMU is turned on, and no documentation
517 * for the gvid interface (or for the particular PDC_PCI subroutines used
518 * by the FireGL-UX rom) has been found.
519 */
520 int32_t
sti_gvid(void * v,uint32_t cmd,uint32_t * params)521 sti_gvid(void *v, uint32_t cmd, uint32_t *params)
522 {
523 struct sti_screen *scr = v;
524 struct sti_rom *rom = scr->scr_rom;
525
526 /* paranoia */
527 if (cmd != 0x000c0003)
528 return -1;
529
530 switch (params[0]) {
531 case 4:
532 /* register read */
533 params[2] =
534 bus_space_read_4(rom->memt, rom->regh[2], params[1]);
535 return 0;
536 case 5:
537 /* register write */
538 bus_space_write_4(rom->memt, rom->regh[2], params[1],
539 params[2]);
540 return 0;
541 default:
542 return -1;
543 }
544 }
545
546 int
sti_screen_setup(struct sti_screen * scr,int flags)547 sti_screen_setup(struct sti_screen *scr, int flags)
548 {
549 struct sti_rom *rom = scr->scr_rom;
550 bus_space_tag_t memt = rom->memt;
551 bus_space_handle_t romh = rom->romh;
552 struct sti_dd *dd = &rom->rom_dd;
553 struct sti_cfg *cc = &scr->scr_cfg;
554 struct sti_inqconfout inq;
555 struct sti_einqconfout einq;
556 int error, i;
557 int geometry_kluge = 0;
558 u_int fontindex = 0;
559
560 bzero(cc, sizeof (*cc));
561 cc->ext_cfg = &scr->scr_ecfg;
562 bzero(cc->ext_cfg, sizeof(*cc->ext_cfg));
563
564 if (dd->dd_stimemreq) {
565 scr->scr_ecfg.addr =
566 malloc(dd->dd_stimemreq, M_DEVBUF, M_NOWAIT | M_ZERO);
567 if (!scr->scr_ecfg.addr) {
568 printf("cannot allocate %d bytes for STI\n",
569 dd->dd_stimemreq);
570 return (ENOMEM);
571 }
572 }
573
574 if (dd->dd_ebussup & STI_EBUSSUPPORT_GVID) {
575 scr->scr_ecfg.future.g.gvid_cmd_arg = scr;
576 scr->scr_ecfg.future.g.gvid_cmd =
577 (int32_t (*)(void *, ...))sti_gvid;
578 }
579
580 sti_region_setup(scr);
581
582 if ((error = sti_init(scr, 0))) {
583 printf(": can not initialize (%d)\n", error);
584 goto fail;
585 }
586
587 bzero(&inq, sizeof(inq));
588 bzero(&einq, sizeof(einq));
589 inq.ext = &einq;
590 if ((error = sti_inqcfg(scr, &inq))) {
591 printf(": error %d inquiring config\n", error);
592 goto fail;
593 }
594
595 /*
596 * Older (rev 8.02) boards report wrong offset values,
597 * similar to the displayable area size, at least in m68k mode.
598 * Attempt to detect this and adjust here.
599 */
600 if (inq.owidth == inq.width && inq.oheight == inq.height)
601 geometry_kluge = 1;
602
603 if (geometry_kluge) {
604 scr->scr_cfg.oscr_width = inq.owidth =
605 inq.fbwidth - inq.width;
606 scr->scr_cfg.oscr_height = inq.oheight =
607 inq.fbheight - inq.height;
608 }
609
610 /*
611 * Save a few fields for sti_describe_screen() later
612 */
613 scr->fbheight = inq.fbheight;
614 scr->fbwidth = inq.fbwidth;
615 scr->oheight = inq.oheight;
616 scr->owidth = inq.owidth;
617 bcopy(inq.name, scr->name, sizeof(scr->name));
618
619 if ((error = sti_init(scr, STI_TEXTMODE | flags))) {
620 printf(": can not initialize (%d)\n", error);
621 goto fail;
622 }
623 #ifdef STIDEBUG
624 printf("conf: bpp=%d planes=%d attr=%b\n"
625 "crt=0x%x:0x%x:0x%x hw=0x%x:0x%x:0x%x\n", inq.bpp,
626 inq.planes, inq.attributes, STI_INQCONF_BITS,
627 einq.crt_config[0], einq.crt_config[1], einq.crt_config[2],
628 einq.crt_hw[0], einq.crt_hw[1], einq.crt_hw[2]);
629 #endif
630 scr->scr_bpp = inq.bppu;
631
632 /*
633 * Although scr->scr_ecfg.current_monitor is not filled by
634 * sti_init() as expected, we can nevertheless walk the monitor
635 * list, if there is any, and if we find a mode matching our
636 * resolution, pick its font index.
637 */
638 if (dd->dd_montbl != 0) {
639 STI_ENABLE_ROM(rom->rom_softc);
640
641 for (i = 0; i < dd->dd_nmon; i++) {
642 u_int offs = dd->dd_montbl + 8 * i;
643 u_int32_t m[2];
644 sti_mon_t mon = (void *)m;
645 if (rom->rom_devtype == STI_DEVTYPE1) {
646 m[0] = parseword(4 * offs);
647 m[1] = parseword(4 * (offs + 4));
648 } else {
649 bus_space_read_raw_region_4(memt, romh, offs,
650 (u_int8_t *)mon, sizeof(*mon));
651 }
652
653 if (mon->width == scr->scr_cfg.scr_width &&
654 mon->height == scr->scr_cfg.scr_height) {
655 fontindex = mon->font;
656 break;
657 }
658 }
659
660 STI_DISABLE_ROM(rom->rom_softc);
661
662 #ifdef STIDEBUG
663 printf("font index: %d\n", fontindex);
664 #endif
665 }
666
667 if ((error = sti_fetchfonts(scr, &inq, dd->dd_fntaddr, fontindex))) {
668 printf(": cannot fetch fonts (%d)\n", error);
669 goto fail;
670 }
671
672 /*
673 * setup screen descriptions:
674 * figure number of fonts supported;
675 * allocate wscons structures;
676 * calculate dimensions.
677 */
678
679 strlcpy(scr->scr_wsd.name, "std", sizeof(scr->scr_wsd.name));
680 scr->scr_wsd.ncols = inq.width / scr->scr_curfont.width;
681 scr->scr_wsd.nrows = inq.height / scr->scr_curfont.height;
682 scr->scr_wsd.textops = &sti_emulops;
683 scr->scr_wsd.fontwidth = scr->scr_curfont.width;
684 scr->scr_wsd.fontheight = scr->scr_curfont.height;
685 scr->scr_wsd.capabilities = WSSCREEN_REVERSE;
686
687 scr->scr_scrlist[0] = &scr->scr_wsd;
688 scr->scr_screenlist.nscreens = 1;
689 scr->scr_screenlist.screens =
690 (const struct wsscreen_descr **)scr->scr_scrlist;
691
692 #ifndef SMALL_KERNEL
693 /*
694 * Decide which board-specific routines to use.
695 */
696
697 switch (dd->dd_grid[0]) {
698 case STI_DD_CRX:
699 scr->setupfb = ngle_elk_setupfb;
700 scr->putcmap = ngle_putcmap;
701
702 scr->reg10_value = 0x13601000;
703 if (scr->scr_bpp > 8)
704 scr->reg12_value = NGLE_BUFF1_CMAP3;
705 else
706 scr->reg12_value = NGLE_BUFF1_CMAP0;
707 scr->cmap_finish_register = NGLE_REG_1;
708 break;
709
710 case STI_DD_TIMBER:
711 scr->setupfb = ngle_timber_setupfb;
712 scr->putcmap = ngle_putcmap;
713
714 scr->reg10_value = 0x13602000;
715 scr->reg12_value = NGLE_BUFF1_CMAP0;
716 scr->cmap_finish_register = NGLE_REG_1;
717 break;
718
719 case STI_DD_ARTIST:
720 scr->setupfb = ngle_artist_setupfb;
721 scr->putcmap = ngle_putcmap;
722
723 scr->reg10_value = 0x13601000;
724 scr->reg12_value = NGLE_ARTIST_CMAP0;
725 scr->cmap_finish_register = NGLE_REG_26;
726 break;
727
728 case STI_DD_EG:
729 scr->setupfb = ngle_artist_setupfb;
730 scr->putcmap = ngle_putcmap;
731
732 scr->reg10_value = 0x13601000;
733 if (scr->scr_bpp > 8) {
734 scr->reg12_value = NGLE_BUFF1_CMAP3;
735 scr->cmap_finish_register = NGLE_REG_1;
736 } else {
737 scr->reg12_value = NGLE_ARTIST_CMAP0;
738 scr->cmap_finish_register = NGLE_REG_26;
739 }
740 break;
741
742 case STI_DD_GRX:
743 case STI_DD_CRX24:
744 case STI_DD_EVRX:
745 case STI_DD_3X2V:
746 case STI_DD_DUAL_CRX:
747 case STI_DD_HCRX:
748 case STI_DD_SUMMIT:
749 case STI_DD_PINNACLE:
750 case STI_DD_LEGO:
751 case STI_DD_FIREGL:
752 default:
753 scr->setupfb = NULL;
754 scr->putcmap =
755 rom->scment == NULL ? NULL : ngle_default_putcmap;
756 break;
757 }
758 #endif
759
760 return (0);
761
762 fail:
763 /* free resources */
764 if (scr->scr_romfont != NULL) {
765 free(scr->scr_romfont, M_DEVBUF, 0);
766 scr->scr_romfont = NULL;
767 }
768 if (scr->scr_ecfg.addr != NULL) {
769 free(scr->scr_ecfg.addr, M_DEVBUF, 0);
770 scr->scr_ecfg.addr = NULL;
771 }
772
773 return (ENXIO);
774 }
775
776 void
sti_describe_screen(struct sti_softc * sc,struct sti_screen * scr)777 sti_describe_screen(struct sti_softc *sc, struct sti_screen *scr)
778 {
779 struct sti_font *fp = &scr->scr_curfont;
780
781 printf("%s: %s, %dx%d frame buffer, %dx%dx%d display\n",
782 sc->sc_dev.dv_xname, scr->name, scr->fbwidth, scr->fbheight,
783 scr->scr_cfg.scr_width, scr->scr_cfg.scr_height, scr->scr_bpp);
784
785 printf("%s: %dx%d font type %d, %d bpc, charset %d-%d\n",
786 sc->sc_dev.dv_xname, fp->width, fp->height,
787 fp->type, fp->bpc, fp->first, fp->last);
788 }
789
790 void
sti_describe(struct sti_softc * sc)791 sti_describe(struct sti_softc *sc)
792 {
793 struct sti_rom *rom = sc->sc_rom;
794 struct sti_dd *dd = &rom->rom_dd;
795
796 printf(": rev %d.%02d;%d, ID 0x%08X%08X\n",
797 dd->dd_grrev >> 4, dd->dd_grrev & 0xf,
798 dd->dd_lrrev, dd->dd_grid[0], dd->dd_grid[1]);
799
800 if (sc->sc_scr != NULL)
801 sti_describe_screen(sc, sc->sc_scr);
802 }
803
804 /*
805 * Final part of attachment. On hppa where we use the PDC console
806 * during autoconf, this has to be postponed until autoconf has
807 * completed.
808 */
809 void
sti_end_attach(void * v)810 sti_end_attach(void *v)
811 {
812 struct sti_softc *sc = (struct sti_softc *)v;
813
814 if (sc->sc_scr != NULL)
815 sti_end_attach_screen(sc, sc->sc_scr,
816 sc->sc_flags & STI_CONSOLE ? 1 : 0);
817 }
818
819 void
sti_end_attach_screen(struct sti_softc * sc,struct sti_screen * scr,int console)820 sti_end_attach_screen(struct sti_softc *sc, struct sti_screen *scr, int console)
821 {
822 struct wsemuldisplaydev_attach_args waa;
823
824 scr->scr_wsmode = WSDISPLAYIO_MODE_EMUL;
825
826 waa.console = console;
827 waa.scrdata = &scr->scr_screenlist;
828 waa.accessops = &sti_accessops;
829 waa.accesscookie = scr;
830 waa.defaultscreens = 0;
831
832 /* attach as console if required */
833 if (console && !ISSET(sc->sc_flags, STI_ATTACHED)) {
834 uint32_t defattr;
835
836 sti_pack_attr(scr, 0, 0, 0, &defattr);
837 wsdisplay_cnattach(&scr->scr_wsd, scr,
838 0, scr->scr_wsd.nrows - 1, defattr);
839 sc->sc_flags |= STI_ATTACHED;
840 }
841
842 config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint);
843 }
844
845 u_int
sti_rom_size(bus_space_tag_t memt,bus_space_handle_t romh)846 sti_rom_size(bus_space_tag_t memt, bus_space_handle_t romh)
847 {
848 int devtype;
849 u_int romend;
850
851 devtype = bus_space_read_1(memt, romh, 3);
852 if (devtype == STI_DEVTYPE4) {
853 bus_space_read_raw_region_4(memt, romh, 0x18,
854 (u_int8_t *)&romend, 4);
855 } else {
856 romend = parseword(0x50);
857 }
858
859 return (round_page(romend));
860 }
861
862 int
sti_fetchfonts(struct sti_screen * scr,struct sti_inqconfout * inq,u_int32_t baseaddr,u_int fontindex)863 sti_fetchfonts(struct sti_screen *scr, struct sti_inqconfout *inq,
864 u_int32_t baseaddr, u_int fontindex)
865 {
866 struct sti_rom *rom = scr->scr_rom;
867 bus_space_tag_t memt = rom->memt;
868 bus_space_handle_t romh = rom->romh;
869 struct sti_font *fp = &scr->scr_curfont;
870 u_int32_t addr;
871 int size;
872 #ifdef notyet
873 int uc;
874 struct {
875 struct sti_unpmvflags flags;
876 struct sti_unpmvin in;
877 struct sti_unpmvout out;
878 } a;
879 #endif
880
881 /*
882 * Get the first PROM font in memory
883 */
884
885 STI_ENABLE_ROM(rom->rom_softc);
886
887 rescan:
888 addr = baseaddr;
889 do {
890 if (rom->rom_devtype == STI_DEVTYPE1) {
891 fp->first = parseshort(addr + 0x00);
892 fp->last = parseshort(addr + 0x08);
893 fp->width = bus_space_read_1(memt, romh,
894 addr + 0x13);
895 fp->height = bus_space_read_1(memt, romh,
896 addr + 0x17);
897 fp->type = bus_space_read_1(memt, romh,
898 addr + 0x1b);
899 fp->bpc = bus_space_read_1(memt, romh,
900 addr + 0x1f);
901 fp->next = parseword(addr + 0x20);
902 fp->uheight= bus_space_read_1(memt, romh,
903 addr + 0x33);
904 fp->uoffset= bus_space_read_1(memt, romh,
905 addr + 0x37);
906 } else { /* STI_DEVTYPE4 */
907 bus_space_read_raw_region_4(memt, romh, addr,
908 (u_int8_t *)fp, sizeof(struct sti_font));
909 }
910
911 #ifdef STIDEBUG
912 STI_DISABLE_ROM(rom->rom_softc);
913 printf("font@%p: %d-%d, %dx%d, type %d, next %x\n",
914 (void *)addr, fp->first, fp->last, fp->width, fp->height,
915 fp->type, fp->next);
916 STI_ENABLE_ROM(rom->rom_softc);
917 #endif
918
919 if (fontindex == 0) {
920 size = sizeof(struct sti_font) +
921 (fp->last - fp->first + 1) * fp->bpc;
922 if (rom->rom_devtype == STI_DEVTYPE1)
923 size *= 4;
924 scr->scr_romfont = malloc(size, M_DEVBUF, M_NOWAIT);
925 if (scr->scr_romfont == NULL)
926 return (ENOMEM);
927
928 bus_space_read_raw_region_4(memt, romh, addr,
929 (u_int8_t *)scr->scr_romfont, size);
930
931 break;
932 }
933
934 addr = baseaddr + fp->next;
935 fontindex--;
936 } while (fp->next != 0);
937
938 /*
939 * If our font index was bogus, we did not find the expected font.
940 * In this case, pick the first one and be done with it.
941 */
942 if (fp->next == 0 && scr->scr_romfont == NULL) {
943 fontindex = 0;
944 goto rescan;
945 }
946
947 STI_DISABLE_ROM(rom->rom_softc);
948
949 #ifdef notyet
950 /*
951 * If there is enough room in the off-screen framebuffer memory,
952 * display all the characters there in order to display them
953 * faster with blkmv operations rather than unpmv later on.
954 */
955 if (size <= inq->fbheight *
956 (inq->fbwidth - inq->width - inq->owidth)) {
957 bzero(&a, sizeof(a));
958 a.flags.flags = STI_UNPMVF_WAIT;
959 a.in.fg_colour = STI_COLOUR_WHITE;
960 a.in.bg_colour = STI_COLOUR_BLACK;
961 a.in.font_addr = scr->scr_romfont;
962
963 scr->scr_fontmaxcol = inq->fbheight / fp->height;
964 scr->scr_fontbase = inq->width + inq->owidth;
965 for (uc = fp->first; uc <= fp->last; uc++) {
966 a.in.x = ((uc - fp->first) / scr->scr_fontmaxcol) *
967 fp->width + scr->scr_fontbase;
968 a.in.y = ((uc - fp->first) % scr->scr_fontmaxcol) *
969 fp->height;
970 a.in.index = uc;
971
972 (*scr->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
973 if (a.out.errno) {
974 #ifdef STIDEBUG
975 printf("sti_unpmv %d returned %d\n",
976 uc, a.out.errno);
977 #endif
978 return (0);
979 }
980 }
981
982 free(scr->scr_romfont, M_DEVBUF, 0);
983 scr->scr_romfont = NULL;
984 }
985 #endif
986
987 return (0);
988 }
989
990 /*
991 * Wrappers around STI code pointers
992 */
993
994 int
sti_init(struct sti_screen * scr,int mode)995 sti_init(struct sti_screen *scr, int mode)
996 {
997 struct sti_rom *rom = scr->scr_rom;
998 struct {
999 struct sti_initflags flags;
1000 struct sti_initin in;
1001 struct sti_einitin ein;
1002 struct sti_initout out;
1003 } a;
1004
1005 bzero(&a, sizeof(a));
1006
1007 a.flags.flags = STI_INITF_WAIT | STI_INITF_EBET;
1008 if (mode & STI_TEXTMODE) {
1009 a.flags.flags |= STI_INITF_TEXT /* | STI_INITF_PNTS */ |
1010 STI_INITF_ICMT | STI_INITF_CMB;
1011 if (mode & STI_CLEARSCR)
1012 a.flags.flags |= STI_INITF_CLEAR;
1013 } else if (mode & STI_FBMODE) {
1014 a.flags.flags |= STI_INITF_NTEXT /* | STI_INITF_PTS */;
1015 }
1016
1017 a.in.text_planes = 1;
1018 a.in.ext_in = &a.ein;
1019 #ifdef STIDEBUG
1020 printf("sti_init,%p(%x, %p, %p, %p)\n",
1021 rom->init, a.flags.flags, &a.in, &a.out, &scr->scr_cfg);
1022 #endif
1023 /*
1024 * Make the ROM visible during initialization, some devices
1025 * look for various data into their ROM image.
1026 */
1027 if (rom->rom_enable)
1028 STI_ENABLE_ROM(rom->rom_softc);
1029 (*rom->init)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1030 if (rom->rom_enable)
1031 STI_DISABLE_ROM(rom->rom_softc);
1032 if (a.out.text_planes != a.in.text_planes)
1033 return (-1); /* not colliding with sti errno values */
1034 return (a.out.errno);
1035 }
1036
1037 int
sti_inqcfg(struct sti_screen * scr,struct sti_inqconfout * out)1038 sti_inqcfg(struct sti_screen *scr, struct sti_inqconfout *out)
1039 {
1040 struct sti_rom *rom = scr->scr_rom;
1041 struct {
1042 struct sti_inqconfflags flags;
1043 struct sti_inqconfin in;
1044 } a;
1045
1046 bzero(&a, sizeof(a));
1047
1048 a.flags.flags = STI_INQCONFF_WAIT;
1049 (*rom->inqconf)(&a.flags, &a.in, out, &scr->scr_cfg);
1050
1051 return out->errno;
1052 }
1053
1054 void
sti_bmove(struct sti_screen * scr,int x1,int y1,int x2,int y2,int h,int w,enum sti_bmove_funcs f)1055 sti_bmove(struct sti_screen *scr, int x1, int y1, int x2, int y2, int h, int w,
1056 enum sti_bmove_funcs f)
1057 {
1058 struct sti_rom *rom = scr->scr_rom;
1059 struct {
1060 struct sti_blkmvflags flags;
1061 struct sti_blkmvin in;
1062 struct sti_blkmvout out;
1063 } a;
1064
1065 bzero(&a, sizeof(a));
1066
1067 a.flags.flags = STI_BLKMVF_WAIT;
1068 switch (f) {
1069 case bmf_clear:
1070 a.flags.flags |= STI_BLKMVF_CLR;
1071 a.in.bg_colour = STI_COLOUR_BLACK;
1072 break;
1073 case bmf_underline:
1074 case bmf_copy:
1075 a.in.fg_colour = STI_COLOUR_WHITE;
1076 a.in.bg_colour = STI_COLOUR_BLACK;
1077 break;
1078 case bmf_invert:
1079 a.flags.flags |= STI_BLKMVF_COLR;
1080 a.in.fg_colour = STI_COLOUR_BLACK;
1081 a.in.bg_colour = STI_COLOUR_WHITE;
1082 break;
1083 }
1084 a.in.srcx = x1;
1085 a.in.srcy = y1;
1086 a.in.dstx = x2;
1087 a.in.dsty = y2;
1088 a.in.height = h;
1089 a.in.width = w;
1090
1091 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1092 #ifdef STIDEBUG
1093 if (a.out.errno)
1094 printf("sti_blkmv returned %d\n", a.out.errno);
1095 #endif
1096 }
1097
1098 int
sti_setcment(struct sti_screen * scr,u_int i,u_char r,u_char g,u_char b)1099 sti_setcment(struct sti_screen *scr, u_int i, u_char r, u_char g, u_char b)
1100 {
1101 struct sti_rom *rom = scr->scr_rom;
1102 struct {
1103 struct sti_scmentflags flags;
1104 struct sti_scmentin in;
1105 struct sti_scmentout out;
1106 } a;
1107
1108 bzero(&a, sizeof(a));
1109
1110 a.flags.flags = STI_SCMENTF_WAIT;
1111 a.in.entry = i;
1112 a.in.value = (r << 16) | (g << 8) | b;
1113
1114 (*rom->scment)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1115 #ifdef STIDEBUG
1116 if (a.out.errno)
1117 printf("sti_setcment(%d, %u, %u, %u): %d\n",
1118 i, r, g, b, a.out.errno);
1119 #endif
1120
1121 return a.out.errno;
1122 }
1123
1124 /*
1125 * wsdisplay accessops
1126 */
1127
1128 int
sti_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)1129 sti_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1130 {
1131 struct sti_screen *scr = (struct sti_screen *)v;
1132 struct wsdisplay_fbinfo *wdf;
1133 struct wsdisplay_cmap *cmapp;
1134 u_int mode, idx, count;
1135 int ret;
1136
1137 ret = 0;
1138 switch (cmd) {
1139 case WSDISPLAYIO_SMODE:
1140 mode = *(u_int *)data;
1141 switch (mode) {
1142 case WSDISPLAYIO_MODE_EMUL:
1143 if (scr->scr_wsmode != WSDISPLAYIO_MODE_EMUL)
1144 ret = sti_init(scr, STI_TEXTMODE);
1145 break;
1146 case WSDISPLAYIO_MODE_DUMBFB:
1147 if (scr->scr_wsmode != WSDISPLAYIO_MODE_DUMBFB) {
1148 if (scr->setupfb != NULL)
1149 scr->setupfb(scr);
1150 else
1151 #if 0
1152 ret = sti_init(scr, STI_FBMODE);
1153 #else
1154 ret = EINVAL;
1155 #endif
1156 }
1157 break;
1158 case WSDISPLAYIO_MODE_MAPPED:
1159 default:
1160 ret = EINVAL;
1161 break;
1162 }
1163 if (ret == 0)
1164 scr->scr_wsmode = mode;
1165 break;
1166
1167 case WSDISPLAYIO_GTYPE:
1168 *(u_int *)data = WSDISPLAY_TYPE_STI;
1169 break;
1170
1171 case WSDISPLAYIO_GINFO:
1172 wdf = (struct wsdisplay_fbinfo *)data;
1173 wdf->height = scr->scr_cfg.scr_height;
1174 wdf->width = scr->scr_cfg.scr_width;
1175 wdf->depth = scr->scr_bpp;
1176 if (scr->scr_bpp > 8)
1177 wdf->stride = scr->scr_cfg.fb_width * 4;
1178 else
1179 wdf->stride = scr->scr_cfg.fb_width;
1180 wdf->offset = 0;
1181 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1182 wdf->cmsize = 0;
1183 else
1184 wdf->cmsize = STI_NCMAP;
1185 break;
1186
1187 case WSDISPLAYIO_LINEBYTES:
1188 if (scr->scr_bpp > 8)
1189 *(u_int *)data = scr->scr_cfg.fb_width * 4;
1190 else
1191 *(u_int *)data = scr->scr_cfg.fb_width;
1192 break;
1193
1194 case WSDISPLAYIO_GETSUPPORTEDDEPTH:
1195 if (scr->scr_bpp > 8)
1196 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
1197 else
1198 *(u_int *)data = WSDISPLAYIO_DEPTH_8;
1199 break;
1200
1201 case WSDISPLAYIO_GETCMAP:
1202 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1203 return ENODEV;
1204 cmapp = (struct wsdisplay_cmap *)data;
1205 idx = cmapp->index;
1206 count = cmapp->count;
1207 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1208 return EINVAL;
1209 if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
1210 break;
1211 if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
1212 break;
1213 if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
1214 break;
1215 break;
1216
1217 case WSDISPLAYIO_PUTCMAP:
1218 if (scr->putcmap == NULL || scr->scr_bpp > 8)
1219 return ENODEV;
1220 cmapp = (struct wsdisplay_cmap *)data;
1221 idx = cmapp->index;
1222 count = cmapp->count;
1223 if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
1224 return EINVAL;
1225 if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
1226 break;
1227 if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
1228 break;
1229 if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
1230 break;
1231 ret = scr->putcmap(scr, idx, count);
1232 break;
1233
1234 case WSDISPLAYIO_SVIDEO:
1235 case WSDISPLAYIO_GVIDEO:
1236 break;
1237
1238 default:
1239 return (-1); /* not supported yet */
1240 }
1241
1242 return (ret);
1243 }
1244
1245 paddr_t
sti_mmap(void * v,off_t offset,int prot)1246 sti_mmap(void *v, off_t offset, int prot)
1247 {
1248 struct sti_screen *scr = (struct sti_screen *)v;
1249 #if 0
1250 struct sti_rom *rom = scr->scr_rom;
1251 #endif
1252 paddr_t pa;
1253
1254 if ((offset & PAGE_MASK) != 0)
1255 return -1;
1256
1257 if (offset < 0 || offset >= scr->fblen)
1258 return -1;
1259
1260 #if 0 /* XXX not all platforms provide bus_space_mmap() yet */
1261 pa = bus_space_mmap(rom->memt, scr->fbaddr, offset, prot,
1262 BUS_SPACE_MAP_LINEAR);
1263 #else
1264 pa = scr->fbaddr + offset;
1265 #endif
1266
1267 return pa;
1268 }
1269
1270 int
sti_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * cxp,int * cyp,uint32_t * defattr)1271 sti_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1272 int *cxp, int *cyp, uint32_t *defattr)
1273 {
1274 struct sti_screen *scr = (struct sti_screen *)v;
1275
1276 if (scr->scr_nscreens > 0)
1277 return ENOMEM;
1278
1279 *cookiep = scr;
1280 *cxp = 0;
1281 *cyp = 0;
1282 sti_pack_attr(scr, 0, 0, 0, defattr);
1283 scr->scr_nscreens++;
1284 return 0;
1285 }
1286
1287 void
sti_free_screen(void * v,void * cookie)1288 sti_free_screen(void *v, void *cookie)
1289 {
1290 struct sti_screen *scr = (struct sti_screen *)v;
1291
1292 scr->scr_nscreens--;
1293 }
1294
1295 int
sti_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)1296 sti_show_screen(void *v, void *cookie, int waitok,
1297 void (*cb)(void *, int, int), void *cbarg)
1298 {
1299 #if 0
1300 struct sti_screen *scr = (struct sti_screen *)v;
1301 #endif
1302
1303 return 0;
1304 }
1305
1306 /*
1307 * wsdisplay emulops
1308 */
1309
1310 int
sti_cursor(void * v,int on,int row,int col)1311 sti_cursor(void *v, int on, int row, int col)
1312 {
1313 struct sti_screen *scr = (struct sti_screen *)v;
1314 struct sti_font *fp = &scr->scr_curfont;
1315
1316 sti_bmove(scr,
1317 col * fp->width, row * fp->height,
1318 col * fp->width, row * fp->height,
1319 fp->height, fp->width, bmf_invert);
1320
1321 return 0;
1322 }
1323
1324 /*
1325 * ISO 8859-1 part of Unicode to HP Roman font index conversion array.
1326 */
1327 static const u_int8_t
1328 sti_unitoroman[0x100 - 0xa0] = {
1329 0xa0, 0xb8, 0xbf, 0xbb, 0xba, 0xbc, 0, 0xbd,
1330 0xab, 0, 0xf9, 0xfb, 0, 0xf6, 0, 0xb0,
1331
1332 0xb3, 0xfe, 0, 0, 0xa8, 0xf3, 0xf4, 0xf2,
1333 0, 0, 0xfa, 0xfd, 0xf7, 0xf8, 0, 0xb9,
1334
1335 0xa1, 0xe0, 0xa2, 0xe1, 0xd8, 0xd0, 0xd3, 0xb4,
1336 0xa3, 0xdc, 0xa4, 0xa5, 0xe6, 0xe5, 0xa6, 0xa7,
1337
1338 0xe3, 0xb6, 0xe8, 0xe7, 0xdf, 0xe9, 0xda, 0,
1339 0xd2, 0xad, 0xed, 0xae, 0xdb, 0xb1, 0xf0, 0xde,
1340
1341 0xc8, 0xc4, 0xc0, 0xe2, 0xcc, 0xd4, 0xd7, 0xb5,
1342 0xc9, 0xc5, 0xc1, 0xcd, 0xd9, 0xd5, 0xd1, 0xdd,
1343
1344 0xe4, 0xb7, 0xca, 0xc6, 0xc2, 0xea, 0xce, 0,
1345 0xd6, 0xcb, 0xc7, 0xc3, 0xcf, 0xb2, 0xf1, 0xef
1346 };
1347
1348 int
sti_mapchar(void * v,int uni,u_int * index)1349 sti_mapchar(void *v, int uni, u_int *index)
1350 {
1351 struct sti_screen *scr = (struct sti_screen *)v;
1352 struct sti_font *fp = &scr->scr_curfont;
1353 int c;
1354
1355 switch (fp->type) {
1356 case STI_FONT_HPROMAN8:
1357 if (uni >= 0x80 && uni < 0xa0)
1358 c = -1;
1359 else if (uni >= 0xa0 && uni < 0x100) {
1360 c = (int)sti_unitoroman[uni - 0xa0];
1361 if (c == 0)
1362 c = -1;
1363 } else
1364 c = uni;
1365 break;
1366 default:
1367 c = uni;
1368 break;
1369 }
1370
1371 if (c == -1 || c < fp->first || c > fp->last) {
1372 *index = '?';
1373 return (0);
1374 }
1375
1376 *index = c;
1377 return (5);
1378 }
1379
1380 int
sti_putchar(void * v,int row,int col,u_int uc,uint32_t attr)1381 sti_putchar(void *v, int row, int col, u_int uc, uint32_t attr)
1382 {
1383 struct sti_screen *scr = (struct sti_screen *)v;
1384 struct sti_rom *rom = scr->scr_rom;
1385 struct sti_font *fp = &scr->scr_curfont;
1386 int bg, fg;
1387
1388 sti_unpack_attr(scr, attr, &fg, &bg, NULL);
1389
1390 if (scr->scr_romfont != NULL) {
1391 /*
1392 * Font is in memory, use unpmv
1393 */
1394 struct {
1395 struct sti_unpmvflags flags;
1396 struct sti_unpmvin in;
1397 struct sti_unpmvout out;
1398 } a;
1399
1400 bzero(&a, sizeof(a));
1401
1402 a.flags.flags = STI_UNPMVF_WAIT;
1403 a.in.fg_colour = fg;
1404 a.in.bg_colour = bg;
1405
1406 a.in.x = col * fp->width;
1407 a.in.y = row * fp->height;
1408 a.in.font_addr = scr->scr_romfont;
1409 a.in.index = uc;
1410
1411 (*rom->unpmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1412 } else {
1413 /*
1414 * Font is in frame buffer, use blkmv
1415 */
1416 struct {
1417 struct sti_blkmvflags flags;
1418 struct sti_blkmvin in;
1419 struct sti_blkmvout out;
1420 } a;
1421
1422 bzero(&a, sizeof(a));
1423
1424 a.flags.flags = STI_BLKMVF_WAIT;
1425 a.in.fg_colour = fg;
1426 a.in.bg_colour = bg;
1427
1428 a.in.srcx = ((uc - fp->first) / scr->scr_fontmaxcol) *
1429 fp->width + scr->scr_fontbase;
1430 a.in.srcy = ((uc - fp->first) % scr->scr_fontmaxcol) *
1431 fp->height;
1432 a.in.dstx = col * fp->width;
1433 a.in.dsty = row * fp->height;
1434 a.in.height = fp->height;
1435 a.in.width = fp->width;
1436
1437 (*rom->blkmv)(&a.flags, &a.in, &a.out, &scr->scr_cfg);
1438 }
1439
1440 return 0;
1441 }
1442
1443 int
sti_copycols(void * v,int row,int srccol,int dstcol,int ncols)1444 sti_copycols(void *v, int row, int srccol, int dstcol, int ncols)
1445 {
1446 struct sti_screen *scr = (struct sti_screen *)v;
1447 struct sti_font *fp = &scr->scr_curfont;
1448
1449 sti_bmove(scr,
1450 srccol * fp->width, row * fp->height,
1451 dstcol * fp->width, row * fp->height,
1452 fp->height, ncols * fp->width, bmf_copy);
1453
1454 return 0;
1455 }
1456
1457 int
sti_erasecols(void * v,int row,int startcol,int ncols,uint32_t attr)1458 sti_erasecols(void *v, int row, int startcol, int ncols, uint32_t attr)
1459 {
1460 struct sti_screen *scr = (struct sti_screen *)v;
1461 struct sti_font *fp = &scr->scr_curfont;
1462
1463 sti_bmove(scr,
1464 startcol * fp->width, row * fp->height,
1465 startcol * fp->width, row * fp->height,
1466 fp->height, ncols * fp->width, bmf_clear);
1467
1468 return 0;
1469 }
1470
1471 int
sti_copyrows(void * v,int srcrow,int dstrow,int nrows)1472 sti_copyrows(void *v, int srcrow, int dstrow, int nrows)
1473 {
1474 struct sti_screen *scr = (struct sti_screen *)v;
1475 struct sti_font *fp = &scr->scr_curfont;
1476
1477 sti_bmove(scr, 0, srcrow * fp->height, 0, dstrow * fp->height,
1478 nrows * fp->height, scr->scr_cfg.scr_width, bmf_copy);
1479
1480 return 0;
1481 }
1482
1483 int
sti_eraserows(void * v,int srcrow,int nrows,uint32_t attr)1484 sti_eraserows(void *v, int srcrow, int nrows, uint32_t attr)
1485 {
1486 struct sti_screen *scr = (struct sti_screen *)v;
1487 struct sti_font *fp = &scr->scr_curfont;
1488
1489 sti_bmove(scr, 0, srcrow * fp->height, 0, srcrow * fp->height,
1490 nrows * fp->height, scr->scr_cfg.scr_width, bmf_clear);
1491
1492 return 0;
1493 }
1494
1495 int
sti_pack_attr(void * v,int fg,int bg,int flags,uint32_t * pattr)1496 sti_pack_attr(void *v, int fg, int bg, int flags, uint32_t *pattr)
1497 {
1498 #if 0
1499 struct sti_screen *scr = (struct sti_screen *)v;
1500 #endif
1501
1502 *pattr = flags & WSATTR_REVERSE;
1503 return 0;
1504 }
1505
1506 void
sti_unpack_attr(void * v,uint32_t attr,int * fg,int * bg,int * ul)1507 sti_unpack_attr(void *v, uint32_t attr, int *fg, int *bg, int *ul)
1508 {
1509 #if 0
1510 struct sti_screen *scr = (struct sti_screen *)v;
1511 #endif
1512
1513 if (attr & WSATTR_REVERSE) {
1514 *fg = STI_COLOUR_BLACK;
1515 *bg = STI_COLOUR_WHITE;
1516 } else {
1517 *fg = STI_COLOUR_WHITE;
1518 *bg = STI_COLOUR_BLACK;
1519 }
1520 if (ul != NULL)
1521 *ul = 0;
1522 }
1523
1524 int
ngle_default_putcmap(struct sti_screen * scr,u_int idx,u_int count)1525 ngle_default_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1526 {
1527 int i, ret;
1528
1529 for (i = idx + count - 1; i >= (int)idx; i--)
1530 if ((ret = sti_setcment(scr, i, scr->scr_rcmap[i],
1531 scr->scr_gcmap[i], scr->scr_bcmap[i])))
1532 return EINVAL;
1533
1534 return 0;
1535 }
1536
1537 #ifndef SMALL_KERNEL
1538
1539 void ngle_setup_hw(bus_space_tag_t, bus_space_handle_t);
1540 void ngle_setup_fb(bus_space_tag_t, bus_space_handle_t, uint32_t);
1541 void ngle_setup_attr_planes(struct sti_screen *scr);
1542 void ngle_setup_bt458(struct sti_screen *scr);
1543
1544 #define ngle_bt458_write(memt, memh, r, v) \
1545 bus_space_write_4(memt, memh, NGLE_REG_RAMDAC + ((r) << 2), (v) << 24)
1546
1547 void
ngle_artist_setupfb(struct sti_screen * scr)1548 ngle_artist_setupfb(struct sti_screen *scr)
1549 {
1550 struct sti_rom *rom = scr->scr_rom;
1551 bus_space_tag_t memt = rom->memt;
1552 bus_space_handle_t memh = rom->regh[2];
1553
1554 ngle_setup_bt458(scr);
1555
1556 ngle_setup_hw(memt, memh);
1557 ngle_setup_fb(memt, memh, scr->reg10_value);
1558
1559 ngle_setup_attr_planes(scr);
1560
1561 ngle_setup_hw(memt, memh);
1562 bus_space_write_4(memt, memh, NGLE_REG_21,
1563 bus_space_read_4(memt, memh, NGLE_REG_21) | 0x0a000000);
1564 bus_space_write_4(memt, memh, NGLE_REG_27,
1565 bus_space_read_4(memt, memh, NGLE_REG_27) | 0x00800000);
1566 }
1567
1568 void
ngle_elk_setupfb(struct sti_screen * scr)1569 ngle_elk_setupfb(struct sti_screen *scr)
1570 {
1571 struct sti_rom *rom = scr->scr_rom;
1572 bus_space_tag_t memt = rom->memt;
1573 bus_space_handle_t memh = rom->regh[2];
1574
1575 ngle_setup_bt458(scr);
1576
1577 ngle_setup_hw(memt, memh);
1578 ngle_setup_fb(memt, memh, scr->reg10_value);
1579
1580 ngle_setup_attr_planes(scr);
1581
1582 ngle_setup_hw(memt, memh);
1583 /* enable overlay planes in Bt458 command register */
1584 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1585 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1586 }
1587
1588 void
ngle_timber_setupfb(struct sti_screen * scr)1589 ngle_timber_setupfb(struct sti_screen *scr)
1590 {
1591 struct sti_rom *rom = scr->scr_rom;
1592 bus_space_tag_t memt = rom->memt;
1593 bus_space_handle_t memh = rom->regh[2];
1594
1595 ngle_setup_bt458(scr);
1596
1597 ngle_setup_hw(memt, memh);
1598 /* enable overlay planes in Bt458 command register */
1599 ngle_bt458_write(memt, memh, 0x0c, 0x06);
1600 ngle_bt458_write(memt, memh, 0x0e, 0x43);
1601 }
1602
1603 void
ngle_setup_bt458(struct sti_screen * scr)1604 ngle_setup_bt458(struct sti_screen *scr)
1605 {
1606 struct sti_rom *rom = scr->scr_rom;
1607 bus_space_tag_t memt = rom->memt;
1608 bus_space_handle_t memh = rom->regh[2];
1609
1610 ngle_setup_hw(memt, memh);
1611 /* set Bt458 read mask register to all planes */
1612 ngle_bt458_write(memt, memh, 0x08, 0x04);
1613 ngle_bt458_write(memt, memh, 0x0a, 0xff);
1614 }
1615
1616 void
ngle_setup_attr_planes(struct sti_screen * scr)1617 ngle_setup_attr_planes(struct sti_screen *scr)
1618 {
1619 struct sti_rom *rom = scr->scr_rom;
1620 bus_space_tag_t memt = rom->memt;
1621 bus_space_handle_t memh = rom->regh[2];
1622
1623 ngle_setup_hw(memt, memh);
1624 bus_space_write_4(memt, memh, NGLE_REG_11, 0x2ea0d000);
1625 bus_space_write_4(memt, memh, NGLE_REG_14, 0x23000302);
1626 bus_space_write_4(memt, memh, NGLE_REG_12, scr->reg12_value);
1627 bus_space_write_4(memt, memh, NGLE_REG_8, 0xffffffff);
1628
1629 bus_space_write_4(memt, memh, NGLE_REG_6, 0x00000000);
1630 bus_space_write_4(memt, memh, NGLE_REG_9,
1631 (scr->scr_cfg.scr_width << 16) | scr->scr_cfg.scr_height);
1632 bus_space_write_4(memt, memh, NGLE_REG_6, 0x05000000);
1633 bus_space_write_4(memt, memh, NGLE_REG_9, 0x00040001);
1634
1635 ngle_setup_hw(memt, memh);
1636 bus_space_write_4(memt, memh, NGLE_REG_12, 0x00000000);
1637
1638 ngle_setup_fb(memt, memh, scr->reg10_value);
1639 }
1640
1641 int
ngle_putcmap(struct sti_screen * scr,u_int idx,u_int count)1642 ngle_putcmap(struct sti_screen *scr, u_int idx, u_int count)
1643 {
1644 struct sti_rom *rom = scr->scr_rom;
1645 bus_space_tag_t memt = rom->memt;
1646 bus_space_handle_t memh = rom->regh[2];
1647 uint8_t *r, *g, *b;
1648 uint32_t cmap_finish;
1649
1650 if (scr->scr_bpp > 8)
1651 cmap_finish = 0x83000100;
1652 else
1653 cmap_finish = 0x80000100;
1654
1655 r = scr->scr_rcmap + idx;
1656 g = scr->scr_gcmap + idx;
1657 b = scr->scr_bcmap + idx;
1658
1659 ngle_setup_hw(memt, memh);
1660 bus_space_write_4(memt, memh, NGLE_REG_10, 0xbbe0f000);
1661 bus_space_write_4(memt, memh, NGLE_REG_14, 0x03000300);
1662 bus_space_write_4(memt, memh, NGLE_REG_13, 0xffffffff);
1663
1664 while (count-- != 0) {
1665 ngle_setup_hw(memt, memh);
1666 bus_space_write_4(memt, memh, NGLE_REG_3, 0x400 | (idx << 2));
1667 bus_space_write_4(memt, memh, NGLE_REG_4,
1668 (*r << 16) | (*g << 8) | *b);
1669
1670 idx++;
1671 r++, g++, b++;
1672 }
1673
1674 bus_space_write_4(memt, memh, NGLE_REG_2, 0x400);
1675 bus_space_write_4(memt, memh, scr->cmap_finish_register, cmap_finish);
1676 ngle_setup_fb(memt, memh, scr->reg10_value);
1677
1678
1679 return 0;
1680 }
1681
1682 void
ngle_setup_hw(bus_space_tag_t memt,bus_space_handle_t memh)1683 ngle_setup_hw(bus_space_tag_t memt, bus_space_handle_t memh)
1684 {
1685 uint8_t stat;
1686
1687 do {
1688 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1689 if (stat == 0)
1690 stat = bus_space_read_1(memt, memh, NGLE_REG_15b0);
1691 } while (stat != 0);
1692 }
1693
1694 void
ngle_setup_fb(bus_space_tag_t memt,bus_space_handle_t memh,uint32_t reg10)1695 ngle_setup_fb(bus_space_tag_t memt, bus_space_handle_t memh, uint32_t reg10)
1696 {
1697 ngle_setup_hw(memt, memh);
1698 bus_space_write_4(memt, memh, NGLE_REG_10, reg10);
1699 bus_space_write_4(memt, memh, NGLE_REG_14, 0x83000300);
1700 ngle_setup_hw(memt, memh);
1701 bus_space_write_1(memt, memh, NGLE_REG_16b1, 1);
1702 }
1703 #endif /* SMALL_KERNEL */
1704