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