root/drivers/gpu/drm/sun4i/sun8i_ui_layer.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun8i_ui_layer_enable
  2. sun8i_ui_layer_update_coord
  3. sun8i_ui_layer_update_formats
  4. sun8i_ui_layer_update_buffer
  5. sun8i_ui_layer_atomic_check
  6. sun8i_ui_layer_atomic_disable
  7. sun8i_ui_layer_atomic_update
  8. sun8i_ui_layer_init_one

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
   4  *
   5  * Based on sun4i_layer.h, which is:
   6  *   Copyright (C) 2015 Free Electrons
   7  *   Copyright (C) 2015 NextThing Co
   8  *
   9  *   Maxime Ripard <maxime.ripard@free-electrons.com>
  10  */
  11 
  12 #include <drm/drm_atomic.h>
  13 #include <drm/drm_atomic_helper.h>
  14 #include <drm/drm_crtc.h>
  15 #include <drm/drm_fb_cma_helper.h>
  16 #include <drm/drm_fourcc.h>
  17 #include <drm/drm_gem_cma_helper.h>
  18 #include <drm/drm_gem_framebuffer_helper.h>
  19 #include <drm/drm_plane_helper.h>
  20 #include <drm/drm_probe_helper.h>
  21 
  22 #include "sun8i_ui_layer.h"
  23 #include "sun8i_mixer.h"
  24 #include "sun8i_ui_scaler.h"
  25 
  26 static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
  27                                   int overlay, bool enable, unsigned int zpos,
  28                                   unsigned int old_zpos)
  29 {
  30         u32 val, bld_base, ch_base;
  31 
  32         bld_base = sun8i_blender_base(mixer);
  33         ch_base = sun8i_channel_base(mixer, channel);
  34 
  35         DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
  36                          enable ? "En" : "Dis", channel, overlay);
  37 
  38         if (enable)
  39                 val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
  40         else
  41                 val = 0;
  42 
  43         regmap_update_bits(mixer->engine.regs,
  44                            SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
  45                            SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
  46 
  47         if (!enable || zpos != old_zpos) {
  48                 regmap_update_bits(mixer->engine.regs,
  49                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  50                                    SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
  51                                    0);
  52 
  53                 regmap_update_bits(mixer->engine.regs,
  54                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
  55                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
  56                                    0);
  57         }
  58 
  59         if (enable) {
  60                 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
  61 
  62                 regmap_update_bits(mixer->engine.regs,
  63                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  64                                    val, val);
  65 
  66                 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
  67 
  68                 regmap_update_bits(mixer->engine.regs,
  69                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
  70                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
  71                                    val);
  72         }
  73 }
  74 
  75 static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
  76                                        int overlay, struct drm_plane *plane,
  77                                        unsigned int zpos)
  78 {
  79         struct drm_plane_state *state = plane->state;
  80         u32 src_w, src_h, dst_w, dst_h;
  81         u32 bld_base, ch_base;
  82         u32 outsize, insize;
  83         u32 hphase, vphase;
  84 
  85         DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
  86                          channel, overlay);
  87 
  88         bld_base = sun8i_blender_base(mixer);
  89         ch_base = sun8i_channel_base(mixer, channel);
  90 
  91         src_w = drm_rect_width(&state->src) >> 16;
  92         src_h = drm_rect_height(&state->src) >> 16;
  93         dst_w = drm_rect_width(&state->dst);
  94         dst_h = drm_rect_height(&state->dst);
  95 
  96         hphase = state->src.x1 & 0xffff;
  97         vphase = state->src.y1 & 0xffff;
  98 
  99         insize = SUN8I_MIXER_SIZE(src_w, src_h);
 100         outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
 101 
 102         if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
 103                 bool interlaced = false;
 104                 u32 val;
 105 
 106                 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
 107                                  dst_w, dst_h);
 108                 regmap_write(mixer->engine.regs,
 109                              SUN8I_MIXER_GLOBAL_SIZE,
 110                              outsize);
 111                 regmap_write(mixer->engine.regs,
 112                              SUN8I_MIXER_BLEND_OUTSIZE(bld_base), outsize);
 113 
 114                 if (state->crtc)
 115                         interlaced = state->crtc->state->adjusted_mode.flags
 116                                 & DRM_MODE_FLAG_INTERLACE;
 117 
 118                 if (interlaced)
 119                         val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
 120                 else
 121                         val = 0;
 122 
 123                 regmap_update_bits(mixer->engine.regs,
 124                                    SUN8I_MIXER_BLEND_OUTCTL(bld_base),
 125                                    SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
 126                                    val);
 127 
 128                 DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
 129                                  interlaced ? "on" : "off");
 130         }
 131 
 132         /* Set height and width */
 133         DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
 134                          state->src.x1 >> 16, state->src.y1 >> 16);
 135         DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
 136         regmap_write(mixer->engine.regs,
 137                      SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
 138                      insize);
 139         regmap_write(mixer->engine.regs,
 140                      SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
 141                      insize);
 142 
 143         if (insize != outsize || hphase || vphase) {
 144                 u32 hscale, vscale;
 145 
 146                 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
 147 
 148                 hscale = state->src_w / state->crtc_w;
 149                 vscale = state->src_h / state->crtc_h;
 150 
 151                 sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
 152                                       dst_h, hscale, vscale, hphase, vphase);
 153                 sun8i_ui_scaler_enable(mixer, channel, true);
 154         } else {
 155                 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
 156                 sun8i_ui_scaler_enable(mixer, channel, false);
 157         }
 158 
 159         /* Set base coordinates */
 160         DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 161                          state->dst.x1, state->dst.y1);
 162         DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
 163         regmap_write(mixer->engine.regs,
 164                      SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
 165                      SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
 166         regmap_write(mixer->engine.regs,
 167                      SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
 168                      outsize);
 169 
 170         return 0;
 171 }
 172 
 173 static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 174                                          int overlay, struct drm_plane *plane)
 175 {
 176         struct drm_plane_state *state = plane->state;
 177         const struct de2_fmt_info *fmt_info;
 178         u32 val, ch_base;
 179 
 180         ch_base = sun8i_channel_base(mixer, channel);
 181 
 182         fmt_info = sun8i_mixer_format_info(state->fb->format->format);
 183         if (!fmt_info || !fmt_info->rgb) {
 184                 DRM_DEBUG_DRIVER("Invalid format\n");
 185                 return -EINVAL;
 186         }
 187 
 188         val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
 189         regmap_update_bits(mixer->engine.regs,
 190                            SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
 191                            SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
 192 
 193         return 0;
 194 }
 195 
 196 static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
 197                                         int overlay, struct drm_plane *plane)
 198 {
 199         struct drm_plane_state *state = plane->state;
 200         struct drm_framebuffer *fb = state->fb;
 201         struct drm_gem_cma_object *gem;
 202         dma_addr_t paddr;
 203         u32 ch_base;
 204         int bpp;
 205 
 206         ch_base = sun8i_channel_base(mixer, channel);
 207 
 208         /* Get the physical address of the buffer in memory */
 209         gem = drm_fb_cma_get_gem_obj(fb, 0);
 210 
 211         DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
 212 
 213         /* Compute the start of the displayed memory */
 214         bpp = fb->format->cpp[0];
 215         paddr = gem->paddr + fb->offsets[0];
 216 
 217         /* Fixup framebuffer address for src coordinates */
 218         paddr += (state->src.x1 >> 16) * bpp;
 219         paddr += (state->src.y1 >> 16) * fb->pitches[0];
 220 
 221         /* Set the line width */
 222         DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
 223         regmap_write(mixer->engine.regs,
 224                      SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
 225                      fb->pitches[0]);
 226 
 227         DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
 228 
 229         regmap_write(mixer->engine.regs,
 230                      SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
 231                      lower_32_bits(paddr));
 232 
 233         return 0;
 234 }
 235 
 236 static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
 237                                        struct drm_plane_state *state)
 238 {
 239         struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
 240         struct drm_crtc *crtc = state->crtc;
 241         struct drm_crtc_state *crtc_state;
 242         int min_scale, max_scale;
 243 
 244         if (!crtc)
 245                 return 0;
 246 
 247         crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
 248         if (WARN_ON(!crtc_state))
 249                 return -EINVAL;
 250 
 251         min_scale = DRM_PLANE_HELPER_NO_SCALING;
 252         max_scale = DRM_PLANE_HELPER_NO_SCALING;
 253 
 254         if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
 255                 min_scale = SUN8I_UI_SCALER_SCALE_MIN;
 256                 max_scale = SUN8I_UI_SCALER_SCALE_MAX;
 257         }
 258 
 259         return drm_atomic_helper_check_plane_state(state, crtc_state,
 260                                                    min_scale, max_scale,
 261                                                    true, true);
 262 }
 263 
 264 static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane,
 265                                           struct drm_plane_state *old_state)
 266 {
 267         struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
 268         unsigned int old_zpos = old_state->normalized_zpos;
 269         struct sun8i_mixer *mixer = layer->mixer;
 270 
 271         sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
 272                               old_zpos);
 273 }
 274 
 275 static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
 276                                          struct drm_plane_state *old_state)
 277 {
 278         struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
 279         unsigned int zpos = plane->state->normalized_zpos;
 280         unsigned int old_zpos = old_state->normalized_zpos;
 281         struct sun8i_mixer *mixer = layer->mixer;
 282 
 283         if (!plane->state->visible) {
 284                 sun8i_ui_layer_enable(mixer, layer->channel,
 285                                       layer->overlay, false, 0, old_zpos);
 286                 return;
 287         }
 288 
 289         sun8i_ui_layer_update_coord(mixer, layer->channel,
 290                                     layer->overlay, plane, zpos);
 291         sun8i_ui_layer_update_formats(mixer, layer->channel,
 292                                       layer->overlay, plane);
 293         sun8i_ui_layer_update_buffer(mixer, layer->channel,
 294                                      layer->overlay, plane);
 295         sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay,
 296                               true, zpos, old_zpos);
 297 }
 298 
 299 static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
 300         .prepare_fb     = drm_gem_fb_prepare_fb,
 301         .atomic_check   = sun8i_ui_layer_atomic_check,
 302         .atomic_disable = sun8i_ui_layer_atomic_disable,
 303         .atomic_update  = sun8i_ui_layer_atomic_update,
 304 };
 305 
 306 static const struct drm_plane_funcs sun8i_ui_layer_funcs = {
 307         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
 308         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 309         .destroy                = drm_plane_cleanup,
 310         .disable_plane          = drm_atomic_helper_disable_plane,
 311         .reset                  = drm_atomic_helper_plane_reset,
 312         .update_plane           = drm_atomic_helper_update_plane,
 313 };
 314 
 315 static const u32 sun8i_ui_layer_formats[] = {
 316         DRM_FORMAT_ABGR1555,
 317         DRM_FORMAT_ABGR4444,
 318         DRM_FORMAT_ABGR8888,
 319         DRM_FORMAT_ARGB1555,
 320         DRM_FORMAT_ARGB4444,
 321         DRM_FORMAT_ARGB8888,
 322         DRM_FORMAT_BGR565,
 323         DRM_FORMAT_BGR888,
 324         DRM_FORMAT_BGRA5551,
 325         DRM_FORMAT_BGRA4444,
 326         DRM_FORMAT_BGRA8888,
 327         DRM_FORMAT_BGRX8888,
 328         DRM_FORMAT_RGB565,
 329         DRM_FORMAT_RGB888,
 330         DRM_FORMAT_RGBA4444,
 331         DRM_FORMAT_RGBA5551,
 332         DRM_FORMAT_RGBA8888,
 333         DRM_FORMAT_RGBX8888,
 334         DRM_FORMAT_XBGR8888,
 335         DRM_FORMAT_XRGB8888,
 336 };
 337 
 338 struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
 339                                                struct sun8i_mixer *mixer,
 340                                                int index)
 341 {
 342         enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
 343         int channel = mixer->cfg->vi_num + index;
 344         struct sun8i_ui_layer *layer;
 345         unsigned int plane_cnt;
 346         int ret;
 347 
 348         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
 349         if (!layer)
 350                 return ERR_PTR(-ENOMEM);
 351 
 352         if (index == 0)
 353                 type = DRM_PLANE_TYPE_PRIMARY;
 354 
 355         /* possible crtcs are set later */
 356         ret = drm_universal_plane_init(drm, &layer->plane, 0,
 357                                        &sun8i_ui_layer_funcs,
 358                                        sun8i_ui_layer_formats,
 359                                        ARRAY_SIZE(sun8i_ui_layer_formats),
 360                                        NULL, type, NULL);
 361         if (ret) {
 362                 dev_err(drm->dev, "Couldn't initialize layer\n");
 363                 return ERR_PTR(ret);
 364         }
 365 
 366         plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
 367 
 368         ret = drm_plane_create_zpos_property(&layer->plane, channel,
 369                                              0, plane_cnt - 1);
 370         if (ret) {
 371                 dev_err(drm->dev, "Couldn't add zpos property\n");
 372                 return ERR_PTR(ret);
 373         }
 374 
 375         drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
 376         layer->mixer = mixer;
 377         layer->channel = channel;
 378         layer->overlay = 0;
 379 
 380         return layer;
 381 }

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