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