root/drivers/gpu/drm/armada/armada_plane.c

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

DEFINITIONS

This source file includes following definitions.
  1. armada_drm_plane_calc
  2. armada_drm_plane_prepare_fb
  3. armada_drm_plane_cleanup_fb
  4. armada_drm_plane_atomic_check
  5. armada_drm_primary_plane_atomic_update
  6. armada_drm_primary_plane_atomic_disable
  7. armada_plane_reset
  8. armada_plane_duplicate_state
  9. armada_drm_primary_plane_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2012 Russell King
   4  *  Rewritten from the dovefb driver, and Armada510 manuals.
   5  */
   6 
   7 #include <drm/drm_atomic.h>
   8 #include <drm/drm_atomic_helper.h>
   9 #include <drm/drm_fourcc.h>
  10 #include <drm/drm_plane_helper.h>
  11 
  12 #include "armada_crtc.h"
  13 #include "armada_drm.h"
  14 #include "armada_fb.h"
  15 #include "armada_gem.h"
  16 #include "armada_hw.h"
  17 #include "armada_plane.h"
  18 #include "armada_trace.h"
  19 
  20 static const uint32_t armada_primary_formats[] = {
  21         DRM_FORMAT_UYVY,
  22         DRM_FORMAT_YUYV,
  23         DRM_FORMAT_VYUY,
  24         DRM_FORMAT_YVYU,
  25         DRM_FORMAT_ARGB8888,
  26         DRM_FORMAT_ABGR8888,
  27         DRM_FORMAT_XRGB8888,
  28         DRM_FORMAT_XBGR8888,
  29         DRM_FORMAT_RGB888,
  30         DRM_FORMAT_BGR888,
  31         DRM_FORMAT_ARGB1555,
  32         DRM_FORMAT_ABGR1555,
  33         DRM_FORMAT_RGB565,
  34         DRM_FORMAT_BGR565,
  35 };
  36 
  37 void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
  38         u16 pitches[3], bool interlaced)
  39 {
  40         struct drm_framebuffer *fb = state->fb;
  41         const struct drm_format_info *format = fb->format;
  42         unsigned int num_planes = format->num_planes;
  43         unsigned int x = state->src.x1 >> 16;
  44         unsigned int y = state->src.y1 >> 16;
  45         u32 addr = drm_fb_obj(fb)->dev_addr;
  46         int i;
  47 
  48         DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
  49                       fb->pitches[0], x, y, format->cpp[0] * 8);
  50 
  51         if (num_planes > 3)
  52                 num_planes = 3;
  53 
  54         addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
  55                       x * format->cpp[0];
  56         pitches[0] = fb->pitches[0];
  57 
  58         y /= format->vsub;
  59         x /= format->hsub;
  60 
  61         for (i = 1; i < num_planes; i++) {
  62                 addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
  63                               x * format->cpp[i];
  64                 pitches[i] = fb->pitches[i];
  65         }
  66         for (; i < 3; i++) {
  67                 addrs[0][i] = 0;
  68                 pitches[i] = 0;
  69         }
  70         if (interlaced) {
  71                 for (i = 0; i < 3; i++) {
  72                         addrs[1][i] = addrs[0][i] + pitches[i];
  73                         pitches[i] *= 2;
  74                 }
  75         } else {
  76                 for (i = 0; i < 3; i++)
  77                         addrs[1][i] = addrs[0][i];
  78         }
  79 }
  80 
  81 int armada_drm_plane_prepare_fb(struct drm_plane *plane,
  82         struct drm_plane_state *state)
  83 {
  84         DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
  85                 plane->base.id, plane->name,
  86                 state->fb ? state->fb->base.id : 0);
  87 
  88         /*
  89          * Take a reference on the new framebuffer - we want to
  90          * hold on to it while the hardware is displaying it.
  91          */
  92         if (state->fb)
  93                 drm_framebuffer_get(state->fb);
  94         return 0;
  95 }
  96 
  97 void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
  98         struct drm_plane_state *old_state)
  99 {
 100         DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
 101                 plane->base.id, plane->name,
 102                 old_state->fb ? old_state->fb->base.id : 0);
 103 
 104         if (old_state->fb)
 105                 drm_framebuffer_put(old_state->fb);
 106 }
 107 
 108 int armada_drm_plane_atomic_check(struct drm_plane *plane,
 109         struct drm_plane_state *state)
 110 {
 111         struct armada_plane_state *st = to_armada_plane_state(state);
 112         struct drm_crtc *crtc = state->crtc;
 113         struct drm_crtc_state *crtc_state;
 114         bool interlace;
 115         int ret;
 116 
 117         if (!state->fb || WARN_ON(!state->crtc)) {
 118                 state->visible = false;
 119                 return 0;
 120         }
 121 
 122         if (state->state)
 123                 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
 124         else
 125                 crtc_state = crtc->state;
 126 
 127         ret = drm_atomic_helper_check_plane_state(state, crtc_state, 0,
 128                                                   INT_MAX, true, false);
 129         if (ret)
 130                 return ret;
 131 
 132         interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
 133         if (interlace) {
 134                 if ((state->dst.y1 | state->dst.y2) & 1)
 135                         return -EINVAL;
 136                 st->src_hw = drm_rect_height(&state->src) >> 17;
 137                 st->dst_yx = state->dst.y1 >> 1;
 138                 st->dst_hw = drm_rect_height(&state->dst) >> 1;
 139         } else {
 140                 st->src_hw = drm_rect_height(&state->src) >> 16;
 141                 st->dst_yx = state->dst.y1;
 142                 st->dst_hw = drm_rect_height(&state->dst);
 143         }
 144 
 145         st->src_hw <<= 16;
 146         st->src_hw |= drm_rect_width(&state->src) >> 16;
 147         st->dst_yx <<= 16;
 148         st->dst_yx |= state->dst.x1 & 0x0000ffff;
 149         st->dst_hw <<= 16;
 150         st->dst_hw |= drm_rect_width(&state->dst) & 0x0000ffff;
 151 
 152         armada_drm_plane_calc(state, st->addrs, st->pitches, interlace);
 153         st->interlace = interlace;
 154 
 155         return 0;
 156 }
 157 
 158 static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
 159         struct drm_plane_state *old_state)
 160 {
 161         struct drm_plane_state *state = plane->state;
 162         struct armada_crtc *dcrtc;
 163         struct armada_regs *regs;
 164         u32 cfg, cfg_mask, val;
 165         unsigned int idx;
 166 
 167         DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 168 
 169         if (!state->fb || WARN_ON(!state->crtc))
 170                 return;
 171 
 172         DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
 173                 plane->base.id, plane->name,
 174                 state->crtc->base.id, state->crtc->name,
 175                 state->fb->base.id,
 176                 old_state->visible, state->visible);
 177 
 178         dcrtc = drm_to_armada_crtc(state->crtc);
 179         regs = dcrtc->regs + dcrtc->regs_idx;
 180 
 181         idx = 0;
 182         if (!old_state->visible && state->visible) {
 183                 val = CFG_PDWN64x66;
 184                 if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
 185                         val |= CFG_PDWN256x24;
 186                 armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
 187         }
 188         val = armada_src_hw(state);
 189         if (armada_src_hw(old_state) != val)
 190                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
 191         val = armada_dst_yx(state);
 192         if (armada_dst_yx(old_state) != val)
 193                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
 194         val = armada_dst_hw(state);
 195         if (armada_dst_hw(old_state) != val)
 196                 armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
 197         if (old_state->src.x1 != state->src.x1 ||
 198             old_state->src.y1 != state->src.y1 ||
 199             old_state->fb != state->fb ||
 200             state->crtc->state->mode_changed) {
 201                 armada_reg_queue_set(regs, idx, armada_addr(state, 0, 0),
 202                                      LCD_CFG_GRA_START_ADDR0);
 203                 armada_reg_queue_set(regs, idx, armada_addr(state, 1, 0),
 204                                      LCD_CFG_GRA_START_ADDR1);
 205                 armada_reg_queue_mod(regs, idx, armada_pitch(state, 0), 0xffff,
 206                                      LCD_CFG_GRA_PITCH);
 207         }
 208         if (old_state->fb != state->fb ||
 209             state->crtc->state->mode_changed) {
 210                 cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
 211                       CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
 212                 if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
 213                         cfg |= CFG_PALETTE_ENA;
 214                 if (state->visible)
 215                         cfg |= CFG_GRA_ENA;
 216                 if (to_armada_plane_state(state)->interlace)
 217                         cfg |= CFG_GRA_FTOGGLE;
 218                 cfg_mask = CFG_GRAFORMAT |
 219                            CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
 220                                        CFG_SWAPYU | CFG_YUV2RGB) |
 221                            CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
 222                            CFG_GRA_ENA;
 223         } else if (old_state->visible != state->visible) {
 224                 cfg = state->visible ? CFG_GRA_ENA : 0;
 225                 cfg_mask = CFG_GRA_ENA;
 226         } else {
 227                 cfg = cfg_mask = 0;
 228         }
 229         if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
 230             drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
 231                 cfg_mask |= CFG_GRA_HSMOOTH;
 232                 if (drm_rect_width(&state->src) >> 16 !=
 233                     drm_rect_width(&state->dst))
 234                         cfg |= CFG_GRA_HSMOOTH;
 235         }
 236 
 237         if (cfg_mask)
 238                 armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
 239                                      LCD_SPU_DMA_CTRL0);
 240 
 241         dcrtc->regs_idx += idx;
 242 }
 243 
 244 static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
 245         struct drm_plane_state *old_state)
 246 {
 247         struct armada_crtc *dcrtc;
 248         struct armada_regs *regs;
 249         unsigned int idx = 0;
 250 
 251         DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 252 
 253         if (!old_state->crtc)
 254                 return;
 255 
 256         DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
 257                 plane->base.id, plane->name,
 258                 old_state->crtc->base.id, old_state->crtc->name,
 259                 old_state->fb->base.id);
 260 
 261         dcrtc = drm_to_armada_crtc(old_state->crtc);
 262         regs = dcrtc->regs + dcrtc->regs_idx;
 263 
 264         /* Disable plane and power down most RAMs and FIFOs */
 265         armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
 266         armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
 267                              CFG_PDWN32x32 | CFG_PDWN64x66,
 268                              0, LCD_SPU_SRAM_PARA1);
 269 
 270         dcrtc->regs_idx += idx;
 271 }
 272 
 273 static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
 274         .prepare_fb     = armada_drm_plane_prepare_fb,
 275         .cleanup_fb     = armada_drm_plane_cleanup_fb,
 276         .atomic_check   = armada_drm_plane_atomic_check,
 277         .atomic_update  = armada_drm_primary_plane_atomic_update,
 278         .atomic_disable = armada_drm_primary_plane_atomic_disable,
 279 };
 280 
 281 void armada_plane_reset(struct drm_plane *plane)
 282 {
 283         struct armada_plane_state *st;
 284         if (plane->state)
 285                 __drm_atomic_helper_plane_destroy_state(plane->state);
 286         kfree(plane->state);
 287         st = kzalloc(sizeof(*st), GFP_KERNEL);
 288         if (st)
 289                 __drm_atomic_helper_plane_reset(plane, &st->base);
 290 }
 291 
 292 struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
 293 {
 294         struct armada_plane_state *st;
 295 
 296         if (WARN_ON(!plane->state))
 297                 return NULL;
 298 
 299         st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
 300         if (st)
 301                 __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
 302 
 303         return &st->base;
 304 }
 305 
 306 static const struct drm_plane_funcs armada_primary_plane_funcs = {
 307         .update_plane   = drm_atomic_helper_update_plane,
 308         .disable_plane  = drm_atomic_helper_disable_plane,
 309         .destroy        = drm_primary_helper_destroy,
 310         .reset          = armada_plane_reset,
 311         .atomic_duplicate_state = armada_plane_duplicate_state,
 312         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 313 };
 314 
 315 int armada_drm_primary_plane_init(struct drm_device *drm,
 316         struct drm_plane *primary)
 317 {
 318         int ret;
 319 
 320         drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
 321 
 322         ret = drm_universal_plane_init(drm, primary, 0,
 323                                        &armada_primary_plane_funcs,
 324                                        armada_primary_formats,
 325                                        ARRAY_SIZE(armada_primary_formats),
 326                                        NULL,
 327                                        DRM_PLANE_TYPE_PRIMARY, NULL);
 328 
 329         return ret;
 330 }

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