Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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