1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Red Hat 4 * 5 * based in parts on udlfb.c: 6 * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> 7 * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> 8 * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> 9 */ 10 11 #include <linux/bitfield.h> 12 13 #include <drm/drm_atomic.h> 14 #include <drm/drm_atomic_helper.h> 15 #include <drm/drm_crtc_helper.h> 16 #include <drm/drm_damage_helper.h> 17 #include <drm/drm_drv.h> 18 #include <drm/drm_edid.h> 19 #include <drm/drm_fourcc.h> 20 #include <drm/drm_gem_atomic_helper.h> 21 #include <drm/drm_gem_framebuffer_helper.h> 22 #include <drm/drm_gem_shmem_helper.h> 23 #include <drm/drm_modeset_helper_vtables.h> 24 #include <drm/drm_plane_helper.h> 25 #include <drm/drm_probe_helper.h> 26 #include <drm/drm_vblank.h> 27 28 #include "udl_drv.h" 29 #include "udl_proto.h" 30 31 /* 32 * All DisplayLink bulk operations start with 0xaf (UDL_MSG_BULK), followed by 33 * a specific command code. All operations are written to a command buffer, which 34 * the driver sends to the device. 35 */ 36 static char *udl_set_register(char *buf, u8 reg, u8 val) 37 { 38 *buf++ = UDL_MSG_BULK; 39 *buf++ = UDL_CMD_WRITEREG; 40 *buf++ = reg; 41 *buf++ = val; 42 43 return buf; 44 } 45 46 static char *udl_vidreg_lock(char *buf) 47 { 48 return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_LOCK); 49 } 50 51 static char *udl_vidreg_unlock(char *buf) 52 { 53 return udl_set_register(buf, UDL_REG_VIDREG, UDL_VIDREG_UNLOCK); 54 } 55 56 static char *udl_set_blank_mode(char *buf, u8 mode) 57 { 58 return udl_set_register(buf, UDL_REG_BLANKMODE, mode); 59 } 60 61 static char *udl_set_color_depth(char *buf, u8 selection) 62 { 63 return udl_set_register(buf, UDL_REG_COLORDEPTH, selection); 64 } 65 66 static char *udl_set_base16bpp(char *buf, u32 base) 67 { 68 /* the base pointer is 24 bits wide, 0x20 is hi byte. */ 69 u8 reg20 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); 70 u8 reg21 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); 71 u8 reg22 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); 72 73 buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR2, reg20); 74 buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR1, reg21); 75 buf = udl_set_register(buf, UDL_REG_BASE16BPP_ADDR0, reg22); 76 77 return buf; 78 } 79 80 /* 81 * DisplayLink HW has separate 16bpp and 8bpp framebuffers. 82 * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer 83 */ 84 static char *udl_set_base8bpp(char *buf, u32 base) 85 { 86 /* the base pointer is 24 bits wide, 0x26 is hi byte. */ 87 u8 reg26 = FIELD_GET(UDL_BASE_ADDR2_MASK, base); 88 u8 reg27 = FIELD_GET(UDL_BASE_ADDR1_MASK, base); 89 u8 reg28 = FIELD_GET(UDL_BASE_ADDR0_MASK, base); 90 91 buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR2, reg26); 92 buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR1, reg27); 93 buf = udl_set_register(buf, UDL_REG_BASE8BPP_ADDR0, reg28); 94 95 return buf; 96 } 97 98 static char *udl_set_register_16(char *wrptr, u8 reg, u16 value) 99 { 100 wrptr = udl_set_register(wrptr, reg, value >> 8); 101 return udl_set_register(wrptr, reg+1, value); 102 } 103 104 /* 105 * This is kind of weird because the controller takes some 106 * register values in a different byte order than other registers. 107 */ 108 static char *udl_set_register_16be(char *wrptr, u8 reg, u16 value) 109 { 110 wrptr = udl_set_register(wrptr, reg, value); 111 return udl_set_register(wrptr, reg+1, value >> 8); 112 } 113 114 /* 115 * LFSR is linear feedback shift register. The reason we have this is 116 * because the display controller needs to minimize the clock depth of 117 * various counters used in the display path. So this code reverses the 118 * provided value into the lfsr16 value by counting backwards to get 119 * the value that needs to be set in the hardware comparator to get the 120 * same actual count. This makes sense once you read above a couple of 121 * times and think about it from a hardware perspective. 122 */ 123 static u16 udl_lfsr16(u16 actual_count) 124 { 125 u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */ 126 127 while (actual_count--) { 128 lv = ((lv << 1) | 129 (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1)) 130 & 0xFFFF; 131 } 132 133 return (u16) lv; 134 } 135 136 /* 137 * This does LFSR conversion on the value that is to be written. 138 * See LFSR explanation above for more detail. 139 */ 140 static char *udl_set_register_lfsr16(char *wrptr, u8 reg, u16 value) 141 { 142 return udl_set_register_16(wrptr, reg, udl_lfsr16(value)); 143 } 144 145 /* 146 * Takes a DRM display mode and converts it into the DisplayLink 147 * equivalent register commands. 148 */ 149 static char *udl_set_display_mode(char *buf, struct drm_display_mode *mode) 150 { 151 u16 reg01 = mode->crtc_htotal - mode->crtc_hsync_start; 152 u16 reg03 = reg01 + mode->crtc_hdisplay; 153 u16 reg05 = mode->crtc_vtotal - mode->crtc_vsync_start; 154 u16 reg07 = reg05 + mode->crtc_vdisplay; 155 u16 reg09 = mode->crtc_htotal - 1; 156 u16 reg0b = 1; /* libdlo hardcodes hsync start to 1 */ 157 u16 reg0d = mode->crtc_hsync_end - mode->crtc_hsync_start + 1; 158 u16 reg0f = mode->hdisplay; 159 u16 reg11 = mode->crtc_vtotal; 160 u16 reg13 = 0; /* libdlo hardcodes vsync start to 0 */ 161 u16 reg15 = mode->crtc_vsync_end - mode->crtc_vsync_start; 162 u16 reg17 = mode->crtc_vdisplay; 163 u16 reg1b = mode->clock / 5; 164 165 buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYSTART, reg01); 166 buf = udl_set_register_lfsr16(buf, UDL_REG_XDISPLAYEND, reg03); 167 buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYSTART, reg05); 168 buf = udl_set_register_lfsr16(buf, UDL_REG_YDISPLAYEND, reg07); 169 buf = udl_set_register_lfsr16(buf, UDL_REG_XENDCOUNT, reg09); 170 buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCSTART, reg0b); 171 buf = udl_set_register_lfsr16(buf, UDL_REG_HSYNCEND, reg0d); 172 buf = udl_set_register_16(buf, UDL_REG_HPIXELS, reg0f); 173 buf = udl_set_register_lfsr16(buf, UDL_REG_YENDCOUNT, reg11); 174 buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCSTART, reg13); 175 buf = udl_set_register_lfsr16(buf, UDL_REG_VSYNCEND, reg15); 176 buf = udl_set_register_16(buf, UDL_REG_VPIXELS, reg17); 177 buf = udl_set_register_16be(buf, UDL_REG_PIXELCLOCK5KHZ, reg1b); 178 179 return buf; 180 } 181 182 static char *udl_dummy_render(char *wrptr) 183 { 184 *wrptr++ = UDL_MSG_BULK; 185 *wrptr++ = UDL_CMD_WRITECOPY16; 186 *wrptr++ = 0x00; /* from addr */ 187 *wrptr++ = 0x00; 188 *wrptr++ = 0x00; 189 *wrptr++ = 0x01; /* one pixel */ 190 *wrptr++ = 0x00; /* to address */ 191 *wrptr++ = 0x00; 192 *wrptr++ = 0x00; 193 return wrptr; 194 } 195 196 static long udl_log_cpp(unsigned int cpp) 197 { 198 if (WARN_ON(!is_power_of_2(cpp))) 199 return -EINVAL; 200 return __ffs(cpp); 201 } 202 203 static int udl_handle_damage(struct drm_framebuffer *fb, 204 const struct iosys_map *map, 205 const struct drm_rect *clip) 206 { 207 struct drm_device *dev = fb->dev; 208 void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */ 209 int i, ret; 210 char *cmd; 211 struct urb *urb; 212 int log_bpp; 213 214 ret = udl_log_cpp(fb->format->cpp[0]); 215 if (ret < 0) 216 return ret; 217 log_bpp = ret; 218 219 urb = udl_get_urb(dev); 220 if (!urb) 221 return -ENOMEM; 222 cmd = urb->transfer_buffer; 223 224 for (i = clip->y1; i < clip->y2; i++) { 225 const int line_offset = fb->pitches[0] * i; 226 const int byte_offset = line_offset + (clip->x1 << log_bpp); 227 const int dev_byte_offset = (fb->width * i + clip->x1) << log_bpp; 228 const int byte_width = drm_rect_width(clip) << log_bpp; 229 ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr, 230 &cmd, byte_offset, dev_byte_offset, 231 byte_width); 232 if (ret) 233 return ret; 234 } 235 236 if (cmd > (char *)urb->transfer_buffer) { 237 /* Send partial buffer remaining before exiting */ 238 int len; 239 if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length) 240 *cmd++ = UDL_MSG_BULK; 241 len = cmd - (char *)urb->transfer_buffer; 242 ret = udl_submit_urb(dev, urb, len); 243 } else { 244 udl_urb_completion(urb); 245 } 246 247 return 0; 248 } 249 250 /* 251 * Primary plane 252 */ 253 254 static const uint32_t udl_primary_plane_formats[] = { 255 DRM_FORMAT_RGB565, 256 DRM_FORMAT_XRGB8888, 257 }; 258 259 static const uint64_t udl_primary_plane_fmtmods[] = { 260 DRM_FORMAT_MOD_LINEAR, 261 DRM_FORMAT_MOD_INVALID 262 }; 263 264 static void udl_primary_plane_helper_atomic_update(struct drm_plane *plane, 265 struct drm_atomic_state *state) 266 { 267 struct drm_device *dev = plane->dev; 268 struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); 269 struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); 270 struct drm_framebuffer *fb = plane_state->fb; 271 struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 272 struct drm_atomic_helper_damage_iter iter; 273 struct drm_rect damage; 274 int ret, idx; 275 276 if (!fb) 277 return; /* no framebuffer; plane is disabled */ 278 279 ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); 280 if (ret) 281 return; 282 283 if (!drm_dev_enter(dev, &idx)) 284 goto out_drm_gem_fb_end_cpu_access; 285 286 drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); 287 drm_atomic_for_each_plane_damage(&iter, &damage) { 288 udl_handle_damage(fb, &shadow_plane_state->data[0], &damage); 289 } 290 291 drm_dev_exit(idx); 292 293 out_drm_gem_fb_end_cpu_access: 294 drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); 295 } 296 297 static const struct drm_plane_helper_funcs udl_primary_plane_helper_funcs = { 298 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, 299 .atomic_check = drm_plane_helper_atomic_check, 300 .atomic_update = udl_primary_plane_helper_atomic_update, 301 }; 302 303 static const struct drm_plane_funcs udl_primary_plane_funcs = { 304 .update_plane = drm_atomic_helper_update_plane, 305 .disable_plane = drm_atomic_helper_disable_plane, 306 .destroy = drm_plane_cleanup, 307 DRM_GEM_SHADOW_PLANE_FUNCS, 308 }; 309 310 /* 311 * CRTC 312 */ 313 314 static void udl_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state) 315 { 316 struct drm_device *dev = crtc->dev; 317 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 318 struct drm_display_mode *mode = &crtc_state->mode; 319 struct urb *urb; 320 char *buf; 321 int idx; 322 323 if (!drm_dev_enter(dev, &idx)) 324 return; 325 326 urb = udl_get_urb(dev); 327 if (!urb) 328 goto out; 329 330 buf = (char *)urb->transfer_buffer; 331 buf = udl_vidreg_lock(buf); 332 buf = udl_set_color_depth(buf, UDL_COLORDEPTH_16BPP); 333 /* set base for 16bpp segment to 0 */ 334 buf = udl_set_base16bpp(buf, 0); 335 /* set base for 8bpp segment to end of fb */ 336 buf = udl_set_base8bpp(buf, 2 * mode->vdisplay * mode->hdisplay); 337 buf = udl_set_display_mode(buf, mode); 338 buf = udl_set_blank_mode(buf, UDL_BLANKMODE_ON); 339 buf = udl_vidreg_unlock(buf); 340 buf = udl_dummy_render(buf); 341 342 udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); 343 344 out: 345 drm_dev_exit(idx); 346 } 347 348 static void udl_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) 349 { 350 struct drm_device *dev = crtc->dev; 351 struct urb *urb; 352 char *buf; 353 int idx; 354 355 if (!drm_dev_enter(dev, &idx)) 356 return; 357 358 urb = udl_get_urb(dev); 359 if (!urb) 360 goto out; 361 362 buf = (char *)urb->transfer_buffer; 363 buf = udl_vidreg_lock(buf); 364 buf = udl_set_blank_mode(buf, UDL_BLANKMODE_POWERDOWN); 365 buf = udl_vidreg_unlock(buf); 366 buf = udl_dummy_render(buf); 367 368 udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer); 369 370 out: 371 drm_dev_exit(idx); 372 } 373 374 static const struct drm_crtc_helper_funcs udl_crtc_helper_funcs = { 375 .atomic_check = drm_crtc_helper_atomic_check, 376 .atomic_enable = udl_crtc_helper_atomic_enable, 377 .atomic_disable = udl_crtc_helper_atomic_disable, 378 }; 379 380 static const struct drm_crtc_funcs udl_crtc_funcs = { 381 .reset = drm_atomic_helper_crtc_reset, 382 .destroy = drm_crtc_cleanup, 383 .set_config = drm_atomic_helper_set_config, 384 .page_flip = drm_atomic_helper_page_flip, 385 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 386 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 387 }; 388 389 /* 390 * Encoder 391 */ 392 393 static const struct drm_encoder_funcs udl_encoder_funcs = { 394 .destroy = drm_encoder_cleanup, 395 }; 396 397 /* 398 * Connector 399 */ 400 401 static int udl_connector_helper_get_modes(struct drm_connector *connector) 402 { 403 struct udl_connector *udl_connector = to_udl_connector(connector); 404 405 drm_connector_update_edid_property(connector, udl_connector->edid); 406 if (udl_connector->edid) 407 return drm_add_edid_modes(connector, udl_connector->edid); 408 409 return 0; 410 } 411 412 static const struct drm_connector_helper_funcs udl_connector_helper_funcs = { 413 .get_modes = udl_connector_helper_get_modes, 414 }; 415 416 static int udl_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len) 417 { 418 struct udl_device *udl = data; 419 struct drm_device *dev = &udl->drm; 420 struct usb_device *udev = udl_to_usb_device(udl); 421 u8 *read_buff; 422 int ret; 423 size_t i; 424 425 read_buff = kmalloc(2, GFP_KERNEL); 426 if (!read_buff) 427 return -ENOMEM; 428 429 for (i = 0; i < len; i++) { 430 int bval = (i + block * EDID_LENGTH) << 8; 431 432 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 433 0x02, (0x80 | (0x02 << 5)), bval, 434 0xA1, read_buff, 2, USB_CTRL_GET_TIMEOUT); 435 if (ret < 0) { 436 drm_err(dev, "Read EDID byte %zu failed err %x\n", i, ret); 437 goto err_kfree; 438 } else if (ret < 1) { 439 ret = -EIO; 440 drm_err(dev, "Read EDID byte %zu failed\n", i); 441 goto err_kfree; 442 } 443 444 buf[i] = read_buff[1]; 445 } 446 447 kfree(read_buff); 448 449 return 0; 450 451 err_kfree: 452 kfree(read_buff); 453 return ret; 454 } 455 456 static enum drm_connector_status udl_connector_detect(struct drm_connector *connector, bool force) 457 { 458 struct drm_device *dev = connector->dev; 459 struct udl_device *udl = to_udl(dev); 460 struct udl_connector *udl_connector = to_udl_connector(connector); 461 enum drm_connector_status status = connector_status_disconnected; 462 int idx; 463 464 /* cleanup previous EDID */ 465 kfree(udl_connector->edid); 466 udl_connector->edid = NULL; 467 468 if (!drm_dev_enter(dev, &idx)) 469 return connector_status_disconnected; 470 471 udl_connector->edid = drm_do_get_edid(connector, udl_get_edid_block, udl); 472 if (udl_connector->edid) 473 status = connector_status_connected; 474 475 drm_dev_exit(idx); 476 477 return status; 478 } 479 480 static void udl_connector_destroy(struct drm_connector *connector) 481 { 482 struct udl_connector *udl_connector = to_udl_connector(connector); 483 484 drm_connector_cleanup(connector); 485 kfree(udl_connector->edid); 486 kfree(udl_connector); 487 } 488 489 static const struct drm_connector_funcs udl_connector_funcs = { 490 .reset = drm_atomic_helper_connector_reset, 491 .detect = udl_connector_detect, 492 .fill_modes = drm_helper_probe_single_connector_modes, 493 .destroy = udl_connector_destroy, 494 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 495 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 496 }; 497 498 struct drm_connector *udl_connector_init(struct drm_device *dev) 499 { 500 struct udl_connector *udl_connector; 501 struct drm_connector *connector; 502 int ret; 503 504 udl_connector = kzalloc(sizeof(*udl_connector), GFP_KERNEL); 505 if (!udl_connector) 506 return ERR_PTR(-ENOMEM); 507 508 connector = &udl_connector->connector; 509 ret = drm_connector_init(dev, connector, &udl_connector_funcs, DRM_MODE_CONNECTOR_VGA); 510 if (ret) 511 goto err_kfree; 512 513 drm_connector_helper_add(connector, &udl_connector_helper_funcs); 514 515 connector->polled = DRM_CONNECTOR_POLL_CONNECT | 516 DRM_CONNECTOR_POLL_DISCONNECT; 517 518 return connector; 519 520 err_kfree: 521 kfree(udl_connector); 522 return ERR_PTR(ret); 523 } 524 525 /* 526 * Modesetting 527 */ 528 529 static enum drm_mode_status udl_mode_config_mode_valid(struct drm_device *dev, 530 const struct drm_display_mode *mode) 531 { 532 struct udl_device *udl = to_udl(dev); 533 534 if (udl->sku_pixel_limit) { 535 if (mode->vdisplay * mode->hdisplay > udl->sku_pixel_limit) 536 return MODE_MEM; 537 } 538 539 return MODE_OK; 540 } 541 542 static const struct drm_mode_config_funcs udl_mode_config_funcs = { 543 .fb_create = drm_gem_fb_create_with_dirty, 544 .mode_valid = udl_mode_config_mode_valid, 545 .atomic_check = drm_atomic_helper_check, 546 .atomic_commit = drm_atomic_helper_commit, 547 }; 548 549 int udl_modeset_init(struct drm_device *dev) 550 { 551 struct udl_device *udl = to_udl(dev); 552 struct drm_plane *primary_plane; 553 struct drm_crtc *crtc; 554 struct drm_encoder *encoder; 555 struct drm_connector *connector; 556 int ret; 557 558 ret = drmm_mode_config_init(dev); 559 if (ret) 560 return ret; 561 562 dev->mode_config.min_width = 640; 563 dev->mode_config.min_height = 480; 564 dev->mode_config.max_width = 2048; 565 dev->mode_config.max_height = 2048; 566 dev->mode_config.preferred_depth = 16; 567 dev->mode_config.funcs = &udl_mode_config_funcs; 568 569 primary_plane = &udl->primary_plane; 570 ret = drm_universal_plane_init(dev, primary_plane, 0, 571 &udl_primary_plane_funcs, 572 udl_primary_plane_formats, 573 ARRAY_SIZE(udl_primary_plane_formats), 574 udl_primary_plane_fmtmods, 575 DRM_PLANE_TYPE_PRIMARY, NULL); 576 if (ret) 577 return ret; 578 drm_plane_helper_add(primary_plane, &udl_primary_plane_helper_funcs); 579 drm_plane_enable_fb_damage_clips(primary_plane); 580 581 crtc = &udl->crtc; 582 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 583 &udl_crtc_funcs, NULL); 584 if (ret) 585 return ret; 586 drm_crtc_helper_add(crtc, &udl_crtc_helper_funcs); 587 588 encoder = &udl->encoder; 589 ret = drm_encoder_init(dev, encoder, &udl_encoder_funcs, DRM_MODE_ENCODER_DAC, NULL); 590 if (ret) 591 return ret; 592 encoder->possible_crtcs = drm_crtc_mask(crtc); 593 594 connector = udl_connector_init(dev); 595 if (IS_ERR(connector)) 596 return PTR_ERR(connector); 597 ret = drm_connector_attach_encoder(connector, encoder); 598 if (ret) 599 return ret; 600 601 drm_mode_config_reset(dev); 602 603 return 0; 604 } 605