root/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_crtc_state_to_atmel_hlcdc_crtc_state
  2. drm_crtc_to_atmel_hlcdc_crtc
  3. atmel_hlcdc_crtc_mode_set_nofb
  4. atmel_hlcdc_crtc_mode_valid
  5. atmel_hlcdc_crtc_atomic_disable
  6. atmel_hlcdc_crtc_atomic_enable
  7. atmel_hlcdc_connector_output_mode
  8. atmel_hlcdc_crtc_select_output_mode
  9. atmel_hlcdc_crtc_atomic_check
  10. atmel_hlcdc_crtc_atomic_begin
  11. atmel_hlcdc_crtc_atomic_flush
  12. atmel_hlcdc_crtc_destroy
  13. atmel_hlcdc_crtc_finish_page_flip
  14. atmel_hlcdc_crtc_irq
  15. atmel_hlcdc_crtc_reset
  16. atmel_hlcdc_crtc_duplicate_state
  17. atmel_hlcdc_crtc_destroy_state
  18. atmel_hlcdc_crtc_enable_vblank
  19. atmel_hlcdc_crtc_disable_vblank
  20. atmel_hlcdc_crtc_create

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2014 Traphandler
   4  * Copyright (C) 2014 Free Electrons
   5  *
   6  * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
   7  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
   8  */
   9 
  10 #include <linux/clk.h>
  11 #include <linux/mfd/atmel-hlcdc.h>
  12 #include <linux/pinctrl/consumer.h>
  13 #include <linux/pm.h>
  14 #include <linux/pm_runtime.h>
  15 
  16 #include <video/videomode.h>
  17 
  18 #include <drm/drm_atomic.h>
  19 #include <drm/drm_atomic_helper.h>
  20 #include <drm/drm_crtc.h>
  21 #include <drm/drm_modeset_helper_vtables.h>
  22 #include <drm/drm_probe_helper.h>
  23 #include <drm/drm_vblank.h>
  24 
  25 #include "atmel_hlcdc_dc.h"
  26 
  27 /**
  28  * Atmel HLCDC CRTC state structure
  29  *
  30  * @base: base CRTC state
  31  * @output_mode: RGBXXX output mode
  32  */
  33 struct atmel_hlcdc_crtc_state {
  34         struct drm_crtc_state base;
  35         unsigned int output_mode;
  36 };
  37 
  38 static inline struct atmel_hlcdc_crtc_state *
  39 drm_crtc_state_to_atmel_hlcdc_crtc_state(struct drm_crtc_state *state)
  40 {
  41         return container_of(state, struct atmel_hlcdc_crtc_state, base);
  42 }
  43 
  44 /**
  45  * Atmel HLCDC CRTC structure
  46  *
  47  * @base: base DRM CRTC structure
  48  * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
  49  * @event: pointer to the current page flip event
  50  * @id: CRTC id (returned by drm_crtc_index)
  51  */
  52 struct atmel_hlcdc_crtc {
  53         struct drm_crtc base;
  54         struct atmel_hlcdc_dc *dc;
  55         struct drm_pending_vblank_event *event;
  56         int id;
  57 };
  58 
  59 static inline struct atmel_hlcdc_crtc *
  60 drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
  61 {
  62         return container_of(crtc, struct atmel_hlcdc_crtc, base);
  63 }
  64 
  65 static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
  66 {
  67         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
  68         struct regmap *regmap = crtc->dc->hlcdc->regmap;
  69         struct drm_display_mode *adj = &c->state->adjusted_mode;
  70         struct atmel_hlcdc_crtc_state *state;
  71         unsigned long mode_rate;
  72         struct videomode vm;
  73         unsigned long prate;
  74         unsigned int mask = ATMEL_HLCDC_CLKDIV_MASK | ATMEL_HLCDC_CLKPOL;
  75         unsigned int cfg = 0;
  76         int div, ret;
  77 
  78         ret = clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
  79         if (ret)
  80                 return;
  81 
  82         vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
  83         vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
  84         vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
  85         vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
  86         vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
  87         vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
  88 
  89         regmap_write(regmap, ATMEL_HLCDC_CFG(1),
  90                      (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
  91 
  92         regmap_write(regmap, ATMEL_HLCDC_CFG(2),
  93                      (vm.vfront_porch - 1) | (vm.vback_porch << 16));
  94 
  95         regmap_write(regmap, ATMEL_HLCDC_CFG(3),
  96                      (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
  97 
  98         regmap_write(regmap, ATMEL_HLCDC_CFG(4),
  99                      (adj->crtc_hdisplay - 1) |
 100                      ((adj->crtc_vdisplay - 1) << 16));
 101 
 102         prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
 103         mode_rate = adj->crtc_clock * 1000;
 104         if (!crtc->dc->desc->fixed_clksrc) {
 105                 prate *= 2;
 106                 cfg |= ATMEL_HLCDC_CLKSEL;
 107                 mask |= ATMEL_HLCDC_CLKSEL;
 108         }
 109 
 110         div = DIV_ROUND_UP(prate, mode_rate);
 111         if (div < 2) {
 112                 div = 2;
 113         } else if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK) {
 114                 /* The divider ended up too big, try a lower base rate. */
 115                 cfg &= ~ATMEL_HLCDC_CLKSEL;
 116                 prate /= 2;
 117                 div = DIV_ROUND_UP(prate, mode_rate);
 118                 if (ATMEL_HLCDC_CLKDIV(div) & ~ATMEL_HLCDC_CLKDIV_MASK)
 119                         div = ATMEL_HLCDC_CLKDIV_MASK;
 120         } else {
 121                 int div_low = prate / mode_rate;
 122 
 123                 if (div_low >= 2 &&
 124                     (10 * (prate / div_low - mode_rate) <
 125                      (mode_rate - prate / div)))
 126                         /*
 127                          * At least 10 times better when using a higher
 128                          * frequency than requested, instead of a lower.
 129                          * So, go with that.
 130                          */
 131                         div = div_low;
 132         }
 133 
 134         cfg |= ATMEL_HLCDC_CLKDIV(div);
 135 
 136         regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0), mask, cfg);
 137 
 138         state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
 139         cfg = state->output_mode << 8;
 140 
 141         if (adj->flags & DRM_MODE_FLAG_NVSYNC)
 142                 cfg |= ATMEL_HLCDC_VSPOL;
 143 
 144         if (adj->flags & DRM_MODE_FLAG_NHSYNC)
 145                 cfg |= ATMEL_HLCDC_HSPOL;
 146 
 147         regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
 148                            ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
 149                            ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
 150                            ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
 151                            ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
 152                            ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK,
 153                            cfg);
 154 
 155         clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
 156 }
 157 
 158 static enum drm_mode_status
 159 atmel_hlcdc_crtc_mode_valid(struct drm_crtc *c,
 160                             const struct drm_display_mode *mode)
 161 {
 162         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 163 
 164         return atmel_hlcdc_dc_mode_valid(crtc->dc, mode);
 165 }
 166 
 167 static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
 168                                             struct drm_crtc_state *old_state)
 169 {
 170         struct drm_device *dev = c->dev;
 171         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 172         struct regmap *regmap = crtc->dc->hlcdc->regmap;
 173         unsigned int status;
 174 
 175         drm_crtc_vblank_off(c);
 176 
 177         pm_runtime_get_sync(dev->dev);
 178 
 179         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
 180         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 181                (status & ATMEL_HLCDC_DISP))
 182                 cpu_relax();
 183 
 184         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
 185         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 186                (status & ATMEL_HLCDC_SYNC))
 187                 cpu_relax();
 188 
 189         regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
 190         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 191                (status & ATMEL_HLCDC_PIXEL_CLK))
 192                 cpu_relax();
 193 
 194         clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
 195         pinctrl_pm_select_sleep_state(dev->dev);
 196 
 197         pm_runtime_allow(dev->dev);
 198 
 199         pm_runtime_put_sync(dev->dev);
 200 }
 201 
 202 static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
 203                                            struct drm_crtc_state *old_state)
 204 {
 205         struct drm_device *dev = c->dev;
 206         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 207         struct regmap *regmap = crtc->dc->hlcdc->regmap;
 208         unsigned int status;
 209 
 210         pm_runtime_get_sync(dev->dev);
 211 
 212         pm_runtime_forbid(dev->dev);
 213 
 214         pinctrl_pm_select_default_state(dev->dev);
 215         clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
 216 
 217         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
 218         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 219                !(status & ATMEL_HLCDC_PIXEL_CLK))
 220                 cpu_relax();
 221 
 222 
 223         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
 224         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 225                !(status & ATMEL_HLCDC_SYNC))
 226                 cpu_relax();
 227 
 228         regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
 229         while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
 230                !(status & ATMEL_HLCDC_DISP))
 231                 cpu_relax();
 232 
 233         pm_runtime_put_sync(dev->dev);
 234 
 235         drm_crtc_vblank_on(c);
 236 }
 237 
 238 #define ATMEL_HLCDC_RGB444_OUTPUT       BIT(0)
 239 #define ATMEL_HLCDC_RGB565_OUTPUT       BIT(1)
 240 #define ATMEL_HLCDC_RGB666_OUTPUT       BIT(2)
 241 #define ATMEL_HLCDC_RGB888_OUTPUT       BIT(3)
 242 #define ATMEL_HLCDC_OUTPUT_MODE_MASK    GENMASK(3, 0)
 243 
 244 static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
 245 {
 246         struct drm_connector *connector = state->connector;
 247         struct drm_display_info *info = &connector->display_info;
 248         struct drm_encoder *encoder;
 249         unsigned int supported_fmts = 0;
 250         int j;
 251 
 252         encoder = state->best_encoder;
 253         if (!encoder)
 254                 encoder = connector->encoder;
 255 
 256         switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
 257         case 0:
 258                 break;
 259         case MEDIA_BUS_FMT_RGB444_1X12:
 260                 return ATMEL_HLCDC_RGB444_OUTPUT;
 261         case MEDIA_BUS_FMT_RGB565_1X16:
 262                 return ATMEL_HLCDC_RGB565_OUTPUT;
 263         case MEDIA_BUS_FMT_RGB666_1X18:
 264                 return ATMEL_HLCDC_RGB666_OUTPUT;
 265         case MEDIA_BUS_FMT_RGB888_1X24:
 266                 return ATMEL_HLCDC_RGB888_OUTPUT;
 267         default:
 268                 return -EINVAL;
 269         }
 270 
 271         for (j = 0; j < info->num_bus_formats; j++) {
 272                 switch (info->bus_formats[j]) {
 273                 case MEDIA_BUS_FMT_RGB444_1X12:
 274                         supported_fmts |= ATMEL_HLCDC_RGB444_OUTPUT;
 275                         break;
 276                 case MEDIA_BUS_FMT_RGB565_1X16:
 277                         supported_fmts |= ATMEL_HLCDC_RGB565_OUTPUT;
 278                         break;
 279                 case MEDIA_BUS_FMT_RGB666_1X18:
 280                         supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT;
 281                         break;
 282                 case MEDIA_BUS_FMT_RGB888_1X24:
 283                         supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT;
 284                         break;
 285                 default:
 286                         break;
 287                 }
 288         }
 289 
 290         return supported_fmts;
 291 }
 292 
 293 static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
 294 {
 295         unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
 296         struct atmel_hlcdc_crtc_state *hstate;
 297         struct drm_connector_state *cstate;
 298         struct drm_connector *connector;
 299         struct atmel_hlcdc_crtc *crtc;
 300         int i;
 301 
 302         crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
 303 
 304         for_each_new_connector_in_state(state->state, connector, cstate, i) {
 305                 unsigned int supported_fmts = 0;
 306 
 307                 if (!cstate->crtc)
 308                         continue;
 309 
 310                 supported_fmts = atmel_hlcdc_connector_output_mode(cstate);
 311 
 312                 if (crtc->dc->desc->conflicting_output_formats)
 313                         output_fmts &= supported_fmts;
 314                 else
 315                         output_fmts |= supported_fmts;
 316         }
 317 
 318         if (!output_fmts)
 319                 return -EINVAL;
 320 
 321         hstate = drm_crtc_state_to_atmel_hlcdc_crtc_state(state);
 322         hstate->output_mode = fls(output_fmts) - 1;
 323 
 324         return 0;
 325 }
 326 
 327 static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
 328                                          struct drm_crtc_state *s)
 329 {
 330         int ret;
 331 
 332         ret = atmel_hlcdc_crtc_select_output_mode(s);
 333         if (ret)
 334                 return ret;
 335 
 336         ret = atmel_hlcdc_plane_prepare_disc_area(s);
 337         if (ret)
 338                 return ret;
 339 
 340         return atmel_hlcdc_plane_prepare_ahb_routing(s);
 341 }
 342 
 343 static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c,
 344                                           struct drm_crtc_state *old_s)
 345 {
 346         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 347 
 348         if (c->state->event) {
 349                 c->state->event->pipe = drm_crtc_index(c);
 350 
 351                 WARN_ON(drm_crtc_vblank_get(c) != 0);
 352 
 353                 crtc->event = c->state->event;
 354                 c->state->event = NULL;
 355         }
 356 }
 357 
 358 static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc,
 359                                           struct drm_crtc_state *old_s)
 360 {
 361         /* TODO: write common plane control register if available */
 362 }
 363 
 364 static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
 365         .mode_valid = atmel_hlcdc_crtc_mode_valid,
 366         .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
 367         .atomic_check = atmel_hlcdc_crtc_atomic_check,
 368         .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
 369         .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
 370         .atomic_enable = atmel_hlcdc_crtc_atomic_enable,
 371         .atomic_disable = atmel_hlcdc_crtc_atomic_disable,
 372 };
 373 
 374 static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
 375 {
 376         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 377 
 378         drm_crtc_cleanup(c);
 379         kfree(crtc);
 380 }
 381 
 382 static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
 383 {
 384         struct drm_device *dev = crtc->base.dev;
 385         unsigned long flags;
 386 
 387         spin_lock_irqsave(&dev->event_lock, flags);
 388         if (crtc->event) {
 389                 drm_crtc_send_vblank_event(&crtc->base, crtc->event);
 390                 drm_crtc_vblank_put(&crtc->base);
 391                 crtc->event = NULL;
 392         }
 393         spin_unlock_irqrestore(&dev->event_lock, flags);
 394 }
 395 
 396 void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
 397 {
 398         drm_crtc_handle_vblank(c);
 399         atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
 400 }
 401 
 402 static void atmel_hlcdc_crtc_reset(struct drm_crtc *crtc)
 403 {
 404         struct atmel_hlcdc_crtc_state *state;
 405 
 406         if (crtc->state) {
 407                 __drm_atomic_helper_crtc_destroy_state(crtc->state);
 408                 state = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
 409                 kfree(state);
 410                 crtc->state = NULL;
 411         }
 412 
 413         state = kzalloc(sizeof(*state), GFP_KERNEL);
 414         if (state) {
 415                 crtc->state = &state->base;
 416                 crtc->state->crtc = crtc;
 417         }
 418 }
 419 
 420 static struct drm_crtc_state *
 421 atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
 422 {
 423         struct atmel_hlcdc_crtc_state *state, *cur;
 424 
 425         if (WARN_ON(!crtc->state))
 426                 return NULL;
 427 
 428         state = kmalloc(sizeof(*state), GFP_KERNEL);
 429         if (!state)
 430                 return NULL;
 431         __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
 432 
 433         cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
 434         state->output_mode = cur->output_mode;
 435 
 436         return &state->base;
 437 }
 438 
 439 static void atmel_hlcdc_crtc_destroy_state(struct drm_crtc *crtc,
 440                                            struct drm_crtc_state *s)
 441 {
 442         struct atmel_hlcdc_crtc_state *state;
 443 
 444         state = drm_crtc_state_to_atmel_hlcdc_crtc_state(s);
 445         __drm_atomic_helper_crtc_destroy_state(s);
 446         kfree(state);
 447 }
 448 
 449 static int atmel_hlcdc_crtc_enable_vblank(struct drm_crtc *c)
 450 {
 451         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 452         struct regmap *regmap = crtc->dc->hlcdc->regmap;
 453 
 454         /* Enable SOF (Start Of Frame) interrupt for vblank counting */
 455         regmap_write(regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
 456 
 457         return 0;
 458 }
 459 
 460 static void atmel_hlcdc_crtc_disable_vblank(struct drm_crtc *c)
 461 {
 462         struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
 463         struct regmap *regmap = crtc->dc->hlcdc->regmap;
 464 
 465         regmap_write(regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
 466 }
 467 
 468 static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
 469         .page_flip = drm_atomic_helper_page_flip,
 470         .set_config = drm_atomic_helper_set_config,
 471         .destroy = atmel_hlcdc_crtc_destroy,
 472         .reset = atmel_hlcdc_crtc_reset,
 473         .atomic_duplicate_state =  atmel_hlcdc_crtc_duplicate_state,
 474         .atomic_destroy_state = atmel_hlcdc_crtc_destroy_state,
 475         .enable_vblank = atmel_hlcdc_crtc_enable_vblank,
 476         .disable_vblank = atmel_hlcdc_crtc_disable_vblank,
 477         .gamma_set = drm_atomic_helper_legacy_gamma_set,
 478 };
 479 
 480 int atmel_hlcdc_crtc_create(struct drm_device *dev)
 481 {
 482         struct atmel_hlcdc_plane *primary = NULL, *cursor = NULL;
 483         struct atmel_hlcdc_dc *dc = dev->dev_private;
 484         struct atmel_hlcdc_crtc *crtc;
 485         int ret;
 486         int i;
 487 
 488         crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
 489         if (!crtc)
 490                 return -ENOMEM;
 491 
 492         crtc->dc = dc;
 493 
 494         for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
 495                 if (!dc->layers[i])
 496                         continue;
 497 
 498                 switch (dc->layers[i]->desc->type) {
 499                 case ATMEL_HLCDC_BASE_LAYER:
 500                         primary = atmel_hlcdc_layer_to_plane(dc->layers[i]);
 501                         break;
 502 
 503                 case ATMEL_HLCDC_CURSOR_LAYER:
 504                         cursor = atmel_hlcdc_layer_to_plane(dc->layers[i]);
 505                         break;
 506 
 507                 default:
 508                         break;
 509                 }
 510         }
 511 
 512         ret = drm_crtc_init_with_planes(dev, &crtc->base, &primary->base,
 513                                         &cursor->base, &atmel_hlcdc_crtc_funcs,
 514                                         NULL);
 515         if (ret < 0)
 516                 goto fail;
 517 
 518         crtc->id = drm_crtc_index(&crtc->base);
 519 
 520         for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
 521                 struct atmel_hlcdc_plane *overlay;
 522 
 523                 if (dc->layers[i] &&
 524                     dc->layers[i]->desc->type == ATMEL_HLCDC_OVERLAY_LAYER) {
 525                         overlay = atmel_hlcdc_layer_to_plane(dc->layers[i]);
 526                         overlay->base.possible_crtcs = 1 << crtc->id;
 527                 }
 528         }
 529 
 530         drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
 531         drm_crtc_vblank_reset(&crtc->base);
 532 
 533         drm_mode_crtc_set_gamma_size(&crtc->base, ATMEL_HLCDC_CLUT_SIZE);
 534         drm_crtc_enable_color_mgmt(&crtc->base, 0, false,
 535                                    ATMEL_HLCDC_CLUT_SIZE);
 536 
 537         dc->crtc = &crtc->base;
 538 
 539         return 0;
 540 
 541 fail:
 542         atmel_hlcdc_crtc_destroy(&crtc->base);
 543         return ret;
 544 }

/* [<][>][^][v][top][bottom][index][help] */