1/* 2 * shmob_drm_crtc.c -- SH Mobile DRM CRTCs 3 * 4 * Copyright (C) 2012 Renesas Electronics Corporation 5 * 6 * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <linux/backlight.h> 15#include <linux/clk.h> 16 17#include <drm/drmP.h> 18#include <drm/drm_crtc.h> 19#include <drm/drm_crtc_helper.h> 20#include <drm/drm_fb_cma_helper.h> 21#include <drm/drm_gem_cma_helper.h> 22#include <drm/drm_plane_helper.h> 23 24#include <video/sh_mobile_meram.h> 25 26#include "shmob_drm_backlight.h" 27#include "shmob_drm_crtc.h" 28#include "shmob_drm_drv.h" 29#include "shmob_drm_kms.h" 30#include "shmob_drm_plane.h" 31#include "shmob_drm_regs.h" 32 33/* 34 * TODO: panel support 35 */ 36 37/* ----------------------------------------------------------------------------- 38 * Clock management 39 */ 40 41static int shmob_drm_clk_on(struct shmob_drm_device *sdev) 42{ 43 int ret; 44 45 if (sdev->clock) { 46 ret = clk_prepare_enable(sdev->clock); 47 if (ret < 0) 48 return ret; 49 } 50#if 0 51 if (sdev->meram_dev && sdev->meram_dev->pdev) 52 pm_runtime_get_sync(&sdev->meram_dev->pdev->dev); 53#endif 54 55 return 0; 56} 57 58static void shmob_drm_clk_off(struct shmob_drm_device *sdev) 59{ 60#if 0 61 if (sdev->meram_dev && sdev->meram_dev->pdev) 62 pm_runtime_put_sync(&sdev->meram_dev->pdev->dev); 63#endif 64 if (sdev->clock) 65 clk_disable_unprepare(sdev->clock); 66} 67 68/* ----------------------------------------------------------------------------- 69 * CRTC 70 */ 71 72static void shmob_drm_crtc_setup_geometry(struct shmob_drm_crtc *scrtc) 73{ 74 struct drm_crtc *crtc = &scrtc->crtc; 75 struct shmob_drm_device *sdev = crtc->dev->dev_private; 76 const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; 77 const struct drm_display_mode *mode = &crtc->mode; 78 u32 value; 79 80 value = sdev->ldmt1r 81 | ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : LDMT1R_VPOL) 82 | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : LDMT1R_HPOL) 83 | ((idata->flags & SHMOB_DRM_IFACE_FL_DWPOL) ? LDMT1R_DWPOL : 0) 84 | ((idata->flags & SHMOB_DRM_IFACE_FL_DIPOL) ? LDMT1R_DIPOL : 0) 85 | ((idata->flags & SHMOB_DRM_IFACE_FL_DAPOL) ? LDMT1R_DAPOL : 0) 86 | ((idata->flags & SHMOB_DRM_IFACE_FL_HSCNT) ? LDMT1R_HSCNT : 0) 87 | ((idata->flags & SHMOB_DRM_IFACE_FL_DWCNT) ? LDMT1R_DWCNT : 0); 88 lcdc_write(sdev, LDMT1R, value); 89 90 if (idata->interface >= SHMOB_DRM_IFACE_SYS8A && 91 idata->interface <= SHMOB_DRM_IFACE_SYS24) { 92 /* Setup SYS bus. */ 93 value = (idata->sys.cs_setup << LDMT2R_CSUP_SHIFT) 94 | (idata->sys.vsync_active_high ? LDMT2R_RSV : 0) 95 | (idata->sys.vsync_dir_input ? LDMT2R_VSEL : 0) 96 | (idata->sys.write_setup << LDMT2R_WCSC_SHIFT) 97 | (idata->sys.write_cycle << LDMT2R_WCEC_SHIFT) 98 | (idata->sys.write_strobe << LDMT2R_WCLW_SHIFT); 99 lcdc_write(sdev, LDMT2R, value); 100 101 value = (idata->sys.read_latch << LDMT3R_RDLC_SHIFT) 102 | (idata->sys.read_setup << LDMT3R_RCSC_SHIFT) 103 | (idata->sys.read_cycle << LDMT3R_RCEC_SHIFT) 104 | (idata->sys.read_strobe << LDMT3R_RCLW_SHIFT); 105 lcdc_write(sdev, LDMT3R, value); 106 } 107 108 value = ((mode->hdisplay / 8) << 16) /* HDCN */ 109 | (mode->htotal / 8); /* HTCN */ 110 lcdc_write(sdev, LDHCNR, value); 111 112 value = (((mode->hsync_end - mode->hsync_start) / 8) << 16) /* HSYNW */ 113 | (mode->hsync_start / 8); /* HSYNP */ 114 lcdc_write(sdev, LDHSYNR, value); 115 116 value = ((mode->hdisplay & 7) << 24) | ((mode->htotal & 7) << 16) 117 | (((mode->hsync_end - mode->hsync_start) & 7) << 8) 118 | (mode->hsync_start & 7); 119 lcdc_write(sdev, LDHAJR, value); 120 121 value = ((mode->vdisplay) << 16) /* VDLN */ 122 | mode->vtotal; /* VTLN */ 123 lcdc_write(sdev, LDVLNR, value); 124 125 value = ((mode->vsync_end - mode->vsync_start) << 16) /* VSYNW */ 126 | mode->vsync_start; /* VSYNP */ 127 lcdc_write(sdev, LDVSYNR, value); 128} 129 130static void shmob_drm_crtc_start_stop(struct shmob_drm_crtc *scrtc, bool start) 131{ 132 struct shmob_drm_device *sdev = scrtc->crtc.dev->dev_private; 133 u32 value; 134 135 value = lcdc_read(sdev, LDCNT2R); 136 if (start) 137 lcdc_write(sdev, LDCNT2R, value | LDCNT2R_DO); 138 else 139 lcdc_write(sdev, LDCNT2R, value & ~LDCNT2R_DO); 140 141 /* Wait until power is applied/stopped. */ 142 while (1) { 143 value = lcdc_read(sdev, LDPMR) & LDPMR_LPS; 144 if ((start && value) || (!start && !value)) 145 break; 146 147 cpu_relax(); 148 } 149 150 if (!start) { 151 /* Stop the dot clock. */ 152 lcdc_write(sdev, LDDCKSTPR, LDDCKSTPR_DCKSTP); 153 } 154} 155 156/* 157 * shmob_drm_crtc_start - Configure and start the LCDC 158 * @scrtc: the SH Mobile CRTC 159 * 160 * Configure and start the LCDC device. External devices (clocks, MERAM, panels, 161 * ...) are not touched by this function. 162 */ 163static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) 164{ 165 struct drm_crtc *crtc = &scrtc->crtc; 166 struct shmob_drm_device *sdev = crtc->dev->dev_private; 167 const struct shmob_drm_interface_data *idata = &sdev->pdata->iface; 168 const struct shmob_drm_format_info *format; 169 struct drm_device *dev = sdev->ddev; 170 struct drm_plane *plane; 171 u32 value; 172 int ret; 173 174 if (scrtc->started) 175 return; 176 177 format = shmob_drm_format_info(crtc->primary->fb->pixel_format); 178 if (WARN_ON(format == NULL)) 179 return; 180 181 /* Enable clocks before accessing the hardware. */ 182 ret = shmob_drm_clk_on(sdev); 183 if (ret < 0) 184 return; 185 186 /* Reset and enable the LCDC. */ 187 lcdc_write(sdev, LDCNT2R, lcdc_read(sdev, LDCNT2R) | LDCNT2R_BR); 188 lcdc_wait_bit(sdev, LDCNT2R, LDCNT2R_BR, 0); 189 lcdc_write(sdev, LDCNT2R, LDCNT2R_ME); 190 191 /* Stop the LCDC first and disable all interrupts. */ 192 shmob_drm_crtc_start_stop(scrtc, false); 193 lcdc_write(sdev, LDINTR, 0); 194 195 /* Configure power supply, dot clocks and start them. */ 196 lcdc_write(sdev, LDPMR, 0); 197 198 value = sdev->lddckr; 199 if (idata->clk_div) { 200 /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider 201 * denominator. 202 */ 203 lcdc_write(sdev, LDDCKPAT1R, 0); 204 lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1); 205 206 if (idata->clk_div == 1) 207 value |= LDDCKR_MOSEL; 208 else 209 value |= idata->clk_div; 210 } 211 212 lcdc_write(sdev, LDDCKR, value); 213 lcdc_write(sdev, LDDCKSTPR, 0); 214 lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0); 215 216 /* TODO: Setup SYS panel */ 217 218 /* Setup geometry, format, frame buffer memory and operation mode. */ 219 shmob_drm_crtc_setup_geometry(scrtc); 220 221 /* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */ 222 lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1); 223 lcdc_write(sdev, LDMLSR, scrtc->line_size); 224 lcdc_write(sdev, LDSA1R, scrtc->dma[0]); 225 if (format->yuv) 226 lcdc_write(sdev, LDSA2R, scrtc->dma[1]); 227 lcdc_write(sdev, LDSM1R, 0); 228 229 /* Word and long word swap. */ 230 switch (format->fourcc) { 231 case DRM_FORMAT_RGB565: 232 case DRM_FORMAT_NV21: 233 case DRM_FORMAT_NV61: 234 case DRM_FORMAT_NV42: 235 value = LDDDSR_LS | LDDDSR_WS; 236 break; 237 case DRM_FORMAT_RGB888: 238 case DRM_FORMAT_NV12: 239 case DRM_FORMAT_NV16: 240 case DRM_FORMAT_NV24: 241 value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; 242 break; 243 case DRM_FORMAT_ARGB8888: 244 default: 245 value = LDDDSR_LS; 246 break; 247 } 248 lcdc_write(sdev, LDDDSR, value); 249 250 /* Setup planes. */ 251 drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { 252 if (plane->crtc == crtc) 253 shmob_drm_plane_setup(plane); 254 } 255 256 /* Enable the display output. */ 257 lcdc_write(sdev, LDCNT1R, LDCNT1R_DE); 258 259 shmob_drm_crtc_start_stop(scrtc, true); 260 261 scrtc->started = true; 262} 263 264static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc) 265{ 266 struct drm_crtc *crtc = &scrtc->crtc; 267 struct shmob_drm_device *sdev = crtc->dev->dev_private; 268 269 if (!scrtc->started) 270 return; 271 272 /* Disable the MERAM cache. */ 273 if (scrtc->cache) { 274 sh_mobile_meram_cache_free(sdev->meram, scrtc->cache); 275 scrtc->cache = NULL; 276 } 277 278 /* Stop the LCDC. */ 279 shmob_drm_crtc_start_stop(scrtc, false); 280 281 /* Disable the display output. */ 282 lcdc_write(sdev, LDCNT1R, 0); 283 284 /* Stop clocks. */ 285 shmob_drm_clk_off(sdev); 286 287 scrtc->started = false; 288} 289 290void shmob_drm_crtc_suspend(struct shmob_drm_crtc *scrtc) 291{ 292 shmob_drm_crtc_stop(scrtc); 293} 294 295void shmob_drm_crtc_resume(struct shmob_drm_crtc *scrtc) 296{ 297 if (scrtc->dpms != DRM_MODE_DPMS_ON) 298 return; 299 300 shmob_drm_crtc_start(scrtc); 301} 302 303static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, 304 int x, int y) 305{ 306 struct drm_crtc *crtc = &scrtc->crtc; 307 struct drm_framebuffer *fb = crtc->primary->fb; 308 struct shmob_drm_device *sdev = crtc->dev->dev_private; 309 struct drm_gem_cma_object *gem; 310 unsigned int bpp; 311 312 bpp = scrtc->format->yuv ? 8 : scrtc->format->bpp; 313 gem = drm_fb_cma_get_gem_obj(fb, 0); 314 scrtc->dma[0] = gem->paddr + fb->offsets[0] 315 + y * fb->pitches[0] + x * bpp / 8; 316 317 if (scrtc->format->yuv) { 318 bpp = scrtc->format->bpp - 8; 319 gem = drm_fb_cma_get_gem_obj(fb, 1); 320 scrtc->dma[1] = gem->paddr + fb->offsets[1] 321 + y / (bpp == 4 ? 2 : 1) * fb->pitches[1] 322 + x * (bpp == 16 ? 2 : 1); 323 } 324 325 if (scrtc->cache) 326 sh_mobile_meram_cache_update(sdev->meram, scrtc->cache, 327 scrtc->dma[0], scrtc->dma[1], 328 &scrtc->dma[0], &scrtc->dma[1]); 329} 330 331static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc) 332{ 333 struct drm_crtc *crtc = &scrtc->crtc; 334 struct shmob_drm_device *sdev = crtc->dev->dev_private; 335 336 shmob_drm_crtc_compute_base(scrtc, crtc->x, crtc->y); 337 338 lcdc_write_mirror(sdev, LDSA1R, scrtc->dma[0]); 339 if (scrtc->format->yuv) 340 lcdc_write_mirror(sdev, LDSA2R, scrtc->dma[1]); 341 342 lcdc_write(sdev, LDRCNTR, lcdc_read(sdev, LDRCNTR) ^ LDRCNTR_MRS); 343} 344 345#define to_shmob_crtc(c) container_of(c, struct shmob_drm_crtc, crtc) 346 347static void shmob_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 348{ 349 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); 350 351 if (scrtc->dpms == mode) 352 return; 353 354 if (mode == DRM_MODE_DPMS_ON) 355 shmob_drm_crtc_start(scrtc); 356 else 357 shmob_drm_crtc_stop(scrtc); 358 359 scrtc->dpms = mode; 360} 361 362static bool shmob_drm_crtc_mode_fixup(struct drm_crtc *crtc, 363 const struct drm_display_mode *mode, 364 struct drm_display_mode *adjusted_mode) 365{ 366 return true; 367} 368 369static void shmob_drm_crtc_mode_prepare(struct drm_crtc *crtc) 370{ 371 shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 372} 373 374static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, 375 struct drm_display_mode *mode, 376 struct drm_display_mode *adjusted_mode, 377 int x, int y, 378 struct drm_framebuffer *old_fb) 379{ 380 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); 381 struct shmob_drm_device *sdev = crtc->dev->dev_private; 382 const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram; 383 const struct shmob_drm_format_info *format; 384 void *cache; 385 386 format = shmob_drm_format_info(crtc->primary->fb->pixel_format); 387 if (format == NULL) { 388 dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n", 389 crtc->primary->fb->pixel_format); 390 return -EINVAL; 391 } 392 393 scrtc->format = format; 394 scrtc->line_size = crtc->primary->fb->pitches[0]; 395 396 if (sdev->meram) { 397 /* Enable MERAM cache if configured. We need to de-init 398 * configured ICBs before we can re-initialize them. 399 */ 400 if (scrtc->cache) { 401 sh_mobile_meram_cache_free(sdev->meram, scrtc->cache); 402 scrtc->cache = NULL; 403 } 404 405 cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata, 406 crtc->primary->fb->pitches[0], 407 adjusted_mode->vdisplay, 408 format->meram, 409 &scrtc->line_size); 410 if (!IS_ERR(cache)) 411 scrtc->cache = cache; 412 } 413 414 shmob_drm_crtc_compute_base(scrtc, x, y); 415 416 return 0; 417} 418 419static void shmob_drm_crtc_mode_commit(struct drm_crtc *crtc) 420{ 421 shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 422} 423 424static int shmob_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 425 struct drm_framebuffer *old_fb) 426{ 427 shmob_drm_crtc_update_base(to_shmob_crtc(crtc)); 428 429 return 0; 430} 431 432static const struct drm_crtc_helper_funcs crtc_helper_funcs = { 433 .dpms = shmob_drm_crtc_dpms, 434 .mode_fixup = shmob_drm_crtc_mode_fixup, 435 .prepare = shmob_drm_crtc_mode_prepare, 436 .commit = shmob_drm_crtc_mode_commit, 437 .mode_set = shmob_drm_crtc_mode_set, 438 .mode_set_base = shmob_drm_crtc_mode_set_base, 439}; 440 441void shmob_drm_crtc_cancel_page_flip(struct shmob_drm_crtc *scrtc, 442 struct drm_file *file) 443{ 444 struct drm_pending_vblank_event *event; 445 struct drm_device *dev = scrtc->crtc.dev; 446 unsigned long flags; 447 448 /* Destroy the pending vertical blanking event associated with the 449 * pending page flip, if any, and disable vertical blanking interrupts. 450 */ 451 spin_lock_irqsave(&dev->event_lock, flags); 452 event = scrtc->event; 453 if (event && event->base.file_priv == file) { 454 scrtc->event = NULL; 455 event->base.destroy(&event->base); 456 drm_vblank_put(dev, 0); 457 } 458 spin_unlock_irqrestore(&dev->event_lock, flags); 459} 460 461void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc) 462{ 463 struct drm_pending_vblank_event *event; 464 struct drm_device *dev = scrtc->crtc.dev; 465 unsigned long flags; 466 467 spin_lock_irqsave(&dev->event_lock, flags); 468 event = scrtc->event; 469 scrtc->event = NULL; 470 if (event) { 471 drm_send_vblank_event(dev, 0, event); 472 drm_vblank_put(dev, 0); 473 } 474 spin_unlock_irqrestore(&dev->event_lock, flags); 475} 476 477static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, 478 struct drm_framebuffer *fb, 479 struct drm_pending_vblank_event *event, 480 uint32_t page_flip_flags) 481{ 482 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); 483 struct drm_device *dev = scrtc->crtc.dev; 484 unsigned long flags; 485 486 spin_lock_irqsave(&dev->event_lock, flags); 487 if (scrtc->event != NULL) { 488 spin_unlock_irqrestore(&dev->event_lock, flags); 489 return -EBUSY; 490 } 491 spin_unlock_irqrestore(&dev->event_lock, flags); 492 493 crtc->primary->fb = fb; 494 shmob_drm_crtc_update_base(scrtc); 495 496 if (event) { 497 event->pipe = 0; 498 drm_vblank_get(dev, 0); 499 spin_lock_irqsave(&dev->event_lock, flags); 500 scrtc->event = event; 501 spin_unlock_irqrestore(&dev->event_lock, flags); 502 } 503 504 return 0; 505} 506 507static const struct drm_crtc_funcs crtc_funcs = { 508 .destroy = drm_crtc_cleanup, 509 .set_config = drm_crtc_helper_set_config, 510 .page_flip = shmob_drm_crtc_page_flip, 511}; 512 513int shmob_drm_crtc_create(struct shmob_drm_device *sdev) 514{ 515 struct drm_crtc *crtc = &sdev->crtc.crtc; 516 int ret; 517 518 sdev->crtc.dpms = DRM_MODE_DPMS_OFF; 519 520 ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs); 521 if (ret < 0) 522 return ret; 523 524 drm_crtc_helper_add(crtc, &crtc_helper_funcs); 525 526 return 0; 527} 528 529/* ----------------------------------------------------------------------------- 530 * Encoder 531 */ 532 533#define to_shmob_encoder(e) \ 534 container_of(e, struct shmob_drm_encoder, encoder) 535 536static void shmob_drm_encoder_dpms(struct drm_encoder *encoder, int mode) 537{ 538 struct shmob_drm_encoder *senc = to_shmob_encoder(encoder); 539 struct shmob_drm_device *sdev = encoder->dev->dev_private; 540 struct shmob_drm_connector *scon = &sdev->connector; 541 542 if (senc->dpms == mode) 543 return; 544 545 shmob_drm_backlight_dpms(scon, mode); 546 547 senc->dpms = mode; 548} 549 550static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, 551 const struct drm_display_mode *mode, 552 struct drm_display_mode *adjusted_mode) 553{ 554 struct drm_device *dev = encoder->dev; 555 struct shmob_drm_device *sdev = dev->dev_private; 556 struct drm_connector *connector = &sdev->connector.connector; 557 const struct drm_display_mode *panel_mode; 558 559 if (list_empty(&connector->modes)) { 560 dev_dbg(dev->dev, "mode_fixup: empty modes list\n"); 561 return false; 562 } 563 564 /* The flat panel mode is fixed, just copy it to the adjusted mode. */ 565 panel_mode = list_first_entry(&connector->modes, 566 struct drm_display_mode, head); 567 drm_mode_copy(adjusted_mode, panel_mode); 568 569 return true; 570} 571 572static void shmob_drm_encoder_mode_prepare(struct drm_encoder *encoder) 573{ 574 /* No-op, everything is handled in the CRTC code. */ 575} 576 577static void shmob_drm_encoder_mode_set(struct drm_encoder *encoder, 578 struct drm_display_mode *mode, 579 struct drm_display_mode *adjusted_mode) 580{ 581 /* No-op, everything is handled in the CRTC code. */ 582} 583 584static void shmob_drm_encoder_mode_commit(struct drm_encoder *encoder) 585{ 586 /* No-op, everything is handled in the CRTC code. */ 587} 588 589static const struct drm_encoder_helper_funcs encoder_helper_funcs = { 590 .dpms = shmob_drm_encoder_dpms, 591 .mode_fixup = shmob_drm_encoder_mode_fixup, 592 .prepare = shmob_drm_encoder_mode_prepare, 593 .commit = shmob_drm_encoder_mode_commit, 594 .mode_set = shmob_drm_encoder_mode_set, 595}; 596 597static void shmob_drm_encoder_destroy(struct drm_encoder *encoder) 598{ 599 drm_encoder_cleanup(encoder); 600} 601 602static const struct drm_encoder_funcs encoder_funcs = { 603 .destroy = shmob_drm_encoder_destroy, 604}; 605 606int shmob_drm_encoder_create(struct shmob_drm_device *sdev) 607{ 608 struct drm_encoder *encoder = &sdev->encoder.encoder; 609 int ret; 610 611 sdev->encoder.dpms = DRM_MODE_DPMS_OFF; 612 613 encoder->possible_crtcs = 1; 614 615 ret = drm_encoder_init(sdev->ddev, encoder, &encoder_funcs, 616 DRM_MODE_ENCODER_LVDS); 617 if (ret < 0) 618 return ret; 619 620 drm_encoder_helper_add(encoder, &encoder_helper_funcs); 621 622 return 0; 623} 624 625void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, bool enable) 626{ 627 unsigned long flags; 628 u32 ldintr; 629 630 /* Be careful not to acknowledge any pending interrupt. */ 631 spin_lock_irqsave(&sdev->irq_lock, flags); 632 ldintr = lcdc_read(sdev, LDINTR) | LDINTR_STATUS_MASK; 633 if (enable) 634 ldintr |= LDINTR_VEE; 635 else 636 ldintr &= ~LDINTR_VEE; 637 lcdc_write(sdev, LDINTR, ldintr); 638 spin_unlock_irqrestore(&sdev->irq_lock, flags); 639} 640 641/* ----------------------------------------------------------------------------- 642 * Connector 643 */ 644 645#define to_shmob_connector(c) \ 646 container_of(c, struct shmob_drm_connector, connector) 647 648static int shmob_drm_connector_get_modes(struct drm_connector *connector) 649{ 650 struct shmob_drm_device *sdev = connector->dev->dev_private; 651 struct drm_display_mode *mode; 652 653 mode = drm_mode_create(connector->dev); 654 if (mode == NULL) 655 return 0; 656 657 mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 658 mode->clock = sdev->pdata->panel.mode.clock; 659 mode->hdisplay = sdev->pdata->panel.mode.hdisplay; 660 mode->hsync_start = sdev->pdata->panel.mode.hsync_start; 661 mode->hsync_end = sdev->pdata->panel.mode.hsync_end; 662 mode->htotal = sdev->pdata->panel.mode.htotal; 663 mode->vdisplay = sdev->pdata->panel.mode.vdisplay; 664 mode->vsync_start = sdev->pdata->panel.mode.vsync_start; 665 mode->vsync_end = sdev->pdata->panel.mode.vsync_end; 666 mode->vtotal = sdev->pdata->panel.mode.vtotal; 667 mode->flags = sdev->pdata->panel.mode.flags; 668 669 drm_mode_set_name(mode); 670 drm_mode_probed_add(connector, mode); 671 672 connector->display_info.width_mm = sdev->pdata->panel.width_mm; 673 connector->display_info.height_mm = sdev->pdata->panel.height_mm; 674 675 return 1; 676} 677 678static struct drm_encoder * 679shmob_drm_connector_best_encoder(struct drm_connector *connector) 680{ 681 struct shmob_drm_connector *scon = to_shmob_connector(connector); 682 683 return scon->encoder; 684} 685 686static const struct drm_connector_helper_funcs connector_helper_funcs = { 687 .get_modes = shmob_drm_connector_get_modes, 688 .best_encoder = shmob_drm_connector_best_encoder, 689}; 690 691static void shmob_drm_connector_destroy(struct drm_connector *connector) 692{ 693 struct shmob_drm_connector *scon = to_shmob_connector(connector); 694 695 shmob_drm_backlight_exit(scon); 696 drm_connector_unregister(connector); 697 drm_connector_cleanup(connector); 698} 699 700static enum drm_connector_status 701shmob_drm_connector_detect(struct drm_connector *connector, bool force) 702{ 703 return connector_status_connected; 704} 705 706static const struct drm_connector_funcs connector_funcs = { 707 .dpms = drm_helper_connector_dpms, 708 .detect = shmob_drm_connector_detect, 709 .fill_modes = drm_helper_probe_single_connector_modes, 710 .destroy = shmob_drm_connector_destroy, 711}; 712 713int shmob_drm_connector_create(struct shmob_drm_device *sdev, 714 struct drm_encoder *encoder) 715{ 716 struct drm_connector *connector = &sdev->connector.connector; 717 int ret; 718 719 sdev->connector.encoder = encoder; 720 721 connector->display_info.width_mm = sdev->pdata->panel.width_mm; 722 connector->display_info.height_mm = sdev->pdata->panel.height_mm; 723 724 ret = drm_connector_init(sdev->ddev, connector, &connector_funcs, 725 DRM_MODE_CONNECTOR_LVDS); 726 if (ret < 0) 727 return ret; 728 729 drm_connector_helper_add(connector, &connector_helper_funcs); 730 ret = drm_connector_register(connector); 731 if (ret < 0) 732 goto err_cleanup; 733 734 ret = shmob_drm_backlight_init(&sdev->connector); 735 if (ret < 0) 736 goto err_sysfs; 737 738 ret = drm_mode_connector_attach_encoder(connector, encoder); 739 if (ret < 0) 740 goto err_backlight; 741 742 connector->encoder = encoder; 743 744 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 745 drm_object_property_set_value(&connector->base, 746 sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); 747 748 return 0; 749 750err_backlight: 751 shmob_drm_backlight_exit(&sdev->connector); 752err_sysfs: 753 drm_connector_unregister(connector); 754err_cleanup: 755 drm_connector_cleanup(connector); 756 return ret; 757} 758