Linux Audio

Check our new training course

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