cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

omap_plane.c (16933B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
      4 * Author: Rob Clark <rob.clark@linaro.org>
      5 */
      6
      7#include <drm/drm_atomic.h>
      8#include <drm/drm_atomic_helper.h>
      9#include <drm/drm_gem_atomic_helper.h>
     10#include <drm/drm_plane_helper.h>
     11#include <drm/drm_fourcc.h>
     12
     13#include "omap_dmm_tiler.h"
     14#include "omap_drv.h"
     15
     16/*
     17 * plane funcs
     18 */
     19
     20#define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base)
     21
     22struct omap_plane_state {
     23	/* Must be first. */
     24	struct drm_plane_state base;
     25
     26	struct omap_hw_overlay *overlay;
     27	struct omap_hw_overlay *r_overlay;  /* right overlay */
     28};
     29
     30#define to_omap_plane(x) container_of(x, struct omap_plane, base)
     31
     32struct omap_plane {
     33	struct drm_plane base;
     34	enum omap_plane_id id;
     35};
     36
     37bool is_omap_plane_dual_overlay(struct drm_plane_state *state)
     38{
     39	struct omap_plane_state *omap_state = to_omap_plane_state(state);
     40
     41	return !!omap_state->r_overlay;
     42}
     43
     44static int omap_plane_prepare_fb(struct drm_plane *plane,
     45				 struct drm_plane_state *new_state)
     46{
     47	if (!new_state->fb)
     48		return 0;
     49
     50	drm_gem_plane_helper_prepare_fb(plane, new_state);
     51
     52	return omap_framebuffer_pin(new_state->fb);
     53}
     54
     55static void omap_plane_cleanup_fb(struct drm_plane *plane,
     56				  struct drm_plane_state *old_state)
     57{
     58	if (old_state->fb)
     59		omap_framebuffer_unpin(old_state->fb);
     60}
     61
     62static void omap_plane_atomic_update(struct drm_plane *plane,
     63				     struct drm_atomic_state *state)
     64{
     65	struct omap_drm_private *priv = plane->dev->dev_private;
     66	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
     67									   plane);
     68	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
     69									   plane);
     70	struct omap_plane_state *new_omap_state;
     71	struct omap_plane_state *old_omap_state;
     72	struct omap_overlay_info info, r_info;
     73	enum omap_plane_id ovl_id, r_ovl_id;
     74	int ret;
     75	bool dual_ovl;
     76
     77	new_omap_state = to_omap_plane_state(new_state);
     78	old_omap_state = to_omap_plane_state(old_state);
     79
     80	dual_ovl = is_omap_plane_dual_overlay(new_state);
     81
     82	/* Cleanup previously held overlay if needed */
     83	if (old_omap_state->overlay)
     84		omap_overlay_update_state(priv, old_omap_state->overlay);
     85	if (old_omap_state->r_overlay)
     86		omap_overlay_update_state(priv, old_omap_state->r_overlay);
     87
     88	if (!new_omap_state->overlay) {
     89		DBG("[PLANE:%d:%s] no overlay attached", plane->base.id, plane->name);
     90		return;
     91	}
     92
     93	ovl_id = new_omap_state->overlay->id;
     94	DBG("%s, crtc=%p fb=%p", plane->name, new_state->crtc,
     95	    new_state->fb);
     96
     97	memset(&info, 0, sizeof(info));
     98	info.rotation_type = OMAP_DSS_ROT_NONE;
     99	info.rotation = DRM_MODE_ROTATE_0;
    100	info.global_alpha = new_state->alpha >> 8;
    101	info.zorder = new_state->normalized_zpos;
    102	if (new_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
    103		info.pre_mult_alpha = 1;
    104	else
    105		info.pre_mult_alpha = 0;
    106	info.color_encoding = new_state->color_encoding;
    107	info.color_range = new_state->color_range;
    108
    109	r_info = info;
    110
    111	/* update scanout: */
    112	omap_framebuffer_update_scanout(new_state->fb, new_state, &info,
    113					dual_ovl ? &r_info : NULL);
    114
    115	DBG("%s: %dx%d -> %dx%d (%d)",
    116			new_omap_state->overlay->name, info.width, info.height,
    117			info.out_width, info.out_height, info.screen_width);
    118	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
    119			&info.paddr, &info.p_uv_addr);
    120
    121	if (dual_ovl) {
    122		r_ovl_id = new_omap_state->r_overlay->id;
    123		/*
    124		 * If the current plane uses 2 hw planes the very next
    125		 * zorder is used by the r_overlay so we just use the
    126		 * main overlay zorder + 1
    127		 */
    128		r_info.zorder = info.zorder + 1;
    129
    130		DBG("%s: %dx%d -> %dx%d (%d)",
    131		    new_omap_state->r_overlay->name,
    132		    r_info.width, r_info.height,
    133		    r_info.out_width, r_info.out_height, r_info.screen_width);
    134		DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y,
    135		    &r_info.paddr, &r_info.p_uv_addr);
    136	}
    137
    138	/* and finally, update omapdss: */
    139	ret = dispc_ovl_setup(priv->dispc, ovl_id, &info,
    140			      omap_crtc_timings(new_state->crtc), false,
    141			      omap_crtc_channel(new_state->crtc));
    142	if (ret) {
    143		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
    144			plane->name);
    145		dispc_ovl_enable(priv->dispc, ovl_id, false);
    146		return;
    147	}
    148
    149	dispc_ovl_enable(priv->dispc, ovl_id, true);
    150
    151	if (dual_ovl) {
    152		ret = dispc_ovl_setup(priv->dispc, r_ovl_id, &r_info,
    153				      omap_crtc_timings(new_state->crtc), false,
    154				      omap_crtc_channel(new_state->crtc));
    155		if (ret) {
    156			dev_err(plane->dev->dev, "Failed to setup plane right-overlay %s\n",
    157				plane->name);
    158			dispc_ovl_enable(priv->dispc, r_ovl_id, false);
    159			dispc_ovl_enable(priv->dispc, ovl_id, false);
    160			return;
    161		}
    162
    163		dispc_ovl_enable(priv->dispc, r_ovl_id, true);
    164	}
    165}
    166
    167static void omap_plane_atomic_disable(struct drm_plane *plane,
    168				      struct drm_atomic_state *state)
    169{
    170	struct omap_drm_private *priv = plane->dev->dev_private;
    171	struct omap_plane *omap_plane = to_omap_plane(plane);
    172	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
    173									   plane);
    174	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    175									   plane);
    176	struct omap_plane_state *new_omap_state;
    177	struct omap_plane_state *old_omap_state;
    178
    179	new_omap_state = to_omap_plane_state(new_state);
    180	old_omap_state = to_omap_plane_state(old_state);
    181
    182	if (!old_omap_state->overlay)
    183		return;
    184
    185	new_state->rotation = DRM_MODE_ROTATE_0;
    186	new_state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : omap_plane->id;
    187
    188	omap_overlay_update_state(priv, old_omap_state->overlay);
    189	new_omap_state->overlay = NULL;
    190
    191	if (is_omap_plane_dual_overlay(old_state)) {
    192		omap_overlay_update_state(priv, old_omap_state->r_overlay);
    193		new_omap_state->r_overlay = NULL;
    194	}
    195}
    196
    197#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
    198
    199static int omap_plane_atomic_check(struct drm_plane *plane,
    200				   struct drm_atomic_state *state)
    201{
    202	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
    203										 plane);
    204	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
    205										 plane);
    206	struct omap_drm_private *priv = plane->dev->dev_private;
    207	struct omap_plane_state *omap_state = to_omap_plane_state(new_plane_state);
    208	struct omap_global_state *omap_overlay_global_state;
    209	struct drm_crtc_state *crtc_state;
    210	bool new_r_hw_overlay = false;
    211	bool new_hw_overlay = false;
    212	u32 max_width, max_height;
    213	struct drm_crtc *crtc;
    214	u16 width, height;
    215	u32 caps = 0;
    216	u32 fourcc;
    217	int ret;
    218
    219	omap_overlay_global_state = omap_get_global_state(state);
    220	if (IS_ERR(omap_overlay_global_state))
    221		return PTR_ERR(omap_overlay_global_state);
    222
    223	dispc_ovl_get_max_size(priv->dispc, &width, &height);
    224	max_width = width << 16;
    225	max_height = height << 16;
    226
    227	crtc = new_plane_state->crtc ? new_plane_state->crtc : plane->state->crtc;
    228	if (!crtc)
    229		return 0;
    230
    231	crtc_state = drm_atomic_get_existing_crtc_state(state, crtc);
    232	/* we should have a crtc state if the plane is attached to a crtc */
    233	if (WARN_ON(!crtc_state))
    234		return 0;
    235
    236	/*
    237	 * Note: these are just sanity checks to filter out totally bad scaling
    238	 * factors. The real limits must be calculated case by case, and
    239	 * unfortunately we currently do those checks only at the commit
    240	 * phase in dispc.
    241	 */
    242	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
    243						  FRAC_16_16(1, 8), FRAC_16_16(8, 1),
    244						  true, true);
    245	if (ret)
    246		return ret;
    247
    248	DBG("%s: visible %d -> %d", plane->name,
    249	    old_plane_state->visible, new_plane_state->visible);
    250
    251	if (!new_plane_state->visible) {
    252		omap_overlay_release(state, omap_state->overlay);
    253		omap_overlay_release(state, omap_state->r_overlay);
    254		omap_state->overlay = NULL;
    255		omap_state->r_overlay = NULL;
    256		return 0;
    257	}
    258
    259	if (new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0)
    260		return -EINVAL;
    261
    262	if (new_plane_state->crtc_x + new_plane_state->crtc_w > crtc_state->adjusted_mode.hdisplay)
    263		return -EINVAL;
    264
    265	if (new_plane_state->crtc_y + new_plane_state->crtc_h > crtc_state->adjusted_mode.vdisplay)
    266		return -EINVAL;
    267
    268	/* Make sure dimensions are within bounds. */
    269	if (new_plane_state->src_h > max_height || new_plane_state->crtc_h > height)
    270		return -EINVAL;
    271
    272
    273	if (new_plane_state->src_w > max_width || new_plane_state->crtc_w > width) {
    274		bool is_fourcc_yuv = new_plane_state->fb->format->is_yuv;
    275
    276		if (is_fourcc_yuv && (((new_plane_state->src_w >> 16) / 2 & 1) ||
    277				      new_plane_state->crtc_w / 2 & 1)) {
    278			/*
    279			 * When calculating the split overlay width
    280			 * and it yield an odd value we will need to adjust
    281			 * the indivual width +/- 1. So make sure it fits
    282			 */
    283			if (new_plane_state->src_w <= ((2 * width - 1) << 16) &&
    284			    new_plane_state->crtc_w <= (2 * width - 1))
    285				new_r_hw_overlay = true;
    286			else
    287				return -EINVAL;
    288		} else {
    289			if (new_plane_state->src_w <= (2 * max_width) &&
    290			    new_plane_state->crtc_w <= (2 * width))
    291				new_r_hw_overlay = true;
    292			else
    293				return -EINVAL;
    294		}
    295	}
    296
    297	if (new_plane_state->rotation != DRM_MODE_ROTATE_0 &&
    298	    !omap_framebuffer_supports_rotation(new_plane_state->fb))
    299		return -EINVAL;
    300
    301	if ((new_plane_state->src_w >> 16) != new_plane_state->crtc_w ||
    302	    (new_plane_state->src_h >> 16) != new_plane_state->crtc_h)
    303		caps |= OMAP_DSS_OVL_CAP_SCALE;
    304
    305	fourcc = new_plane_state->fb->format->format;
    306
    307	/*
    308	 * (re)allocate hw overlay if we don't have one or
    309	 * there is a caps mismatch
    310	 */
    311	if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) {
    312		new_hw_overlay = true;
    313	} else {
    314		/* check supported format */
    315		if (!dispc_ovl_color_mode_supported(priv->dispc, omap_state->overlay->id,
    316						    fourcc))
    317			new_hw_overlay = true;
    318	}
    319
    320	/*
    321	 * check if we need two overlays and only have 1 or
    322	 * if we had 2 overlays but will only need 1
    323	 */
    324	if ((new_r_hw_overlay && !omap_state->r_overlay) ||
    325	    (!new_r_hw_overlay && omap_state->r_overlay))
    326		new_hw_overlay = true;
    327
    328	if (new_hw_overlay) {
    329		struct omap_hw_overlay *old_ovl = omap_state->overlay;
    330		struct omap_hw_overlay *old_r_ovl = omap_state->r_overlay;
    331		struct omap_hw_overlay *new_ovl = NULL;
    332		struct omap_hw_overlay *new_r_ovl = NULL;
    333
    334		omap_overlay_release(state, old_ovl);
    335		omap_overlay_release(state, old_r_ovl);
    336
    337		ret = omap_overlay_assign(state, plane, caps, fourcc, &new_ovl,
    338					  new_r_hw_overlay ? &new_r_ovl : NULL);
    339		if (ret) {
    340			DBG("%s: failed to assign hw_overlay", plane->name);
    341			omap_state->overlay = NULL;
    342			omap_state->r_overlay = NULL;
    343			return ret;
    344		}
    345
    346		omap_state->overlay = new_ovl;
    347		if (new_r_hw_overlay)
    348			omap_state->r_overlay = new_r_ovl;
    349		else
    350			omap_state->r_overlay = NULL;
    351	}
    352
    353	DBG("plane: %s overlay_id: %d", plane->name, omap_state->overlay->id);
    354
    355	if (omap_state->r_overlay)
    356		DBG("plane: %s r_overlay_id: %d", plane->name, omap_state->r_overlay->id);
    357
    358	return 0;
    359}
    360
    361static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
    362	.prepare_fb = omap_plane_prepare_fb,
    363	.cleanup_fb = omap_plane_cleanup_fb,
    364	.atomic_check = omap_plane_atomic_check,
    365	.atomic_update = omap_plane_atomic_update,
    366	.atomic_disable = omap_plane_atomic_disable,
    367};
    368
    369static void omap_plane_destroy(struct drm_plane *plane)
    370{
    371	struct omap_plane *omap_plane = to_omap_plane(plane);
    372
    373	DBG("%s", plane->name);
    374
    375	drm_plane_cleanup(plane);
    376
    377	kfree(omap_plane);
    378}
    379
    380/* helper to install properties which are common to planes and crtcs */
    381void omap_plane_install_properties(struct drm_plane *plane,
    382		struct drm_mode_object *obj)
    383{
    384	struct drm_device *dev = plane->dev;
    385	struct omap_drm_private *priv = dev->dev_private;
    386
    387	if (priv->has_dmm) {
    388		if (!plane->rotation_property)
    389			drm_plane_create_rotation_property(plane,
    390							   DRM_MODE_ROTATE_0,
    391							   DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
    392							   DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
    393							   DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
    394
    395		/* Attach the rotation property also to the crtc object */
    396		if (plane->rotation_property && obj != &plane->base)
    397			drm_object_attach_property(obj, plane->rotation_property,
    398						   DRM_MODE_ROTATE_0);
    399	}
    400
    401	drm_object_attach_property(obj, priv->zorder_prop, 0);
    402}
    403
    404static void omap_plane_reset(struct drm_plane *plane)
    405{
    406	struct omap_plane_state *omap_state;
    407
    408	if (plane->state)
    409		drm_atomic_helper_plane_destroy_state(plane, plane->state);
    410
    411	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
    412	if (!omap_state)
    413		return;
    414
    415	__drm_atomic_helper_plane_reset(plane, &omap_state->base);
    416}
    417
    418static struct drm_plane_state *
    419omap_plane_atomic_duplicate_state(struct drm_plane *plane)
    420{
    421	struct omap_plane_state *state, *current_state;
    422
    423	if (WARN_ON(!plane->state))
    424		return NULL;
    425
    426	current_state = to_omap_plane_state(plane->state);
    427
    428	state = kmalloc(sizeof(*state), GFP_KERNEL);
    429	if (!state)
    430		return NULL;
    431
    432	__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
    433
    434	state->overlay = current_state->overlay;
    435	state->r_overlay = current_state->r_overlay;
    436
    437	return &state->base;
    438}
    439
    440static void omap_plane_atomic_print_state(struct drm_printer *p,
    441					  const struct drm_plane_state *state)
    442{
    443	struct omap_plane_state *omap_state = to_omap_plane_state(state);
    444
    445	if (omap_state->overlay)
    446		drm_printf(p, "\toverlay=%s (caps=0x%x)\n",
    447			   omap_state->overlay->name,
    448			   omap_state->overlay->caps);
    449	else
    450		drm_printf(p, "\toverlay=None\n");
    451	if (omap_state->r_overlay)
    452		drm_printf(p, "\tr_overlay=%s (caps=0x%x)\n",
    453			   omap_state->r_overlay->name,
    454			   omap_state->r_overlay->caps);
    455	else
    456		drm_printf(p, "\tr_overlay=None\n");
    457}
    458
    459static int omap_plane_atomic_set_property(struct drm_plane *plane,
    460					  struct drm_plane_state *state,
    461					  struct drm_property *property,
    462					  u64 val)
    463{
    464	struct omap_drm_private *priv = plane->dev->dev_private;
    465
    466	if (property == priv->zorder_prop)
    467		state->zpos = val;
    468	else
    469		return -EINVAL;
    470
    471	return 0;
    472}
    473
    474static int omap_plane_atomic_get_property(struct drm_plane *plane,
    475					  const struct drm_plane_state *state,
    476					  struct drm_property *property,
    477					  u64 *val)
    478{
    479	struct omap_drm_private *priv = plane->dev->dev_private;
    480
    481	if (property == priv->zorder_prop)
    482		*val = state->zpos;
    483	else
    484		return -EINVAL;
    485
    486	return 0;
    487}
    488
    489static const struct drm_plane_funcs omap_plane_funcs = {
    490	.update_plane = drm_atomic_helper_update_plane,
    491	.disable_plane = drm_atomic_helper_disable_plane,
    492	.reset = omap_plane_reset,
    493	.destroy = omap_plane_destroy,
    494	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
    495	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
    496	.atomic_set_property = omap_plane_atomic_set_property,
    497	.atomic_get_property = omap_plane_atomic_get_property,
    498	.atomic_print_state = omap_plane_atomic_print_state,
    499};
    500
    501static bool omap_plane_supports_yuv(struct drm_plane *plane)
    502{
    503	struct omap_drm_private *priv = plane->dev->dev_private;
    504	struct omap_plane *omap_plane = to_omap_plane(plane);
    505	const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
    506	u32 i;
    507
    508	for (i = 0; formats[i]; i++)
    509		if (formats[i] == DRM_FORMAT_YUYV ||
    510		    formats[i] == DRM_FORMAT_UYVY ||
    511		    formats[i] == DRM_FORMAT_NV12)
    512			return true;
    513
    514	return false;
    515}
    516
    517/* initialize plane */
    518struct drm_plane *omap_plane_init(struct drm_device *dev,
    519		int idx, enum drm_plane_type type,
    520		u32 possible_crtcs)
    521{
    522	struct omap_drm_private *priv = dev->dev_private;
    523	unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
    524	struct drm_plane *plane;
    525	struct omap_plane *omap_plane;
    526	unsigned int zpos;
    527	int ret;
    528	u32 nformats;
    529	const u32 *formats;
    530
    531	if (WARN_ON(idx >= num_planes))
    532		return ERR_PTR(-EINVAL);
    533
    534	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
    535	if (!omap_plane)
    536		return ERR_PTR(-ENOMEM);
    537
    538	omap_plane->id = idx;
    539
    540	DBG("%d: type=%d", omap_plane->id, type);
    541	DBG("	crtc_mask: 0x%04x", possible_crtcs);
    542
    543	formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
    544	for (nformats = 0; formats[nformats]; ++nformats)
    545		;
    546
    547	plane = &omap_plane->base;
    548
    549	ret = drm_universal_plane_init(dev, plane, possible_crtcs,
    550				       &omap_plane_funcs, formats,
    551				       nformats, NULL, type, NULL);
    552	if (ret < 0)
    553		goto error;
    554
    555	drm_plane_helper_add(plane, &omap_plane_helper_funcs);
    556
    557	omap_plane_install_properties(plane, &plane->base);
    558
    559	/*
    560	 * Set the zpos default depending on whether we are a primary or overlay
    561	 * plane.
    562	 */
    563	if (plane->type == DRM_PLANE_TYPE_PRIMARY)
    564		zpos = 0;
    565	else
    566		zpos = omap_plane->id;
    567	drm_plane_create_zpos_property(plane, zpos, 0, num_planes - 1);
    568	drm_plane_create_alpha_property(plane);
    569	drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
    570					     BIT(DRM_MODE_BLEND_COVERAGE));
    571
    572	if (omap_plane_supports_yuv(plane))
    573		drm_plane_create_color_properties(plane,
    574						  BIT(DRM_COLOR_YCBCR_BT601) |
    575						  BIT(DRM_COLOR_YCBCR_BT709),
    576						  BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
    577						  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
    578						  DRM_COLOR_YCBCR_BT601,
    579						  DRM_COLOR_YCBCR_FULL_RANGE);
    580
    581	return plane;
    582
    583error:
    584	dev_err(dev->dev, "%s(): could not create plane: %d\n",
    585		__func__, omap_plane->id);
    586
    587	kfree(omap_plane);
    588	return NULL;
    589}