1 /* $NetBSD: rk_vop.c,v 1.6 2020/01/05 12:14:35 mrg 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: rk_vop.c,v 1.6 2020/01/05 12:14:35 mrg 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 #include <sys/sysctl.h> 40 41 #include <drm/drmP.h> 42 #include <drm/drm_crtc.h> 43 #include <drm/drm_crtc_helper.h> 44 #include <drm/drm_plane_helper.h> 45 46 #include <dev/fdt/fdtvar.h> 47 #include <dev/fdt/fdt_port.h> 48 49 #include <arm/rockchip/rk_drm.h> 50 51 #define VOP_REG_CFG_DONE 0x0000 52 #define REG_LOAD_EN __BIT(0) 53 #define VOP_SYS_CTRL 0x0008 54 #define VOP_STANDBY_EN __BIT(22) 55 #define MIPI_OUT_EN __BIT(15) 56 #define EDP_OUT_EN __BIT(14) 57 #define HDMI_OUT_EN __BIT(13) 58 #define RGB_OUT_EN __BIT(12) 59 #define VOP_DSP_CTRL0 0x0010 60 #define DSP_OUT_MODE __BITS(3,0) 61 #define DSP_OUT_MODE_RGB888 0 62 #define DSP_OUT_MODE_RGBaaa 15 63 #define VOP_DSP_CTRL1 0x0014 64 #define VOP_WIN0_CTRL 0x0030 65 #define WIN0_LB_MODE __BITS(7,5) 66 #define WIN0_LB_MODE_RGB_3840X2 2 67 #define WIN0_LB_MODE_RGB_2560X4 3 68 #define WIN0_LB_MODE_RGB_1920X5 4 69 #define WIN0_LB_MODE_RGB_1280X8 5 70 #define WIN0_DATA_FMT __BITS(3,1) 71 #define WIN0_DATA_FMT_ARGB888 0 72 #define WIN0_EN __BIT(0) 73 #define VOP_WIN0_COLOR_KEY 0x0038 74 #define VOP_WIN0_VIR 0x003c 75 #define WIN0_VIR_STRIDE __BITS(13,0) 76 #define VOP_WIN0_YRGB_MST 0x0040 77 #define VOP_WIN0_ACT_INFO 0x0048 78 #define WIN0_ACT_HEIGHT __BITS(28,16) 79 #define WIN0_ACT_WIDTH __BITS(12,0) 80 #define VOP_WIN0_DSP_INFO 0x004c 81 #define WIN0_DSP_HEIGHT __BITS(27,16) 82 #define WIN0_DSP_WIDTH __BITS(11,0) 83 #define VOP_WIN0_DSP_ST 0x0050 84 #define WIN0_DSP_YST __BITS(28,16) 85 #define WIN0_DSP_XST __BITS(12,0) 86 #define VOP_POST_DSP_HACT_INFO 0x0170 87 #define DSP_HACT_ST_POST __BITS(28,16) 88 #define DSP_HACT_END_POST __BITS(12,0) 89 #define VOP_POST_DSP_VACT_INFO 0x0174 90 #define DSP_VACT_ST_POST __BITS(28,16) 91 #define DSP_VACT_END_POST __BITS(12,0) 92 #define VOP_DSP_HTOTAL_HS_END 0x0188 93 #define DSP_HS_END __BITS(28,16) 94 #define DSP_HTOTAL __BITS(12,0) 95 #define VOP_DSP_HACT_ST_END 0x018c 96 #define DSP_HACT_ST __BITS(28,16) 97 #define DSP_HACT_END __BITS(12,0) 98 #define VOP_DSP_VTOTAL_VS_END 0x0190 99 #define DSP_VS_END __BITS(28,16) 100 #define DSP_VTOTAL __BITS(12,0) 101 #define VOP_DSP_VACT_ST_END 0x0194 102 #define DSP_VACT_ST __BITS(28,16) 103 #define DSP_VACT_END __BITS(12,0) 104 105 /* 106 * Polarity fields are in different locations depending on SoC and output type, 107 * but always in the same order. 108 */ 109 #define DSP_DCLK_POL __BIT(3) 110 #define DSP_DEN_POL __BIT(2) 111 #define DSP_VSYNC_POL __BIT(1) 112 #define DSP_HSYNC_POL __BIT(0) 113 114 enum vop_ep_type { 115 VOP_EP_MIPI, 116 VOP_EP_EDP, 117 VOP_EP_HDMI, 118 VOP_EP_MIPI1, 119 VOP_EP_DP, 120 VOP_NEP 121 }; 122 123 struct rk_vop_softc; 124 struct rk_vop_config; 125 126 struct rk_vop_crtc { 127 struct drm_crtc base; 128 struct rk_vop_softc *sc; 129 }; 130 131 struct rk_vop_softc { 132 device_t sc_dev; 133 bus_space_tag_t sc_bst; 134 bus_space_handle_t sc_bsh; 135 int sc_phandle; 136 137 struct clk *sc_dclk; 138 139 struct rk_vop_crtc sc_crtc; 140 141 struct fdt_device_ports sc_ports; 142 143 struct rk_vop_config *sc_conf; 144 }; 145 146 #define to_rk_vop_crtc(x) container_of(x, struct rk_vop_crtc, base) 147 148 #define RD4(sc, reg) \ 149 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 150 #define WR4(sc, reg, val) \ 151 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 152 153 struct rk_vop_config { 154 const char *descr; 155 u_int out_mode; 156 void (*init)(struct rk_vop_softc *); 157 void (*set_polarity)(struct rk_vop_softc *, 158 enum vop_ep_type, uint32_t); 159 }; 160 161 #define RK3399_VOP_MIPI_POL __BITS(31,28) 162 #define RK3399_VOP_EDP_POL __BITS(27,24) 163 #define RK3399_VOP_HDMI_POL __BITS(23,20) 164 #define RK3399_VOP_DP_POL __BITS(19,16) 165 166 #define RK3399_VOP_SYS_CTRL_ENABLE __BIT(11) 167 168 static void 169 rk3399_vop_set_polarity(struct rk_vop_softc *sc, enum vop_ep_type ep_type, uint32_t pol) 170 { 171 uint32_t mask, val; 172 173 switch (ep_type) { 174 case VOP_EP_MIPI: 175 case VOP_EP_MIPI1: 176 mask = RK3399_VOP_MIPI_POL; 177 break; 178 case VOP_EP_EDP: 179 mask = RK3399_VOP_EDP_POL; 180 break; 181 case VOP_EP_HDMI: 182 mask = RK3399_VOP_HDMI_POL; 183 break; 184 case VOP_EP_DP: 185 mask = RK3399_VOP_DP_POL; 186 break; 187 default: 188 return; 189 } 190 191 val = RD4(sc, VOP_DSP_CTRL1); 192 val &= ~mask; 193 val |= __SHIFTIN(pol, mask); 194 WR4(sc, VOP_DSP_CTRL1, val); 195 } 196 197 static void 198 rk3399_vop_init(struct rk_vop_softc *sc) 199 { 200 uint32_t val; 201 202 val = RD4(sc, VOP_SYS_CTRL); 203 val |= RK3399_VOP_SYS_CTRL_ENABLE; 204 WR4(sc, VOP_SYS_CTRL, val); 205 } 206 207 static const struct rk_vop_config rk3399_vop_lit_config = { 208 .descr = "RK3399 VOPL", 209 .out_mode = DSP_OUT_MODE_RGB888, 210 .init = rk3399_vop_init, 211 .set_polarity = rk3399_vop_set_polarity, 212 }; 213 214 static const struct rk_vop_config rk3399_vop_big_config = { 215 .descr = "RK3399 VOPB", 216 .out_mode = DSP_OUT_MODE_RGBaaa, 217 .init = rk3399_vop_init, 218 .set_polarity = rk3399_vop_set_polarity, 219 }; 220 221 static const struct of_compat_data compat_data[] = { 222 { "rockchip,rk3399-vop-big", (uintptr_t)&rk3399_vop_big_config }, 223 { "rockchip,rk3399-vop-lit", (uintptr_t)&rk3399_vop_lit_config }, 224 { NULL } 225 }; 226 227 static int 228 rk_vop_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb, 229 int x, int y, int atomic) 230 { 231 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 232 struct rk_vop_softc * const sc = mixer_crtc->sc; 233 struct rk_drm_framebuffer *sfb = atomic? 234 to_rk_drm_framebuffer(fb) : 235 to_rk_drm_framebuffer(crtc->primary->fb); 236 237 uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr; 238 239 paddr += y * sfb->base.pitches[0]; 240 paddr += x * drm_format_plane_cpp(sfb->base.pixel_format, 0); 241 242 KASSERT((paddr & ~0xffffffff) == 0); 243 244 const uint32_t vir = __SHIFTIN(sfb->base.pitches[0] / 4, 245 WIN0_VIR_STRIDE); 246 WR4(sc, VOP_WIN0_VIR, vir); 247 248 /* Framebuffer start address */ 249 WR4(sc, VOP_WIN0_YRGB_MST, (uint32_t)paddr); 250 251 return 0; 252 } 253 254 static void 255 rk_vop_destroy(struct drm_crtc *crtc) 256 { 257 drm_crtc_cleanup(crtc); 258 } 259 260 static const struct drm_crtc_funcs rk_vop_crtc_funcs = { 261 .set_config = drm_crtc_helper_set_config, 262 .destroy = rk_vop_destroy, 263 }; 264 265 static void 266 rk_vop_dpms(struct drm_crtc *crtc, int mode) 267 { 268 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 269 struct rk_vop_softc * const sc = mixer_crtc->sc; 270 uint32_t val; 271 272 val = RD4(sc, VOP_SYS_CTRL); 273 274 switch (mode) { 275 case DRM_MODE_DPMS_ON: 276 val &= ~VOP_STANDBY_EN; 277 break; 278 case DRM_MODE_DPMS_STANDBY: 279 case DRM_MODE_DPMS_SUSPEND: 280 case DRM_MODE_DPMS_OFF: 281 val |= VOP_STANDBY_EN; 282 break; 283 } 284 285 WR4(sc, VOP_SYS_CTRL, val); 286 287 /* Commit settings */ 288 WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); 289 } 290 291 static bool 292 rk_vop_mode_fixup(struct drm_crtc *crtc, 293 const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) 294 { 295 return true; 296 } 297 298 static int 299 rk_vop_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 300 struct drm_display_mode *adjusted_mode, int x, int y, 301 struct drm_framebuffer *old_fb) 302 { 303 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 304 struct rk_vop_softc * const sc = mixer_crtc->sc; 305 uint32_t val; 306 u_int lb_mode; 307 int error; 308 u_int pol; 309 int connector_type = 0; 310 struct drm_connector * connector; 311 312 const u_int hactive = adjusted_mode->hdisplay; 313 const u_int hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start; 314 const u_int hback_porch = adjusted_mode->htotal - adjusted_mode->hsync_end; 315 const u_int hfront_porch = adjusted_mode->hsync_start - adjusted_mode->hdisplay; 316 317 const u_int vactive = adjusted_mode->vdisplay; 318 const u_int vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start; 319 const u_int vback_porch = adjusted_mode->vtotal - adjusted_mode->vsync_end; 320 const u_int vfront_porch = adjusted_mode->vsync_start - adjusted_mode->vdisplay; 321 322 error = clk_set_rate(sc->sc_dclk, adjusted_mode->clock * 1000); 323 if (error != 0) 324 DRM_ERROR("couldn't set pixel clock: %d\n", error); 325 326 val = __SHIFTIN(hactive - 1, WIN0_ACT_WIDTH) | 327 __SHIFTIN(vactive - 1, WIN0_ACT_HEIGHT); 328 WR4(sc, VOP_WIN0_ACT_INFO, val); 329 330 val = __SHIFTIN(hactive - 1, WIN0_DSP_WIDTH) | 331 __SHIFTIN(vactive - 1, WIN0_DSP_HEIGHT); 332 WR4(sc, VOP_WIN0_DSP_INFO, val); 333 334 val = __SHIFTIN(hsync_len + hback_porch, WIN0_DSP_XST) | 335 __SHIFTIN(vsync_len + vback_porch, WIN0_DSP_YST); 336 WR4(sc, VOP_WIN0_DSP_ST, val); 337 338 WR4(sc, VOP_WIN0_COLOR_KEY, 0); 339 340 if (adjusted_mode->hdisplay > 2560) 341 lb_mode = WIN0_LB_MODE_RGB_3840X2; 342 else if (adjusted_mode->hdisplay > 1920) 343 lb_mode = WIN0_LB_MODE_RGB_2560X4; 344 else if (adjusted_mode->hdisplay > 1280) 345 lb_mode = WIN0_LB_MODE_RGB_1920X5; 346 else 347 lb_mode = WIN0_LB_MODE_RGB_1280X8; 348 349 val = __SHIFTIN(lb_mode, WIN0_LB_MODE) | 350 __SHIFTIN(WIN0_DATA_FMT_ARGB888, WIN0_DATA_FMT) | 351 WIN0_EN; 352 WR4(sc, VOP_WIN0_CTRL, val); 353 354 rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); 355 356 pol = DSP_DCLK_POL; 357 if ((adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) != 0) 358 pol |= DSP_HSYNC_POL; 359 if ((adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) != 0) 360 pol |= DSP_VSYNC_POL; 361 362 drm_for_each_connector(connector, crtc->dev) { 363 if ((connector->encoder) == NULL) 364 continue; 365 if (connector->encoder->crtc == crtc) { 366 connector_type = connector->connector_type; 367 break; 368 } 369 } 370 371 switch (connector_type) { 372 case DRM_MODE_CONNECTOR_HDMIA: 373 sc->sc_conf->set_polarity(sc, VOP_EP_HDMI, pol); 374 break; 375 case DRM_MODE_CONNECTOR_eDP: 376 sc->sc_conf->set_polarity(sc, VOP_EP_EDP, pol); 377 break; 378 } 379 380 val = RD4(sc, VOP_SYS_CTRL); 381 val &= ~VOP_STANDBY_EN; 382 val &= ~(MIPI_OUT_EN|EDP_OUT_EN|HDMI_OUT_EN|RGB_OUT_EN); 383 384 switch (connector_type) { 385 case DRM_MODE_CONNECTOR_HDMIA: 386 val |= HDMI_OUT_EN; 387 break; 388 case DRM_MODE_CONNECTOR_eDP: 389 val |= EDP_OUT_EN; 390 break; 391 } 392 WR4(sc, VOP_SYS_CTRL, val); 393 394 val = RD4(sc, VOP_DSP_CTRL0); 395 val &= ~DSP_OUT_MODE; 396 val |= __SHIFTIN(sc->sc_conf->out_mode, DSP_OUT_MODE); 397 WR4(sc, VOP_DSP_CTRL0, val); 398 399 val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST_POST) | 400 __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END_POST); 401 WR4(sc, VOP_POST_DSP_HACT_INFO, val); 402 403 val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST) | 404 __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END); 405 WR4(sc, VOP_DSP_HACT_ST_END, val); 406 407 val = __SHIFTIN(hsync_len, DSP_HTOTAL) | 408 __SHIFTIN(hsync_len + hback_porch + hactive + hfront_porch, DSP_HS_END); 409 WR4(sc, VOP_DSP_HTOTAL_HS_END, val); 410 411 val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST_POST) | 412 __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END_POST); 413 WR4(sc, VOP_POST_DSP_VACT_INFO, val); 414 415 val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST) | 416 __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END); 417 WR4(sc, VOP_DSP_VACT_ST_END, val); 418 419 val = __SHIFTIN(vsync_len, DSP_VTOTAL) | 420 __SHIFTIN(vsync_len + vback_porch + vactive + vfront_porch, DSP_VS_END); 421 WR4(sc, VOP_DSP_VTOTAL_VS_END, val); 422 423 return 0; 424 } 425 426 static int 427 rk_vop_mode_set_base(struct drm_crtc *crtc, int x, int y, 428 struct drm_framebuffer *old_fb) 429 { 430 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 431 struct rk_vop_softc * const sc = mixer_crtc->sc; 432 433 rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0); 434 435 /* Commit settings */ 436 WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); 437 438 return 0; 439 } 440 441 static int 442 rk_vop_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, 443 int x, int y, enum mode_set_atomic state) 444 { 445 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 446 struct rk_vop_softc * const sc = mixer_crtc->sc; 447 448 rk_vop_mode_do_set_base(crtc, fb, x, y, 1); 449 450 /* Commit settings */ 451 WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); 452 453 return 0; 454 } 455 456 static void 457 rk_vop_disable(struct drm_crtc *crtc) 458 { 459 } 460 461 static void 462 rk_vop_prepare(struct drm_crtc *crtc) 463 { 464 } 465 466 static void 467 rk_vop_commit(struct drm_crtc *crtc) 468 { 469 struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc); 470 struct rk_vop_softc * const sc = mixer_crtc->sc; 471 472 /* Commit settings */ 473 WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN); 474 } 475 476 static const struct drm_crtc_helper_funcs rk_vop_crtc_helper_funcs = { 477 .dpms = rk_vop_dpms, 478 .mode_fixup = rk_vop_mode_fixup, 479 .mode_set = rk_vop_mode_set, 480 .mode_set_base = rk_vop_mode_set_base, 481 .mode_set_base_atomic = rk_vop_mode_set_base_atomic, 482 .disable = rk_vop_disable, 483 .prepare = rk_vop_prepare, 484 .commit = rk_vop_commit, 485 }; 486 487 static int 488 rk_vop_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) 489 { 490 struct rk_vop_softc * const sc = device_private(dev); 491 struct drm_device *ddev; 492 493 if (!activate) 494 return EINVAL; 495 496 ddev = rk_drm_port_device(&sc->sc_ports); 497 if (ddev == NULL) { 498 DRM_ERROR("couldn't find DRM device\n"); 499 return ENXIO; 500 } 501 502 if (sc->sc_crtc.sc == NULL) { 503 sc->sc_crtc.sc = sc; 504 505 drm_crtc_init(ddev, &sc->sc_crtc.base, &rk_vop_crtc_funcs); 506 drm_crtc_helper_add(&sc->sc_crtc.base, &rk_vop_crtc_helper_funcs); 507 508 aprint_debug_dev(dev, "using CRTC %d for %s\n", 509 drm_crtc_index(&sc->sc_crtc.base), sc->sc_conf->descr); 510 } 511 512 const u_int ep_index = fdt_endpoint_index(ep); 513 if (ep_index >= VOP_NEP) { 514 DRM_ERROR("endpoint index %d out of range\n", ep_index); 515 return ENXIO; 516 } 517 518 return fdt_endpoint_activate(ep, activate); 519 } 520 521 static void * 522 rk_vop_ep_get_data(device_t dev, struct fdt_endpoint *ep) 523 { 524 struct rk_vop_softc * const sc = device_private(dev); 525 526 return &sc->sc_crtc.base; 527 } 528 529 static int 530 rk_vop_match(device_t parent, cfdata_t cf, void *aux) 531 { 532 struct fdt_attach_args * const faa = aux; 533 534 return of_match_compat_data(faa->faa_phandle, compat_data); 535 } 536 537 static void 538 rk_vop_attach(device_t parent, device_t self, void *aux) 539 { 540 struct rk_vop_softc * const sc = device_private(self); 541 struct fdt_attach_args * const faa = aux; 542 const int phandle = faa->faa_phandle; 543 const char * const reset_names[] = { "axi", "ahb", "dclk" }; 544 const char * const clock_names[] = { "aclk_vop", "hclk_vop" }; 545 struct fdtbus_reset *rst; 546 bus_addr_t addr; 547 bus_size_t size; 548 u_int n; 549 550 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 551 aprint_error(": couldn't get registers\n"); 552 return; 553 } 554 555 fdtbus_clock_assign(phandle); 556 557 for (n = 0; n < __arraycount(reset_names); n++) { 558 rst = fdtbus_reset_get(phandle, reset_names[n]); 559 if (rst == NULL || fdtbus_reset_deassert(rst) != 0) { 560 aprint_error(": couldn't de-assert reset %s\n", reset_names[n]); 561 return; 562 } 563 } 564 for (n = 0; n < __arraycount(clock_names); n++) { 565 if (fdtbus_clock_enable(phandle, clock_names[n], true) != 0) { 566 aprint_error(": couldn't enable clock %s\n", clock_names[n]); 567 return; 568 } 569 } 570 sc->sc_dclk = fdtbus_clock_get(phandle, "dclk_vop"); 571 if (sc->sc_dclk == NULL || clk_enable(sc->sc_dclk) != 0) { 572 aprint_error(": couldn't enable clock %s\n", "dclk_vop"); 573 return; 574 } 575 576 sc->sc_dev = self; 577 sc->sc_bst = faa->faa_bst; 578 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 579 aprint_error(": couldn't map registers\n"); 580 return; 581 } 582 sc->sc_phandle = faa->faa_phandle; 583 sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data; 584 585 aprint_naive("\n"); 586 aprint_normal(": %s\n", sc->sc_conf->descr); 587 588 if (sc->sc_conf->init != NULL) 589 sc->sc_conf->init(sc); 590 591 sc->sc_ports.dp_ep_activate = rk_vop_ep_activate; 592 sc->sc_ports.dp_ep_get_data = rk_vop_ep_get_data; 593 fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_CRTC); 594 595 const int port_phandle = of_find_firstchild_byname(phandle, "port"); 596 if (port_phandle > 0) 597 rk_drm_register_port(port_phandle, &sc->sc_ports); 598 } 599 600 CFATTACH_DECL_NEW(rk_vop, sizeof(struct rk_vop_softc), 601 rk_vop_match, rk_vop_attach, NULL, NULL); 602