1 /* $NetBSD: sunxi_debe.c,v 1.8 2018/04/07 18:09:33 bouyer Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 Manuel Bouyer <bouyer@antioche.eu.org> 5 * All rights reserved. 6 * 7 * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include "genfb.h" 33 34 #ifndef SUNXI_DEBE_VIDEOMEM 35 #define SUNXI_DEBE_VIDEOMEM (16 * 1024 * 1024) 36 #endif 37 38 #define SUNXI_DEBE_CURMAX 64 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c,v 1.8 2018/04/07 18:09:33 bouyer Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/bus.h> 45 #include <sys/device.h> 46 #include <sys/intr.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/mutex.h> 50 #include <sys/condvar.h> 51 52 #include <dev/fdt/fdtvar.h> 53 #include <dev/fdt/fdt_port.h> 54 55 #include <dev/videomode/videomode.h> 56 #include <dev/wscons/wsconsio.h> 57 #include <dev/wsfb/genfbvar.h> 58 59 #include <arm/sunxi/sunxi_debereg.h> 60 #include <arm/sunxi/sunxi_display.h> 61 #include <arm/sunxi/sunxi_platform.h> 62 #include <machine/bootconfig.h> 63 64 enum sunxi_debe_type { 65 DEBE_A10 = 1, 66 }; 67 68 struct sunxi_debe_softc { 69 device_t sc_dev; 70 device_t sc_fbdev; 71 enum sunxi_debe_type sc_type; 72 bus_space_tag_t sc_bst; 73 bus_space_handle_t sc_bsh; 74 bus_dma_tag_t sc_dmat; 75 76 struct clk *sc_clk_ahb; 77 struct clk *sc_clk_mod; 78 struct clk *sc_clk_ram; 79 80 bus_dma_segment_t sc_dmasegs[1]; 81 bus_size_t sc_dmasize; 82 bus_dmamap_t sc_dmamap; 83 void *sc_dmap; 84 85 bool sc_cursor_enable; 86 int sc_cursor_x, sc_cursor_y; 87 int sc_hot_x, sc_hot_y; 88 uint8_t sc_cursor_bitmap[8 * SUNXI_DEBE_CURMAX]; 89 uint8_t sc_cursor_mask[8 * SUNXI_DEBE_CURMAX]; 90 91 int sc_phandle; 92 struct fdt_device_ports sc_ports; 93 struct fdt_endpoint *sc_out_ep; 94 int sc_unit; /* debe0 or debe1 */ 95 }; 96 97 #define DEBE_READ(sc, reg) \ 98 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 99 #define DEBE_WRITE(sc, reg, val) \ 100 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 101 102 static const struct of_compat_data compat_data[] = { 103 {"allwinner,sun4i-a10-display-backend", DEBE_A10}, 104 {"allwinner,sun7i-a20-display-backend", DEBE_A10}, 105 {NULL} 106 }; 107 108 struct sunxifb_attach_args { 109 void *afb_fb; 110 uint32_t afb_width; 111 uint32_t afb_height; 112 bus_dma_tag_t afb_dmat; 113 bus_dma_segment_t *afb_dmasegs; 114 int afb_ndmasegs; 115 }; 116 117 static void sunxi_debe_ep_connect(device_t, struct fdt_endpoint *, bool); 118 static int sunxi_debe_ep_enable(device_t, struct fdt_endpoint *, bool); 119 static int sunxi_debe_match(device_t, cfdata_t, void *); 120 static void sunxi_debe_attach(device_t, device_t, void *); 121 122 static int sunxi_debe_alloc_videomem(struct sunxi_debe_softc *); 123 static void sunxi_debe_setup_fbdev(struct sunxi_debe_softc *, 124 const struct videomode *); 125 126 static int sunxi_debe_set_curpos(struct sunxi_debe_softc *, int, int); 127 static int sunxi_debe_set_cursor(struct sunxi_debe_softc *, 128 struct wsdisplay_cursor *); 129 static int sunxi_debe_ioctl(device_t, u_long, void *); 130 static void sunxi_befb_set_videomode(device_t, u_int, u_int); 131 void sunxi_debe_dump_regs(int); 132 133 static struct sunxi_debe_softc *debe_console_sc; 134 static int sunxi_simplefb_phandle = -1; 135 136 CFATTACH_DECL_NEW(sunxi_debe, sizeof(struct sunxi_debe_softc), 137 sunxi_debe_match, sunxi_debe_attach, NULL, NULL); 138 139 static int 140 sunxi_debe_match(device_t parent, cfdata_t cf, void *aux) 141 { 142 struct fdt_attach_args * const faa = aux; 143 144 return of_match_compat_data(faa->faa_phandle, compat_data); 145 } 146 147 static void 148 sunxi_debe_attach(device_t parent, device_t self, void *aux) 149 { 150 struct sunxi_debe_softc *sc = device_private(self); 151 struct fdt_attach_args * const faa = aux; 152 const int phandle = faa->faa_phandle; 153 bus_addr_t addr; 154 bus_size_t size; 155 struct fdtbus_reset *rst; 156 int error; 157 158 sc->sc_dev = self; 159 sc->sc_phandle = phandle; 160 sc->sc_bst = faa->faa_bst; 161 sc->sc_dmat = faa->faa_dmat; 162 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 163 aprint_error(": couldn't get registers\n"); 164 } 165 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 166 aprint_error(": couldn't map registers\n"); 167 return; 168 } 169 170 sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb"); 171 sc->sc_clk_mod = fdtbus_clock_get(phandle, "mod"); 172 sc->sc_clk_ram = fdtbus_clock_get(phandle, "ram"); 173 174 rst = fdtbus_reset_get_index(phandle, 0); 175 if (rst == NULL) { 176 aprint_error(": couldn't get reset\n"); 177 return; 178 } 179 if (fdtbus_reset_assert(rst) != 0) { 180 aprint_error(": couldn't assert reset\n"); 181 return; 182 } 183 delay(1); 184 if (fdtbus_reset_deassert(rst) != 0) { 185 aprint_error(": couldn't de-assert reset\n"); 186 return; 187 } 188 189 if (sc->sc_clk_ahb == NULL || sc->sc_clk_mod == NULL 190 || sc->sc_clk_ram == NULL) { 191 aprint_error(": couldn't get clocks\n"); 192 aprint_debug_dev(self, "clk ahb %s mod %s ram %s\n", 193 sc->sc_clk_ahb == NULL ? "missing" : "present", 194 sc->sc_clk_mod == NULL ? "missing" : "present", 195 sc->sc_clk_ram == NULL ? "missing" : "present"); 196 return; 197 } 198 199 error = clk_set_rate(sc->sc_clk_mod, 300000000); 200 if (error) { 201 aprint_error("couln't set mod clock rate (%d)\n", error); 202 return; 203 } 204 205 if (clk_enable(sc->sc_clk_ahb) != 0 || 206 clk_enable(sc->sc_clk_mod) != 0) { 207 aprint_error(": couldn't enable clocks\n"); 208 return; 209 } 210 if (clk_disable(sc->sc_clk_ram) != 0) { 211 aprint_error(": couldn't disable ram clock\n"); 212 } 213 214 sc->sc_type = of_search_compatible(faa->faa_phandle, compat_data)->data; 215 216 aprint_naive("\n"); 217 aprint_normal(": Display Engine Backend (%s)\n", 218 fdtbus_get_string(phandle, "name")); 219 220 221 for (unsigned int reg = 0x800; reg < 0x1000; reg += 4) { 222 DEBE_WRITE(sc, reg, 0); 223 } 224 225 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, SUNXI_DEBE_MODCTL_EN); 226 227 sc->sc_dmasize = SUNXI_DEBE_VIDEOMEM; 228 229 DEBE_WRITE(sc, SUNXI_DEBE_HWC_PALETTE_TABLE, 0); 230 231 error = sunxi_debe_alloc_videomem(sc); 232 if (error) { 233 aprint_error_dev(sc->sc_dev, 234 "couldn't allocate video memory, error = %d\n", error); 235 return; 236 } 237 238 sc->sc_unit = -1; 239 sc->sc_ports.dp_ep_connect = sunxi_debe_ep_connect; 240 sc->sc_ports.dp_ep_enable = sunxi_debe_ep_enable; 241 fdt_ports_register(&sc->sc_ports, self, phandle, EP_OTHER); 242 243 if (clk_disable(sc->sc_clk_ahb) != 0 || 244 clk_disable(sc->sc_clk_mod) != 0) { 245 aprint_error(": couldn't disable clocks\n"); 246 return; 247 } 248 } 249 250 static void 251 sunxi_debe_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect) 252 { 253 struct sunxi_debe_softc *sc = device_private(self); 254 struct fdt_endpoint *rep = fdt_endpoint_remote(ep); 255 int rep_idx = fdt_endpoint_index(rep); 256 257 KASSERT(device_is_a(self, "sunxidebe")); 258 if (!connect) { 259 aprint_error_dev(self, "endpoint disconnect not supported\n"); 260 return; 261 } 262 263 if (fdt_endpoint_port_index(ep) == 1) { 264 bool do_print = (sc->sc_unit == -1); 265 /* 266 * one of our output endpoints has been connected. 267 * the remote id is our unit number 268 */ 269 if (sc->sc_unit != -1 && rep_idx != -1 && 270 sc->sc_unit != rep_idx) { 271 aprint_error_dev(self, ": remote id %d doens't match" 272 " discovered unit number %d\n", 273 rep_idx, sc->sc_unit); 274 return; 275 } 276 if (!device_is_a(fdt_endpoint_device(rep), "sunxitcon")) { 277 aprint_error_dev(self, 278 ": output %d connected to unknown device\n", 279 fdt_endpoint_index(ep)); 280 return; 281 } 282 if (rep_idx != -1) 283 sc->sc_unit = rep_idx; 284 else { 285 /* assume only one debe */ 286 sc->sc_unit = 0; 287 } 288 if (do_print) 289 aprint_verbose_dev(self, "debe unit %d\n", sc->sc_unit); 290 } 291 } 292 293 static int 294 sunxi_debe_alloc_videomem(struct sunxi_debe_softc *sc) 295 { 296 int error, nsegs; 297 298 error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmasize, 0x1000, 0, 299 sc->sc_dmasegs, 1, &nsegs, BUS_DMA_WAITOK); 300 if (error) 301 return error; 302 error = bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, nsegs, 303 sc->sc_dmasize, &sc->sc_dmap, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 304 if (error) 305 goto free; 306 error = bus_dmamap_create(sc->sc_dmat, sc->sc_dmasize, 1, 307 sc->sc_dmasize, 0, BUS_DMA_WAITOK, &sc->sc_dmamap); 308 if (error) 309 goto unmap; 310 error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmap, 311 sc->sc_dmasize, NULL, BUS_DMA_WAITOK); 312 if (error) 313 goto destroy; 314 315 memset(sc->sc_dmap, 0, sc->sc_dmasize); 316 317 return 0; 318 319 destroy: 320 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 321 unmap: 322 bus_dmamem_unmap(sc->sc_dmat, sc->sc_dmap, sc->sc_dmasize); 323 free: 324 bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, nsegs); 325 326 sc->sc_dmasize = 0; 327 sc->sc_dmap = NULL; 328 329 return error; 330 } 331 332 static void 333 sunxi_debe_setup_fbdev(struct sunxi_debe_softc *sc, const struct videomode *mode) 334 { 335 if (mode == NULL) 336 return; 337 338 const u_int interlace_p = !!(mode->flags & VID_INTERLACE); 339 const u_int fb_width = mode->hdisplay; 340 const u_int fb_height = (mode->vdisplay << interlace_p); 341 342 if (mode && sc->sc_fbdev == NULL) { 343 /* see if we are the console */ 344 if (sunxi_simplefb_phandle >= 0) { 345 const char *cons_pipeline = 346 fdtbus_get_string(sunxi_simplefb_phandle, 347 "allwinner,pipeline"); 348 struct fdt_endpoint *ep = fdt_endpoint_get_from_index( 349 &sc->sc_ports, SUNXI_PORT_OUTPUT, sc->sc_unit); 350 struct fdt_endpoint *rep = fdt_endpoint_remote(ep); 351 if (sunxi_tcon_is_console( 352 fdt_endpoint_device(rep), cons_pipeline)) 353 debe_console_sc = sc; 354 } else if (debe_console_sc == NULL) { 355 if (match_bootconf_option(boot_args, 356 "console", "fb0")) { 357 if (sc->sc_unit == 0) 358 debe_console_sc = sc; 359 } else if (match_bootconf_option(boot_args, 360 "console", "fb1")) { 361 if (sc->sc_unit == 1) 362 debe_console_sc = sc; 363 } else if (match_bootconf_option(boot_args, 364 "console", "fb")) { 365 /* match first activated */ 366 debe_console_sc = sc; 367 } 368 } 369 struct sunxifb_attach_args afb = { 370 .afb_fb = sc->sc_dmap, 371 .afb_width = fb_width, 372 .afb_height = fb_height, 373 .afb_dmat = sc->sc_dmat, 374 .afb_dmasegs = sc->sc_dmasegs, 375 .afb_ndmasegs = 1 376 }; 377 sc->sc_fbdev = config_found_ia(sc->sc_dev, "sunxidebe", 378 &afb, NULL); 379 } else if (sc->sc_fbdev != NULL) { 380 sunxi_befb_set_videomode(sc->sc_fbdev, fb_width, fb_height); 381 } 382 } 383 384 static int 385 sunxi_debe_set_curpos(struct sunxi_debe_softc *sc, int x, int y) 386 { 387 int xx, yy; 388 u_int yoff, xoff; 389 390 xoff = yoff = 0; 391 xx = x - sc->sc_hot_x; 392 yy = y - sc->sc_hot_y; 393 if (xx < 0) { 394 xoff -= xx; 395 xx = 0; 396 } 397 if (yy < 0) { 398 yoff -= yy; 399 yy = 0; 400 } 401 402 DEBE_WRITE(sc, SUNXI_DEBE_HWCCTL_REG, 403 __SHIFTIN(yy, SUNXI_DEBE_HWCCTL_YCOOR) | 404 __SHIFTIN(xx, SUNXI_DEBE_HWCCTL_XCOOR)); 405 DEBE_WRITE(sc, SUNXI_DEBE_HWCFBCTL_REG, 406 #if SUNXI_DEBE_CURMAX == 32 407 __SHIFTIN(SUNXI_DEBE_HWCFBCTL_YSIZE_32, SUNXI_DEBE_HWCFBCTL_YSIZE) | 408 __SHIFTIN(SUNXI_DEBE_HWCFBCTL_XSIZE_32, SUNXI_DEBE_HWCFBCTL_XSIZE) | 409 #else 410 __SHIFTIN(SUNXI_DEBE_HWCFBCTL_YSIZE_64, SUNXI_DEBE_HWCFBCTL_YSIZE) | 411 __SHIFTIN(SUNXI_DEBE_HWCFBCTL_XSIZE_64, SUNXI_DEBE_HWCFBCTL_XSIZE) | 412 #endif 413 __SHIFTIN(SUNXI_DEBE_HWCFBCTL_FBFMT_2BPP, SUNXI_DEBE_HWCFBCTL_FBFMT) | 414 __SHIFTIN(yoff, SUNXI_DEBE_HWCFBCTL_YCOOROFF) | 415 __SHIFTIN(xoff, SUNXI_DEBE_HWCFBCTL_XCOOROFF)); 416 417 return 0; 418 } 419 420 static int 421 sunxi_debe_set_cursor(struct sunxi_debe_softc *sc, struct wsdisplay_cursor *cur) 422 { 423 uint32_t val; 424 uint8_t r[4], g[4], b[4]; 425 u_int index, count, shift, off, pcnt; 426 int i, j, idx, error; 427 uint8_t mask; 428 429 if (cur->which & WSDISPLAY_CURSOR_DOCUR) { 430 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 431 if (cur->enable) 432 val |= SUNXI_DEBE_MODCTL_HWC_EN; 433 else 434 val &= ~SUNXI_DEBE_MODCTL_HWC_EN; 435 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val); 436 437 sc->sc_cursor_enable = cur->enable; 438 } 439 440 if (cur->which & WSDISPLAY_CURSOR_DOHOT) { 441 sc->sc_hot_x = cur->hot.x; 442 sc->sc_hot_y = cur->hot.y; 443 cur->which |= WSDISPLAY_CURSOR_DOPOS; 444 } 445 446 if (cur->which & WSDISPLAY_CURSOR_DOPOS) { 447 sunxi_debe_set_curpos(sc, cur->pos.x, cur->pos.y); 448 } 449 450 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) { 451 index = cur->cmap.index; 452 count = cur->cmap.count; 453 if (index >= 2 || count > 2 - index) 454 return EINVAL; 455 error = copyin(cur->cmap.red, &r[index], count); 456 if (error) 457 return error; 458 error = copyin(cur->cmap.green, &g[index], count); 459 if (error) 460 return error; 461 error = copyin(cur->cmap.blue, &b[index], count); 462 if (error) 463 return error; 464 465 for (i = index; i < (index + count); i++) { 466 DEBE_WRITE(sc, 467 SUNXI_DEBE_HWC_PALETTE_TABLE + (4 * (i + 2)), 468 (r[i] << 16) | (g[i] << 8) | b[i] | 0xff000000); 469 } 470 } 471 472 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) { 473 error = copyin(cur->mask, sc->sc_cursor_mask, 474 SUNXI_DEBE_CURMAX * 8); 475 if (error) 476 return error; 477 error = copyin(cur->image, sc->sc_cursor_bitmap, 478 SUNXI_DEBE_CURMAX * 8); 479 if (error) 480 return error; 481 } 482 483 if (cur->which & (WSDISPLAY_CURSOR_DOCMAP|WSDISPLAY_CURSOR_DOSHAPE)) { 484 for (i = 0, pcnt = 0; i < SUNXI_DEBE_CURMAX * 8; i++) { 485 for (j = 0, mask = 1; j < 8; j++, mask <<= 1, pcnt++) { 486 idx = ((sc->sc_cursor_mask[i] & mask) ? 2 : 0) | 487 ((sc->sc_cursor_bitmap[i] & mask) ? 1 : 0); 488 off = (pcnt >> 4) * 4; 489 shift = (pcnt & 0xf) * 2; 490 val = DEBE_READ(sc, 491 SUNXI_DEBE_HWC_PATTERN_BLOCK + off); 492 val &= ~(3 << shift); 493 val |= (idx << shift); 494 DEBE_WRITE(sc, 495 SUNXI_DEBE_HWC_PATTERN_BLOCK + off, val); 496 } 497 } 498 } 499 500 return 0; 501 } 502 503 static int 504 sunxi_debe_ep_enable(device_t dev, struct fdt_endpoint *ep, bool enable) 505 { 506 struct sunxi_debe_softc *sc; 507 uint32_t val; 508 509 KASSERT(device_is_a(dev, "sunxidebe")); 510 sc = device_private(dev); 511 512 if (enable) { 513 if (clk_enable(sc->sc_clk_ram) != 0) { 514 device_printf(dev, 515 ": warning: failed to enable ram clock\n"); 516 } 517 val = DEBE_READ(sc, SUNXI_DEBE_REGBUFFCTL_REG); 518 val |= SUNXI_DEBE_REGBUFFCTL_REGLOADCTL; 519 DEBE_WRITE(sc, SUNXI_DEBE_REGBUFFCTL_REG, val); 520 521 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 522 val |= SUNXI_DEBE_MODCTL_START_CTL; 523 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val); 524 #ifdef SUNXI_DEBE_DEBUG 525 sunxi_debe_dump_regs(sc->sc_unit); 526 #endif 527 } else { 528 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 529 val &= ~SUNXI_DEBE_MODCTL_START_CTL; 530 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val); 531 if (clk_disable(sc->sc_clk_ram) != 0) { 532 device_printf(dev, 533 ": warning: failed to disable ram clock\n"); 534 } 535 } 536 #if 0 537 for (int i = 0; i < 0x1000; i += 4) { 538 printf("DEBE 0x%04x: 0x%08x\n", i, DEBE_READ(sc, i)); 539 } 540 #endif 541 return 0; 542 } 543 544 void 545 sunxi_debe_set_videomode(device_t dev, const struct videomode *mode) 546 { 547 struct sunxi_debe_softc *sc; 548 uint32_t val; 549 550 KASSERT(device_is_a(dev, "sunxidebe")); 551 sc = device_private(dev); 552 553 if (mode) { 554 const u_int interlace_p = !!(mode->flags & VID_INTERLACE); 555 const u_int width = mode->hdisplay; 556 const u_int height = (mode->vdisplay << interlace_p); 557 const u_int fb_width = width; 558 const u_int fb_height = height; 559 uint32_t vmem = width * height * 4; 560 561 if (vmem > sc->sc_dmasize) { 562 device_printf(sc->sc_dev, 563 "not enough memory for %ux%u fb (req %u have %u)\n", 564 width, height, vmem, (unsigned int)sc->sc_dmasize); 565 return; 566 } 567 568 paddr_t pa = sc->sc_dmamap->dm_segs[0].ds_addr; 569 #if !defined(ALLWINNER_A80) && 0 570 #define SUNXI_SDRAM_PBASE-0 0x40000000 571 /* 572 * On 2GB systems, we need to subtract AWIN_SDRAM_PBASE from 573 * the phys addr. 574 */ 575 if (pa >= SUNXI_SDRAM_PBASE) 576 pa -= SUNXI_SDRAM_PBASE; 577 #endif 578 579 /* notify fb */ 580 sunxi_debe_setup_fbdev(sc, mode); 581 582 DEBE_WRITE(sc, SUNXI_DEBE_DISSIZE_REG, 583 ((height - 1) << 16) | (width - 1)); 584 DEBE_WRITE(sc, SUNXI_DEBE_LAYSIZE_REG, 585 ((fb_height - 1) << 16) | (fb_width - 1)); 586 DEBE_WRITE(sc, SUNXI_DEBE_LAYCOOR_REG, 0); 587 DEBE_WRITE(sc, SUNXI_DEBE_LAYLINEWIDTH_REG, (fb_width << 5)); 588 DEBE_WRITE(sc, SUNXI_DEBE_LAYFB_L32ADD_REG, pa << 3); 589 DEBE_WRITE(sc, SUNXI_DEBE_LAYFB_H4ADD_REG, pa >> 29); 590 591 val = DEBE_READ(sc, SUNXI_DEBE_ATTCTL1_REG); 592 val &= ~SUNXI_DEBE_ATTCTL1_LAY_FBFMT; 593 val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBFMT_XRGB8888, 594 SUNXI_DEBE_ATTCTL1_LAY_FBFMT); 595 val &= ~SUNXI_DEBE_ATTCTL1_LAY_BRSWAPEN; 596 val &= ~SUNXI_DEBE_ATTCTL1_LAY_FBPS; 597 #if __ARMEB__ 598 val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBPS_32BPP_BGRA, 599 SUNXI_DEBE_ATTCTL1_LAY_FBPS); 600 #else 601 val |= __SHIFTIN(SUNXI_DEBE_ATTCTL1_LAY_FBPS_32BPP_ARGB, 602 SUNXI_DEBE_ATTCTL1_LAY_FBPS); 603 #endif 604 DEBE_WRITE(sc, SUNXI_DEBE_ATTCTL1_REG, val); 605 606 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 607 val |= SUNXI_DEBE_MODCTL_LAY0_EN; 608 if (interlace_p) { 609 val |= SUNXI_DEBE_MODCTL_ITLMOD_EN; 610 } else { 611 val &= ~SUNXI_DEBE_MODCTL_ITLMOD_EN; 612 } 613 val &= ~SUNXI_DEBE_MODCTL_OUT_SEL; 614 if (sc->sc_unit == 1) { 615 val |= __SHIFTIN(SUNXI_DEBE_MODCTL_OUT_SEL_LCD1, 616 SUNXI_DEBE_MODCTL_OUT_SEL); 617 } 618 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val); 619 } else { 620 /* disable */ 621 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 622 val &= ~SUNXI_DEBE_MODCTL_LAY0_EN; 623 val &= ~SUNXI_DEBE_MODCTL_START_CTL; 624 DEBE_WRITE(sc, SUNXI_DEBE_MODCTL_REG, val); 625 626 /* notify fb */ 627 sunxi_debe_setup_fbdev(sc, mode); 628 } 629 } 630 631 static int 632 sunxi_debe_ioctl(device_t self, u_long cmd, void *data) 633 { 634 struct sunxi_debe_softc *sc = device_private(self); 635 struct wsdisplay_curpos *cp; 636 uint32_t val; 637 int enable; 638 639 switch (cmd) { 640 case WSDISPLAYIO_SVIDEO: 641 enable = *(int *)data; 642 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 643 if (enable) { 644 if (val & SUNXI_DEBE_MODCTL_START_CTL) { 645 /* already enabled */ 646 return 0; 647 } 648 } else { 649 if ((val & SUNXI_DEBE_MODCTL_START_CTL) == 0) { 650 /* already disabled */ 651 return 0; 652 } 653 } 654 return fdt_endpoint_enable(sc->sc_out_ep, enable); 655 case WSDISPLAYIO_GVIDEO: 656 val = DEBE_READ(sc, SUNXI_DEBE_MODCTL_REG); 657 *(int *)data = !!(val & SUNXI_DEBE_MODCTL_LAY0_EN); 658 return 0; 659 case WSDISPLAYIO_GCURPOS: 660 cp = data; 661 cp->x = sc->sc_cursor_x; 662 cp->y = sc->sc_cursor_y; 663 return 0; 664 case WSDISPLAYIO_SCURPOS: 665 cp = data; 666 return sunxi_debe_set_curpos(sc, cp->x, cp->y); 667 case WSDISPLAYIO_GCURMAX: 668 cp = data; 669 cp->x = SUNXI_DEBE_CURMAX; 670 cp->y = SUNXI_DEBE_CURMAX; 671 return 0; 672 case WSDISPLAYIO_SCURSOR: 673 return sunxi_debe_set_cursor(sc, data); 674 } 675 676 return EPASSTHROUGH; 677 } 678 679 /* genfb attachement */ 680 681 struct sunxi_befb_softc { 682 struct genfb_softc sc_gen; 683 device_t sc_debedev; 684 685 bus_dma_tag_t sc_dmat; 686 bus_dma_segment_t *sc_dmasegs; 687 int sc_ndmasegs; 688 }; 689 690 static device_t sunxi_befb_consoledev = NULL; 691 692 static int sunxi_befb_match(device_t, cfdata_t, void *); 693 static void sunxi_befb_attach(device_t, device_t, void *); 694 695 static int sunxi_befb_ioctl(void *, void *, u_long, void *, int, lwp_t *); 696 static paddr_t sunxi_befb_mmap(void *, void *, off_t, int); 697 static bool sunxi_befb_shutdown(device_t, int); 698 699 CFATTACH_DECL_NEW(sunxi_befb, sizeof(struct sunxi_befb_softc), 700 sunxi_befb_match, sunxi_befb_attach, NULL, NULL); 701 702 static int 703 sunxi_befb_match(device_t parent, cfdata_t cf, void *aux) 704 { 705 return 1; 706 } 707 708 static void 709 sunxi_befb_attach(device_t parent, device_t self, void *aux) 710 { 711 struct sunxi_befb_softc *sc = device_private(self); 712 struct sunxifb_attach_args * const afb = aux; 713 prop_dictionary_t cfg = device_properties(self); 714 struct genfb_ops ops; 715 716 sc->sc_gen.sc_dev = self; 717 sc->sc_debedev = parent; 718 sc->sc_dmat = afb->afb_dmat; 719 sc->sc_dmasegs = afb->afb_dmasegs; 720 sc->sc_ndmasegs = afb->afb_ndmasegs; 721 722 prop_dictionary_set_uint32(cfg, "width", afb->afb_width); 723 prop_dictionary_set_uint32(cfg, "height", afb->afb_height); 724 prop_dictionary_set_uint8(cfg, "depth", 32); 725 prop_dictionary_set_uint16(cfg, "linebytes", afb->afb_width * 4); 726 prop_dictionary_set_uint32(cfg, "address", 0); 727 prop_dictionary_set_uint32(cfg, "virtual_address", 728 (uintptr_t)afb->afb_fb); 729 730 genfb_init(&sc->sc_gen); 731 732 if (sc->sc_gen.sc_width == 0 || sc->sc_gen.sc_fbsize == 0) { 733 aprint_normal(": disabled\n"); 734 return; 735 } 736 737 pmf_device_register1(self, NULL, NULL, sunxi_befb_shutdown); 738 739 memset(&ops, 0, sizeof(ops)); 740 ops.genfb_ioctl = sunxi_befb_ioctl; 741 ops.genfb_mmap = sunxi_befb_mmap; 742 743 aprint_naive("\n"); 744 745 bool is_console = (debe_console_sc == device_private(parent)); 746 if (is_console) 747 aprint_normal(": switching to framebuffer console\n"); 748 else 749 aprint_normal("\n"); 750 751 #ifdef WSDISPLAY_MULTICONS 752 /* 753 * if we support multicons, only the first framebuffer is console, 754 * unless we already know which framebuffer will be the console 755 */ 756 if (!is_console && debe_console_sc == NULL && 757 sunxi_befb_consoledev == NULL) 758 is_console = true; 759 #endif 760 prop_dictionary_set_bool(cfg, "is_console", is_console); 761 if (is_console) { 762 KASSERT(sunxi_befb_consoledev == NULL); 763 sunxi_befb_consoledev = self; 764 } 765 766 genfb_attach(&sc->sc_gen, &ops); 767 } 768 769 static int 770 sunxi_befb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l) 771 { 772 struct sunxi_befb_softc *sc = v; 773 struct wsdisplayio_bus_id *busid; 774 struct wsdisplayio_fbinfo *fbi; 775 struct rasops_info *ri; 776 int error; 777 778 switch (cmd) { 779 case WSDISPLAYIO_GTYPE: 780 *(u_int *)data = WSDISPLAY_TYPE_ALLWINNER; 781 return 0; 782 case WSDISPLAYIO_GET_BUSID: 783 busid = data; 784 busid->bus_type = WSDISPLAYIO_BUS_SOC; 785 return 0; 786 case WSDISPLAYIO_GET_FBINFO: 787 fbi = data; 788 ri = &sc->sc_gen.vd.active->scr_ri; 789 error = wsdisplayio_get_fbinfo(ri, fbi); 790 if (error == 0) { 791 fbi->fbi_flags |= WSFB_VRAM_IS_RAM; 792 fbi->fbi_fbsize = sc->sc_dmasegs[0].ds_len; 793 } 794 return error; 795 case WSDISPLAYIO_SVIDEO: 796 case WSDISPLAYIO_GVIDEO: 797 case WSDISPLAYIO_GCURPOS: 798 case WSDISPLAYIO_SCURPOS: 799 case WSDISPLAYIO_GCURMAX: 800 case WSDISPLAYIO_SCURSOR: 801 return sunxi_debe_ioctl(sc->sc_debedev, cmd, data); 802 default: 803 return EPASSTHROUGH; 804 } 805 } 806 807 static paddr_t 808 sunxi_befb_mmap(void *v, void *vs, off_t off, int prot) 809 { 810 struct sunxi_befb_softc *sc = v; 811 812 if (off < 0 || off >= sc->sc_dmasegs[0].ds_len) 813 return -1; 814 815 return bus_dmamem_mmap(sc->sc_dmat, sc->sc_dmasegs, sc->sc_ndmasegs, 816 off, prot, BUS_DMA_PREFETCHABLE); 817 } 818 819 static bool 820 sunxi_befb_shutdown(device_t self, int flags) 821 { 822 genfb_enable_polling(self); 823 return true; 824 } 825 826 static void 827 sunxi_befb_set_videomode(device_t dev, u_int width, u_int height) 828 { 829 struct sunxi_befb_softc *sc = device_private(dev); 830 831 if (sc->sc_gen.sc_width != width || sc->sc_gen.sc_height != height) { 832 device_printf(sc->sc_gen.sc_dev, 833 "mode switching not yet supported\n"); 834 } 835 } 836 837 int 838 sunxi_debe_pipeline(int phandle, bool active) 839 { 840 device_t dev; 841 struct sunxi_debe_softc *sc; 842 struct fdt_endpoint *ep; 843 int i, error; 844 845 if (!active) 846 return EOPNOTSUPP; 847 848 for (i = 0;;i++) { 849 dev = device_find_by_driver_unit("sunxidebe", i); 850 if (dev == NULL) 851 return ENODEV; 852 sc = device_private(dev); 853 if (sc->sc_phandle == phandle) 854 break; 855 } 856 aprint_normal("activate %s\n", device_xname(dev)); 857 if (clk_enable(sc->sc_clk_ahb) != 0 || 858 clk_enable(sc->sc_clk_mod) != 0) { 859 aprint_error_dev(dev, "couldn't enable clocks\n"); 860 return EIO; 861 } 862 /* connect debd0 to tcon0, debe1 to tcon1 */ 863 ep = fdt_endpoint_get_from_index(&sc->sc_ports, SUNXI_PORT_OUTPUT, 864 sc->sc_unit); 865 if (ep == NULL) { 866 aprint_error_dev(dev, "no output endpoint for %d\n", 867 sc->sc_unit); 868 return ENODEV; 869 } 870 error = fdt_endpoint_activate(ep, true); 871 if (error) 872 return error; 873 874 sc->sc_out_ep = ep; 875 error = fdt_endpoint_enable(ep, true); 876 return error; 877 } 878 879 /* 880 * we don't want to take over console at this time - simplefb will 881 * do a better job than us. We will take over later. 882 * But we want to record the /chose/framebuffer phandle if there is one 883 */ 884 885 static const char * const simplefb_compatible[] = { 886 "allwinner,simple-framebuffer", 887 NULL 888 }; 889 890 static int 891 sunxidebe_console_match(int phandle) 892 { 893 if (of_match_compatible(phandle, simplefb_compatible)) { 894 sunxi_simplefb_phandle = phandle; 895 } 896 return 0; 897 } 898 899 static void 900 sunxidebe_console_consinit(struct fdt_attach_args *faa, u_int uart_freq) 901 { 902 panic("sunxidebe_console_consinit"); 903 } 904 905 static const struct fdt_console sunxidebe_fdt_console = { 906 .match = sunxidebe_console_match, 907 .consinit = sunxidebe_console_consinit 908 }; 909 910 FDT_CONSOLE(sunxidebe, &sunxidebe_fdt_console); 911 912 #if defined(SUNXI_DEBE_DEBUG) 913 void 914 sunxi_debe_dump_regs(int u) 915 { 916 static const struct { 917 const char *name; 918 uint16_t reg; 919 } regs[] = { 920 { "SUNXI_DEBE_MODCTL_REG", SUNXI_DEBE_MODCTL_REG}, 921 { "SUNXI_DEBE_BACKCOLOR_REG", SUNXI_DEBE_BACKCOLOR_REG}, 922 { "SUNXI_DEBE_DISSIZE_REG", SUNXI_DEBE_DISSIZE_REG}, 923 { "SUNXI_DEBE_LAYSIZE_REG", SUNXI_DEBE_LAYSIZE_REG}, 924 { "SUNXI_DEBE_LAYCOOR_REG", SUNXI_DEBE_LAYCOOR_REG}, 925 { "SUNXI_DEBE_LAYLINEWIDTH_REG", SUNXI_DEBE_LAYLINEWIDTH_REG}, 926 { "SUNXI_DEBE_LAYFB_L32ADD_REG", SUNXI_DEBE_LAYFB_L32ADD_REG}, 927 { "SUNXI_DEBE_LAYFB_H4ADD_REG", SUNXI_DEBE_LAYFB_H4ADD_REG}, 928 { "SUNXI_DEBE_REGBUFFCTL_REG", SUNXI_DEBE_REGBUFFCTL_REG}, 929 { "SUNXI_DEBE_CKMAX_REG", SUNXI_DEBE_CKMAX_REG}, 930 { "SUNXI_DEBE_CKMIN_REG", SUNXI_DEBE_CKMIN_REG}, 931 { "SUNXI_DEBE_CKCFG_REG", SUNXI_DEBE_CKCFG_REG}, 932 { "SUNXI_DEBE_ATTCTL0_REG", SUNXI_DEBE_ATTCTL0_REG}, 933 { "SUNXI_DEBE_ATTCTL1_REG", SUNXI_DEBE_ATTCTL1_REG}, 934 { "SUNXI_DEBE_HWCCTL_REG", SUNXI_DEBE_HWCCTL_REG}, 935 { "SUNXI_DEBE_HWCFBCTL_REG", SUNXI_DEBE_HWCFBCTL_REG}, 936 { "SUNXI_DEBE_WBCTL_REG", SUNXI_DEBE_WBCTL_REG}, 937 { "SUNXI_DEBE_WBADD_REG", SUNXI_DEBE_WBADD_REG}, 938 { "SUNXI_DEBE_WBLINEWIDTH_REG", SUNXI_DEBE_WBLINEWIDTH_REG}, 939 { "SUNXI_DEBE_IYUVCTL_REG", SUNXI_DEBE_IYUVCTL_REG}, 940 { "SUNXI_DEBE_IYUVADD_REG", SUNXI_DEBE_IYUVADD_REG}, 941 { "SUNXI_DEBE_IYUVLINEWIDTH_REG", SUNXI_DEBE_IYUVLINEWIDTH_REG}, 942 { "SUNXI_DEBE_YGCOEF_REG", SUNXI_DEBE_YGCOEF_REG}, 943 { "SUNXI_DEBE_YGCONS_REG", SUNXI_DEBE_YGCONS_REG}, 944 { "SUNXI_DEBE_URCOEF_REG", SUNXI_DEBE_URCOEF_REG}, 945 { "SUNXI_DEBE_URCONS_REG", SUNXI_DEBE_URCONS_REG}, 946 { "SUNXI_DEBE_VBCOEF_REG", SUNXI_DEBE_VBCOEF_REG}, 947 { "SUNXI_DEBE_VBCONS_REG", SUNXI_DEBE_VBCONS_REG}, 948 { "SUNXI_DEBE_OCCTL_REG", SUNXI_DEBE_OCCTL_REG}, 949 { "SUNXI_DEBE_OCRCOEF_REG", SUNXI_DEBE_OCRCOEF_REG}, 950 { "SUNXI_DEBE_OCRCONS_REG", SUNXI_DEBE_OCRCONS_REG}, 951 { "SUNXI_DEBE_OCGCOEF_REG", SUNXI_DEBE_OCGCOEF_REG}, 952 { "SUNXI_DEBE_OCGCONS_REG", SUNXI_DEBE_OCGCONS_REG}, 953 { "SUNXI_DEBE_OCBCOEF_REG", SUNXI_DEBE_OCBCOEF_REG}, 954 { "SUNXI_DEBE_OCBCONS_REG", SUNXI_DEBE_OCBCONS_REG}, 955 }; 956 struct sunxi_debe_softc *sc; 957 device_t dev; 958 959 dev = device_find_by_driver_unit("sunxidebe", u); 960 if (dev == NULL) 961 return; 962 sc = device_private(dev); 963 964 for (int i = 0; i < __arraycount(regs); i++) { 965 printf("%s: 0x%08x\n", regs[i].name, 966 DEBE_READ(sc, regs[i].reg)); 967 } 968 } 969 #endif 970