root/drivers/gpu/drm/arm/display/komeda/komeda_kms.c

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

DEFINITIONS

This source file includes following definitions.
  1. komeda_gem_cma_dumb_create
  2. komeda_kms_irq_handler
  3. komeda_kms_commit_tail
  4. komeda_plane_state_list_add
  5. komeda_crtc_normalize_zpos
  6. komeda_kms_check
  7. komeda_kms_mode_config_init
  8. komeda_kms_attach
  9. komeda_kms_detach

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
   4  * Author: James.Qian.Wang <james.qian.wang@arm.com>
   5  *
   6  */
   7 #include <linux/component.h>
   8 #include <linux/interrupt.h>
   9 
  10 #include <drm/drm_atomic.h>
  11 #include <drm/drm_atomic_helper.h>
  12 #include <drm/drm_drv.h>
  13 #include <drm/drm_fb_helper.h>
  14 #include <drm/drm_gem_cma_helper.h>
  15 #include <drm/drm_gem_framebuffer_helper.h>
  16 #include <drm/drm_irq.h>
  17 #include <drm/drm_probe_helper.h>
  18 #include <drm/drm_vblank.h>
  19 
  20 #include "komeda_dev.h"
  21 #include "komeda_framebuffer.h"
  22 #include "komeda_kms.h"
  23 
  24 DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
  25 
  26 static int komeda_gem_cma_dumb_create(struct drm_file *file,
  27                                       struct drm_device *dev,
  28                                       struct drm_mode_create_dumb *args)
  29 {
  30         struct komeda_dev *mdev = dev->dev_private;
  31         u32 pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
  32 
  33         args->pitch = ALIGN(pitch, mdev->chip.bus_width);
  34 
  35         return drm_gem_cma_dumb_create_internal(file, dev, args);
  36 }
  37 
  38 static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
  39 {
  40         struct drm_device *drm = data;
  41         struct komeda_dev *mdev = drm->dev_private;
  42         struct komeda_kms_dev *kms = to_kdev(drm);
  43         struct komeda_events evts;
  44         irqreturn_t status;
  45         u32 i;
  46 
  47         /* Call into the CHIP to recognize events */
  48         memset(&evts, 0, sizeof(evts));
  49         status = mdev->funcs->irq_handler(mdev, &evts);
  50 
  51         /* Notify the crtc to handle the events */
  52         for (i = 0; i < kms->n_crtcs; i++)
  53                 komeda_crtc_handle_event(&kms->crtcs[i], &evts);
  54 
  55         return status;
  56 }
  57 
  58 static struct drm_driver komeda_kms_driver = {
  59         .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  60         .lastclose                      = drm_fb_helper_lastclose,
  61         .gem_free_object_unlocked       = drm_gem_cma_free_object,
  62         .gem_vm_ops                     = &drm_gem_cma_vm_ops,
  63         .dumb_create                    = komeda_gem_cma_dumb_create,
  64         .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
  65         .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
  66         .gem_prime_get_sg_table         = drm_gem_cma_prime_get_sg_table,
  67         .gem_prime_import_sg_table      = drm_gem_cma_prime_import_sg_table,
  68         .gem_prime_vmap                 = drm_gem_cma_prime_vmap,
  69         .gem_prime_vunmap               = drm_gem_cma_prime_vunmap,
  70         .gem_prime_mmap                 = drm_gem_cma_prime_mmap,
  71         .fops = &komeda_cma_fops,
  72         .name = "komeda",
  73         .desc = "Arm Komeda Display Processor driver",
  74         .date = "20181101",
  75         .major = 0,
  76         .minor = 1,
  77 };
  78 
  79 static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
  80 {
  81         struct drm_device *dev = old_state->dev;
  82 
  83         drm_atomic_helper_commit_modeset_disables(dev, old_state);
  84 
  85         drm_atomic_helper_commit_planes(dev, old_state,
  86                                         DRM_PLANE_COMMIT_ACTIVE_ONLY);
  87 
  88         drm_atomic_helper_commit_modeset_enables(dev, old_state);
  89 
  90         drm_atomic_helper_wait_for_flip_done(dev, old_state);
  91 
  92         drm_atomic_helper_commit_hw_done(old_state);
  93 
  94         drm_atomic_helper_cleanup_planes(dev, old_state);
  95 }
  96 
  97 static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
  98         .atomic_commit_tail = komeda_kms_commit_tail,
  99 };
 100 
 101 static int komeda_plane_state_list_add(struct drm_plane_state *plane_st,
 102                                        struct list_head *zorder_list)
 103 {
 104         struct komeda_plane_state *new = to_kplane_st(plane_st);
 105         struct komeda_plane_state *node, *last;
 106 
 107         last = list_empty(zorder_list) ?
 108                NULL : list_last_entry(zorder_list, typeof(*last), zlist_node);
 109 
 110         /* Considering the list sequence is zpos increasing, so if list is empty
 111          * or the zpos of new node bigger than the last node in list, no need
 112          * loop and just insert the new one to the tail of the list.
 113          */
 114         if (!last || (new->base.zpos > last->base.zpos)) {
 115                 list_add_tail(&new->zlist_node, zorder_list);
 116                 return 0;
 117         }
 118 
 119         /* Build the list by zpos increasing */
 120         list_for_each_entry(node, zorder_list, zlist_node) {
 121                 if (new->base.zpos < node->base.zpos) {
 122                         list_add_tail(&new->zlist_node, &node->zlist_node);
 123                         break;
 124                 } else if (node->base.zpos == new->base.zpos) {
 125                         struct drm_plane *a = node->base.plane;
 126                         struct drm_plane *b = new->base.plane;
 127 
 128                         /* Komeda doesn't support setting a same zpos for
 129                          * different planes.
 130                          */
 131                         DRM_DEBUG_ATOMIC("PLANE: %s and PLANE: %s are configured same zpos: %d.\n",
 132                                          a->name, b->name, node->base.zpos);
 133                         return -EINVAL;
 134                 }
 135         }
 136 
 137         return 0;
 138 }
 139 
 140 static int komeda_crtc_normalize_zpos(struct drm_crtc *crtc,
 141                                       struct drm_crtc_state *crtc_st)
 142 {
 143         struct drm_atomic_state *state = crtc_st->state;
 144         struct komeda_crtc *kcrtc = to_kcrtc(crtc);
 145         struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_st);
 146         struct komeda_plane_state *kplane_st;
 147         struct drm_plane_state *plane_st;
 148         struct drm_plane *plane;
 149         struct list_head zorder_list;
 150         int order = 0, err;
 151 
 152         DRM_DEBUG_ATOMIC("[CRTC:%d:%s] calculating normalized zpos values\n",
 153                          crtc->base.id, crtc->name);
 154 
 155         INIT_LIST_HEAD(&zorder_list);
 156 
 157         /* This loop also added all effected planes into the new state */
 158         drm_for_each_plane_mask(plane, crtc->dev, crtc_st->plane_mask) {
 159                 plane_st = drm_atomic_get_plane_state(state, plane);
 160                 if (IS_ERR(plane_st))
 161                         return PTR_ERR(plane_st);
 162 
 163                 /* Build a list by zpos increasing */
 164                 err = komeda_plane_state_list_add(plane_st, &zorder_list);
 165                 if (err)
 166                         return err;
 167         }
 168 
 169         kcrtc_st->max_slave_zorder = 0;
 170 
 171         list_for_each_entry(kplane_st, &zorder_list, zlist_node) {
 172                 plane_st = &kplane_st->base;
 173                 plane = plane_st->plane;
 174 
 175                 plane_st->normalized_zpos = order++;
 176                 /* When layer_split has been enabled, one plane will be handled
 177                  * by two separated komeda layers (left/right), which may needs
 178                  * two zorders.
 179                  * - zorder: for left_layer for left display part.
 180                  * - zorder + 1: will be reserved for right layer.
 181                  */
 182                 if (to_kplane_st(plane_st)->layer_split)
 183                         order++;
 184 
 185                 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] zpos:%d, normalized zpos: %d\n",
 186                                  plane->base.id, plane->name,
 187                                  plane_st->zpos, plane_st->normalized_zpos);
 188 
 189                 /* calculate max slave zorder */
 190                 if (has_bit(drm_plane_index(plane), kcrtc->slave_planes))
 191                         kcrtc_st->max_slave_zorder =
 192                                 max(plane_st->normalized_zpos,
 193                                     kcrtc_st->max_slave_zorder);
 194         }
 195 
 196         crtc_st->zpos_changed = true;
 197 
 198         return 0;
 199 }
 200 
 201 static int komeda_kms_check(struct drm_device *dev,
 202                             struct drm_atomic_state *state)
 203 {
 204         struct drm_crtc *crtc;
 205         struct drm_crtc_state *new_crtc_st;
 206         int i, err;
 207 
 208         err = drm_atomic_helper_check_modeset(dev, state);
 209         if (err)
 210                 return err;
 211 
 212         /* Komeda need to re-calculate resource assumption in every commit
 213          * so need to add all affected_planes (even unchanged) to
 214          * drm_atomic_state.
 215          */
 216         for_each_new_crtc_in_state(state, crtc, new_crtc_st, i) {
 217                 err = drm_atomic_add_affected_planes(state, crtc);
 218                 if (err)
 219                         return err;
 220 
 221                 err = komeda_crtc_normalize_zpos(crtc, new_crtc_st);
 222                 if (err)
 223                         return err;
 224         }
 225 
 226         err = drm_atomic_helper_check_planes(dev, state);
 227         if (err)
 228                 return err;
 229 
 230         return 0;
 231 }
 232 
 233 static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
 234         .fb_create              = komeda_fb_create,
 235         .atomic_check           = komeda_kms_check,
 236         .atomic_commit          = drm_atomic_helper_commit,
 237 };
 238 
 239 static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
 240                                         struct komeda_dev *mdev)
 241 {
 242         struct drm_mode_config *config = &kms->base.mode_config;
 243 
 244         drm_mode_config_init(&kms->base);
 245 
 246         komeda_kms_setup_crtcs(kms, mdev);
 247 
 248         /* Get value from dev */
 249         config->min_width       = 0;
 250         config->min_height      = 0;
 251         config->max_width       = 4096;
 252         config->max_height      = 4096;
 253         config->allow_fb_modifiers = true;
 254 
 255         config->funcs = &komeda_mode_config_funcs;
 256         config->helper_private = &komeda_mode_config_helpers;
 257 }
 258 
 259 struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
 260 {
 261         struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
 262         struct drm_device *drm;
 263         int err;
 264 
 265         if (!kms)
 266                 return ERR_PTR(-ENOMEM);
 267 
 268         drm = &kms->base;
 269         err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
 270         if (err)
 271                 goto free_kms;
 272 
 273         drm->dev_private = mdev;
 274 
 275         komeda_kms_mode_config_init(kms, mdev);
 276 
 277         err = komeda_kms_add_private_objs(kms, mdev);
 278         if (err)
 279                 goto cleanup_mode_config;
 280 
 281         err = komeda_kms_add_planes(kms, mdev);
 282         if (err)
 283                 goto cleanup_mode_config;
 284 
 285         err = drm_vblank_init(drm, kms->n_crtcs);
 286         if (err)
 287                 goto cleanup_mode_config;
 288 
 289         err = komeda_kms_add_crtcs(kms, mdev);
 290         if (err)
 291                 goto cleanup_mode_config;
 292 
 293         err = komeda_kms_add_wb_connectors(kms, mdev);
 294         if (err)
 295                 goto cleanup_mode_config;
 296 
 297         err = component_bind_all(mdev->dev, kms);
 298         if (err)
 299                 goto cleanup_mode_config;
 300 
 301         drm_mode_config_reset(drm);
 302 
 303         err = devm_request_irq(drm->dev, mdev->irq,
 304                                komeda_kms_irq_handler, IRQF_SHARED,
 305                                drm->driver->name, drm);
 306         if (err)
 307                 goto free_component_binding;
 308 
 309         err = mdev->funcs->enable_irq(mdev);
 310         if (err)
 311                 goto free_component_binding;
 312 
 313         drm->irq_enabled = true;
 314 
 315         drm_kms_helper_poll_init(drm);
 316 
 317         err = drm_dev_register(drm, 0);
 318         if (err)
 319                 goto free_interrupts;
 320 
 321         return kms;
 322 
 323 free_interrupts:
 324         drm_kms_helper_poll_fini(drm);
 325         drm->irq_enabled = false;
 326         mdev->funcs->disable_irq(mdev);
 327 free_component_binding:
 328         component_unbind_all(mdev->dev, drm);
 329 cleanup_mode_config:
 330         drm_mode_config_cleanup(drm);
 331         komeda_kms_cleanup_private_objs(kms);
 332         drm->dev_private = NULL;
 333         drm_dev_put(drm);
 334 free_kms:
 335         kfree(kms);
 336         return ERR_PTR(err);
 337 }
 338 
 339 void komeda_kms_detach(struct komeda_kms_dev *kms)
 340 {
 341         struct drm_device *drm = &kms->base;
 342         struct komeda_dev *mdev = drm->dev_private;
 343 
 344         drm_dev_unregister(drm);
 345         drm_kms_helper_poll_fini(drm);
 346         drm_atomic_helper_shutdown(drm);
 347         drm->irq_enabled = false;
 348         mdev->funcs->disable_irq(mdev);
 349         component_unbind_all(mdev->dev, drm);
 350         drm_mode_config_cleanup(drm);
 351         komeda_kms_cleanup_private_objs(kms);
 352         drm->dev_private = NULL;
 353         drm_dev_put(drm);
 354 }

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