1 /* $NetBSD: w100.c,v 1.3 2020/11/21 17:22:03 thorpej Exp $ */ 2 /* 3 * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved. 4 * Written by Hiroyuki Bessho for Genetec Corporation. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of Genetec Corporation may not be used to endorse or 15 * promote products derived from this software without specific prior 16 * written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: w100.c,v 1.3 2020/11/21 17:22:03 thorpej Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/conf.h> 36 #include <sys/uio.h> 37 #include <sys/kmem.h> 38 #include <sys/kernel.h> /* for cold */ 39 40 #include <uvm/uvm_extern.h> 41 42 #include <dev/cons.h> 43 #include <dev/wscons/wsconsio.h> 44 #include <dev/wscons/wsdisplayvar.h> 45 #include <dev/wscons/wscons_callbacks.h> 46 #include <dev/rasops/rasops.h> 47 #include <dev/wsfont/wsfont.h> 48 49 #include <sys/bus.h> 50 #include <machine/cpu.h> 51 #include <arm/cpufunc.h> 52 53 #include <zaurus/dev/w100reg.h> 54 #include <zaurus/dev/w100var.h> 55 56 #include "wsdisplay.h" 57 58 /* Console */ 59 struct { 60 int is_console; 61 struct w100_wsscreen_descr *descr; 62 const struct w100_panel_geometry *geom; 63 } w100_console; 64 65 static void w100_initialize(struct w100_softc *sc, 66 const struct w100_panel_geometry *geom); 67 static int w100_new_screen(struct w100_softc *sc, int depth, 68 struct w100_screen **scrpp); 69 static void w100_lcd_geometry(struct w100_softc *sc, 70 const struct w100_panel_geometry *geom); 71 #if NWSDISPLAY > 0 72 static void w100_setup_rasops(struct w100_softc *sc, 73 struct rasops_info *rinfo, 74 struct w100_wsscreen_descr *descr, 75 const struct w100_panel_geometry *geom); 76 #endif 77 78 #define w100_reg_write(sc, offset, value) \ 79 bus_space_write_4((sc)->iot, (sc)->ioh_reg, offset, value) 80 81 static void 82 w100_lcd_geometry(struct w100_softc *sc, 83 const struct w100_panel_geometry *geom) 84 { 85 86 sc->geometry = geom; 87 switch (geom->rotate) { 88 case W100_PANEL_ROTATE_CW: 89 sc->display_width = geom->panel_height; 90 sc->display_height = geom->panel_width; 91 w100_reg_write(sc, W100_REG_PCLK_CTRL, 0x00000061); 92 w100_reg_write(sc, W100_REG_GRAPHIC_CTRL, 0x00de1d0e); 93 w100_reg_write(sc, W100_REG_GRAPHIC_OFFSET, 0x00895b00); 94 w100_reg_write(sc, W100_REG_GRAPHIC_PITCH, 0x00000500); 95 break; 96 case W100_PANEL_ROTATE_CCW: 97 sc->display_width = geom->panel_height; 98 sc->display_height = geom->panel_width; 99 w100_reg_write(sc, W100_REG_PCLK_CTRL, 0x00000061); 100 w100_reg_write(sc, W100_REG_GRAPHIC_CTRL, 0x00de1d16); 101 w100_reg_write(sc, W100_REG_GRAPHIC_OFFSET, 0x008004fc); 102 w100_reg_write(sc, W100_REG_GRAPHIC_PITCH, 0x00000500); 103 break; 104 case W100_PANEL_ROTATE_UD: 105 sc->display_width = geom->panel_width; 106 sc->display_height = geom->panel_height; 107 w100_reg_write(sc, W100_REG_PCLK_CTRL, 0x00000021); 108 w100_reg_write(sc, W100_REG_GRAPHIC_CTRL, 0x00ded7e); 109 w100_reg_write(sc, W100_REG_GRAPHIC_OFFSET, 0x00895ffc); 110 w100_reg_write(sc, W100_REG_GRAPHIC_PITCH, 0x000003c0); 111 break; 112 default: 113 sc->display_width = geom->panel_width; 114 sc->display_height = geom->panel_height; 115 w100_reg_write(sc, W100_REG_PCLK_CTRL, 0x00000021); 116 w100_reg_write(sc, W100_REG_GRAPHIC_CTRL, 0x00de1d66); 117 w100_reg_write(sc, W100_REG_GRAPHIC_OFFSET, 0x00800000); 118 w100_reg_write(sc, W100_REG_GRAPHIC_PITCH, 0x000003c0); 119 break; 120 } 121 w100_reg_write(sc, W100_REG_DISP_DB_BUF_CTRL, 0x0000007b); 122 } 123 124 /* 125 * Initialize the LCD controller. 126 */ 127 static void 128 w100_initialize(struct w100_softc *sc, const struct w100_panel_geometry *geom) 129 { 130 131 w100_lcd_geometry(sc, geom); 132 } 133 134 135 /* 136 * Common driver attachment code. 137 */ 138 void 139 w100_attach_subr(struct w100_softc *sc, bus_space_tag_t iot, 140 const struct w100_panel_geometry *geom) 141 { 142 bus_space_handle_t ioh_cfg, ioh_reg, ioh_vram; 143 int error; 144 145 aprint_normal(": ATI Imageon100 LCD controller\n"); 146 aprint_naive("\n"); 147 148 sc->n_screens = 0; 149 LIST_INIT(&sc->screens); 150 151 /* config handler */ 152 error = bus_space_map(iot, W100_CFG_ADDRESS, W100_CFG_SIZE, 0, 153 &ioh_cfg); 154 if (error) { 155 aprint_error_dev(sc->dev, 156 "failed to map config (errorno=%d)\n", error); 157 return; 158 } 159 160 /* register handler */ 161 error = bus_space_map(iot, W100_REG_ADDRESS, W100_REG_SIZE, 0, 162 &ioh_reg); 163 if (error) { 164 aprint_error_dev(sc->dev, 165 "failed to map register (errorno=%d)\n", error); 166 return; 167 } 168 169 /* videomem handler */ 170 error = bus_space_map(iot, W100_EXTMEM_ADDRESS, W100_EXTMEM_SIZE, 0, 171 &ioh_vram); 172 if (error) { 173 aprint_error_dev(sc->dev, 174 "failed to vram register (errorno=%d)\n", error); 175 return; 176 } 177 178 sc->iot = iot; 179 sc->ioh_cfg = ioh_cfg; 180 sc->ioh_reg = ioh_reg; 181 sc->ioh_vram = ioh_vram; 182 183 w100_initialize(sc, geom); 184 185 #if NWSDISPLAY > 0 186 if (w100_console.is_console) { 187 struct w100_wsscreen_descr *descr = w100_console.descr; 188 struct w100_screen *scr; 189 struct rasops_info *ri; 190 long defattr; 191 192 error = w100_new_screen(sc, descr->depth, &scr); 193 if (error) { 194 aprint_error_dev(sc->dev, 195 "unable to create new screen (errno=%d)", error); 196 return; 197 } 198 199 ri = &scr->rinfo; 200 ri->ri_hw = (void *)scr; 201 ri->ri_bits = scr->buf_va; 202 w100_setup_rasops(sc, ri, descr, geom); 203 204 /* assumes 16 bpp */ 205 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 206 207 sc->active = scr; 208 209 wsdisplay_cnattach(&descr->c, ri, ri->ri_ccol, ri->ri_crow, 210 defattr); 211 212 aprint_normal_dev(sc->dev, "console\n"); 213 } 214 #endif 215 } 216 217 int 218 w100_cnattach(struct w100_wsscreen_descr *descr, 219 const struct w100_panel_geometry *geom) 220 { 221 222 w100_console.descr = descr; 223 w100_console.geom = geom; 224 w100_console.is_console = 1; 225 226 return 0; 227 } 228 229 /* 230 * Create and initialize a new screen buffer. 231 */ 232 static int 233 w100_new_screen(struct w100_softc *sc, int depth, struct w100_screen **scrpp) 234 { 235 struct w100_screen *scr = NULL; 236 int error = 0; 237 238 scr = kmem_zalloc(sizeof(*scr), KM_SLEEP); 239 scr->buf_va = (u_char *)bus_space_vaddr(sc->iot, sc->ioh_vram); 240 scr->depth = depth; 241 242 LIST_INSERT_HEAD(&sc->screens, scr, link); 243 sc->n_screens++; 244 245 *scrpp = scr; 246 247 return error; 248 } 249 250 #if NWSDISPLAY > 0 251 /* 252 * Initialize rasops for a screen, as well as struct wsscreen_descr if this 253 * is the first screen creation. 254 */ 255 static void 256 w100_setup_rasops(struct w100_softc *sc, struct rasops_info *rinfo, 257 struct w100_wsscreen_descr *descr, const struct w100_panel_geometry *geom) 258 { 259 260 rinfo->ri_flg = descr->flags; 261 rinfo->ri_depth = descr->depth; 262 rinfo->ri_width = sc->display_width; 263 rinfo->ri_height = sc->display_height; 264 rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8; 265 #ifdef notyet 266 rinfo->ri_wsfcookie = -1; /* XXX */ 267 #endif 268 269 /* swap B and R */ 270 if (descr->depth == 16) { 271 rinfo->ri_rnum = 5; 272 rinfo->ri_rpos = 11; 273 rinfo->ri_gnum = 6; 274 rinfo->ri_gpos = 5; 275 rinfo->ri_bnum = 5; 276 rinfo->ri_bpos = 0; 277 } 278 279 if (descr->c.nrows == 0) { 280 /* get rasops to compute screen size the first time */ 281 rasops_init(rinfo, 100, 100); 282 } else { 283 rasops_init(rinfo, descr->c.nrows, descr->c.ncols); 284 } 285 286 descr->c.nrows = rinfo->ri_rows; 287 descr->c.ncols = rinfo->ri_cols; 288 descr->c.capabilities = rinfo->ri_caps; 289 descr->c.textops = &rinfo->ri_ops; 290 } 291 #endif 292 293 /* 294 * Power management 295 */ 296 void 297 w100_suspend(struct w100_softc *sc) 298 { 299 300 if (sc->active) { 301 /* XXX not yet */ 302 } 303 } 304 305 void 306 w100_resume(struct w100_softc *sc) 307 { 308 309 if (sc->active) { 310 w100_initialize(sc, sc->geometry); 311 /* XXX: and more */ 312 } 313 } 314 315 void 316 w100_power(int why, void *v) 317 { 318 struct w100_softc *sc = v; 319 320 switch (why) { 321 case PWR_SUSPEND: 322 case PWR_STANDBY: 323 w100_suspend(sc); 324 break; 325 326 case PWR_RESUME: 327 w100_resume(sc); 328 break; 329 } 330 } 331 332 /* 333 * Initialize struct wsscreen_descr based on values calculated by 334 * raster operation subsystem. 335 */ 336 #if 0 337 int 338 w100_setup_wsscreen(struct w100_wsscreen_descr *descr, 339 const struct w100_panel_geometry *geom, 340 const char *fontname) 341 { 342 int width = geom->panel_width; 343 int height = geom->panel_height; 344 int cookie = -1; 345 struct rasops_info rinfo; 346 347 memset(&rinfo, 0, sizeof rinfo); 348 349 if (fontname) { 350 wsfont_init(); 351 cookie = wsfont_find(fontname, 0, 0, 0, 352 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R); 353 if (cookie < 0 || 354 wsfont_lock(cookie, &rinfo.ri_font)) 355 return -1; 356 } 357 else { 358 /* let rasops_init() choose any font */ 359 } 360 361 /* let rasops_init calculate # of cols and rows in character */ 362 rinfo.ri_flg = 0; 363 rinfo.ri_depth = descr->depth; 364 rinfo.ri_bits = NULL; 365 rinfo.ri_width = width; 366 rinfo.ri_height = height; 367 rinfo.ri_stride = width * rinfo.ri_depth / 8; 368 rinfo.ri_wsfcookie = cookie; 369 370 rasops_init(&rinfo, 100, 100); 371 372 descr->c.nrows = rinfo.ri_rows; 373 descr->c.ncols = rinfo.ri_cols; 374 descr->c.capabilities = rinfo.ri_caps; 375 376 return cookie; 377 } 378 #endif 379 380 int 381 w100_show_screen(void *v, void *cookie, int waitok, 382 void (*cb)(void *, int, int), void *cbarg) 383 { 384 385 return 0; 386 } 387 388 int 389 w100_alloc_screen(void *v, const struct wsscreen_descr *_type, 390 void **cookiep, int *curxp, int *curyp, long *attrp) 391 { 392 struct w100_softc *sc = v; 393 struct w100_screen *scr; 394 const struct w100_wsscreen_descr *type = 395 (const struct w100_wsscreen_descr *)_type; 396 int error; 397 398 if (sc->n_screens > 0) 399 return ENOMEM; 400 401 error = w100_new_screen(sc, type->depth, &scr); 402 if (error) 403 return error; 404 405 /* 406 * initialize raster operation for this screen. 407 */ 408 scr->rinfo.ri_flg = 0; 409 scr->rinfo.ri_depth = type->depth; 410 scr->rinfo.ri_bits = scr->buf_va; 411 scr->rinfo.ri_width = sc->display_width; 412 scr->rinfo.ri_height = sc->display_height; 413 scr->rinfo.ri_stride = scr->rinfo.ri_width * scr->rinfo.ri_depth / 8; 414 scr->rinfo.ri_wsfcookie = -1; /* XXX */ 415 416 rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols); 417 418 (*scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp); 419 420 *cookiep = scr; 421 *curxp = 0; 422 *curyp = 0; 423 424 return 0; 425 } 426 427 void 428 w100_free_screen(void *v, void *cookie) 429 { 430 struct w100_softc *sc = v; 431 struct w100_screen *scr = cookie; 432 433 LIST_REMOVE(scr, link); 434 sc->n_screens--; 435 } 436 437 int 438 w100_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 439 struct lwp *l) 440 { 441 struct w100_softc *sc = v; 442 struct w100_screen *scr = sc->active; /* ??? */ 443 struct wsdisplay_fbinfo *wsdisp_info; 444 445 switch (cmd) { 446 case WSDISPLAYIO_GTYPE: 447 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; 448 return 0; 449 450 case WSDISPLAYIO_GINFO: 451 wsdisp_info = (struct wsdisplay_fbinfo *)data; 452 wsdisp_info->height = sc->display_height; 453 wsdisp_info->width = sc->display_width; 454 wsdisp_info->depth = scr->depth; 455 wsdisp_info->cmsize = 0; 456 return 0; 457 458 case WSDISPLAYIO_LINEBYTES: 459 *(u_int *)data = scr->rinfo.ri_stride; 460 return 0; 461 462 case WSDISPLAYIO_GETCMAP: 463 case WSDISPLAYIO_PUTCMAP: 464 return EPASSTHROUGH; /* XXX Colormap */ 465 466 case WSDISPLAYIO_SVIDEO: 467 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) { 468 /* XXX: turn it on */ 469 } else { 470 /* XXX: start LCD shutdown */ 471 /* XXX: sleep until interrupt */ 472 } 473 return 0; 474 475 case WSDISPLAYIO_GVIDEO: 476 /* XXX: not yet */ 477 *(u_int *)data = WSDISPLAYIO_VIDEO_ON; 478 return 0; 479 480 case WSDISPLAYIO_GCURPOS: 481 case WSDISPLAYIO_SCURPOS: 482 case WSDISPLAYIO_GCURMAX: 483 case WSDISPLAYIO_GCURSOR: 484 case WSDISPLAYIO_SCURSOR: 485 return EPASSTHROUGH; /* XXX */ 486 } 487 488 return EPASSTHROUGH; 489 } 490 491 paddr_t 492 w100_mmap(void *v, void *vs, off_t offset, int prot) 493 { 494 struct w100_softc *sc = v; 495 struct w100_screen *scr = sc->active; /* ??? */ 496 497 if (scr == NULL) 498 return -1; 499 500 if (offset < 0 || 501 offset >= scr->rinfo.ri_stride * scr->rinfo.ri_height) 502 return -1; 503 504 return arm_btop(W100_EXTMEM_ADDRESS + offset); 505 } 506 507 508 static void 509 w100_cursor(void *cookie, int on, int row, int col) 510 { 511 struct w100_screen *scr = cookie; 512 513 (*scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col); 514 } 515 516 static int 517 w100_mapchar(void *cookie, int c, unsigned int *cp) 518 { 519 struct w100_screen *scr = cookie; 520 521 return (*scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp); 522 } 523 524 static void 525 w100_putchar(void *cookie, int row, int col, u_int uc, long attr) 526 { 527 struct w100_screen *scr = cookie; 528 529 (*scr->rinfo.ri_ops.putchar)(&scr->rinfo, row, col, uc, attr); 530 } 531 532 static void 533 w100_copycols(void *cookie, int row, int src, int dst, int num) 534 { 535 struct w100_screen *scr = cookie; 536 537 (*scr->rinfo.ri_ops.copycols)(&scr->rinfo, row, src, dst, num); 538 } 539 540 static void 541 w100_erasecols(void *cookie, int row, int col, int num, long attr) 542 { 543 struct w100_screen *scr = cookie; 544 545 (*scr->rinfo.ri_ops.erasecols)(&scr->rinfo, row, col, num, attr); 546 } 547 548 static void 549 w100_copyrows(void *cookie, int src, int dst, int num) 550 { 551 struct w100_screen *scr = cookie; 552 553 (*scr->rinfo.ri_ops.copyrows)(&scr->rinfo, src, dst, num); 554 } 555 556 static void 557 w100_eraserows(void *cookie, int row, int num, long attr) 558 { 559 struct w100_screen *scr = cookie; 560 561 (*scr->rinfo.ri_ops.eraserows)(&scr->rinfo, row, num, attr); 562 } 563 564 static int 565 w100_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 566 { 567 struct w100_screen *scr = cookie; 568 569 return (*scr->rinfo.ri_ops.allocattr)(&scr->rinfo, fg, bg, flg, attr); 570 } 571 572 const struct wsdisplay_emulops w100_emulops = { 573 w100_cursor, 574 w100_mapchar, 575 w100_putchar, 576 w100_copycols, 577 w100_erasecols, 578 w100_copyrows, 579 w100_eraserows, 580 w100_alloc_attr 581 }; 582