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