Linux Audio

Check our new training course

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