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

atmel_hlcdc_plane.c (26464B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Free Electrons
      4 * Copyright (C) 2014 Atmel
      5 *
      6 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
      7 */
      8
      9#include <linux/dmapool.h>
     10#include <linux/mfd/atmel-hlcdc.h>
     11
     12#include <drm/drm_atomic.h>
     13#include <drm/drm_atomic_helper.h>
     14#include <drm/drm_fb_cma_helper.h>
     15#include <drm/drm_fourcc.h>
     16#include <drm/drm_gem_cma_helper.h>
     17#include <drm/drm_plane_helper.h>
     18
     19#include "atmel_hlcdc_dc.h"
     20
     21/**
     22 * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
     23 *
     24 * @base: DRM plane state
     25 * @crtc_x: x position of the plane relative to the CRTC
     26 * @crtc_y: y position of the plane relative to the CRTC
     27 * @crtc_w: visible width of the plane
     28 * @crtc_h: visible height of the plane
     29 * @src_x: x buffer position
     30 * @src_y: y buffer position
     31 * @src_w: buffer width
     32 * @src_h: buffer height
     33 * @disc_x: x discard position
     34 * @disc_y: y discard position
     35 * @disc_w: discard width
     36 * @disc_h: discard height
     37 * @ahb_id: AHB identification number
     38 * @bpp: bytes per pixel deduced from pixel_format
     39 * @offsets: offsets to apply to the GEM buffers
     40 * @xstride: value to add to the pixel pointer between each line
     41 * @pstride: value to add to the pixel pointer between each pixel
     42 * @nplanes: number of planes (deduced from pixel_format)
     43 * @dscrs: DMA descriptors
     44 */
     45struct atmel_hlcdc_plane_state {
     46	struct drm_plane_state base;
     47	int crtc_x;
     48	int crtc_y;
     49	unsigned int crtc_w;
     50	unsigned int crtc_h;
     51	uint32_t src_x;
     52	uint32_t src_y;
     53	uint32_t src_w;
     54	uint32_t src_h;
     55
     56	int disc_x;
     57	int disc_y;
     58	int disc_w;
     59	int disc_h;
     60
     61	int ahb_id;
     62
     63	/* These fields are private and should not be touched */
     64	int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
     65	unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
     66	int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
     67	int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
     68	int nplanes;
     69
     70	/* DMA descriptors. */
     71	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
     72};
     73
     74static inline struct atmel_hlcdc_plane_state *
     75drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
     76{
     77	return container_of(s, struct atmel_hlcdc_plane_state, base);
     78}
     79
     80#define SUBPIXEL_MASK			0xffff
     81
     82static uint32_t rgb_formats[] = {
     83	DRM_FORMAT_C8,
     84	DRM_FORMAT_XRGB4444,
     85	DRM_FORMAT_ARGB4444,
     86	DRM_FORMAT_RGBA4444,
     87	DRM_FORMAT_ARGB1555,
     88	DRM_FORMAT_RGB565,
     89	DRM_FORMAT_RGB888,
     90	DRM_FORMAT_XRGB8888,
     91	DRM_FORMAT_ARGB8888,
     92	DRM_FORMAT_RGBA8888,
     93};
     94
     95struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
     96	.formats = rgb_formats,
     97	.nformats = ARRAY_SIZE(rgb_formats),
     98};
     99
    100static uint32_t rgb_and_yuv_formats[] = {
    101	DRM_FORMAT_C8,
    102	DRM_FORMAT_XRGB4444,
    103	DRM_FORMAT_ARGB4444,
    104	DRM_FORMAT_RGBA4444,
    105	DRM_FORMAT_ARGB1555,
    106	DRM_FORMAT_RGB565,
    107	DRM_FORMAT_RGB888,
    108	DRM_FORMAT_XRGB8888,
    109	DRM_FORMAT_ARGB8888,
    110	DRM_FORMAT_RGBA8888,
    111	DRM_FORMAT_AYUV,
    112	DRM_FORMAT_YUYV,
    113	DRM_FORMAT_UYVY,
    114	DRM_FORMAT_YVYU,
    115	DRM_FORMAT_VYUY,
    116	DRM_FORMAT_NV21,
    117	DRM_FORMAT_NV61,
    118	DRM_FORMAT_YUV422,
    119	DRM_FORMAT_YUV420,
    120};
    121
    122struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
    123	.formats = rgb_and_yuv_formats,
    124	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
    125};
    126
    127static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
    128{
    129	switch (format) {
    130	case DRM_FORMAT_C8:
    131		*mode = ATMEL_HLCDC_C8_MODE;
    132		break;
    133	case DRM_FORMAT_XRGB4444:
    134		*mode = ATMEL_HLCDC_XRGB4444_MODE;
    135		break;
    136	case DRM_FORMAT_ARGB4444:
    137		*mode = ATMEL_HLCDC_ARGB4444_MODE;
    138		break;
    139	case DRM_FORMAT_RGBA4444:
    140		*mode = ATMEL_HLCDC_RGBA4444_MODE;
    141		break;
    142	case DRM_FORMAT_RGB565:
    143		*mode = ATMEL_HLCDC_RGB565_MODE;
    144		break;
    145	case DRM_FORMAT_RGB888:
    146		*mode = ATMEL_HLCDC_RGB888_MODE;
    147		break;
    148	case DRM_FORMAT_ARGB1555:
    149		*mode = ATMEL_HLCDC_ARGB1555_MODE;
    150		break;
    151	case DRM_FORMAT_XRGB8888:
    152		*mode = ATMEL_HLCDC_XRGB8888_MODE;
    153		break;
    154	case DRM_FORMAT_ARGB8888:
    155		*mode = ATMEL_HLCDC_ARGB8888_MODE;
    156		break;
    157	case DRM_FORMAT_RGBA8888:
    158		*mode = ATMEL_HLCDC_RGBA8888_MODE;
    159		break;
    160	case DRM_FORMAT_AYUV:
    161		*mode = ATMEL_HLCDC_AYUV_MODE;
    162		break;
    163	case DRM_FORMAT_YUYV:
    164		*mode = ATMEL_HLCDC_YUYV_MODE;
    165		break;
    166	case DRM_FORMAT_UYVY:
    167		*mode = ATMEL_HLCDC_UYVY_MODE;
    168		break;
    169	case DRM_FORMAT_YVYU:
    170		*mode = ATMEL_HLCDC_YVYU_MODE;
    171		break;
    172	case DRM_FORMAT_VYUY:
    173		*mode = ATMEL_HLCDC_VYUY_MODE;
    174		break;
    175	case DRM_FORMAT_NV21:
    176		*mode = ATMEL_HLCDC_NV21_MODE;
    177		break;
    178	case DRM_FORMAT_NV61:
    179		*mode = ATMEL_HLCDC_NV61_MODE;
    180		break;
    181	case DRM_FORMAT_YUV420:
    182		*mode = ATMEL_HLCDC_YUV420_MODE;
    183		break;
    184	case DRM_FORMAT_YUV422:
    185		*mode = ATMEL_HLCDC_YUV422_MODE;
    186		break;
    187	default:
    188		return -ENOTSUPP;
    189	}
    190
    191	return 0;
    192}
    193
    194static u32 heo_downscaling_xcoef[] = {
    195	0x11343311,
    196	0x000000f7,
    197	0x1635300c,
    198	0x000000f9,
    199	0x1b362c08,
    200	0x000000fb,
    201	0x1f372804,
    202	0x000000fe,
    203	0x24382400,
    204	0x00000000,
    205	0x28371ffe,
    206	0x00000004,
    207	0x2c361bfb,
    208	0x00000008,
    209	0x303516f9,
    210	0x0000000c,
    211};
    212
    213static u32 heo_downscaling_ycoef[] = {
    214	0x00123737,
    215	0x00173732,
    216	0x001b382d,
    217	0x001f3928,
    218	0x00243824,
    219	0x0028391f,
    220	0x002d381b,
    221	0x00323717,
    222};
    223
    224static u32 heo_upscaling_xcoef[] = {
    225	0xf74949f7,
    226	0x00000000,
    227	0xf55f33fb,
    228	0x000000fe,
    229	0xf5701efe,
    230	0x000000ff,
    231	0xf87c0dff,
    232	0x00000000,
    233	0x00800000,
    234	0x00000000,
    235	0x0d7cf800,
    236	0x000000ff,
    237	0x1e70f5ff,
    238	0x000000fe,
    239	0x335ff5fe,
    240	0x000000fb,
    241};
    242
    243static u32 heo_upscaling_ycoef[] = {
    244	0x00004040,
    245	0x00075920,
    246	0x00056f0c,
    247	0x00027b03,
    248	0x00008000,
    249	0x00037b02,
    250	0x000c6f05,
    251	0x00205907,
    252};
    253
    254#define ATMEL_HLCDC_XPHIDEF	4
    255#define ATMEL_HLCDC_YPHIDEF	4
    256
    257static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
    258						  u32 dstsize,
    259						  u32 phidef)
    260{
    261	u32 factor, max_memsize;
    262
    263	factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
    264	max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
    265
    266	if (max_memsize > srcsize - 1)
    267		factor--;
    268
    269	return factor;
    270}
    271
    272static void
    273atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
    274				      const u32 *coeff_tab, int size,
    275				      unsigned int cfg_offs)
    276{
    277	int i;
    278
    279	for (i = 0; i < size; i++)
    280		atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
    281					    coeff_tab[i]);
    282}
    283
    284static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
    285					   struct atmel_hlcdc_plane_state *state)
    286{
    287	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    288	u32 xfactor, yfactor;
    289
    290	if (!desc->layout.scaler_config)
    291		return;
    292
    293	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
    294		atmel_hlcdc_layer_write_cfg(&plane->layer,
    295					    desc->layout.scaler_config, 0);
    296		return;
    297	}
    298
    299	if (desc->layout.phicoeffs.x) {
    300		xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
    301							state->crtc_w,
    302							ATMEL_HLCDC_XPHIDEF);
    303
    304		yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
    305							state->crtc_h,
    306							ATMEL_HLCDC_YPHIDEF);
    307
    308		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
    309				state->crtc_w < state->src_w ?
    310				heo_downscaling_xcoef :
    311				heo_upscaling_xcoef,
    312				ARRAY_SIZE(heo_upscaling_xcoef),
    313				desc->layout.phicoeffs.x);
    314
    315		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
    316				state->crtc_h < state->src_h ?
    317				heo_downscaling_ycoef :
    318				heo_upscaling_ycoef,
    319				ARRAY_SIZE(heo_upscaling_ycoef),
    320				desc->layout.phicoeffs.y);
    321	} else {
    322		xfactor = (1024 * state->src_w) / state->crtc_w;
    323		yfactor = (1024 * state->src_h) / state->crtc_h;
    324	}
    325
    326	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
    327				    ATMEL_HLCDC_LAYER_SCALER_ENABLE |
    328				    ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
    329								     yfactor));
    330}
    331
    332static void
    333atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
    334				      struct atmel_hlcdc_plane_state *state)
    335{
    336	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    337
    338	if (desc->layout.size)
    339		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
    340					ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
    341							       state->crtc_h));
    342
    343	if (desc->layout.memsize)
    344		atmel_hlcdc_layer_write_cfg(&plane->layer,
    345					desc->layout.memsize,
    346					ATMEL_HLCDC_LAYER_SIZE(state->src_w,
    347							       state->src_h));
    348
    349	if (desc->layout.pos)
    350		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
    351					ATMEL_HLCDC_LAYER_POS(state->crtc_x,
    352							      state->crtc_y));
    353
    354	atmel_hlcdc_plane_setup_scaler(plane, state);
    355}
    356
    357static void
    358atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
    359					struct atmel_hlcdc_plane_state *state)
    360{
    361	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
    362	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    363	const struct drm_format_info *format = state->base.fb->format;
    364
    365	/*
    366	 * Rotation optimization is not working on RGB888 (rotation is still
    367	 * working but without any optimization).
    368	 */
    369	if (format->format == DRM_FORMAT_RGB888)
    370		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
    371
    372	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
    373				    cfg);
    374
    375	cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
    376
    377	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
    378		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
    379		       ATMEL_HLCDC_LAYER_ITER;
    380
    381		if (format->has_alpha)
    382			cfg |= ATMEL_HLCDC_LAYER_LAEN;
    383		else
    384			cfg |= ATMEL_HLCDC_LAYER_GAEN |
    385			       ATMEL_HLCDC_LAYER_GA(state->base.alpha);
    386	}
    387
    388	if (state->disc_h && state->disc_w)
    389		cfg |= ATMEL_HLCDC_LAYER_DISCEN;
    390
    391	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
    392				    cfg);
    393}
    394
    395static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
    396					struct atmel_hlcdc_plane_state *state)
    397{
    398	u32 cfg;
    399	int ret;
    400
    401	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
    402					       &cfg);
    403	if (ret)
    404		return;
    405
    406	if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
    407	     state->base.fb->format->format == DRM_FORMAT_NV61) &&
    408	    drm_rotation_90_or_270(state->base.rotation))
    409		cfg |= ATMEL_HLCDC_YUV422ROT;
    410
    411	atmel_hlcdc_layer_write_cfg(&plane->layer,
    412				    ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
    413}
    414
    415static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
    416					  struct atmel_hlcdc_plane_state *state)
    417{
    418	struct drm_crtc *crtc = state->base.crtc;
    419	struct drm_color_lut *lut;
    420	int idx;
    421
    422	if (!crtc || !crtc->state)
    423		return;
    424
    425	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
    426		return;
    427
    428	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
    429
    430	for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
    431		u32 val = ((lut->red << 8) & 0xff0000) |
    432			(lut->green & 0xff00) |
    433			(lut->blue >> 8);
    434
    435		atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
    436	}
    437}
    438
    439static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
    440					struct atmel_hlcdc_plane_state *state)
    441{
    442	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    443	struct drm_framebuffer *fb = state->base.fb;
    444	u32 sr;
    445	int i;
    446
    447	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
    448
    449	for (i = 0; i < state->nplanes; i++) {
    450		struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
    451
    452		state->dscrs[i]->addr = gem->paddr + state->offsets[i];
    453
    454		atmel_hlcdc_layer_write_reg(&plane->layer,
    455					    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
    456					    state->dscrs[i]->self);
    457
    458		if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
    459			atmel_hlcdc_layer_write_reg(&plane->layer,
    460					ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
    461					state->dscrs[i]->addr);
    462			atmel_hlcdc_layer_write_reg(&plane->layer,
    463					ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
    464					state->dscrs[i]->ctrl);
    465			atmel_hlcdc_layer_write_reg(&plane->layer,
    466					ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
    467					state->dscrs[i]->self);
    468		}
    469
    470		if (desc->layout.xstride[i])
    471			atmel_hlcdc_layer_write_cfg(&plane->layer,
    472						    desc->layout.xstride[i],
    473						    state->xstride[i]);
    474
    475		if (desc->layout.pstride[i])
    476			atmel_hlcdc_layer_write_cfg(&plane->layer,
    477						    desc->layout.pstride[i],
    478						    state->pstride[i]);
    479	}
    480}
    481
    482int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
    483{
    484	unsigned int ahb_load[2] = { };
    485	struct drm_plane *plane;
    486
    487	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
    488		struct atmel_hlcdc_plane_state *plane_state;
    489		struct drm_plane_state *plane_s;
    490		unsigned int pixels, load = 0;
    491		int i;
    492
    493		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
    494		if (IS_ERR(plane_s))
    495			return PTR_ERR(plane_s);
    496
    497		plane_state =
    498			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
    499
    500		pixels = (plane_state->src_w * plane_state->src_h) -
    501			 (plane_state->disc_w * plane_state->disc_h);
    502
    503		for (i = 0; i < plane_state->nplanes; i++)
    504			load += pixels * plane_state->bpp[i];
    505
    506		if (ahb_load[0] <= ahb_load[1])
    507			plane_state->ahb_id = 0;
    508		else
    509			plane_state->ahb_id = 1;
    510
    511		ahb_load[plane_state->ahb_id] += load;
    512	}
    513
    514	return 0;
    515}
    516
    517int
    518atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
    519{
    520	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
    521	const struct atmel_hlcdc_layer_cfg_layout *layout;
    522	struct atmel_hlcdc_plane_state *primary_state;
    523	struct drm_plane_state *primary_s;
    524	struct atmel_hlcdc_plane *primary;
    525	struct drm_plane *ovl;
    526
    527	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
    528	layout = &primary->layer.desc->layout;
    529	if (!layout->disc_pos || !layout->disc_size)
    530		return 0;
    531
    532	primary_s = drm_atomic_get_plane_state(c_state->state,
    533					       &primary->base);
    534	if (IS_ERR(primary_s))
    535		return PTR_ERR(primary_s);
    536
    537	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
    538
    539	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
    540		struct atmel_hlcdc_plane_state *ovl_state;
    541		struct drm_plane_state *ovl_s;
    542
    543		if (ovl == c_state->crtc->primary)
    544			continue;
    545
    546		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
    547		if (IS_ERR(ovl_s))
    548			return PTR_ERR(ovl_s);
    549
    550		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
    551
    552		if (!ovl_s->visible ||
    553		    !ovl_s->fb ||
    554		    ovl_s->fb->format->has_alpha ||
    555		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
    556			continue;
    557
    558		/* TODO: implement a smarter hidden area detection */
    559		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
    560			continue;
    561
    562		disc_x = ovl_state->crtc_x;
    563		disc_y = ovl_state->crtc_y;
    564		disc_h = ovl_state->crtc_h;
    565		disc_w = ovl_state->crtc_w;
    566	}
    567
    568	primary_state->disc_x = disc_x;
    569	primary_state->disc_y = disc_y;
    570	primary_state->disc_w = disc_w;
    571	primary_state->disc_h = disc_h;
    572
    573	return 0;
    574}
    575
    576static void
    577atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
    578				   struct atmel_hlcdc_plane_state *state)
    579{
    580	const struct atmel_hlcdc_layer_cfg_layout *layout;
    581
    582	layout = &plane->layer.desc->layout;
    583	if (!layout->disc_pos || !layout->disc_size)
    584		return;
    585
    586	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
    587				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
    588							   state->disc_y));
    589
    590	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
    591				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
    592							    state->disc_h));
    593}
    594
    595static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
    596					  struct drm_atomic_state *state)
    597{
    598	struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
    599	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
    600	struct atmel_hlcdc_plane_state *hstate =
    601				drm_plane_state_to_atmel_hlcdc_plane_state(s);
    602	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    603	struct drm_framebuffer *fb = hstate->base.fb;
    604	const struct drm_display_mode *mode;
    605	struct drm_crtc_state *crtc_state;
    606	int ret;
    607	int i;
    608
    609	if (!hstate->base.crtc || WARN_ON(!fb))
    610		return 0;
    611
    612	crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
    613	mode = &crtc_state->adjusted_mode;
    614
    615	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
    616						  (1 << 16) / 2048,
    617						  INT_MAX, true, true);
    618	if (ret || !s->visible)
    619		return ret;
    620
    621	hstate->src_x = s->src.x1;
    622	hstate->src_y = s->src.y1;
    623	hstate->src_w = drm_rect_width(&s->src);
    624	hstate->src_h = drm_rect_height(&s->src);
    625	hstate->crtc_x = s->dst.x1;
    626	hstate->crtc_y = s->dst.y1;
    627	hstate->crtc_w = drm_rect_width(&s->dst);
    628	hstate->crtc_h = drm_rect_height(&s->dst);
    629
    630	if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
    631	    SUBPIXEL_MASK)
    632		return -EINVAL;
    633
    634	hstate->src_x >>= 16;
    635	hstate->src_y >>= 16;
    636	hstate->src_w >>= 16;
    637	hstate->src_h >>= 16;
    638
    639	hstate->nplanes = fb->format->num_planes;
    640	if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
    641		return -EINVAL;
    642
    643	for (i = 0; i < hstate->nplanes; i++) {
    644		unsigned int offset = 0;
    645		int xdiv = i ? fb->format->hsub : 1;
    646		int ydiv = i ? fb->format->vsub : 1;
    647
    648		hstate->bpp[i] = fb->format->cpp[i];
    649		if (!hstate->bpp[i])
    650			return -EINVAL;
    651
    652		switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
    653		case DRM_MODE_ROTATE_90:
    654			offset = (hstate->src_y / ydiv) *
    655				 fb->pitches[i];
    656			offset += ((hstate->src_x + hstate->src_w - 1) /
    657				   xdiv) * hstate->bpp[i];
    658			hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
    659					    fb->pitches[i]) -
    660					  (2 * hstate->bpp[i]);
    661			hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
    662			break;
    663		case DRM_MODE_ROTATE_180:
    664			offset = ((hstate->src_y + hstate->src_h - 1) /
    665				  ydiv) * fb->pitches[i];
    666			offset += ((hstate->src_x + hstate->src_w - 1) /
    667				   xdiv) * hstate->bpp[i];
    668			hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
    669					   hstate->bpp[i]) - fb->pitches[i];
    670			hstate->pstride[i] = -2 * hstate->bpp[i];
    671			break;
    672		case DRM_MODE_ROTATE_270:
    673			offset = ((hstate->src_y + hstate->src_h - 1) /
    674				  ydiv) * fb->pitches[i];
    675			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
    676			hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
    677					  fb->pitches[i];
    678			hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
    679			break;
    680		case DRM_MODE_ROTATE_0:
    681		default:
    682			offset = (hstate->src_y / ydiv) * fb->pitches[i];
    683			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
    684			hstate->xstride[i] = fb->pitches[i] -
    685					  ((hstate->src_w / xdiv) *
    686					   hstate->bpp[i]);
    687			hstate->pstride[i] = 0;
    688			break;
    689		}
    690
    691		hstate->offsets[i] = offset + fb->offsets[i];
    692	}
    693
    694	/*
    695	 * Swap width and size in case of 90 or 270 degrees rotation
    696	 */
    697	if (drm_rotation_90_or_270(hstate->base.rotation)) {
    698		swap(hstate->src_w, hstate->src_h);
    699	}
    700
    701	if (!desc->layout.size &&
    702	    (mode->hdisplay != hstate->crtc_w ||
    703	     mode->vdisplay != hstate->crtc_h))
    704		return -EINVAL;
    705
    706	if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
    707	    (!desc->layout.memsize ||
    708	     hstate->base.fb->format->has_alpha))
    709		return -EINVAL;
    710
    711	return 0;
    712}
    713
    714static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
    715					     struct drm_atomic_state *state)
    716{
    717	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
    718
    719	/* Disable interrupts */
    720	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
    721				    0xffffffff);
    722
    723	/* Disable the layer */
    724	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
    725				    ATMEL_HLCDC_LAYER_RST |
    726				    ATMEL_HLCDC_LAYER_A2Q |
    727				    ATMEL_HLCDC_LAYER_UPDATE);
    728
    729	/* Clear all pending interrupts */
    730	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
    731}
    732
    733static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
    734					    struct drm_atomic_state *state)
    735{
    736	struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
    737								       p);
    738	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
    739	struct atmel_hlcdc_plane_state *hstate =
    740			drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
    741	u32 sr;
    742
    743	if (!new_s->crtc || !new_s->fb)
    744		return;
    745
    746	if (!hstate->base.visible) {
    747		atmel_hlcdc_plane_atomic_disable(p, state);
    748		return;
    749	}
    750
    751	atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
    752	atmel_hlcdc_plane_update_general_settings(plane, hstate);
    753	atmel_hlcdc_plane_update_format(plane, hstate);
    754	atmel_hlcdc_plane_update_clut(plane, hstate);
    755	atmel_hlcdc_plane_update_buffers(plane, hstate);
    756	atmel_hlcdc_plane_update_disc_area(plane, hstate);
    757
    758	/* Enable the overrun interrupts. */
    759	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
    760				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
    761				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
    762				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
    763
    764	/* Apply the new config at the next SOF event. */
    765	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
    766	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
    767			ATMEL_HLCDC_LAYER_UPDATE |
    768			(sr & ATMEL_HLCDC_LAYER_EN ?
    769			 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
    770}
    771
    772static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
    773{
    774	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    775
    776	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
    777	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
    778		int ret;
    779
    780		ret = drm_plane_create_alpha_property(&plane->base);
    781		if (ret)
    782			return ret;
    783	}
    784
    785	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
    786		int ret;
    787
    788		ret = drm_plane_create_rotation_property(&plane->base,
    789							 DRM_MODE_ROTATE_0,
    790							 DRM_MODE_ROTATE_0 |
    791							 DRM_MODE_ROTATE_90 |
    792							 DRM_MODE_ROTATE_180 |
    793							 DRM_MODE_ROTATE_270);
    794		if (ret)
    795			return ret;
    796	}
    797
    798	if (desc->layout.csc) {
    799		/*
    800		 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
    801		 * userspace modify these factors (using a BLOB property ?).
    802		 */
    803		atmel_hlcdc_layer_write_cfg(&plane->layer,
    804					    desc->layout.csc,
    805					    0x4c900091);
    806		atmel_hlcdc_layer_write_cfg(&plane->layer,
    807					    desc->layout.csc + 1,
    808					    0x7a5f5090);
    809		atmel_hlcdc_layer_write_cfg(&plane->layer,
    810					    desc->layout.csc + 2,
    811					    0x40040890);
    812	}
    813
    814	return 0;
    815}
    816
    817void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
    818{
    819	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
    820	u32 isr;
    821
    822	isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
    823
    824	/*
    825	 * There's not much we can do in case of overrun except informing
    826	 * the user. However, we are in interrupt context here, hence the
    827	 * use of dev_dbg().
    828	 */
    829	if (isr &
    830	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
    831	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
    832		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
    833			desc->name);
    834}
    835
    836static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
    837	.atomic_check = atmel_hlcdc_plane_atomic_check,
    838	.atomic_update = atmel_hlcdc_plane_atomic_update,
    839	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
    840};
    841
    842static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
    843					 struct atmel_hlcdc_plane_state *state)
    844{
    845	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
    846	int i;
    847
    848	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
    849		struct atmel_hlcdc_dma_channel_dscr *dscr;
    850		dma_addr_t dscr_dma;
    851
    852		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
    853		if (!dscr)
    854			goto err;
    855
    856		dscr->addr = 0;
    857		dscr->next = dscr_dma;
    858		dscr->self = dscr_dma;
    859		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
    860
    861		state->dscrs[i] = dscr;
    862	}
    863
    864	return 0;
    865
    866err:
    867	for (i--; i >= 0; i--) {
    868		dma_pool_free(dc->dscrpool, state->dscrs[i],
    869			      state->dscrs[i]->self);
    870	}
    871
    872	return -ENOMEM;
    873}
    874
    875static void atmel_hlcdc_plane_reset(struct drm_plane *p)
    876{
    877	struct atmel_hlcdc_plane_state *state;
    878
    879	if (p->state) {
    880		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
    881
    882		if (state->base.fb)
    883			drm_framebuffer_put(state->base.fb);
    884
    885		kfree(state);
    886		p->state = NULL;
    887	}
    888
    889	state = kzalloc(sizeof(*state), GFP_KERNEL);
    890	if (state) {
    891		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
    892			kfree(state);
    893			dev_err(p->dev->dev,
    894				"Failed to allocate initial plane state\n");
    895			return;
    896		}
    897		__drm_atomic_helper_plane_reset(p, &state->base);
    898	}
    899}
    900
    901static struct drm_plane_state *
    902atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
    903{
    904	struct atmel_hlcdc_plane_state *state =
    905			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
    906	struct atmel_hlcdc_plane_state *copy;
    907
    908	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
    909	if (!copy)
    910		return NULL;
    911
    912	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
    913		kfree(copy);
    914		return NULL;
    915	}
    916
    917	if (copy->base.fb)
    918		drm_framebuffer_get(copy->base.fb);
    919
    920	return &copy->base;
    921}
    922
    923static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
    924						   struct drm_plane_state *s)
    925{
    926	struct atmel_hlcdc_plane_state *state =
    927			drm_plane_state_to_atmel_hlcdc_plane_state(s);
    928	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
    929	int i;
    930
    931	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
    932		dma_pool_free(dc->dscrpool, state->dscrs[i],
    933			      state->dscrs[i]->self);
    934	}
    935
    936	if (s->fb)
    937		drm_framebuffer_put(s->fb);
    938
    939	kfree(state);
    940}
    941
    942static const struct drm_plane_funcs layer_plane_funcs = {
    943	.update_plane = drm_atomic_helper_update_plane,
    944	.disable_plane = drm_atomic_helper_disable_plane,
    945	.destroy = drm_plane_cleanup,
    946	.reset = atmel_hlcdc_plane_reset,
    947	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
    948	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
    949};
    950
    951static int atmel_hlcdc_plane_create(struct drm_device *dev,
    952				    const struct atmel_hlcdc_layer_desc *desc)
    953{
    954	struct atmel_hlcdc_dc *dc = dev->dev_private;
    955	struct atmel_hlcdc_plane *plane;
    956	enum drm_plane_type type;
    957	int ret;
    958
    959	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
    960	if (!plane)
    961		return -ENOMEM;
    962
    963	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
    964
    965	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
    966		type = DRM_PLANE_TYPE_PRIMARY;
    967	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
    968		type = DRM_PLANE_TYPE_CURSOR;
    969	else
    970		type = DRM_PLANE_TYPE_OVERLAY;
    971
    972	ret = drm_universal_plane_init(dev, &plane->base, 0,
    973				       &layer_plane_funcs,
    974				       desc->formats->formats,
    975				       desc->formats->nformats,
    976				       NULL, type, NULL);
    977	if (ret)
    978		return ret;
    979
    980	drm_plane_helper_add(&plane->base,
    981			     &atmel_hlcdc_layer_plane_helper_funcs);
    982
    983	/* Set default property values*/
    984	ret = atmel_hlcdc_plane_init_properties(plane);
    985	if (ret)
    986		return ret;
    987
    988	dc->layers[desc->id] = &plane->layer;
    989
    990	return 0;
    991}
    992
    993int atmel_hlcdc_create_planes(struct drm_device *dev)
    994{
    995	struct atmel_hlcdc_dc *dc = dev->dev_private;
    996	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
    997	int nlayers = dc->desc->nlayers;
    998	int i, ret;
    999
   1000	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
   1001				sizeof(struct atmel_hlcdc_dma_channel_dscr),
   1002				sizeof(u64), 0);
   1003	if (!dc->dscrpool)
   1004		return -ENOMEM;
   1005
   1006	for (i = 0; i < nlayers; i++) {
   1007		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
   1008		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
   1009		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
   1010			continue;
   1011
   1012		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
   1013		if (ret)
   1014			return ret;
   1015	}
   1016
   1017	return 0;
   1018}