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

armada_plane.c (9200B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2012 Russell King
      4 *  Rewritten from the dovefb driver, and Armada510 manuals.
      5 */
      6
      7#include <drm/drm_atomic.h>
      8#include <drm/drm_atomic_helper.h>
      9#include <drm/drm_fourcc.h>
     10#include <drm/drm_plane_helper.h>
     11
     12#include "armada_crtc.h"
     13#include "armada_drm.h"
     14#include "armada_fb.h"
     15#include "armada_gem.h"
     16#include "armada_hw.h"
     17#include "armada_plane.h"
     18#include "armada_trace.h"
     19
     20static const uint32_t armada_primary_formats[] = {
     21	DRM_FORMAT_UYVY,
     22	DRM_FORMAT_YUYV,
     23	DRM_FORMAT_VYUY,
     24	DRM_FORMAT_YVYU,
     25	DRM_FORMAT_ARGB8888,
     26	DRM_FORMAT_ABGR8888,
     27	DRM_FORMAT_XRGB8888,
     28	DRM_FORMAT_XBGR8888,
     29	DRM_FORMAT_RGB888,
     30	DRM_FORMAT_BGR888,
     31	DRM_FORMAT_ARGB1555,
     32	DRM_FORMAT_ABGR1555,
     33	DRM_FORMAT_RGB565,
     34	DRM_FORMAT_BGR565,
     35};
     36
     37void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
     38	u16 pitches[3], bool interlaced)
     39{
     40	struct drm_framebuffer *fb = state->fb;
     41	const struct drm_format_info *format = fb->format;
     42	unsigned int num_planes = format->num_planes;
     43	unsigned int x = state->src.x1 >> 16;
     44	unsigned int y = state->src.y1 >> 16;
     45	u32 addr = drm_fb_obj(fb)->dev_addr;
     46	int i;
     47
     48	DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
     49		      fb->pitches[0], x, y, format->cpp[0] * 8);
     50
     51	if (num_planes > 3)
     52		num_planes = 3;
     53
     54	addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
     55		      x * format->cpp[0];
     56	pitches[0] = fb->pitches[0];
     57
     58	y /= format->vsub;
     59	x /= format->hsub;
     60
     61	for (i = 1; i < num_planes; i++) {
     62		addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
     63			      x * format->cpp[i];
     64		pitches[i] = fb->pitches[i];
     65	}
     66	for (; i < 3; i++) {
     67		addrs[0][i] = 0;
     68		pitches[i] = 0;
     69	}
     70	if (interlaced) {
     71		for (i = 0; i < 3; i++) {
     72			addrs[1][i] = addrs[0][i] + pitches[i];
     73			pitches[i] *= 2;
     74		}
     75	} else {
     76		for (i = 0; i < 3; i++)
     77			addrs[1][i] = addrs[0][i];
     78	}
     79}
     80
     81int armada_drm_plane_atomic_check(struct drm_plane *plane,
     82	struct drm_atomic_state *state)
     83{
     84	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
     85										 plane);
     86	struct armada_plane_state *st = to_armada_plane_state(new_plane_state);
     87	struct drm_crtc *crtc = new_plane_state->crtc;
     88	struct drm_crtc_state *crtc_state;
     89	bool interlace;
     90	int ret;
     91
     92	if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {
     93		new_plane_state->visible = false;
     94		return 0;
     95	}
     96
     97	if (state)
     98		crtc_state = drm_atomic_get_existing_crtc_state(state,
     99								crtc);
    100	else
    101		crtc_state = crtc->state;
    102
    103	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
    104						  0,
    105						  INT_MAX, true, false);
    106	if (ret)
    107		return ret;
    108
    109	interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
    110	if (interlace) {
    111		if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)
    112			return -EINVAL;
    113		st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;
    114		st->dst_yx = new_plane_state->dst.y1 >> 1;
    115		st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;
    116	} else {
    117		st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;
    118		st->dst_yx = new_plane_state->dst.y1;
    119		st->dst_hw = drm_rect_height(&new_plane_state->dst);
    120	}
    121
    122	st->src_hw <<= 16;
    123	st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;
    124	st->dst_yx <<= 16;
    125	st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;
    126	st->dst_hw <<= 16;
    127	st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;
    128
    129	armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,
    130			      interlace);
    131	st->interlace = interlace;
    132
    133	return 0;
    134}
    135
    136static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
    137	struct drm_atomic_state *state)
    138{
    139	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    140									   plane);
    141	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
    142									   plane);
    143	struct armada_crtc *dcrtc;
    144	struct armada_regs *regs;
    145	u32 cfg, cfg_mask, val;
    146	unsigned int idx;
    147
    148	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
    149
    150	if (!new_state->fb || WARN_ON(!new_state->crtc))
    151		return;
    152
    153	DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
    154		plane->base.id, plane->name,
    155		new_state->crtc->base.id, new_state->crtc->name,
    156		new_state->fb->base.id,
    157		old_state->visible, new_state->visible);
    158
    159	dcrtc = drm_to_armada_crtc(new_state->crtc);
    160	regs = dcrtc->regs + dcrtc->regs_idx;
    161
    162	idx = 0;
    163	if (!old_state->visible && new_state->visible) {
    164		val = CFG_PDWN64x66;
    165		if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
    166			val |= CFG_PDWN256x24;
    167		armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
    168	}
    169	val = armada_src_hw(new_state);
    170	if (armada_src_hw(old_state) != val)
    171		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
    172	val = armada_dst_yx(new_state);
    173	if (armada_dst_yx(old_state) != val)
    174		armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
    175	val = armada_dst_hw(new_state);
    176	if (armada_dst_hw(old_state) != val)
    177		armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
    178	if (old_state->src.x1 != new_state->src.x1 ||
    179	    old_state->src.y1 != new_state->src.y1 ||
    180	    old_state->fb != new_state->fb ||
    181	    new_state->crtc->state->mode_changed) {
    182		armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
    183				     LCD_CFG_GRA_START_ADDR0);
    184		armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
    185				     LCD_CFG_GRA_START_ADDR1);
    186		armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),
    187				     0xffff,
    188				     LCD_CFG_GRA_PITCH);
    189	}
    190	if (old_state->fb != new_state->fb ||
    191	    new_state->crtc->state->mode_changed) {
    192		cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
    193		      CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);
    194		if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
    195			cfg |= CFG_PALETTE_ENA;
    196		if (new_state->visible)
    197			cfg |= CFG_GRA_ENA;
    198		if (to_armada_plane_state(new_state)->interlace)
    199			cfg |= CFG_GRA_FTOGGLE;
    200		cfg_mask = CFG_GRAFORMAT |
    201			   CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
    202				       CFG_SWAPYU | CFG_YUV2RGB) |
    203			   CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
    204			   CFG_GRA_ENA;
    205	} else if (old_state->visible != new_state->visible) {
    206		cfg = new_state->visible ? CFG_GRA_ENA : 0;
    207		cfg_mask = CFG_GRA_ENA;
    208	} else {
    209		cfg = cfg_mask = 0;
    210	}
    211	if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
    212	    drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
    213		cfg_mask |= CFG_GRA_HSMOOTH;
    214		if (drm_rect_width(&new_state->src) >> 16 !=
    215		    drm_rect_width(&new_state->dst))
    216			cfg |= CFG_GRA_HSMOOTH;
    217	}
    218
    219	if (cfg_mask)
    220		armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
    221				     LCD_SPU_DMA_CTRL0);
    222
    223	dcrtc->regs_idx += idx;
    224}
    225
    226static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
    227	struct drm_atomic_state *state)
    228{
    229	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
    230									   plane);
    231	struct armada_crtc *dcrtc;
    232	struct armada_regs *regs;
    233	unsigned int idx = 0;
    234
    235	DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
    236
    237	if (!old_state->crtc)
    238		return;
    239
    240	DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
    241		plane->base.id, plane->name,
    242		old_state->crtc->base.id, old_state->crtc->name,
    243		old_state->fb->base.id);
    244
    245	dcrtc = drm_to_armada_crtc(old_state->crtc);
    246	regs = dcrtc->regs + dcrtc->regs_idx;
    247
    248	/* Disable plane and power down most RAMs and FIFOs */
    249	armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
    250	armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
    251			     CFG_PDWN32x32 | CFG_PDWN64x66,
    252			     0, LCD_SPU_SRAM_PARA1);
    253
    254	dcrtc->regs_idx += idx;
    255}
    256
    257static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
    258	.atomic_check	= armada_drm_plane_atomic_check,
    259	.atomic_update	= armada_drm_primary_plane_atomic_update,
    260	.atomic_disable	= armada_drm_primary_plane_atomic_disable,
    261};
    262
    263void armada_plane_reset(struct drm_plane *plane)
    264{
    265	struct armada_plane_state *st;
    266	if (plane->state)
    267		__drm_atomic_helper_plane_destroy_state(plane->state);
    268	kfree(plane->state);
    269	st = kzalloc(sizeof(*st), GFP_KERNEL);
    270	if (st)
    271		__drm_atomic_helper_plane_reset(plane, &st->base);
    272}
    273
    274struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
    275{
    276	struct armada_plane_state *st;
    277
    278	if (WARN_ON(!plane->state))
    279		return NULL;
    280
    281	st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
    282	if (st)
    283		__drm_atomic_helper_plane_duplicate_state(plane, &st->base);
    284
    285	return &st->base;
    286}
    287
    288static const struct drm_plane_funcs armada_primary_plane_funcs = {
    289	.update_plane	= drm_atomic_helper_update_plane,
    290	.disable_plane	= drm_atomic_helper_disable_plane,
    291	.destroy	= drm_primary_helper_destroy,
    292	.reset		= armada_plane_reset,
    293	.atomic_duplicate_state = armada_plane_duplicate_state,
    294	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
    295};
    296
    297int armada_drm_primary_plane_init(struct drm_device *drm,
    298	struct drm_plane *primary)
    299{
    300	int ret;
    301
    302	drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
    303
    304	ret = drm_universal_plane_init(drm, primary, 0,
    305				       &armada_primary_plane_funcs,
    306				       armada_primary_formats,
    307				       ARRAY_SIZE(armada_primary_formats),
    308				       NULL,
    309				       DRM_PLANE_TYPE_PRIMARY, NULL);
    310
    311	return ret;
    312}