brintos

brintos / linux-shallow public Read only

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