1 /* $NetBSD: ti_lcdc.c,v 1.14 2022/09/25 07:50:32 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 Jared D. McNeill <jmcneill (at) invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: ti_lcdc.c,v 1.14 2022/09/25 07:50:32 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/intr.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/conf.h> 39 40 #include <uvm/uvm_extern.h> 41 #include <uvm/uvm_object.h> 42 #include <uvm/uvm_device.h> 43 44 #include <drm/drm_crtc.h> 45 #include <drm/drm_crtc_helper.h> 46 #include <drm/drm_drv.h> 47 #include <drm/drm_fb_helper.h> 48 #include <drm/drm_file.h> 49 #include <drm/drm_fourcc.h> 50 #include <drm/drm_plane_helper.h> 51 52 #include <dev/fdt/fdtvar.h> 53 #include <dev/fdt/fdt_port.h> 54 55 #include <arm/ti/ti_prcm.h> 56 #include <arm/ti/ti_lcdc.h> 57 #include <arm/ti/ti_lcdcreg.h> 58 59 static const struct device_compatible_entry compat_data[] = { 60 { .compat = "ti,am33xx-tilcdc" }, 61 DEVICE_COMPAT_EOL 62 }; 63 64 enum { 65 TILCDC_PORT_OUTPUT = 0, 66 }; 67 68 static int tilcdc_match(device_t, cfdata_t, void *); 69 static void tilcdc_attach(device_t, device_t, void *); 70 71 static int tilcdc_load(struct drm_device *, unsigned long); 72 static void tilcdc_unload(struct drm_device *); 73 74 static void tilcdc_drm_task_work(struct work *, void *); 75 76 static struct drm_driver tilcdc_driver = { 77 .driver_features = DRIVER_MODESET | DRIVER_GEM, 78 .dev_priv_size = 0, 79 .load = tilcdc_load, 80 .unload = tilcdc_unload, 81 82 .gem_free_object = drm_gem_cma_free_object, 83 .mmap_object = drm_gem_or_legacy_mmap_object, 84 .gem_uvm_ops = &drm_gem_cma_uvm_ops, 85 86 .dumb_create = drm_gem_cma_dumb_create, 87 88 .name = DRIVER_NAME, 89 .desc = DRIVER_DESC, 90 .date = DRIVER_DATE, 91 .major = DRIVER_MAJOR, 92 .minor = DRIVER_MINOR, 93 .patchlevel = DRIVER_PATCHLEVEL, 94 }; 95 96 CFATTACH_DECL_NEW(ti_lcdc, sizeof(struct tilcdc_softc), 97 tilcdc_match, tilcdc_attach, NULL, NULL); 98 99 static int 100 tilcdc_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, 101 int x, int y, int atomic) 102 { 103 struct tilcdc_crtc *mixer_crtc = to_tilcdc_crtc(crtc); 104 struct tilcdc_softc * const sc = mixer_crtc->sc; 105 struct tilcdc_framebuffer *sfb = atomic? 106 to_tilcdc_framebuffer(fb) : 107 to_tilcdc_framebuffer(crtc->primary->fb); 108 109 const uint32_t paddr = (uint32_t)sfb->obj->dmamap->dm_segs[0].ds_addr; 110 const u_int psize = sfb->obj->dmamap->dm_segs[0].ds_len; 111 112 /* Framebuffer start address */ 113 WR4(sc, LCD_LCDDMA_FB0_BASE, paddr); 114 WR4(sc, LCD_LCDDMA_FB0_CEILING, paddr + psize - 1); 115 116 return 0; 117 } 118 119 static void 120 tilcdc_destroy(struct drm_crtc *crtc) 121 { 122 drm_crtc_cleanup(crtc); 123 } 124 125 static const struct drm_crtc_funcs tilcdc_crtc_funcs = { 126 .set_config = drm_crtc_helper_set_config, 127 .destroy = tilcdc_destroy, 128 }; 129 130 static void 131 tilcdc_dpms(struct drm_crtc *crtc, int mode) 132 { 133 } 134 135 static bool 136 tilcdc_mode_fixup(struct drm_crtc *crtc, 137 const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 138 { 139 #if 0 140 adjusted_mode->hskew = mode->hsync_end - mode->hsync_start; 141 adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW; 142 143 adjusted_mode->flags &= ~(DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PHSYNC); 144 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 145 adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC; 146 else 147 adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC; 148 #endif 149 150 return true; 151 } 152 153 static int 154 tilcdc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 155 struct drm_display_mode *adjusted_mode, int x, int y, 156 struct drm_framebuffer *old_fb) 157 { 158 struct tilcdc_crtc *mixer_crtc = to_tilcdc_crtc(crtc); 159 struct tilcdc_softc * const sc = mixer_crtc->sc; 160 int clk_div, div, diff, best_diff; 161 uint32_t val; 162 163 const u_int hspw = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; 164 const u_int hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end; 165 const u_int hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay; 166 const u_int vspw = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; 167 const u_int vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end; 168 const u_int vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay; 169 170 const u_int rate = clk_get_rate(sc->sc_clk); 171 172 clk_div = 255; 173 best_diff = -1; 174 for (div = 2; div < 255; div++) { 175 const int pixel_clock = (rate / div) / 1000; 176 diff = abs(adjusted_mode->crtc_clock - pixel_clock); 177 if (best_diff == -1 || diff < best_diff) { 178 best_diff = diff; 179 clk_div = div; 180 } 181 } 182 if (clk_div == 255) { 183 device_printf(sc->sc_dev, "couldn't configure pixel clock (%u)\n", 184 adjusted_mode->crtc_clock); 185 return ERANGE; 186 } 187 188 val = CTRL_RASTER_MODE | 189 (clk_div << CTRL_DIV_SHIFT); 190 WR4(sc, LCD_CTRL, val); 191 192 val = RASTER_TIMING_0_HFP(hfp) | 193 RASTER_TIMING_0_HBP(hbp) | 194 RASTER_TIMING_0_HSW(hspw) | 195 RASTER_TIMING_0_PPL(adjusted_mode->hdisplay); 196 WR4(sc, LCD_RASTER_TIMING_0, val); 197 198 val = RASTER_TIMING_1_VFP(vfp) | 199 RASTER_TIMING_1_VBP(vbp) | 200 RASTER_TIMING_1_VSW(vspw) | 201 RASTER_TIMING_1_LPP(adjusted_mode->vdisplay); 202 WR4(sc, LCD_RASTER_TIMING_1, val); 203 204 val = RASTER_TIMING_2_HFP(hfp) | 205 RASTER_TIMING_2_HBP(hbp) | 206 RASTER_TIMING_2_HSW(hspw) | 207 RASTER_TIMING_2_LPP(adjusted_mode->vdisplay); 208 /* XXX TDA HDMI TX */ 209 val |= RASTER_TIMING_2_IPC; 210 val |= RASTER_TIMING_2_PHSVS; 211 val |= RASTER_TIMING_2_PHSVS_RISE; 212 val |= RASTER_TIMING_2_ACB(255); 213 val |= RASTER_TIMING_2_ACBI(0); 214 WR4(sc, LCD_RASTER_TIMING_2, val); 215 216 val = (4 << LCDDMA_CTRL_BURST_SIZE_SHIFT) | 217 (0 << LCDDMA_CTRL_TH_FIFO_RDY_SHIFT) | 218 LCDDMA_CTRL_FB0_ONLY; 219 WR4(sc, LCD_LCDDMA_CTRL, val); 220 221 /* XXX TDA HDMI TX */ 222 val = RASTER_CTRL_LCDTFT | 223 RASTER_CTRL_TFT24 | 224 RASTER_CTRL_TFT24_UNPACKED | 225 RASTER_CTRL_REQDLY(0x80) | 226 RASTER_CTRL_PALMODE_DATA_ONLY; 227 WR4(sc, LCD_RASTER_CTRL, val); 228 229 tilcdc_mode_do_set_base(crtc, old_fb, x, y, 0); 230 231 return 0; 232 } 233 234 static int 235 tilcdc_mode_set_base(struct drm_crtc *crtc, int x, int y, 236 struct drm_framebuffer *old_fb) 237 { 238 tilcdc_mode_do_set_base(crtc, old_fb, x, y, 0); 239 240 return 0; 241 } 242 243 static int 244 tilcdc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, 245 int x, int y, enum mode_set_atomic state) 246 { 247 tilcdc_mode_do_set_base(crtc, fb, x, y, 1); 248 249 return 0; 250 } 251 252 static void 253 tilcdc_disable(struct drm_crtc *crtc) 254 { 255 } 256 257 static void 258 tilcdc_prepare(struct drm_crtc *crtc) 259 { 260 } 261 262 static void 263 tilcdc_commit(struct drm_crtc *crtc) 264 { 265 struct tilcdc_crtc *mixer_crtc = to_tilcdc_crtc(crtc); 266 struct tilcdc_softc * const sc = mixer_crtc->sc; 267 uint32_t val; 268 269 WR4(sc, LCD_CLKC_ENABLE, CLKC_ENABLE_DMA | CLKC_ENABLE_CORE); 270 WR4(sc, LCD_CLKC_RESET, CLKC_RESET_MAIN); 271 delay(100); 272 WR4(sc, LCD_CLKC_RESET, 0); 273 274 val = RD4(sc, LCD_RASTER_CTRL); 275 WR4(sc, LCD_RASTER_CTRL, val | RASTER_CTRL_LCDEN); 276 } 277 278 static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = { 279 .dpms = tilcdc_dpms, 280 .mode_fixup = tilcdc_mode_fixup, 281 .mode_set = tilcdc_mode_set, 282 .mode_set_base = tilcdc_mode_set_base, 283 .mode_set_base_atomic = tilcdc_mode_set_base_atomic, 284 .disable = tilcdc_disable, 285 .prepare = tilcdc_prepare, 286 .commit = tilcdc_commit, 287 }; 288 289 static void 290 tilcdc_encoder_destroy(struct drm_encoder *encoder) 291 { 292 } 293 294 static const struct drm_encoder_funcs tilcdc_encoder_funcs = { 295 .destroy = tilcdc_encoder_destroy, 296 }; 297 298 static void 299 tilcdc_encoder_dpms(struct drm_encoder *encoder, int mode) 300 { 301 } 302 303 static bool 304 tilcdc_encoder_mode_fixup(struct drm_encoder *encoder, 305 const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 306 { 307 return true; 308 } 309 310 static void 311 tilcdc_encoder_mode_set(struct drm_encoder *encoder, 312 struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 313 { 314 } 315 316 static void 317 tilcdc_encoder_prepare(struct drm_encoder *encoder) 318 { 319 } 320 321 static void 322 tilcdc_encoder_commit(struct drm_encoder *encoder) 323 { 324 } 325 326 static const struct drm_encoder_helper_funcs tilcdc_encoder_helper_funcs = { 327 .dpms = tilcdc_encoder_dpms, 328 .mode_fixup = tilcdc_encoder_mode_fixup, 329 .prepare = tilcdc_encoder_prepare, 330 .commit = tilcdc_encoder_commit, 331 .mode_set = tilcdc_encoder_mode_set, 332 }; 333 334 static int 335 tilcdc_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) 336 { 337 struct tilcdc_softc * const sc = device_private(dev); 338 struct drm_device *ddev = sc->sc_ddev; 339 340 if (!activate) 341 return EINVAL; 342 343 sc->sc_crtc.sc = sc; 344 345 WR4(sc, LCD_SYSCONFIG, SYSCONFIG_STANDBY_SMART | SYSCONFIG_IDLE_SMART); 346 347 drm_crtc_init(ddev, &sc->sc_crtc.base, &tilcdc_crtc_funcs); 348 drm_crtc_helper_add(&sc->sc_crtc.base, &tilcdc_crtc_helper_funcs); 349 350 sc->sc_encoder.sc = sc; 351 sc->sc_encoder.base.possible_crtcs = 1 << drm_crtc_index(&sc->sc_crtc.base); 352 353 drm_encoder_init(ddev, &sc->sc_encoder.base, &tilcdc_encoder_funcs, 354 DRM_MODE_ENCODER_TMDS, NULL); 355 drm_encoder_helper_add(&sc->sc_encoder.base, 356 &tilcdc_encoder_helper_funcs); 357 358 return fdt_endpoint_activate(ep, activate); 359 } 360 361 static void * 362 tilcdc_ep_get_data(device_t dev, struct fdt_endpoint *ep) 363 { 364 struct tilcdc_softc * const sc = device_private(dev); 365 366 return &sc->sc_encoder.base; 367 } 368 369 static int 370 tilcdc_match(device_t parent, cfdata_t cf, void *aux) 371 { 372 struct fdt_attach_args * const faa = aux; 373 374 return of_compatible_match(faa->faa_phandle, compat_data); 375 } 376 377 static void 378 tilcdc_attach(device_t parent, device_t self, void *aux) 379 { 380 struct tilcdc_softc * const sc = device_private(self); 381 struct fdt_attach_args * const faa = aux; 382 const int phandle = faa->faa_phandle; 383 struct drm_driver * const driver = &tilcdc_driver; 384 prop_dictionary_t dict = device_properties(self); 385 bool is_disabled; 386 bus_addr_t addr; 387 bus_size_t size; 388 int error; 389 390 if (prop_dictionary_get_bool(dict, "disabled", &is_disabled) && is_disabled) { 391 aprint_normal(": TI LCDC (disabled)\n"); 392 return; 393 } 394 395 #ifdef WSDISPLAY_MULTICONS 396 const bool is_console = true; 397 prop_dictionary_set_bool(dict, "is_console", is_console); 398 #endif 399 400 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 401 aprint_error(": couldn't get registers\n"); 402 return; 403 } 404 405 sc->sc_dev = self; 406 sc->sc_phandle = faa->faa_phandle; 407 sc->sc_dmat = faa->faa_dmat; 408 sc->sc_bst = faa->faa_bst; 409 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 410 aprint_error(": couldn't map registers\n"); 411 return; 412 } 413 sc->sc_clk = ti_prcm_get_hwmod(phandle, 0); 414 if (sc->sc_clk == NULL || clk_enable(sc->sc_clk) != 0) { 415 aprint_error(": couldn't enable module\n"); 416 return; 417 } 418 419 aprint_naive("\n"); 420 aprint_normal(": TI LCDC\n"); 421 422 sc->sc_ports.dp_ep_activate = tilcdc_ep_activate; 423 sc->sc_ports.dp_ep_get_data = tilcdc_ep_get_data; 424 fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_ENCODER); 425 426 sc->sc_task_thread = NULL; 427 SIMPLEQ_INIT(&sc->sc_tasks); 428 if (workqueue_create(&sc->sc_task_wq, "tilcdcdrm", 429 &tilcdc_drm_task_work, NULL, PRI_NONE, IPL_NONE, WQ_MPSAFE)) { 430 aprint_error_dev(self, "unable to create workqueue\n"); 431 sc->sc_task_wq = NULL; 432 return; 433 } 434 435 sc->sc_ddev = drm_dev_alloc(driver, sc->sc_dev); 436 if (IS_ERR(sc->sc_ddev)) { 437 aprint_error_dev(self, "couldn't allocate DRM device\n"); 438 return; 439 } 440 sc->sc_ddev->dev_private = sc; 441 sc->sc_ddev->bst = sc->sc_bst; 442 sc->sc_ddev->bus_dmat = sc->sc_dmat; 443 sc->sc_ddev->dmat = sc->sc_ddev->bus_dmat; 444 sc->sc_ddev->dmat_subregion_p = false; 445 446 /* 447 * Cause any tasks issued synchronously during attach to be 448 * processed at the end of this function. 449 */ 450 sc->sc_task_thread = curlwp; 451 452 error = -drm_dev_register(sc->sc_ddev, 0); 453 if (error) { 454 drm_dev_put(sc->sc_ddev); 455 sc->sc_ddev = NULL; 456 aprint_error_dev(self, "couldn't register DRM device: %d\n", 457 error); 458 goto out; 459 } 460 sc->sc_dev_registered = true; 461 462 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 463 driver->name, driver->major, driver->minor, driver->patchlevel, 464 driver->date, sc->sc_ddev->primary->index); 465 466 /* 467 * Process asynchronous tasks queued synchronously during 468 * attach. This will be for display detection to attach a 469 * framebuffer, so we have the opportunity for a console device 470 * to attach before autoconf has completed, in time for init(8) 471 * to find that console without panicking. 472 */ 473 while (!SIMPLEQ_EMPTY(&sc->sc_tasks)) { 474 struct tilcdc_drm_task *const task = 475 SIMPLEQ_FIRST(&sc->sc_tasks); 476 477 SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, tdt_u.queue); 478 (*task->tdt_fn)(task); 479 } 480 481 out: /* Cause any subsequent tasks to be processed by the workqueue. */ 482 atomic_store_relaxed(&sc->sc_task_thread, NULL); 483 } 484 485 static int 486 tilcdc_fb_create_handle(struct drm_framebuffer *fb, 487 struct drm_file *file, unsigned int *handle) 488 { 489 struct tilcdc_framebuffer *sfb = to_tilcdc_framebuffer(fb); 490 491 return drm_gem_handle_create(file, &sfb->obj->base, handle); 492 } 493 494 static void 495 tilcdc_fb_destroy(struct drm_framebuffer *fb) 496 { 497 struct tilcdc_framebuffer *sfb = to_tilcdc_framebuffer(fb); 498 499 drm_framebuffer_cleanup(fb); 500 drm_gem_object_put_unlocked(&sfb->obj->base); 501 kmem_free(sfb, sizeof(*sfb)); 502 } 503 504 static const struct drm_framebuffer_funcs tilcdc_framebuffer_funcs = { 505 .create_handle = tilcdc_fb_create_handle, 506 .destroy = tilcdc_fb_destroy, 507 }; 508 509 static struct drm_framebuffer * 510 tilcdc_fb_create(struct drm_device *ddev, struct drm_file *file, 511 const struct drm_mode_fb_cmd2 *cmd) 512 { 513 struct tilcdc_framebuffer *fb; 514 struct drm_gem_object *gem_obj; 515 int error; 516 517 if (cmd->flags) 518 return NULL; 519 520 gem_obj = drm_gem_object_lookup(file, cmd->handles[0]); 521 if (gem_obj == NULL) 522 return NULL; 523 524 fb = kmem_zalloc(sizeof(*fb), KM_SLEEP); 525 drm_helper_mode_fill_fb_struct(ddev, &fb->base, cmd); 526 fb->obj = to_drm_gem_cma_obj(gem_obj); 527 528 error = drm_framebuffer_init(ddev, &fb->base, 529 &tilcdc_framebuffer_funcs); 530 if (error != 0) 531 goto dealloc; 532 533 return &fb->base; 534 535 dealloc: 536 drm_framebuffer_cleanup(&fb->base); 537 kmem_free(fb, sizeof(*fb)); 538 drm_gem_object_put_unlocked(gem_obj); 539 540 return NULL; 541 } 542 543 static struct drm_mode_config_funcs tilcdc_mode_config_funcs = { 544 .fb_create = tilcdc_fb_create, 545 }; 546 547 static int 548 tilcdc_fb_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) 549 { 550 struct tilcdc_softc * const sc = tilcdc_private(helper->dev); 551 struct drm_device *ddev = helper->dev; 552 struct tilcdc_framebuffer *sfb = to_tilcdc_framebuffer(helper->fb); 553 struct drm_framebuffer *fb = helper->fb; 554 struct tilcdcfb_attach_args tfa; 555 const char *br_wiring; 556 uint32_t pixel_format; 557 int error; 558 559 const u_int width = sizes->surface_width; 560 const u_int height = sizes->surface_height; 561 const u_int pitch = width * (32 / 8); 562 563 br_wiring = fdtbus_get_string(sc->sc_phandle, "blue-and-red-wiring"); 564 if (br_wiring && strcmp(br_wiring, "straight") == 0) { 565 pixel_format = DRM_FORMAT_XBGR8888; 566 } else { 567 pixel_format = DRM_FORMAT_XRGB8888; 568 } 569 570 const size_t size = roundup(height * pitch, PAGE_SIZE); 571 572 sfb->obj = drm_gem_cma_create(ddev, size); 573 if (sfb->obj == NULL) { 574 DRM_ERROR("failed to allocate memory for framebuffer\n"); 575 return -ENOMEM; 576 } 577 578 fb->pitches[0] = pitch; 579 fb->offsets[0] = 0; 580 fb->width = width; 581 fb->height = height; 582 fb->modifier = 0; 583 fb->flags = 0; 584 fb->format = drm_format_info(pixel_format); 585 fb->dev = ddev; 586 587 error = drm_framebuffer_init(ddev, fb, &tilcdc_framebuffer_funcs); 588 if (error != 0) { 589 DRM_ERROR("failed to initialize framebuffer\n"); 590 return error; 591 } 592 593 memset(&tfa, 0, sizeof(tfa)); 594 tfa.tfa_drm_dev = ddev; 595 tfa.tfa_fb_helper = helper; 596 tfa.tfa_fb_sizes = *sizes; 597 tfa.tfa_fb_bst = sc->sc_bst; 598 tfa.tfa_fb_dmat = sc->sc_dmat; 599 tfa.tfa_fb_linebytes = helper->fb->pitches[0]; 600 601 helper->fbdev = config_found(ddev->dev, &tfa, NULL, 602 CFARGS(.iattr = "tilcdcfbbus")); 603 if (helper->fbdev == NULL) { 604 DRM_ERROR("unable to attach framebuffer\n"); 605 return -ENXIO; 606 } 607 608 return 0; 609 } 610 611 static struct drm_fb_helper_funcs tilcdc_fb_helper_funcs = { 612 .fb_probe = tilcdc_fb_probe, 613 }; 614 615 static int 616 tilcdc_load(struct drm_device *ddev, unsigned long flags) 617 { 618 struct tilcdc_softc * const sc = tilcdc_private(ddev); 619 struct tilcdc_fbdev *fbdev; 620 struct fdt_endpoint *ep; 621 int error; 622 623 drm_mode_config_init(ddev); 624 ddev->mode_config.min_width = 0; 625 ddev->mode_config.min_height = 0; 626 ddev->mode_config.max_width = 2048; 627 ddev->mode_config.max_height = 2048; 628 ddev->mode_config.funcs = &tilcdc_mode_config_funcs; 629 630 ep = fdt_endpoint_get_from_index(&sc->sc_ports, TILCDC_PORT_OUTPUT, 0); 631 if (ep == NULL) { 632 aprint_error_dev(sc->sc_dev, "couldn't find endpoint\n"); 633 error = ENXIO; 634 goto drmerr; 635 } 636 error = fdt_endpoint_activate_direct(ep, true); 637 if (error != 0) { 638 aprint_error_dev(sc->sc_dev, "couldn't activate endpoint: %d\n", error); 639 error = ENXIO; 640 goto drmerr; 641 } 642 643 fbdev = kmem_zalloc(sizeof(*fbdev), KM_SLEEP); 644 645 drm_fb_helper_prepare(ddev, &fbdev->helper, &tilcdc_fb_helper_funcs); 646 647 error = drm_fb_helper_init(ddev, &fbdev->helper, 1); 648 if (error) 649 goto allocerr; 650 651 fbdev->helper.fb = kmem_zalloc(sizeof(struct tilcdc_framebuffer), 652 KM_SLEEP); 653 654 drm_fb_helper_single_add_all_connectors(&fbdev->helper); 655 656 drm_helper_disable_unused_functions(ddev); 657 658 drm_fb_helper_initial_config(&fbdev->helper, 32); 659 660 return 0; 661 662 allocerr: 663 kmem_free(fbdev, sizeof(*fbdev)); 664 drmerr: 665 drm_mode_config_cleanup(ddev); 666 667 return error; 668 } 669 670 static void 671 tilcdc_unload(struct drm_device *ddev) 672 { 673 674 drm_mode_config_cleanup(ddev); 675 } 676 677 static void 678 tilcdc_drm_task_work(struct work *work, void *cookie) 679 { 680 struct tilcdc_drm_task *task = container_of(work, 681 struct tilcdc_drm_task, tdt_u.work); 682 683 (*task->tdt_fn)(task); 684 } 685 686 void 687 tilcdc_task_init(struct tilcdc_drm_task *task, 688 void (*fn)(struct tilcdc_drm_task *)) 689 { 690 691 task->tdt_fn = fn; 692 } 693 694 void 695 tilcdc_task_schedule(device_t self, struct tilcdc_drm_task *task) 696 { 697 struct tilcdc_softc *sc = device_private(self); 698 699 if (atomic_load_relaxed(&sc->sc_task_thread) == curlwp) 700 SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, tdt_u.queue); 701 else 702 workqueue_enqueue(sc->sc_task_wq, &task->tdt_u.work, NULL); 703 } 704