1 /* $OpenBSD: amdisplay.c,v 1.20 2024/11/06 07:09:45 miod Exp $ */ 2 /* 3 * Copyright (c) 2016 Ian Sutton <ians@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <dev/wscons/wsconsio.h> 24 #include <dev/wscons/wsdisplayvar.h> 25 #include <dev/rasops/rasops.h> 26 #include <dev/videomode/videomode.h> 27 #include <dev/videomode/edidvar.h> 28 29 #include <dev/ofw/openfirm.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 #include <dev/ofw/fdt.h> 32 #include <machine/fdt.h> 33 34 #include <armv7/omap/prcmvar.h> 35 #include <armv7/omap/amdisplayreg.h> 36 #include <armv7/omap/nxphdmivar.h> 37 38 #ifdef LCD_DEBUG 39 #define str(X) #X 40 int lcd_dbg_thresh = 20; 41 #define DPRINTF(n,s) do { if ((n) <= lcd_dbg_thresh) printf s; } while (0) 42 #else 43 #define DPRINTF(n,s) do {} while (0) 44 #endif 45 46 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 47 48 #define LCD_MAX_PELCLK 170000 /* kHz */ 49 #define LCD_MASTER_OSC 24000000 /* Hz */ 50 #define LCD_M1_MAX 2048 51 #define LCD_M2_MAX 31 52 #define LCD_N_MAX 128 53 54 #define HREAD4(sc, reg) \ 55 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 56 #define HWRITE4(sc, reg, val) \ 57 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 58 #define HSET4(sc, reg, bits) \ 59 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 60 #define HCLR4(sc, reg, bits) \ 61 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 62 63 struct amdisplay_softc { 64 struct device sc_dev; 65 bus_space_tag_t sc_iot; 66 bus_space_handle_t sc_ioh; 67 bus_dma_tag_t sc_dmat; 68 void *sc_ih; 69 70 int sc_flags; 71 #define LCD_RESET_PENDING (1 << 0) 72 #define LCD_MODE_COMPAT (1 << 1) 73 #define LCD_MODE_ALLOC (1 << 2) 74 75 struct edid_info sc_edid; 76 struct videomode *sc_active_mode; 77 int sc_active_depth; 78 79 bus_dmamap_t sc_fb0_dma; 80 bus_dma_segment_t sc_fb0_dma_segs[1]; 81 void *sc_fb0; 82 int sc_fb_dma_nsegs; 83 bus_size_t sc_fb_size; 84 85 struct rasops_info sc_ro; 86 struct wsscreen_descr sc_wsd; 87 struct wsscreen_list sc_wsl; 88 struct wsscreen_descr *sc_scrlist[1]; 89 }; 90 91 int amdisplay_match(struct device *, void *, void *); 92 void amdisplay_attach(struct device *, struct device *, void *); 93 int amdisplay_detach(struct device *, int); 94 int amdisplay_intr(void *); 95 96 int amdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *); 97 paddr_t amdisplay_mmap(void *, off_t, int); 98 int amdisplay_alloc_screen(void *, const struct wsscreen_descr *, 99 void **, int *, int *, uint32_t *); 100 101 int amdisplay_setup_dma(struct amdisplay_softc *); 102 void amdisplay_conf_crt_timings(struct amdisplay_softc *); 103 void amdisplay_calc_freq(uint64_t); 104 105 struct wsdisplay_accessops amdisplay_accessops = { 106 .ioctl = amdisplay_ioctl, 107 .mmap = amdisplay_mmap, 108 .alloc_screen = amdisplay_alloc_screen, 109 .free_screen = rasops_free_screen, 110 .show_screen = rasops_show_screen, 111 .getchar = rasops_getchar, 112 .load_font = rasops_load_font, 113 .list_font = rasops_list_font, 114 }; 115 116 const struct cfattach amdisplay_ca = { 117 sizeof(struct amdisplay_softc), amdisplay_match, amdisplay_attach, 118 amdisplay_detach 119 }; 120 121 struct cfdriver amdisplay_cd = { 122 NULL, "amdisplay", DV_DULL 123 }; 124 125 #ifdef LCD_DEBUG 126 void 127 preg(uint32_t reg, char *rn, struct amdisplay_softc *sc) 128 { 129 uint32_t read; 130 131 read = HREAD4(sc, reg); 132 DPRINTF(16, ("%s: %s: 0x%08x\n", DEVNAME(sc), rn, read)); 133 } 134 135 void 136 dumpregs(struct amdisplay_softc *sc) 137 { 138 preg(LCD_PID, str(AMDISPLAY_PID), sc); 139 preg(LCD_CTRL, str(AMDISPLAY_CTRL), sc); 140 preg(LCD_RASTER_CTRL, str(AMDISPLAY_RASTER_CTRL), sc); 141 preg(LCD_RASTER_TIMING_0, str(AMDISPLAY_RASTER_TIMING_0), sc); 142 preg(LCD_RASTER_TIMING_1, str(AMDISPLAY_RASTER_TIMING_1), sc); 143 preg(LCD_RASTER_TIMING_2, str(AMDISPLAY_RASTER_TIMING_2), sc); 144 preg(LCD_RASTER_SUBPANEL, str(AMDISPLAY_RASTER_SUBPANEL), sc); 145 preg(LCD_RASTER_SUBPANEL_2, str(AMDISPLAY_RASTER_SUBPANEL_2), sc); 146 preg(LCD_LCDDMA_CTRL, str(AMDISPLAY_LCDDMA_CTRL), sc); 147 148 /* accessing these regs is liable to occur during CPU lockout period */ 149 #if 0 150 preg(LCD_LCDDMA_FB0_BASE, str(AMDISPLAY_LCDDMA_FB0_BASE), sc); 151 preg(LCD_LCDDMA_FB0_CEILING, str(AMDISPLAY_LCDDMA_FB0_CEILING), sc); 152 preg(LCD_LCDDMA_FB1_BASE, str(AMDISPLAY_LCDDMA_FB1_BASE), sc); 153 preg(LCD_LCDDMA_FB1_CEILING, str(AMDISPLAY_LCDDMA_FB1_CEILING), sc); 154 #endif 155 156 preg(LCD_SYSCONFIG, str(AMDISPLAY_SYSCONFIG), sc); 157 preg(LCD_IRQSTATUS_RAW, str(AMDISPLAY_IRQSTATUS_RAW), sc); 158 preg(LCD_IRQSTATUS, str(AMDISPLAY_IRQSTATUS), sc); 159 preg(LCD_IRQENABLE_SET, str(AMDISPLAY_IRQENABLE_SET), sc); 160 preg(LCD_IRQENABLE_CLEAR, str(AMDISPLAY_IRQENABLE_CLEAR), sc); 161 preg(LCD_CLKC_ENABLE, str(AMDISPLAY_CLKC_ENABLE), sc); 162 preg(LCD_CLKC_RESET, str(AMDISPLAY_CLKC_RESET), sc); 163 } 164 #endif 165 166 int 167 amdisplay_match(struct device *parent, void *v, void *aux) 168 { 169 struct fdt_attach_args *faa = aux; 170 return OF_is_compatible(faa->fa_node, "ti,am33xx-tilcdc"); 171 } 172 173 void 174 amdisplay_attach(struct device *parent, struct device *self, void *args) 175 { 176 struct amdisplay_softc *sc = (struct amdisplay_softc *) self; 177 struct fdt_attach_args *faa = args; 178 struct wsemuldisplaydev_attach_args wsaa; 179 uint64_t pel_clk = 0; 180 uint32_t reg; 181 uint8_t *edid_buf; 182 int stride, i = 0; 183 184 sc->sc_iot = faa->fa_iot; 185 sc->sc_dmat = faa->fa_dmat; 186 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 187 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 188 panic("%s: bus_space_map failed!", __func__); 189 190 /* enable clock module */ 191 prcm_enablemodule(PRCM_LCDC); 192 193 /* force ourselves out of standby/idle states */ 194 reg = HREAD4(sc, LCD_SYSCONFIG); 195 reg &= ~(LCD_SYSCONFIG_STANDBYMODE | LCD_SYSCONFIG_IDLEMODE); 196 reg |= (0x2 << LCD_SYSCONFIG_STANDBYMODE_SHAMT) 197 | (0x2 << LCD_SYSCONFIG_IDLEMODE_SHAMT); 198 HWRITE4(sc, LCD_SYSCONFIG, reg); 199 200 sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, 201 amdisplay_intr, sc, DEVNAME(sc)); 202 203 printf("\n"); 204 205 /* read/parse EDID bits from TDA19988 HDMI PHY */ 206 edid_buf = malloc(EDID_LENGTH, M_DEVBUF, M_WAITOK | M_ZERO); 207 sc->sc_active_mode = malloc(sizeof(struct videomode), M_DEVBUF, 208 M_WAITOK | M_ZERO); 209 sc->sc_flags |= LCD_MODE_ALLOC; 210 211 if (nxphdmi_get_edid(edid_buf, EDID_LENGTH) || 212 edid_parse(DEVNAME(sc), edid_buf, &sc->sc_edid)) { 213 printf("%s: no display attached.\n", DEVNAME(sc)); 214 free(edid_buf, M_DEVBUF, EDID_LENGTH); 215 amdisplay_detach(self, 0); 216 return; 217 } 218 219 free(edid_buf, M_DEVBUF, EDID_LENGTH); 220 221 #if defined(LCD_DEBUG) && defined(EDID_DEBUG) 222 edid_print(&sc->sc_edid); 223 #endif 224 225 /* determine max supported resolution our clock signal can handle */ 226 for (; i < sc->sc_edid.edid_nmodes - 1; i++) { 227 if (sc->sc_edid.edid_modes[i].dot_clock < LCD_MAX_PELCLK && 228 sc->sc_edid.edid_modes[i].dot_clock > pel_clk) { 229 pel_clk = sc->sc_edid.edid_modes[i].dot_clock; 230 memcpy(sc->sc_active_mode, &sc->sc_edid.edid_modes[i], 231 sizeof(struct videomode)); 232 } 233 } 234 235 i = 0; 236 printf("%s: %s :: %d kHz pclk\n", DEVNAME(sc), 237 sc->sc_active_mode->name, sc->sc_active_mode->dot_clock); 238 239 pel_clk *= 2000; 240 amdisplay_calc_freq(pel_clk); 241 242 sc->sc_active_mode->flags |= VID_HSKEW; 243 sc->sc_active_depth = 16; 244 245 /* configure DMA framebuffer */ 246 if (amdisplay_setup_dma(sc)) { 247 printf("%s: couldn't allocate DMA framebuffer\n", DEVNAME(sc)); 248 amdisplay_detach(self, 0); 249 return; 250 } 251 252 /* setup rasops */ 253 stride = sc->sc_active_mode->hdisplay * sc->sc_active_depth / 8; 254 255 sc->sc_ro.ri_depth = sc->sc_active_depth; 256 sc->sc_ro.ri_width = sc->sc_active_mode->hdisplay; 257 sc->sc_ro.ri_height = sc->sc_active_mode->vdisplay; 258 sc->sc_ro.ri_stride = stride; 259 sc->sc_ro.ri_bits = sc->sc_fb0; 260 261 sc->sc_ro.ri_rpos = 0; 262 sc->sc_ro.ri_rnum = 5; 263 sc->sc_ro.ri_gpos = 5; 264 sc->sc_ro.ri_gnum = 6; 265 sc->sc_ro.ri_bpos = 11; 266 sc->sc_ro.ri_bnum = 5; 267 sc->sc_ro.ri_hw = sc; 268 sc->sc_ro.ri_flg = RI_CENTER | RI_VCONS | RI_WRONLY | 269 RI_CLEAR | RI_FULLCLEAR; 270 271 if (rasops_init(&sc->sc_ro, 200, 200)) { 272 printf("%s: no rasops\n", DEVNAME(sc)); 273 amdisplay_detach(self, 0); 274 return; 275 } 276 277 /* ensure controller is off */ 278 HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); 279 delay(100); 280 281 /* set clock divisor needed for 640x480 VGA timings */ 282 reg = HREAD4(sc, LCD_CTRL); 283 reg &= ~LCD_CTRL_CLKDIV; 284 reg |= (0x2 << LCD_CTRL_CLKDIV_SHAMT); 285 286 /* select raster mode & reset-on-underflow, write */ 287 reg |= LCD_CTRL_MODESEL; 288 HWRITE4(sc, LCD_CTRL, reg); 289 290 /* set stn565 + active matrix + palette loading only mode, delay */ 291 reg = HREAD4(sc, LCD_RASTER_CTRL); 292 reg &= 0xF8000C7C; 293 reg |= (LCD_RASTER_CTRL_LCDTFT) 294 | (0x02 << LCD_RASTER_CTRL_PALMODE_SHAMT) 295 | (0xFF << LCD_RASTER_CTRL_REQDLY_SHAMT); 296 HWRITE4(sc, LCD_RASTER_CTRL, reg); 297 298 /* set timing values */ 299 amdisplay_conf_crt_timings(sc); 300 301 /* configure HDMI transmitter (TDA19988) with our mode details */ 302 nxphdmi_set_videomode(sc->sc_active_mode); 303 304 /* latch pins/pads according to fdt node */ 305 pinctrl_byphandle(LCD_FDT_PHANDLE); 306 307 /* configure DMA transfer settings */ 308 reg = HREAD4(sc, LCD_LCDDMA_CTRL); 309 reg &= ~(LCD_LCDDMA_CTRL_DMA_MASTER_PRIO 310 | LCD_LCDDMA_CTRL_TH_FIFO_READY 311 | LCD_LCDDMA_CTRL_BURST_SIZE 312 | LCD_LCDDMA_CTRL_BYTE_SWAP 313 | LCD_LCDDMA_CTRL_BIGENDIAN 314 | LCD_LCDDMA_CTRL_FRAME_MODE); 315 reg |= (0x4 << LCD_LCDDMA_CTRL_BURST_SIZE_SHAMT) 316 | LCD_LCDDMA_CTRL_FRAME_MODE; 317 HWRITE4(sc, LCD_LCDDMA_CTRL, reg); 318 319 /* set framebuffer location + bounds */ 320 HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr); 321 HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr 322 + sc->sc_fb_size)); 323 HWRITE4(sc, LCD_LCDDMA_FB1, sc->sc_fb0_dma_segs[0].ds_addr); 324 HWRITE4(sc, LCD_LCDDMA_FB1_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr 325 + sc->sc_fb_size)); 326 327 /* enable all intrs. */ 328 reg = 0; 329 reg |= (LCD_IRQ_EOF1 | LCD_IRQ_EOF0 | LCD_IRQ_PL | LCD_IRQ_FUF | 330 LCD_IRQ_ACB | LCD_IRQ_SYNC | LCD_IRQ_RR_DONE | LCD_IRQ_DONE); 331 332 HWRITE4(sc, LCD_IRQENABLE_SET, reg); 333 334 /* enable dma & core clocks */ 335 HSET4(sc, LCD_CLKC_ENABLE, LCD_CLKC_ENABLE_DMA_CLK_EN 336 | LCD_CLKC_ENABLE_CORE_CLK_EN 337 | LCD_CLKC_ENABLE_LIDD_CLK_EN); 338 339 /* perform controller clock reset */ 340 HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); 341 delay(100); 342 HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); 343 344 /* configure wsdisplay descr. */ 345 strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 346 sc->sc_wsd.capabilities = sc->sc_ro.ri_caps; 347 sc->sc_wsd.nrows = sc->sc_ro.ri_rows; 348 sc->sc_wsd.ncols = sc->sc_ro.ri_cols; 349 sc->sc_wsd.textops = &sc->sc_ro.ri_ops; 350 sc->sc_wsd.fontwidth = sc->sc_ro.ri_font->fontwidth; 351 sc->sc_wsd.fontheight = sc->sc_ro.ri_font->fontheight; 352 353 sc->sc_scrlist[0] = &sc->sc_wsd; 354 sc->sc_wsl.nscreens = 1; 355 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 356 357 /* attach console */ 358 memset(&wsaa, 0, sizeof(wsaa)); 359 wsaa.scrdata = &sc->sc_wsl; 360 wsaa.accessops = &amdisplay_accessops; 361 wsaa.accesscookie = &sc->sc_ro; 362 363 config_found_sm(self, &wsaa, wsemuldisplaydevprint, 364 wsemuldisplaydevsubmatch); 365 366 /* enable controller */ 367 HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); 368 } 369 370 int 371 amdisplay_detach(struct device *self, int flags) 372 { 373 struct amdisplay_softc *sc = (struct amdisplay_softc *)self; 374 375 if (ISSET(sc->sc_flags, LCD_MODE_ALLOC)) 376 free(sc->sc_active_mode, M_DEVBUF, sizeof(struct videomode)); 377 378 if (!sc->sc_fb0) 379 return 0; 380 381 bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, sc->sc_fb_size, 382 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 383 384 bus_dmamap_unload(sc->sc_dmat, sc->sc_fb0_dma); 385 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)(sc->sc_fb0), sc->sc_fb_size); 386 bus_dmamem_free(sc->sc_dmat, sc->sc_fb0_dma_segs, sc->sc_fb_dma_nsegs); 387 bus_dmamap_destroy(sc->sc_dmat, sc->sc_fb0_dma); 388 389 return 0; 390 } 391 392 int 393 amdisplay_intr(void *arg) 394 { 395 struct amdisplay_softc *sc = arg; 396 uint32_t reg; 397 398 reg = HREAD4(sc, LCD_IRQSTATUS); 399 HWRITE4(sc, LCD_IRQSTATUS, reg); 400 401 DPRINTF(25, ("%s: intr 0x%08x\n", DEVNAME(sc), reg)); 402 403 if (ISSET(reg, LCD_IRQ_PL)) { 404 DPRINTF(10, ("%s: palette loaded, irq: 0x%08x\n", 405 DEVNAME(sc), reg)); 406 HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); 407 delay(100); 408 HCLR4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_PALMODE); 409 HSET4(sc, LCD_RASTER_CTRL, 0x02 << LCD_RASTER_CTRL_PALMODE_SHAMT); 410 HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); 411 } 412 413 if (ISSET(reg, LCD_IRQ_FUF)) { 414 DPRINTF(15, ("%s: FIFO underflow\n", DEVNAME(sc))); 415 } 416 417 if (ISSET(reg, LCD_IRQ_SYNC)) { 418 sc->sc_flags |= LCD_RESET_PENDING; 419 DPRINTF(18, ("%s: sync lost\n", DEVNAME(sc))); 420 } 421 422 if (ISSET(reg, LCD_IRQ_RR_DONE)) { 423 DPRINTF(21, ("%s: frame done\n", DEVNAME(sc))); 424 HWRITE4(sc, LCD_LCDDMA_FB0, sc->sc_fb0_dma_segs[0].ds_addr); 425 HWRITE4(sc, LCD_LCDDMA_FB0_CEIL, (sc->sc_fb0_dma_segs[0].ds_addr 426 + sc->sc_fb_size) - 1); 427 } 428 429 if (ISSET(reg, LCD_IRQ_EOF0)) { 430 DPRINTF(21, ("%s: framebuffer 0 done\n", DEVNAME(sc))); 431 } 432 433 if (ISSET(reg, LCD_IRQ_EOF1)) { 434 DPRINTF(21, ("%s: framebuffer 1 done\n", DEVNAME(sc))); 435 } 436 437 if (ISSET(reg, LCD_IRQ_DONE)) { 438 if (ISSET(sc->sc_flags, LCD_RESET_PENDING)) { 439 HWRITE4(sc, LCD_IRQSTATUS, 0xFFFFFFFF); 440 HSET4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); 441 delay(10); 442 HCLR4(sc, LCD_CLKC_RESET, LCD_CLKC_RESET_MAIN_RST); 443 HSET4(sc, LCD_RASTER_CTRL, LCD_RASTER_CTRL_LCDEN); 444 sc->sc_flags &= ~LCD_RESET_PENDING; 445 } 446 DPRINTF(15, ("%s: last frame done\n", DEVNAME(sc))); 447 } 448 449 if (ISSET(reg, LCD_IRQ_ACB)) { 450 DPRINTF(15, ("%s: AC bias event\n", DEVNAME(sc))); 451 } 452 453 HWRITE4(sc, LCD_IRQ_END, 0); 454 455 return 0; 456 } 457 458 int 459 amdisplay_setup_dma(struct amdisplay_softc *sc) 460 { 461 bus_size_t bsize; 462 463 bsize = (sc->sc_active_mode->hdisplay * sc->sc_active_mode->vdisplay 464 * sc->sc_active_depth) >> 3; 465 466 sc->sc_fb_size = bsize; 467 sc->sc_fb_dma_nsegs = 1; 468 469 if (bus_dmamap_create(sc->sc_dmat, sc->sc_fb_size, sc->sc_fb_dma_nsegs, 470 sc->sc_fb_size, 0, BUS_DMA_NOWAIT, &(sc->sc_fb0_dma))) 471 return -1; 472 473 if (bus_dmamem_alloc(sc->sc_dmat, sc->sc_fb_size, 4, 0, 474 sc->sc_fb0_dma_segs, 1, &(sc->sc_fb_dma_nsegs), 475 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) 476 return -2; 477 478 if (bus_dmamem_map(sc->sc_dmat, sc->sc_fb0_dma_segs, 479 sc->sc_fb_dma_nsegs, sc->sc_fb_size, (caddr_t *)&(sc->sc_fb0), 480 BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_NOCACHE)) 481 return -3; 482 483 if (bus_dmamap_load(sc->sc_dmat, sc->sc_fb0_dma, sc->sc_fb0, bsize, 484 NULL, BUS_DMA_NOWAIT)) 485 return -4; 486 487 memset(sc->sc_fb0, 0, bsize); 488 489 bus_dmamap_sync(sc->sc_dmat, sc->sc_fb0_dma, 0, bsize, 490 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 491 492 return 0; 493 } 494 495 void 496 amdisplay_conf_crt_timings(struct amdisplay_softc *sc) 497 { 498 uint32_t timing0, timing1, timing2; 499 uint32_t hbp, hfp, hsw, vbp, vfp, vsw, width, height; 500 struct videomode *m = sc->sc_active_mode; 501 502 timing0 = 0; 503 timing1 = 0; 504 timing2 = 0; 505 506 hbp = (m->htotal - m->hsync_end) - 1; 507 hfp = (m->hsync_start - m->hdisplay) - 1; 508 hsw = (m->hsync_end - m->hsync_start) - 1; 509 510 vbp = (m->vtotal - m->vsync_end); 511 vfp = (m->vsync_start - m->vdisplay); 512 vsw = (m->vsync_end - m->vsync_start) - 1; 513 514 height = m->vdisplay - 1; 515 width = m->hdisplay - 1; 516 517 /* Horizontal back porch */ 518 timing0 |= (hbp & 0xff) << LCD_RASTER_TIMING_0_HBP_SHAMT; 519 timing2 |= ((hbp >> 8) & 3) << LCD_RASTER_TIMING_2_HPB_HIGHBITS_SHAMT; 520 /* Horizontal front porch */ 521 timing0 |= (hfp & 0xff) << LCD_RASTER_TIMING_0_HFP_SHAMT; 522 timing2 |= ((hfp >> 8) & 3) << 0; 523 /* Horizontal sync width */ 524 timing0 |= (hsw & 0x3f) << LCD_RASTER_TIMING_0_HSW_SHAMT; 525 timing2 |= ((hsw >> 6) & 0xf) << LCD_RASTER_TIMING_2_HSW_HIGHBITS_SHAMT; 526 527 /* Vertical back porch, front porch, sync width */ 528 timing1 |= (vbp & 0xff) << LCD_RASTER_TIMING_1_VBP_SHAMT; 529 timing1 |= (vfp & 0xff) << LCD_RASTER_TIMING_1_VFP_SHAMT; 530 timing1 |= (vsw & 0x3f) << LCD_RASTER_TIMING_1_VSW_SHAMT; 531 532 /* Pixels per line */ 533 timing0 |= ((width >> 10) & 1) 534 << LCD_RASTER_TIMING_0_PPLMSB_SHAMT; 535 timing0 |= ((width >> 4) & 0x3f) 536 << LCD_RASTER_TIMING_0_PPLLSB_SHAMT; 537 538 /* Lines per panel */ 539 timing1 |= (height & 0x3ff); 540 timing2 |= ((height >> 10 ) & 1) 541 << LCD_RASTER_TIMING_2_LPP_B10_SHAMT; 542 543 /* waveform settings */ 544 timing2 |= LCD_RASTER_TIMING_2_PHSVS_ON_OFF; 545 timing2 |= (0xff << LCD_RASTER_TIMING_2_ACBI_SHAMT); 546 547 if (!ISSET(m->flags, VID_NHSYNC)) 548 timing2 |= LCD_RASTER_TIMING_2_IHS; 549 if (!ISSET(m->flags, VID_NVSYNC)) 550 timing2 |= LCD_RASTER_TIMING_2_IVS; 551 552 HWRITE4(sc, LCD_RASTER_TIMING_0, timing0); 553 HWRITE4(sc, LCD_RASTER_TIMING_1, timing1); 554 HWRITE4(sc, LCD_RASTER_TIMING_2, timing2); 555 } 556 557 void 558 amdisplay_calc_freq(uint64_t freq) 559 { 560 uint64_t mul, div, i, j, delta, min_delta; 561 562 min_delta = freq; 563 for (i = 1; i < LCD_M1_MAX; i++) { 564 for (j = 1; j < LCD_N_MAX; j++) { 565 delta = abs(freq - i * (LCD_MASTER_OSC / j)); 566 if (delta < min_delta) { 567 mul = i; 568 div = j; 569 min_delta = delta; 570 } 571 if (min_delta == 0) 572 break; 573 } 574 } 575 div--; 576 577 prcm_setclock(4, div); 578 prcm_setclock(3, mul); 579 prcm_setclock(5, 1); 580 } 581 582 int 583 amdisplay_ioctl(void *sconf, u_long cmd, caddr_t data, int flat, struct proc *p) 584 { 585 struct rasops_info *ri = sconf; 586 struct wsdisplay_fbinfo *wdf; 587 588 switch (cmd) { 589 case WSDISPLAYIO_GTYPE: 590 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; 591 return 0; 592 case WSDISPLAYIO_GINFO: 593 wdf = (struct wsdisplay_fbinfo *)data; 594 wdf->width = ri->ri_width; 595 wdf->height = ri->ri_height; 596 wdf->depth = ri->ri_depth; 597 wdf->stride = ri->ri_stride; 598 wdf->offset = 0; 599 wdf->cmsize = 0; 600 break; 601 case WSDISPLAYIO_LINEBYTES: 602 *(u_int *)data = ri->ri_stride; 603 break; 604 case WSDISPLAYIO_SMODE: 605 break; 606 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 607 switch (ri->ri_depth) { 608 case 32: 609 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 610 break; 611 case 24: 612 *(u_int *)data = WSDISPLAYIO_DEPTH_24_24; 613 break; 614 case 16: 615 *(u_int *)data = WSDISPLAYIO_DEPTH_16; 616 break; 617 case 15: 618 *(u_int *)data = WSDISPLAYIO_DEPTH_15; 619 break; 620 default: 621 return -1; 622 } 623 break; 624 default: 625 return -1; 626 } 627 628 return 0; 629 } 630 631 paddr_t 632 amdisplay_mmap(void *sconf, off_t off, int prot) 633 { 634 struct rasops_info *ri = sconf; 635 struct amdisplay_softc *sc = ri->ri_hw; 636 637 if (off < 0 || off >= sc->sc_fb_size) 638 return -1; 639 640 return bus_dmamem_mmap(sc->sc_dmat, &sc->sc_fb0_dma_segs[0], 641 sc->sc_fb_dma_nsegs, off, prot, BUS_DMA_COHERENT); 642 } 643 644 int 645 amdisplay_alloc_screen(void *sconf, const struct wsscreen_descr *type, 646 void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 647 { 648 return rasops_alloc_screen(sconf, cookiep, curxp, curyp, attrp); 649 } 650