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

malidp_mw.c (7499B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
      4 * Author: Brian Starkey <brian.starkey@arm.com>
      5 *
      6 * ARM Mali DP Writeback connector implementation
      7 */
      8
      9#include <drm/drm_atomic.h>
     10#include <drm/drm_atomic_helper.h>
     11#include <drm/drm_crtc.h>
     12#include <drm/drm_fb_cma_helper.h>
     13#include <drm/drm_fourcc.h>
     14#include <drm/drm_gem_cma_helper.h>
     15#include <drm/drm_probe_helper.h>
     16#include <drm/drm_writeback.h>
     17
     18#include "malidp_drv.h"
     19#include "malidp_hw.h"
     20#include "malidp_mw.h"
     21
     22#define to_mw_state(_state) (struct malidp_mw_connector_state *)(_state)
     23
     24struct malidp_mw_connector_state {
     25	struct drm_connector_state base;
     26	dma_addr_t addrs[2];
     27	s32 pitches[2];
     28	u8 format;
     29	u8 n_planes;
     30	bool rgb2yuv_initialized;
     31	const s16 *rgb2yuv_coeffs;
     32};
     33
     34static int malidp_mw_connector_get_modes(struct drm_connector *connector)
     35{
     36	struct drm_device *dev = connector->dev;
     37
     38	return drm_add_modes_noedid(connector, dev->mode_config.max_width,
     39				    dev->mode_config.max_height);
     40}
     41
     42static enum drm_mode_status
     43malidp_mw_connector_mode_valid(struct drm_connector *connector,
     44			       struct drm_display_mode *mode)
     45{
     46	struct drm_device *dev = connector->dev;
     47	struct drm_mode_config *mode_config = &dev->mode_config;
     48	int w = mode->hdisplay, h = mode->vdisplay;
     49
     50	if ((w < mode_config->min_width) || (w > mode_config->max_width))
     51		return MODE_BAD_HVALUE;
     52
     53	if ((h < mode_config->min_height) || (h > mode_config->max_height))
     54		return MODE_BAD_VVALUE;
     55
     56	return MODE_OK;
     57}
     58
     59static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = {
     60	.get_modes = malidp_mw_connector_get_modes,
     61	.mode_valid = malidp_mw_connector_mode_valid,
     62};
     63
     64static void malidp_mw_connector_reset(struct drm_connector *connector)
     65{
     66	struct malidp_mw_connector_state *mw_state =
     67		kzalloc(sizeof(*mw_state), GFP_KERNEL);
     68
     69	if (connector->state)
     70		__drm_atomic_helper_connector_destroy_state(connector->state);
     71
     72	kfree(connector->state);
     73	__drm_atomic_helper_connector_reset(connector, &mw_state->base);
     74}
     75
     76static enum drm_connector_status
     77malidp_mw_connector_detect(struct drm_connector *connector, bool force)
     78{
     79	return connector_status_connected;
     80}
     81
     82static void malidp_mw_connector_destroy(struct drm_connector *connector)
     83{
     84	drm_connector_cleanup(connector);
     85}
     86
     87static struct drm_connector_state *
     88malidp_mw_connector_duplicate_state(struct drm_connector *connector)
     89{
     90	struct malidp_mw_connector_state *mw_state, *mw_current_state;
     91
     92	if (WARN_ON(!connector->state))
     93		return NULL;
     94
     95	mw_state = kzalloc(sizeof(*mw_state), GFP_KERNEL);
     96	if (!mw_state)
     97		return NULL;
     98
     99	mw_current_state = to_mw_state(connector->state);
    100	mw_state->rgb2yuv_coeffs = mw_current_state->rgb2yuv_coeffs;
    101	mw_state->rgb2yuv_initialized = mw_current_state->rgb2yuv_initialized;
    102
    103	__drm_atomic_helper_connector_duplicate_state(connector, &mw_state->base);
    104
    105	return &mw_state->base;
    106}
    107
    108static const struct drm_connector_funcs malidp_mw_connector_funcs = {
    109	.reset = malidp_mw_connector_reset,
    110	.detect = malidp_mw_connector_detect,
    111	.fill_modes = drm_helper_probe_single_connector_modes,
    112	.destroy = malidp_mw_connector_destroy,
    113	.atomic_duplicate_state = malidp_mw_connector_duplicate_state,
    114	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    115};
    116
    117static const s16 rgb2yuv_coeffs_bt709_limited[MALIDP_COLORADJ_NUM_COEFFS] = {
    118	47,  157,   16,
    119	-26,  -87,  112,
    120	112, -102,  -10,
    121	16,  128,  128
    122};
    123
    124static int
    125malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
    126			       struct drm_crtc_state *crtc_state,
    127			       struct drm_connector_state *conn_state)
    128{
    129	struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state);
    130	struct malidp_drm *malidp = encoder->dev->dev_private;
    131	struct drm_framebuffer *fb;
    132	int i, n_planes;
    133
    134	if (!conn_state->writeback_job)
    135		return 0;
    136
    137	fb = conn_state->writeback_job->fb;
    138	if ((fb->width != crtc_state->mode.hdisplay) ||
    139	    (fb->height != crtc_state->mode.vdisplay)) {
    140		DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n",
    141				fb->width, fb->height);
    142		return -EINVAL;
    143	}
    144
    145	if (fb->modifier) {
    146		DRM_DEBUG_KMS("Writeback framebuffer does not support modifiers\n");
    147		return -EINVAL;
    148	}
    149
    150	mw_state->format =
    151		malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
    152					fb->format->format, !!fb->modifier);
    153	if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
    154		DRM_DEBUG_KMS("Invalid pixel format %p4cc\n",
    155			      &fb->format->format);
    156		return -EINVAL;
    157	}
    158
    159	n_planes = fb->format->num_planes;
    160	for (i = 0; i < n_planes; i++) {
    161		struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i);
    162		/* memory write buffers are never rotated */
    163		u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0);
    164
    165		if (fb->pitches[i] & (alignment - 1)) {
    166			DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
    167				      fb->pitches[i], i);
    168			return -EINVAL;
    169		}
    170		mw_state->pitches[i] = fb->pitches[i];
    171		mw_state->addrs[i] = obj->paddr + fb->offsets[i];
    172	}
    173	mw_state->n_planes = n_planes;
    174
    175	if (fb->format->is_yuv)
    176		mw_state->rgb2yuv_coeffs = rgb2yuv_coeffs_bt709_limited;
    177
    178	return 0;
    179}
    180
    181static const struct drm_encoder_helper_funcs malidp_mw_encoder_helper_funcs = {
    182	.atomic_check = malidp_mw_encoder_atomic_check,
    183};
    184
    185static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats)
    186{
    187	const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
    188	u32 *formats;
    189	int n, i;
    190
    191	formats = kcalloc(map->n_pixel_formats, sizeof(*formats),
    192			  GFP_KERNEL);
    193	if (!formats)
    194		return NULL;
    195
    196	for (n = 0, i = 0;  i < map->n_pixel_formats; i++) {
    197		if (map->pixel_formats[i].layer & SE_MEMWRITE)
    198			formats[n++] = map->pixel_formats[i].format;
    199	}
    200
    201	*n_formats = n;
    202
    203	return formats;
    204}
    205
    206int malidp_mw_connector_init(struct drm_device *drm)
    207{
    208	struct malidp_drm *malidp = drm->dev_private;
    209	u32 *formats;
    210	int ret, n_formats;
    211
    212	if (!malidp->dev->hw->enable_memwrite)
    213		return 0;
    214
    215	drm_connector_helper_add(&malidp->mw_connector.base,
    216				 &malidp_mw_connector_helper_funcs);
    217
    218	formats = get_writeback_formats(malidp, &n_formats);
    219	if (!formats)
    220		return -ENOMEM;
    221
    222	ret = drm_writeback_connector_init(drm, &malidp->mw_connector,
    223					   &malidp_mw_connector_funcs,
    224					   &malidp_mw_encoder_helper_funcs,
    225					   formats, n_formats,
    226					   1 << drm_crtc_index(&malidp->crtc));
    227	kfree(formats);
    228	if (ret)
    229		return ret;
    230
    231	return 0;
    232}
    233
    234void malidp_mw_atomic_commit(struct drm_device *drm,
    235			     struct drm_atomic_state *old_state)
    236{
    237	struct malidp_drm *malidp = drm->dev_private;
    238	struct drm_writeback_connector *mw_conn = &malidp->mw_connector;
    239	struct drm_connector_state *conn_state = mw_conn->base.state;
    240	struct malidp_hw_device *hwdev = malidp->dev;
    241	struct malidp_mw_connector_state *mw_state;
    242
    243	if (!conn_state)
    244		return;
    245
    246	mw_state = to_mw_state(conn_state);
    247
    248	if (conn_state->writeback_job) {
    249		struct drm_framebuffer *fb = conn_state->writeback_job->fb;
    250
    251		DRM_DEV_DEBUG_DRIVER(drm->dev,
    252				     "Enable memwrite %ux%u:%d %pad fmt: %u\n",
    253				     fb->width, fb->height,
    254				     mw_state->pitches[0],
    255				     &mw_state->addrs[0],
    256				     mw_state->format);
    257
    258		drm_writeback_queue_job(mw_conn, conn_state);
    259		hwdev->hw->enable_memwrite(hwdev, mw_state->addrs,
    260					   mw_state->pitches, mw_state->n_planes,
    261					   fb->width, fb->height, mw_state->format,
    262					   !mw_state->rgb2yuv_initialized ?
    263					   mw_state->rgb2yuv_coeffs : NULL);
    264		mw_state->rgb2yuv_initialized = !!mw_state->rgb2yuv_coeffs;
    265	} else {
    266		DRM_DEV_DEBUG_DRIVER(drm->dev, "Disable memwrite\n");
    267		hwdev->hw->disable_memwrite(hwdev);
    268	}
    269}