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

overlay.c (15263B)


      1/*
      2 * Copyright 2013 Ilia Mirkin
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     20 * SOFTWARE.
     21 *
     22 * Implementation based on the pre-KMS implementation in xf86-video-nouveau,
     23 * written by Arthur Huillet.
     24 */
     25
     26#include <drm/drm_crtc.h>
     27#include <drm/drm_fourcc.h>
     28
     29#include "nouveau_drv.h"
     30
     31#include "nouveau_bo.h"
     32#include "nouveau_connector.h"
     33#include "nouveau_display.h"
     34#include "nouveau_gem.h"
     35#include "nvreg.h"
     36#include "disp.h"
     37
     38struct nouveau_plane {
     39	struct drm_plane base;
     40	bool flip;
     41	struct nouveau_bo *cur;
     42
     43	struct {
     44		struct drm_property *colorkey;
     45		struct drm_property *contrast;
     46		struct drm_property *brightness;
     47		struct drm_property *hue;
     48		struct drm_property *saturation;
     49	} props;
     50
     51	int colorkey;
     52	int contrast;
     53	int brightness;
     54	int hue;
     55	int saturation;
     56	enum drm_color_encoding color_encoding;
     57
     58	void (*set_params)(struct nouveau_plane *);
     59};
     60
     61static uint32_t formats[] = {
     62	DRM_FORMAT_YUYV,
     63	DRM_FORMAT_UYVY,
     64	DRM_FORMAT_NV12,
     65	DRM_FORMAT_NV21,
     66};
     67
     68/* Sine can be approximated with
     69 * http://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula
     70 * sin(x degrees) ~= 4 x (180 - x) / (40500 - x (180 - x) )
     71 * Note that this only works for the range [0, 180].
     72 * Also note that sin(x) == -sin(x - 180)
     73 */
     74static inline int
     75sin_mul(int degrees, int factor)
     76{
     77	if (degrees > 180) {
     78		degrees -= 180;
     79		factor *= -1;
     80	}
     81	return factor * 4 * degrees * (180 - degrees) /
     82		(40500 - degrees * (180 - degrees));
     83}
     84
     85/* cos(x) = sin(x + 90) */
     86static inline int
     87cos_mul(int degrees, int factor)
     88{
     89	return sin_mul((degrees + 90) % 360, factor);
     90}
     91
     92static int
     93verify_scaling(const struct drm_framebuffer *fb, uint8_t shift,
     94               uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
     95               uint32_t crtc_w, uint32_t crtc_h)
     96{
     97	if (crtc_w < (src_w >> shift) || crtc_h < (src_h >> shift)) {
     98		DRM_DEBUG_KMS("Unsuitable framebuffer scaling: %dx%d -> %dx%d\n",
     99			      src_w, src_h, crtc_w, crtc_h);
    100		return -ERANGE;
    101	}
    102
    103	if (src_x != 0 || src_y != 0) {
    104		DRM_DEBUG_KMS("Unsuitable framebuffer offset: %d,%d\n",
    105                              src_x, src_y);
    106		return -ERANGE;
    107	}
    108
    109	return 0;
    110}
    111
    112static int
    113nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
    114		  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
    115		  unsigned int crtc_w, unsigned int crtc_h,
    116		  uint32_t src_x, uint32_t src_y,
    117		  uint32_t src_w, uint32_t src_h,
    118		  struct drm_modeset_acquire_ctx *ctx)
    119{
    120	struct nouveau_drm *drm = nouveau_drm(plane->dev);
    121	struct nvif_object *dev = &drm->client.device.object;
    122	struct nouveau_plane *nv_plane =
    123		container_of(plane, struct nouveau_plane, base);
    124	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
    125	struct nouveau_bo *cur = nv_plane->cur;
    126	struct nouveau_bo *nvbo;
    127	bool flip = nv_plane->flip;
    128	int soff = NV_PCRTC0_SIZE * nv_crtc->index;
    129	int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index;
    130	unsigned shift = drm->client.device.info.chipset >= 0x30 ? 1 : 3;
    131	unsigned format = 0;
    132	int ret;
    133
    134	/* Source parameters given in 16.16 fixed point, ignore fractional. */
    135	src_x >>= 16;
    136	src_y >>= 16;
    137	src_w >>= 16;
    138	src_h >>= 16;
    139
    140	ret = verify_scaling(fb, shift, 0, 0, src_w, src_h, crtc_w, crtc_h);
    141	if (ret)
    142		return ret;
    143
    144	nvbo = nouveau_gem_object(fb->obj[0]);
    145	ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
    146	if (ret)
    147		return ret;
    148
    149	nv_plane->cur = nvbo;
    150
    151	nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY);
    152	nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0);
    153
    154	nvif_wr32(dev, NV_PVIDEO_BASE(flip), 0);
    155	nvif_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nvbo->offset);
    156	nvif_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w);
    157	nvif_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x);
    158	nvif_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w);
    159	nvif_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h);
    160	nvif_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x);
    161	nvif_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w);
    162
    163	if (fb->format->format == DRM_FORMAT_YUYV ||
    164	    fb->format->format == DRM_FORMAT_NV12)
    165		format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
    166	if (fb->format->format == DRM_FORMAT_NV12 ||
    167	    fb->format->format == DRM_FORMAT_NV21)
    168		format |= NV_PVIDEO_FORMAT_PLANAR;
    169	if (nv_plane->color_encoding == DRM_COLOR_YCBCR_BT709)
    170		format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
    171	if (nv_plane->colorkey & (1 << 24))
    172		format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
    173
    174	if (format & NV_PVIDEO_FORMAT_PLANAR) {
    175		nvif_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0);
    176		nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip),
    177			nvbo->offset + fb->offsets[1]);
    178	}
    179	nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format | fb->pitches[0]);
    180	nvif_wr32(dev, NV_PVIDEO_STOP, 0);
    181	/* TODO: wait for vblank? */
    182	nvif_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1);
    183	nv_plane->flip = !flip;
    184
    185	if (cur)
    186		nouveau_bo_unpin(cur);
    187
    188	return 0;
    189}
    190
    191static int
    192nv10_disable_plane(struct drm_plane *plane,
    193		   struct drm_modeset_acquire_ctx *ctx)
    194{
    195	struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object;
    196	struct nouveau_plane *nv_plane =
    197		container_of(plane, struct nouveau_plane, base);
    198
    199	nvif_wr32(dev, NV_PVIDEO_STOP, 1);
    200	if (nv_plane->cur) {
    201		nouveau_bo_unpin(nv_plane->cur);
    202		nv_plane->cur = NULL;
    203	}
    204
    205	return 0;
    206}
    207
    208static void
    209nv_destroy_plane(struct drm_plane *plane)
    210{
    211	drm_plane_force_disable(plane);
    212	drm_plane_cleanup(plane);
    213	kfree(plane);
    214}
    215
    216static void
    217nv10_set_params(struct nouveau_plane *plane)
    218{
    219	struct nvif_object *dev = &nouveau_drm(plane->base.dev)->client.device.object;
    220	u32 luma = (plane->brightness - 512) << 16 | plane->contrast;
    221	u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) |
    222		(cos_mul(plane->hue, plane->saturation) & 0xffff);
    223	u32 format = 0;
    224
    225	nvif_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma);
    226	nvif_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma);
    227	nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma);
    228	nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma);
    229	nvif_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff);
    230
    231	if (plane->cur) {
    232		if (plane->color_encoding == DRM_COLOR_YCBCR_BT709)
    233			format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
    234		if (plane->colorkey & (1 << 24))
    235			format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY;
    236		nvif_mask(dev, NV_PVIDEO_FORMAT(plane->flip),
    237			NV_PVIDEO_FORMAT_MATRIX_ITURBT709 |
    238			NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY,
    239			format);
    240	}
    241}
    242
    243static int
    244nv_set_property(struct drm_plane *plane,
    245		struct drm_property *property,
    246		uint64_t value)
    247{
    248	struct nouveau_plane *nv_plane =
    249		container_of(plane, struct nouveau_plane, base);
    250
    251	if (property == nv_plane->props.colorkey)
    252		nv_plane->colorkey = value;
    253	else if (property == nv_plane->props.contrast)
    254		nv_plane->contrast = value;
    255	else if (property == nv_plane->props.brightness)
    256		nv_plane->brightness = value;
    257	else if (property == nv_plane->props.hue)
    258		nv_plane->hue = value;
    259	else if (property == nv_plane->props.saturation)
    260		nv_plane->saturation = value;
    261	else if (property == nv_plane->base.color_encoding_property)
    262		nv_plane->color_encoding = value;
    263	else
    264		return -EINVAL;
    265
    266	if (nv_plane->set_params)
    267		nv_plane->set_params(nv_plane);
    268	return 0;
    269}
    270
    271static const struct drm_plane_funcs nv10_plane_funcs = {
    272	.update_plane = nv10_update_plane,
    273	.disable_plane = nv10_disable_plane,
    274	.set_property = nv_set_property,
    275	.destroy = nv_destroy_plane,
    276};
    277
    278static void
    279nv10_overlay_init(struct drm_device *device)
    280{
    281	struct nouveau_drm *drm = nouveau_drm(device);
    282	struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL);
    283	unsigned int num_formats = ARRAY_SIZE(formats);
    284	int ret;
    285
    286	if (!plane)
    287		return;
    288
    289	switch (drm->client.device.info.chipset) {
    290	case 0x10:
    291	case 0x11:
    292	case 0x15:
    293	case 0x1a:
    294	case 0x20:
    295		num_formats = 2;
    296		break;
    297	}
    298
    299	ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */,
    300			     &nv10_plane_funcs,
    301			     formats, num_formats, false);
    302	if (ret)
    303		goto err;
    304
    305	/* Set up the plane properties */
    306	plane->props.colorkey = drm_property_create_range(
    307			device, 0, "colorkey", 0, 0x01ffffff);
    308	plane->props.contrast = drm_property_create_range(
    309			device, 0, "contrast", 0, 8192 - 1);
    310	plane->props.brightness = drm_property_create_range(
    311			device, 0, "brightness", 0, 1024);
    312	plane->props.hue = drm_property_create_range(
    313			device, 0, "hue", 0, 359);
    314	plane->props.saturation = drm_property_create_range(
    315			device, 0, "saturation", 0, 8192 - 1);
    316	if (!plane->props.colorkey ||
    317	    !plane->props.contrast ||
    318	    !plane->props.brightness ||
    319	    !plane->props.hue ||
    320	    !plane->props.saturation)
    321		goto cleanup;
    322
    323	plane->colorkey = 0;
    324	drm_object_attach_property(&plane->base.base,
    325				   plane->props.colorkey, plane->colorkey);
    326
    327	plane->contrast = 0x1000;
    328	drm_object_attach_property(&plane->base.base,
    329				   plane->props.contrast, plane->contrast);
    330
    331	plane->brightness = 512;
    332	drm_object_attach_property(&plane->base.base,
    333				   plane->props.brightness, plane->brightness);
    334
    335	plane->hue = 0;
    336	drm_object_attach_property(&plane->base.base,
    337				   plane->props.hue, plane->hue);
    338
    339	plane->saturation = 0x1000;
    340	drm_object_attach_property(&plane->base.base,
    341				   plane->props.saturation, plane->saturation);
    342
    343	plane->color_encoding = DRM_COLOR_YCBCR_BT601;
    344	drm_plane_create_color_properties(&plane->base,
    345					  BIT(DRM_COLOR_YCBCR_BT601) |
    346					  BIT(DRM_COLOR_YCBCR_BT709),
    347					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
    348					  DRM_COLOR_YCBCR_BT601,
    349					  DRM_COLOR_YCBCR_LIMITED_RANGE);
    350
    351	plane->set_params = nv10_set_params;
    352	nv10_set_params(plane);
    353	drm_plane_force_disable(&plane->base);
    354	return;
    355cleanup:
    356	drm_plane_cleanup(&plane->base);
    357err:
    358	kfree(plane);
    359	NV_ERROR(drm, "Failed to create plane\n");
    360}
    361
    362static int
    363nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
    364		  struct drm_framebuffer *fb, int crtc_x, int crtc_y,
    365		  unsigned int crtc_w, unsigned int crtc_h,
    366		  uint32_t src_x, uint32_t src_y,
    367		  uint32_t src_w, uint32_t src_h,
    368		  struct drm_modeset_acquire_ctx *ctx)
    369{
    370	struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object;
    371	struct nouveau_plane *nv_plane =
    372		container_of(plane, struct nouveau_plane, base);
    373	struct nouveau_bo *cur = nv_plane->cur;
    374	struct nouveau_bo *nvbo;
    375	uint32_t overlay = 1;
    376	int brightness = (nv_plane->brightness - 512) * 62 / 512;
    377	int ret, i;
    378
    379	/* Source parameters given in 16.16 fixed point, ignore fractional. */
    380	src_x >>= 16;
    381	src_y >>= 16;
    382	src_w >>= 16;
    383	src_h >>= 16;
    384
    385	ret = verify_scaling(fb, 0, src_x, src_y, src_w, src_h, crtc_w, crtc_h);
    386	if (ret)
    387		return ret;
    388
    389	nvbo = nouveau_gem_object(fb->obj[0]);
    390	ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false);
    391	if (ret)
    392		return ret;
    393
    394	nv_plane->cur = nvbo;
    395
    396	nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0);
    397	nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0);
    398	nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0);
    399
    400	for (i = 0; i < 2; i++) {
    401		nvif_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i,
    402			  nvbo->offset);
    403		nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i,
    404			  fb->pitches[0]);
    405		nvif_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0);
    406	}
    407	nvif_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x);
    408	nvif_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w);
    409	nvif_wr32(dev, NV_PVIDEO_STEP_SIZE,
    410		(uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1)));
    411
    412	/* It should be possible to convert hue/contrast to this */
    413	nvif_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness);
    414	nvif_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness);
    415	nvif_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness);
    416	nvif_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0);
    417
    418	nvif_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */
    419	nvif_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */
    420
    421	nvif_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03);
    422	nvif_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38);
    423
    424	nvif_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey);
    425
    426	if (nv_plane->colorkey & (1 << 24))
    427		overlay |= 0x10;
    428	if (fb->format->format == DRM_FORMAT_YUYV)
    429		overlay |= 0x100;
    430
    431	nvif_wr32(dev, NV_PVIDEO_OVERLAY, overlay);
    432
    433	nvif_wr32(dev, NV_PVIDEO_SU_STATE, nvif_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16));
    434
    435	if (cur)
    436		nouveau_bo_unpin(cur);
    437
    438	return 0;
    439}
    440
    441static int
    442nv04_disable_plane(struct drm_plane *plane,
    443		   struct drm_modeset_acquire_ctx *ctx)
    444{
    445	struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object;
    446	struct nouveau_plane *nv_plane =
    447		container_of(plane, struct nouveau_plane, base);
    448
    449	nvif_mask(dev, NV_PVIDEO_OVERLAY, 1, 0);
    450	nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0);
    451	nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0);
    452	nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0);
    453	if (nv_plane->cur) {
    454		nouveau_bo_unpin(nv_plane->cur);
    455		nv_plane->cur = NULL;
    456	}
    457
    458	return 0;
    459}
    460
    461static const struct drm_plane_funcs nv04_plane_funcs = {
    462	.update_plane = nv04_update_plane,
    463	.disable_plane = nv04_disable_plane,
    464	.set_property = nv_set_property,
    465	.destroy = nv_destroy_plane,
    466};
    467
    468static void
    469nv04_overlay_init(struct drm_device *device)
    470{
    471	struct nouveau_drm *drm = nouveau_drm(device);
    472	struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL);
    473	int ret;
    474
    475	if (!plane)
    476		return;
    477
    478	ret = drm_plane_init(device, &plane->base, 1 /* single crtc */,
    479			     &nv04_plane_funcs,
    480			     formats, 2, false);
    481	if (ret)
    482		goto err;
    483
    484	/* Set up the plane properties */
    485	plane->props.colorkey = drm_property_create_range(
    486			device, 0, "colorkey", 0, 0x01ffffff);
    487	plane->props.brightness = drm_property_create_range(
    488			device, 0, "brightness", 0, 1024);
    489	if (!plane->props.colorkey ||
    490	    !plane->props.brightness)
    491		goto cleanup;
    492
    493	plane->colorkey = 0;
    494	drm_object_attach_property(&plane->base.base,
    495				   plane->props.colorkey, plane->colorkey);
    496
    497	plane->brightness = 512;
    498	drm_object_attach_property(&plane->base.base,
    499				   plane->props.brightness, plane->brightness);
    500
    501	drm_plane_force_disable(&plane->base);
    502	return;
    503cleanup:
    504	drm_plane_cleanup(&plane->base);
    505err:
    506	kfree(plane);
    507	NV_ERROR(drm, "Failed to create plane\n");
    508}
    509
    510void
    511nouveau_overlay_init(struct drm_device *device)
    512{
    513	struct nvif_device *dev = &nouveau_drm(device)->client.device;
    514	if (dev->info.chipset < 0x10)
    515		nv04_overlay_init(device);
    516	else if (dev->info.chipset <= 0x40)
    517		nv10_overlay_init(device);
    518}