1/* $NetBSD$ */ 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$"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/conf.h> 36#include <sys/uio.h> 37#include <sys/malloc.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 */ 59struct { 60 int is_console; 61 struct w100_wsscreen_descr *descr; 62 const struct w100_panel_geometry *geom; 63} w100_console; 64 65static void w100_initialize(struct w100_softc *sc, 66 const struct w100_panel_geometry *geom); 67static int w100_new_screen(struct w100_softc *sc, int depth, 68 struct w100_screen **scrpp); 69static void w100_lcd_geometry(struct w100_softc *sc, 70 const struct w100_panel_geometry *geom); 71#if NWSDISPLAY > 0 72static 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 81static void 82w100_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 */ 127static void 128w100_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 */ 138void 139w100_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 217int 218w100_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 */ 232static int 233w100_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 = malloc(sizeof(*scr), M_DEVBUF, M_NOWAIT); 239 if (scr == NULL) 240 return ENOMEM; 241 242 memset(scr, 0, sizeof(*scr)); 243 244 scr->buf_va = (u_char *)bus_space_vaddr(sc->iot, sc->ioh_vram); 245 scr->depth = depth; 246 247 LIST_INSERT_HEAD(&sc->screens, scr, link); 248 sc->n_screens++; 249 250 *scrpp = scr; 251 252 return error; 253} 254 255#if NWSDISPLAY > 0 256/* 257 * Initialize rasops for a screen, as well as struct wsscreen_descr if this 258 * is the first screen creation. 259 */ 260static void 261w100_setup_rasops(struct w100_softc *sc, struct rasops_info *rinfo, 262 struct w100_wsscreen_descr *descr, const struct w100_panel_geometry *geom) 263{ 264 265 rinfo->ri_flg = descr->flags; 266 rinfo->ri_depth = descr->depth; 267 rinfo->ri_width = sc->display_width; 268 rinfo->ri_height = sc->display_height; 269 rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8; 270#ifdef notyet 271 rinfo->ri_wsfcookie = -1; /* XXX */ 272#endif 273 274 /* swap B and R */ 275 if (descr->depth == 16) { 276 rinfo->ri_rnum = 5; 277 rinfo->ri_rpos = 11; 278 rinfo->ri_gnum = 6; 279 rinfo->ri_gpos = 5; 280 rinfo->ri_bnum = 5; 281 rinfo->ri_bpos = 0; 282 } 283 284 if (descr->c.nrows == 0) { 285 /* get rasops to compute screen size the first time */ 286 rasops_init(rinfo, 100, 100); 287 } else { 288 rasops_init(rinfo, descr->c.nrows, descr->c.ncols); 289 } 290 291 descr->c.nrows = rinfo->ri_rows; 292 descr->c.ncols = rinfo->ri_cols; 293 descr->c.capabilities = rinfo->ri_caps; 294 descr->c.textops = &rinfo->ri_ops; 295} 296#endif 297 298/* 299 * Power management 300 */ 301void 302w100_suspend(struct w100_softc *sc) 303{ 304 305 if (sc->active) { 306 /* XXX not yet */ 307 } 308} 309 310void 311w100_resume(struct w100_softc *sc) 312{ 313 314 if (sc->active) { 315 w100_initialize(sc, sc->geometry); 316 /* XXX: and more */ 317 } 318} 319 320void 321w100_power(int why, void *v) 322{ 323 struct w100_softc *sc = v; 324 325 switch (why) { 326 case PWR_SUSPEND: 327 case PWR_STANDBY: 328 w100_suspend(sc); 329 break; 330 331 case PWR_RESUME: 332 w100_resume(sc); 333 break; 334 } 335} 336 337/* 338 * Initialize struct wsscreen_descr based on values calculated by 339 * raster operation subsystem. 340 */ 341#if 0 342int 343w100_setup_wsscreen(struct w100_wsscreen_descr *descr, 344 const struct w100_panel_geometry *geom, 345 const char *fontname) 346{ 347 int width = geom->panel_width; 348 int height = geom->panel_height; 349 int cookie = -1; 350 struct rasops_info rinfo; 351 352 memset(&rinfo, 0, sizeof rinfo); 353 354 if (fontname) { 355 wsfont_init(); 356 cookie = wsfont_find(fontname, 0, 0, 0, 357 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R); 358 if (cookie < 0 || 359 wsfont_lock(cookie, &rinfo.ri_font)) 360 return -1; 361 } 362 else { 363 /* let rasops_init() choose any font */ 364 } 365 366 /* let rasops_init calculate # of cols and rows in character */ 367 rinfo.ri_flg = 0; 368 rinfo.ri_depth = descr->depth; 369 rinfo.ri_bits = NULL; 370 rinfo.ri_width = width; 371 rinfo.ri_height = height; 372 rinfo.ri_stride = width * rinfo.ri_depth / 8; 373 rinfo.ri_wsfcookie = cookie; 374 375 rasops_init(&rinfo, 100, 100); 376 377 descr->c.nrows = rinfo.ri_rows; 378 descr->c.ncols = rinfo.ri_cols; 379 descr->c.capabilities = rinfo.ri_caps; 380 381 return cookie; 382} 383#endif 384 385int 386w100_show_screen(void *v, void *cookie, int waitok, 387 void (*cb)(void *, int, int), void *cbarg) 388{ 389 390 return 0; 391} 392 393int 394w100_alloc_screen(void *v, const struct wsscreen_descr *_type, 395 void **cookiep, int *curxp, int *curyp, long *attrp) 396{ 397 struct w100_softc *sc = v; 398 struct w100_screen *scr; 399 const struct w100_wsscreen_descr *type = 400 (const struct w100_wsscreen_descr *)_type; 401 int error; 402 403 if (sc->n_screens > 0) 404 return ENOMEM; 405 406 error = w100_new_screen(sc, type->depth, &scr); 407 if (error) 408 return error; 409 410 /* 411 * initialize raster operation for this screen. 412 */ 413 scr->rinfo.ri_flg = 0; 414 scr->rinfo.ri_depth = type->depth; 415 scr->rinfo.ri_bits = scr->buf_va; 416 scr->rinfo.ri_width = sc->display_width; 417 scr->rinfo.ri_height = sc->display_height; 418 scr->rinfo.ri_stride = scr->rinfo.ri_width * scr->rinfo.ri_depth / 8; 419 scr->rinfo.ri_wsfcookie = -1; /* XXX */ 420 421 rasops_init(&scr->rinfo, type->c.nrows, type->c.ncols); 422 423 (*scr->rinfo.ri_ops.allocattr)(&scr->rinfo, 0, 0, 0, attrp); 424 425 *cookiep = scr; 426 *curxp = 0; 427 *curyp = 0; 428 429 return 0; 430} 431 432void 433w100_free_screen(void *v, void *cookie) 434{ 435 struct w100_softc *sc = v; 436 struct w100_screen *scr = cookie; 437 438 LIST_REMOVE(scr, link); 439 sc->n_screens--; 440} 441 442int 443w100_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 444 struct lwp *l) 445{ 446 struct w100_softc *sc = v; 447 struct w100_screen *scr = sc->active; /* ??? */ 448 struct wsdisplay_fbinfo *wsdisp_info; 449 450 switch (cmd) { 451 case WSDISPLAYIO_GTYPE: 452 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; 453 return 0; 454 455 case WSDISPLAYIO_GINFO: 456 wsdisp_info = (struct wsdisplay_fbinfo *)data; 457 wsdisp_info->height = sc->display_height; 458 wsdisp_info->width = sc->display_width; 459 wsdisp_info->depth = scr->depth; 460 wsdisp_info->cmsize = 0; 461 return 0; 462 463 case WSDISPLAYIO_LINEBYTES: 464 *(u_int *)data = scr->rinfo.ri_stride; 465 return 0; 466 467 case WSDISPLAYIO_GETCMAP: 468 case WSDISPLAYIO_PUTCMAP: 469 return EPASSTHROUGH; /* XXX Colormap */ 470 471 case WSDISPLAYIO_SVIDEO: 472 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) { 473 /* XXX: turn it on */ 474 } else { 475 /* XXX: start LCD shutdown */ 476 /* XXX: sleep until interrupt */ 477 } 478 return 0; 479 480 case WSDISPLAYIO_GVIDEO: 481 /* XXX: not yet */ 482 *(u_int *)data = WSDISPLAYIO_VIDEO_ON; 483 return 0; 484 485 case WSDISPLAYIO_GCURPOS: 486 case WSDISPLAYIO_SCURPOS: 487 case WSDISPLAYIO_GCURMAX: 488 case WSDISPLAYIO_GCURSOR: 489 case WSDISPLAYIO_SCURSOR: 490 return EPASSTHROUGH; /* XXX */ 491 } 492 493 return EPASSTHROUGH; 494} 495 496paddr_t 497w100_mmap(void *v, void *vs, off_t offset, int prot) 498{ 499 struct w100_softc *sc = v; 500 struct w100_screen *scr = sc->active; /* ??? */ 501 502 if (scr == NULL) 503 return -1; 504 505 if (offset < 0 || 506 offset >= scr->rinfo.ri_stride * scr->rinfo.ri_height) 507 return -1; 508 509 return arm_btop(W100_EXTMEM_ADDRESS + offset); 510} 511 512 513static void 514w100_cursor(void *cookie, int on, int row, int col) 515{ 516 struct w100_screen *scr = cookie; 517 518 (*scr->rinfo.ri_ops.cursor)(&scr->rinfo, on, row, col); 519} 520 521static int 522w100_mapchar(void *cookie, int c, unsigned int *cp) 523{ 524 struct w100_screen *scr = cookie; 525 526 return (*scr->rinfo.ri_ops.mapchar)(&scr->rinfo, c, cp); 527} 528 529static void 530w100_putchar(void *cookie, int row, int col, u_int uc, long attr) 531{ 532 struct w100_screen *scr = cookie; 533 534 (*scr->rinfo.ri_ops.putchar)(&scr->rinfo, row, col, uc, attr); 535} 536 537static void 538w100_copycols(void *cookie, int row, int src, int dst, int num) 539{ 540 struct w100_screen *scr = cookie; 541 542 (*scr->rinfo.ri_ops.copycols)(&scr->rinfo, row, src, dst, num); 543} 544 545static void 546w100_erasecols(void *cookie, int row, int col, int num, long attr) 547{ 548 struct w100_screen *scr = cookie; 549 550 (*scr->rinfo.ri_ops.erasecols)(&scr->rinfo, row, col, num, attr); 551} 552 553static void 554w100_copyrows(void *cookie, int src, int dst, int num) 555{ 556 struct w100_screen *scr = cookie; 557 558 (*scr->rinfo.ri_ops.copyrows)(&scr->rinfo, src, dst, num); 559} 560 561static void 562w100_eraserows(void *cookie, int row, int num, long attr) 563{ 564 struct w100_screen *scr = cookie; 565 566 (*scr->rinfo.ri_ops.eraserows)(&scr->rinfo, row, num, attr); 567} 568 569static int 570w100_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 571{ 572 struct w100_screen *scr = cookie; 573 574 return (*scr->rinfo.ri_ops.allocattr)(&scr->rinfo, fg, bg, flg, attr); 575} 576 577const struct wsdisplay_emulops w100_emulops = { 578 w100_cursor, 579 w100_mapchar, 580 w100_putchar, 581 w100_copycols, 582 w100_erasecols, 583 w100_copyrows, 584 w100_eraserows, 585 w100_alloc_attr 586}; 587