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 v4.12-rc5 735 lines 20 kB view raw
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->format->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) { 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 void shmob_drm_crtc_mode_prepare(struct drm_crtc *crtc) 363{ 364 shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 365} 366 367static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, 368 struct drm_display_mode *mode, 369 struct drm_display_mode *adjusted_mode, 370 int x, int y, 371 struct drm_framebuffer *old_fb) 372{ 373 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); 374 struct shmob_drm_device *sdev = crtc->dev->dev_private; 375 const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram; 376 const struct shmob_drm_format_info *format; 377 void *cache; 378 379 format = shmob_drm_format_info(crtc->primary->fb->format->format); 380 if (format == NULL) { 381 dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n", 382 crtc->primary->fb->format->format); 383 return -EINVAL; 384 } 385 386 scrtc->format = format; 387 scrtc->line_size = crtc->primary->fb->pitches[0]; 388 389 if (sdev->meram) { 390 /* Enable MERAM cache if configured. We need to de-init 391 * configured ICBs before we can re-initialize them. 392 */ 393 if (scrtc->cache) { 394 sh_mobile_meram_cache_free(sdev->meram, scrtc->cache); 395 scrtc->cache = NULL; 396 } 397 398 cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata, 399 crtc->primary->fb->pitches[0], 400 adjusted_mode->vdisplay, 401 format->meram, 402 &scrtc->line_size); 403 if (!IS_ERR(cache)) 404 scrtc->cache = cache; 405 } 406 407 shmob_drm_crtc_compute_base(scrtc, x, y); 408 409 return 0; 410} 411 412static void shmob_drm_crtc_mode_commit(struct drm_crtc *crtc) 413{ 414 shmob_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 415} 416 417static int shmob_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 418 struct drm_framebuffer *old_fb) 419{ 420 shmob_drm_crtc_update_base(to_shmob_crtc(crtc)); 421 422 return 0; 423} 424 425static const struct drm_crtc_helper_funcs crtc_helper_funcs = { 426 .dpms = shmob_drm_crtc_dpms, 427 .prepare = shmob_drm_crtc_mode_prepare, 428 .commit = shmob_drm_crtc_mode_commit, 429 .mode_set = shmob_drm_crtc_mode_set, 430 .mode_set_base = shmob_drm_crtc_mode_set_base, 431}; 432 433void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc) 434{ 435 struct drm_pending_vblank_event *event; 436 struct drm_device *dev = scrtc->crtc.dev; 437 unsigned long flags; 438 439 spin_lock_irqsave(&dev->event_lock, flags); 440 event = scrtc->event; 441 scrtc->event = NULL; 442 if (event) { 443 drm_crtc_send_vblank_event(&scrtc->crtc, event); 444 drm_crtc_vblank_put(&scrtc->crtc); 445 } 446 spin_unlock_irqrestore(&dev->event_lock, flags); 447} 448 449static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, 450 struct drm_framebuffer *fb, 451 struct drm_pending_vblank_event *event, 452 uint32_t page_flip_flags, 453 struct drm_modeset_acquire_ctx *ctx) 454{ 455 struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); 456 struct drm_device *dev = scrtc->crtc.dev; 457 unsigned long flags; 458 459 spin_lock_irqsave(&dev->event_lock, flags); 460 if (scrtc->event != NULL) { 461 spin_unlock_irqrestore(&dev->event_lock, flags); 462 return -EBUSY; 463 } 464 spin_unlock_irqrestore(&dev->event_lock, flags); 465 466 crtc->primary->fb = fb; 467 shmob_drm_crtc_update_base(scrtc); 468 469 if (event) { 470 event->pipe = 0; 471 drm_crtc_vblank_get(&scrtc->crtc); 472 spin_lock_irqsave(&dev->event_lock, flags); 473 scrtc->event = event; 474 spin_unlock_irqrestore(&dev->event_lock, flags); 475 } 476 477 return 0; 478} 479 480static void shmob_drm_crtc_enable_vblank(struct shmob_drm_device *sdev, 481 bool enable) 482{ 483 unsigned long flags; 484 u32 ldintr; 485 486 /* Be careful not to acknowledge any pending interrupt. */ 487 spin_lock_irqsave(&sdev->irq_lock, flags); 488 ldintr = lcdc_read(sdev, LDINTR) | LDINTR_STATUS_MASK; 489 if (enable) 490 ldintr |= LDINTR_VEE; 491 else 492 ldintr &= ~LDINTR_VEE; 493 lcdc_write(sdev, LDINTR, ldintr); 494 spin_unlock_irqrestore(&sdev->irq_lock, flags); 495} 496 497static int shmob_drm_enable_vblank(struct drm_crtc *crtc) 498{ 499 struct shmob_drm_device *sdev = crtc->dev->dev_private; 500 501 shmob_drm_crtc_enable_vblank(sdev, true); 502 503 return 0; 504} 505 506static void shmob_drm_disable_vblank(struct drm_crtc *crtc) 507{ 508 struct shmob_drm_device *sdev = crtc->dev->dev_private; 509 510 shmob_drm_crtc_enable_vblank(sdev, false); 511} 512 513static const struct drm_crtc_funcs crtc_funcs = { 514 .destroy = drm_crtc_cleanup, 515 .set_config = drm_crtc_helper_set_config, 516 .page_flip = shmob_drm_crtc_page_flip, 517 .enable_vblank = shmob_drm_enable_vblank, 518 .disable_vblank = shmob_drm_disable_vblank, 519}; 520 521int shmob_drm_crtc_create(struct shmob_drm_device *sdev) 522{ 523 struct drm_crtc *crtc = &sdev->crtc.crtc; 524 int ret; 525 526 sdev->crtc.dpms = DRM_MODE_DPMS_OFF; 527 528 ret = drm_crtc_init(sdev->ddev, crtc, &crtc_funcs); 529 if (ret < 0) 530 return ret; 531 532 drm_crtc_helper_add(crtc, &crtc_helper_funcs); 533 534 return 0; 535} 536 537/* ----------------------------------------------------------------------------- 538 * Encoder 539 */ 540 541#define to_shmob_encoder(e) \ 542 container_of(e, struct shmob_drm_encoder, encoder) 543 544static void shmob_drm_encoder_dpms(struct drm_encoder *encoder, int mode) 545{ 546 struct shmob_drm_encoder *senc = to_shmob_encoder(encoder); 547 struct shmob_drm_device *sdev = encoder->dev->dev_private; 548 struct shmob_drm_connector *scon = &sdev->connector; 549 550 if (senc->dpms == mode) 551 return; 552 553 shmob_drm_backlight_dpms(scon, mode); 554 555 senc->dpms = mode; 556} 557 558static bool shmob_drm_encoder_mode_fixup(struct drm_encoder *encoder, 559 const struct drm_display_mode *mode, 560 struct drm_display_mode *adjusted_mode) 561{ 562 struct drm_device *dev = encoder->dev; 563 struct shmob_drm_device *sdev = dev->dev_private; 564 struct drm_connector *connector = &sdev->connector.connector; 565 const struct drm_display_mode *panel_mode; 566 567 if (list_empty(&connector->modes)) { 568 dev_dbg(dev->dev, "mode_fixup: empty modes list\n"); 569 return false; 570 } 571 572 /* The flat panel mode is fixed, just copy it to the adjusted mode. */ 573 panel_mode = list_first_entry(&connector->modes, 574 struct drm_display_mode, head); 575 drm_mode_copy(adjusted_mode, panel_mode); 576 577 return true; 578} 579 580static void shmob_drm_encoder_mode_prepare(struct drm_encoder *encoder) 581{ 582 /* No-op, everything is handled in the CRTC code. */ 583} 584 585static void shmob_drm_encoder_mode_set(struct drm_encoder *encoder, 586 struct drm_display_mode *mode, 587 struct drm_display_mode *adjusted_mode) 588{ 589 /* No-op, everything is handled in the CRTC code. */ 590} 591 592static void shmob_drm_encoder_mode_commit(struct drm_encoder *encoder) 593{ 594 /* No-op, everything is handled in the CRTC code. */ 595} 596 597static const struct drm_encoder_helper_funcs encoder_helper_funcs = { 598 .dpms = shmob_drm_encoder_dpms, 599 .mode_fixup = shmob_drm_encoder_mode_fixup, 600 .prepare = shmob_drm_encoder_mode_prepare, 601 .commit = shmob_drm_encoder_mode_commit, 602 .mode_set = shmob_drm_encoder_mode_set, 603}; 604 605static void shmob_drm_encoder_destroy(struct drm_encoder *encoder) 606{ 607 drm_encoder_cleanup(encoder); 608} 609 610static const struct drm_encoder_funcs encoder_funcs = { 611 .destroy = shmob_drm_encoder_destroy, 612}; 613 614int shmob_drm_encoder_create(struct shmob_drm_device *sdev) 615{ 616 struct drm_encoder *encoder = &sdev->encoder.encoder; 617 int ret; 618 619 sdev->encoder.dpms = DRM_MODE_DPMS_OFF; 620 621 encoder->possible_crtcs = 1; 622 623 ret = drm_encoder_init(sdev->ddev, encoder, &encoder_funcs, 624 DRM_MODE_ENCODER_LVDS, NULL); 625 if (ret < 0) 626 return ret; 627 628 drm_encoder_helper_add(encoder, &encoder_helper_funcs); 629 630 return 0; 631} 632 633/* ----------------------------------------------------------------------------- 634 * Connector 635 */ 636 637#define to_shmob_connector(c) \ 638 container_of(c, struct shmob_drm_connector, connector) 639 640static int shmob_drm_connector_get_modes(struct drm_connector *connector) 641{ 642 struct shmob_drm_device *sdev = connector->dev->dev_private; 643 struct drm_display_mode *mode; 644 645 mode = drm_mode_create(connector->dev); 646 if (mode == NULL) 647 return 0; 648 649 mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; 650 mode->clock = sdev->pdata->panel.mode.clock; 651 mode->hdisplay = sdev->pdata->panel.mode.hdisplay; 652 mode->hsync_start = sdev->pdata->panel.mode.hsync_start; 653 mode->hsync_end = sdev->pdata->panel.mode.hsync_end; 654 mode->htotal = sdev->pdata->panel.mode.htotal; 655 mode->vdisplay = sdev->pdata->panel.mode.vdisplay; 656 mode->vsync_start = sdev->pdata->panel.mode.vsync_start; 657 mode->vsync_end = sdev->pdata->panel.mode.vsync_end; 658 mode->vtotal = sdev->pdata->panel.mode.vtotal; 659 mode->flags = sdev->pdata->panel.mode.flags; 660 661 drm_mode_set_name(mode); 662 drm_mode_probed_add(connector, mode); 663 664 connector->display_info.width_mm = sdev->pdata->panel.width_mm; 665 connector->display_info.height_mm = sdev->pdata->panel.height_mm; 666 667 return 1; 668} 669 670static struct drm_encoder * 671shmob_drm_connector_best_encoder(struct drm_connector *connector) 672{ 673 struct shmob_drm_connector *scon = to_shmob_connector(connector); 674 675 return scon->encoder; 676} 677 678static const struct drm_connector_helper_funcs connector_helper_funcs = { 679 .get_modes = shmob_drm_connector_get_modes, 680 .best_encoder = shmob_drm_connector_best_encoder, 681}; 682 683static void shmob_drm_connector_destroy(struct drm_connector *connector) 684{ 685 struct shmob_drm_connector *scon = to_shmob_connector(connector); 686 687 shmob_drm_backlight_exit(scon); 688 drm_connector_unregister(connector); 689 drm_connector_cleanup(connector); 690} 691 692static const struct drm_connector_funcs connector_funcs = { 693 .dpms = drm_helper_connector_dpms, 694 .fill_modes = drm_helper_probe_single_connector_modes, 695 .destroy = shmob_drm_connector_destroy, 696}; 697 698int shmob_drm_connector_create(struct shmob_drm_device *sdev, 699 struct drm_encoder *encoder) 700{ 701 struct drm_connector *connector = &sdev->connector.connector; 702 int ret; 703 704 sdev->connector.encoder = encoder; 705 706 connector->display_info.width_mm = sdev->pdata->panel.width_mm; 707 connector->display_info.height_mm = sdev->pdata->panel.height_mm; 708 709 ret = drm_connector_init(sdev->ddev, connector, &connector_funcs, 710 DRM_MODE_CONNECTOR_LVDS); 711 if (ret < 0) 712 return ret; 713 714 drm_connector_helper_add(connector, &connector_helper_funcs); 715 716 ret = shmob_drm_backlight_init(&sdev->connector); 717 if (ret < 0) 718 goto err_cleanup; 719 720 ret = drm_mode_connector_attach_encoder(connector, encoder); 721 if (ret < 0) 722 goto err_backlight; 723 724 drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); 725 drm_object_property_set_value(&connector->base, 726 sdev->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); 727 728 return 0; 729 730err_backlight: 731 shmob_drm_backlight_exit(&sdev->connector); 732err_cleanup: 733 drm_connector_cleanup(connector); 734 return ret; 735}