w100.c revision 1.3
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 */ 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 = 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 */ 255static void 256w100_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 */ 296void 297w100_suspend(struct w100_softc *sc) 298{ 299 300 if (sc->active) { 301 /* XXX not yet */ 302 } 303} 304 305void 306w100_resume(struct w100_softc *sc) 307{ 308 309 if (sc->active) { 310 w100_initialize(sc, sc->geometry); 311 /* XXX: and more */ 312 } 313} 314 315void 316w100_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 337int 338w100_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 380int 381w100_show_screen(void *v, void *cookie, int waitok, 382 void (*cb)(void *, int, int), void *cbarg) 383{ 384 385 return 0; 386} 387 388int 389w100_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 427void 428w100_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 437int 438w100_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 491paddr_t 492w100_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 508static void 509w100_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 516static int 517w100_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 524static void 525w100_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 532static void 533w100_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 540static void 541w100_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 548static void 549w100_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 556static void 557w100_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 564static int 565w100_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 572const 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