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