Linux Audio

Check our new training course

Loading...
v6.13.7
   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_blend.h>
  15#include <drm/drm_fb_dma_helper.h>
  16#include <drm/drm_fourcc.h>
  17#include <drm/drm_framebuffer.h>
  18#include <drm/drm_gem_dma_helper.h>
  19
  20#include "atmel_hlcdc_dc.h"
  21
  22/**
  23 * struct atmel_hlcdc_plane_state - 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 * @disc_x: x discard position
  35 * @disc_y: y discard position
  36 * @disc_w: discard width
  37 * @disc_h: discard height
  38 * @ahb_id: AHB identification number
  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	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_LAYER_MAX_PLANES];
  66	unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
  67	int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
  68	int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
  69	int nplanes;
  70
  71	/* DMA descriptors. */
  72	struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
  73};
  74
  75static inline struct atmel_hlcdc_plane_state *
  76drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
  77{
  78	return container_of(s, struct atmel_hlcdc_plane_state, base);
  79}
  80
  81#define SUBPIXEL_MASK			0xffff
  82
  83static uint32_t rgb_formats[] = {
  84	DRM_FORMAT_C8,
  85	DRM_FORMAT_XRGB4444,
  86	DRM_FORMAT_ARGB4444,
  87	DRM_FORMAT_RGBA4444,
  88	DRM_FORMAT_ARGB1555,
  89	DRM_FORMAT_RGB565,
  90	DRM_FORMAT_RGB888,
  91	DRM_FORMAT_XRGB8888,
  92	DRM_FORMAT_ARGB8888,
  93	DRM_FORMAT_RGBA8888,
  94};
  95
  96struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
  97	.formats = rgb_formats,
  98	.nformats = ARRAY_SIZE(rgb_formats),
  99};
 100
 101static uint32_t rgb_and_yuv_formats[] = {
 102	DRM_FORMAT_C8,
 103	DRM_FORMAT_XRGB4444,
 104	DRM_FORMAT_ARGB4444,
 105	DRM_FORMAT_RGBA4444,
 106	DRM_FORMAT_ARGB1555,
 107	DRM_FORMAT_RGB565,
 108	DRM_FORMAT_RGB888,
 109	DRM_FORMAT_XRGB8888,
 110	DRM_FORMAT_ARGB8888,
 111	DRM_FORMAT_RGBA8888,
 112	DRM_FORMAT_AYUV,
 113	DRM_FORMAT_YUYV,
 114	DRM_FORMAT_UYVY,
 115	DRM_FORMAT_YVYU,
 116	DRM_FORMAT_VYUY,
 117	DRM_FORMAT_NV21,
 118	DRM_FORMAT_NV61,
 119	DRM_FORMAT_YUV422,
 120	DRM_FORMAT_YUV420,
 121};
 122
 123struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
 124	.formats = rgb_and_yuv_formats,
 125	.nformats = ARRAY_SIZE(rgb_and_yuv_formats),
 126};
 127
 128static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
 129{
 130	switch (format) {
 131	case DRM_FORMAT_C8:
 132		*mode = ATMEL_HLCDC_C8_MODE;
 133		break;
 134	case DRM_FORMAT_XRGB4444:
 135		*mode = ATMEL_HLCDC_XRGB4444_MODE;
 136		break;
 137	case DRM_FORMAT_ARGB4444:
 138		*mode = ATMEL_HLCDC_ARGB4444_MODE;
 139		break;
 140	case DRM_FORMAT_RGBA4444:
 141		*mode = ATMEL_HLCDC_RGBA4444_MODE;
 142		break;
 143	case DRM_FORMAT_RGB565:
 144		*mode = ATMEL_HLCDC_RGB565_MODE;
 145		break;
 146	case DRM_FORMAT_RGB888:
 147		*mode = ATMEL_HLCDC_RGB888_MODE;
 148		break;
 149	case DRM_FORMAT_ARGB1555:
 150		*mode = ATMEL_HLCDC_ARGB1555_MODE;
 151		break;
 152	case DRM_FORMAT_XRGB8888:
 153		*mode = ATMEL_HLCDC_XRGB8888_MODE;
 154		break;
 155	case DRM_FORMAT_ARGB8888:
 156		*mode = ATMEL_HLCDC_ARGB8888_MODE;
 157		break;
 158	case DRM_FORMAT_RGBA8888:
 159		*mode = ATMEL_HLCDC_RGBA8888_MODE;
 160		break;
 161	case DRM_FORMAT_AYUV:
 162		*mode = ATMEL_HLCDC_AYUV_MODE;
 163		break;
 164	case DRM_FORMAT_YUYV:
 165		*mode = ATMEL_HLCDC_YUYV_MODE;
 166		break;
 167	case DRM_FORMAT_UYVY:
 168		*mode = ATMEL_HLCDC_UYVY_MODE;
 169		break;
 170	case DRM_FORMAT_YVYU:
 171		*mode = ATMEL_HLCDC_YVYU_MODE;
 172		break;
 173	case DRM_FORMAT_VYUY:
 174		*mode = ATMEL_HLCDC_VYUY_MODE;
 175		break;
 176	case DRM_FORMAT_NV21:
 177		*mode = ATMEL_HLCDC_NV21_MODE;
 178		break;
 179	case DRM_FORMAT_NV61:
 180		*mode = ATMEL_HLCDC_NV61_MODE;
 181		break;
 182	case DRM_FORMAT_YUV420:
 183		*mode = ATMEL_HLCDC_YUV420_MODE;
 184		break;
 185	case DRM_FORMAT_YUV422:
 186		*mode = ATMEL_HLCDC_YUV422_MODE;
 187		break;
 188	default:
 189		return -ENOTSUPP;
 190	}
 191
 192	return 0;
 193}
 194
 195static u32 heo_downscaling_xcoef[] = {
 196	0x11343311,
 197	0x000000f7,
 198	0x1635300c,
 199	0x000000f9,
 200	0x1b362c08,
 201	0x000000fb,
 202	0x1f372804,
 203	0x000000fe,
 204	0x24382400,
 205	0x00000000,
 206	0x28371ffe,
 207	0x00000004,
 208	0x2c361bfb,
 209	0x00000008,
 210	0x303516f9,
 211	0x0000000c,
 212};
 213
 214static u32 heo_downscaling_ycoef[] = {
 215	0x00123737,
 216	0x00173732,
 217	0x001b382d,
 218	0x001f3928,
 219	0x00243824,
 220	0x0028391f,
 221	0x002d381b,
 222	0x00323717,
 223};
 224
 225static u32 heo_upscaling_xcoef[] = {
 226	0xf74949f7,
 227	0x00000000,
 228	0xf55f33fb,
 229	0x000000fe,
 230	0xf5701efe,
 231	0x000000ff,
 232	0xf87c0dff,
 233	0x00000000,
 234	0x00800000,
 235	0x00000000,
 236	0x0d7cf800,
 237	0x000000ff,
 238	0x1e70f5ff,
 239	0x000000fe,
 240	0x335ff5fe,
 241	0x000000fb,
 242};
 243
 244static u32 heo_upscaling_ycoef[] = {
 245	0x00004040,
 246	0x00075920,
 247	0x00056f0c,
 248	0x00027b03,
 249	0x00008000,
 250	0x00037b02,
 251	0x000c6f05,
 252	0x00205907,
 253};
 254
 255#define ATMEL_HLCDC_XPHIDEF	4
 256#define ATMEL_HLCDC_YPHIDEF	4
 257
 258static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
 259						  u32 dstsize,
 260						  u32 phidef)
 261{
 262	u32 factor, max_memsize;
 263
 264	factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
 265	max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
 266
 267	if (max_memsize > srcsize - 1)
 268		factor--;
 269
 270	return factor;
 271}
 272
 273static void
 274atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
 275				      const u32 *coeff_tab, int size,
 276				      unsigned int cfg_offs)
 277{
 278	int i;
 279
 280	for (i = 0; i < size; i++)
 281		atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
 282					    coeff_tab[i]);
 283}
 284
 285static
 286void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
 287				    struct atmel_hlcdc_plane_state *state)
 288{
 289	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 290	u32 xfactor, yfactor;
 291
 292	if (!desc->layout.scaler_config)
 293		return;
 294
 295	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
 296		atmel_hlcdc_layer_write_cfg(&plane->layer,
 297					    desc->layout.scaler_config, 0);
 298		return;
 299	}
 300
 301	if (desc->layout.phicoeffs.x) {
 302		xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
 303							state->crtc_w,
 304							ATMEL_HLCDC_XPHIDEF);
 305
 306		yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
 307							state->crtc_h,
 308							ATMEL_HLCDC_YPHIDEF);
 309
 310		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
 311				state->crtc_w < state->src_w ?
 312				heo_downscaling_xcoef :
 313				heo_upscaling_xcoef,
 314				ARRAY_SIZE(heo_upscaling_xcoef),
 315				desc->layout.phicoeffs.x);
 316
 317		atmel_hlcdc_plane_scaler_set_phicoeff(plane,
 318				state->crtc_h < state->src_h ?
 319				heo_downscaling_ycoef :
 320				heo_upscaling_ycoef,
 321				ARRAY_SIZE(heo_upscaling_ycoef),
 322				desc->layout.phicoeffs.y);
 323	} else {
 324		xfactor = (1024 * state->src_w) / state->crtc_w;
 325		yfactor = (1024 * state->src_h) / state->crtc_h;
 326	}
 327
 328	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
 329				    ATMEL_HLCDC_LAYER_SCALER_ENABLE |
 330				    ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
 331								     yfactor));
 332}
 333
 334static
 335void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
 336				    struct atmel_hlcdc_plane_state *state)
 337{
 338	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 339	u32 xfactor, yfactor;
 340
 341	if (!desc->layout.scaler_config)
 342		return;
 343
 344	if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
 345		atmel_hlcdc_layer_write_cfg(&plane->layer,
 346					    desc->layout.scaler_config, 0);
 347		return;
 348	}
 349
 350	/* xfactor = round[(2^20 * XMEMSIZE)/XSIZE)] */
 351	xfactor = (u32)(((1 << 20) * state->src_w) / state->crtc_w);
 352
 353	/* yfactor = round[(2^20 * YMEMSIZE)/YSIZE)] */
 354	yfactor = (u32)(((1 << 20) * state->src_h) / state->crtc_h);
 355
 356	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
 357				    ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE |
 358				    ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE |
 359				    ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE |
 360				    ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE);
 361
 362	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 1,
 363				    yfactor);
 364	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 3,
 365				    xfactor);
 366
 367	/*
 368	 * With YCbCr 4:2:2 and YCbYcr 4:2:0 window resampling, configuration
 369	 * register LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT is half
 370	 * the value of yfactor and xfactor.
 371	 */
 372	if (state->base.fb->format->format == DRM_FORMAT_YUV420) {
 373		yfactor /= 2;
 374		xfactor /= 2;
 375	}
 376
 377	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
 378				    yfactor);
 379	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 4,
 380				    xfactor);
 381}
 382
 383static void
 384atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
 385				      struct atmel_hlcdc_plane_state *state)
 386{
 387	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 388	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
 389
 390	if (desc->layout.size)
 391		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
 392					ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
 393							       state->crtc_h));
 394
 395	if (desc->layout.memsize)
 396		atmel_hlcdc_layer_write_cfg(&plane->layer,
 397					desc->layout.memsize,
 398					ATMEL_HLCDC_LAYER_SIZE(state->src_w,
 399							       state->src_h));
 400
 401	if (desc->layout.pos)
 402		atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
 403					ATMEL_HLCDC_LAYER_POS(state->crtc_x,
 404							      state->crtc_y));
 405
 406	dc->desc->ops->plane_setup_scaler(plane, state);
 407}
 408
 409static
 410void atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
 411					       struct atmel_hlcdc_plane_state *state)
 412{
 413	unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
 414	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 415	const struct drm_format_info *format = state->base.fb->format;
 416
 417	/*
 418	 * Rotation optimization is not working on RGB888 (rotation is still
 419	 * working but without any optimization).
 420	 */
 421	if (format->format == DRM_FORMAT_RGB888)
 422		cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
 423
 424	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
 425				    cfg);
 426
 427	cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
 428
 429	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
 430		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
 431		       ATMEL_HLCDC_LAYER_ITER;
 432
 433		if (format->has_alpha)
 434			cfg |= ATMEL_HLCDC_LAYER_LAEN;
 435		else
 436			cfg |= ATMEL_HLCDC_LAYER_GAEN |
 437			       ATMEL_HLCDC_LAYER_GA(state->base.alpha);
 438	}
 439
 440	if (state->disc_h && state->disc_w)
 441		cfg |= ATMEL_HLCDC_LAYER_DISCEN;
 442
 443	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
 444				    cfg);
 445}
 446
 447static
 448void atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
 449					       struct atmel_hlcdc_plane_state *state)
 450{
 451	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 452	const struct drm_format_info *format = state->base.fb->format;
 453	unsigned int cfg;
 454
 455	atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_XLCDC_LAYER_DMA_CFG,
 456				    ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id);
 457
 458	cfg = ATMEL_XLCDC_LAYER_DMA | ATMEL_XLCDC_LAYER_REP;
 459
 460	if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
 461		/*
 462		 * Alpha Blending bits specific to SAM9X7 SoC
 463		 */
 464		cfg |= ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS |
 465		       ATMEL_XLCDC_LAYER_SFACTA_ONE |
 466		       ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS |
 467		       ATMEL_XLCDC_LAYER_DFACTA_ONE;
 468		if (format->has_alpha)
 469			cfg |= ATMEL_XLCDC_LAYER_A0(0xff);
 470		else
 471			cfg |= ATMEL_XLCDC_LAYER_A0(state->base.alpha);
 472	}
 473
 474	if (state->disc_h && state->disc_w)
 475		cfg |= ATMEL_XLCDC_LAYER_DISCEN;
 476
 477	atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
 478				    cfg);
 479}
 480
 481static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
 482					struct atmel_hlcdc_plane_state *state)
 483{
 484	u32 cfg;
 485	int ret;
 486
 487	ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
 488					       &cfg);
 489	if (ret)
 490		return;
 491
 492	if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
 493	     state->base.fb->format->format == DRM_FORMAT_NV61) &&
 494	    drm_rotation_90_or_270(state->base.rotation))
 495		cfg |= ATMEL_HLCDC_YUV422ROT;
 496
 497	atmel_hlcdc_layer_write_cfg(&plane->layer,
 498				    ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
 499}
 500
 501static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
 502					  struct atmel_hlcdc_plane_state *state)
 503{
 504	struct drm_crtc *crtc = state->base.crtc;
 505	struct drm_color_lut *lut;
 506	int idx;
 507
 508	if (!crtc || !crtc->state)
 509		return;
 510
 511	if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
 512		return;
 513
 514	lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
 515
 516	for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
 517		u32 val = ((lut->red << 8) & 0xff0000) |
 518			(lut->green & 0xff00) |
 519			(lut->blue >> 8);
 520
 521		atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
 522	}
 523}
 524
 525static void atmel_hlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
 526				       struct atmel_hlcdc_plane_state *state,
 527				       u32 sr, int i)
 528{
 529	atmel_hlcdc_layer_write_reg(&plane->layer,
 530				    ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
 531				    state->dscrs[i]->self);
 532
 533	if (sr & ATMEL_HLCDC_LAYER_EN)
 534		return;
 535
 536	atmel_hlcdc_layer_write_reg(&plane->layer,
 537				    ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
 538				    state->dscrs[i]->addr);
 539	atmel_hlcdc_layer_write_reg(&plane->layer,
 540				    ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
 541				    state->dscrs[i]->ctrl);
 542	atmel_hlcdc_layer_write_reg(&plane->layer,
 543				    ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
 544				    state->dscrs[i]->self);
 545}
 546
 547static void atmel_xlcdc_update_buffers(struct atmel_hlcdc_plane *plane,
 548				       struct atmel_hlcdc_plane_state *state,
 549				       u32 sr, int i)
 550{
 551	atmel_hlcdc_layer_write_reg(&plane->layer,
 552				    ATMEL_XLCDC_LAYER_PLANE_ADDR(i),
 553				    state->dscrs[i]->addr);
 554}
 555
 556static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
 557					     struct atmel_hlcdc_plane_state *state)
 558{
 559	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 560	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
 561	struct drm_framebuffer *fb = state->base.fb;
 562	u32 sr;
 563	int i;
 564
 565	if (!dc->desc->is_xlcdc)
 566		sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
 567
 568	for (i = 0; i < state->nplanes; i++) {
 569		struct drm_gem_dma_object *gem = drm_fb_dma_get_gem_obj(fb, i);
 570
 571		state->dscrs[i]->addr = gem->dma_addr + state->offsets[i];
 572
 573		dc->desc->ops->lcdc_update_buffers(plane, state, sr, i);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 574
 575		if (desc->layout.xstride[i])
 576			atmel_hlcdc_layer_write_cfg(&plane->layer,
 577						    desc->layout.xstride[i],
 578						    state->xstride[i]);
 579
 580		if (desc->layout.pstride[i])
 581			atmel_hlcdc_layer_write_cfg(&plane->layer,
 582						    desc->layout.pstride[i],
 583						    state->pstride[i]);
 584	}
 585}
 586
 587int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
 588{
 589	unsigned int ahb_load[2] = { };
 590	struct drm_plane *plane;
 591
 592	drm_atomic_crtc_state_for_each_plane(plane, c_state) {
 593		struct atmel_hlcdc_plane_state *plane_state;
 594		struct drm_plane_state *plane_s;
 595		unsigned int pixels, load = 0;
 596		int i;
 597
 598		plane_s = drm_atomic_get_plane_state(c_state->state, plane);
 599		if (IS_ERR(plane_s))
 600			return PTR_ERR(plane_s);
 601
 602		plane_state =
 603			drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
 604
 605		pixels = (plane_state->src_w * plane_state->src_h) -
 606			 (plane_state->disc_w * plane_state->disc_h);
 607
 608		for (i = 0; i < plane_state->nplanes; i++)
 609			load += pixels * plane_state->bpp[i];
 610
 611		if (ahb_load[0] <= ahb_load[1])
 612			plane_state->ahb_id = 0;
 613		else
 614			plane_state->ahb_id = 1;
 615
 616		ahb_load[plane_state->ahb_id] += load;
 617	}
 618
 619	return 0;
 620}
 621
 622int
 623atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
 624{
 625	int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
 626	const struct atmel_hlcdc_layer_cfg_layout *layout;
 627	struct atmel_hlcdc_plane_state *primary_state;
 628	struct drm_plane_state *primary_s;
 629	struct atmel_hlcdc_plane *primary;
 630	struct drm_plane *ovl;
 631
 632	primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
 633	layout = &primary->layer.desc->layout;
 634	if (!layout->disc_pos || !layout->disc_size)
 635		return 0;
 636
 637	primary_s = drm_atomic_get_plane_state(c_state->state,
 638					       &primary->base);
 639	if (IS_ERR(primary_s))
 640		return PTR_ERR(primary_s);
 641
 642	primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
 643
 644	drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
 645		struct atmel_hlcdc_plane_state *ovl_state;
 646		struct drm_plane_state *ovl_s;
 647
 648		if (ovl == c_state->crtc->primary)
 649			continue;
 650
 651		ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
 652		if (IS_ERR(ovl_s))
 653			return PTR_ERR(ovl_s);
 654
 655		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
 656
 657		if (!ovl_s->visible ||
 658		    !ovl_s->fb ||
 659		    ovl_s->fb->format->has_alpha ||
 660		    ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
 661			continue;
 662
 663		/* TODO: implement a smarter hidden area detection */
 664		if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
 665			continue;
 666
 667		disc_x = ovl_state->crtc_x;
 668		disc_y = ovl_state->crtc_y;
 669		disc_h = ovl_state->crtc_h;
 670		disc_w = ovl_state->crtc_w;
 671	}
 672
 673	primary_state->disc_x = disc_x;
 674	primary_state->disc_y = disc_y;
 675	primary_state->disc_w = disc_w;
 676	primary_state->disc_h = disc_h;
 677
 678	return 0;
 679}
 680
 681static void
 682atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
 683				   struct atmel_hlcdc_plane_state *state)
 684{
 685	const struct atmel_hlcdc_layer_cfg_layout *layout;
 686
 687	layout = &plane->layer.desc->layout;
 688	if (!layout->disc_pos || !layout->disc_size)
 689		return;
 690
 691	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
 692				ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
 693							   state->disc_y));
 694
 695	atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
 696				ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
 697							    state->disc_h));
 698}
 699
 700static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
 701					  struct drm_atomic_state *state)
 702{
 703	struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
 704	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 705	struct atmel_hlcdc_plane_state *hstate =
 706				drm_plane_state_to_atmel_hlcdc_plane_state(s);
 707	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 708	struct drm_framebuffer *fb = hstate->base.fb;
 709	const struct drm_display_mode *mode;
 710	struct drm_crtc_state *crtc_state;
 711	int ret;
 
 
 
 
 
 
 
 
 712	int i;
 713
 714	if (!hstate->base.crtc || WARN_ON(!fb))
 715		return 0;
 716
 717	crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
 718	mode = &crtc_state->adjusted_mode;
 719
 720	ret = drm_atomic_helper_check_plane_state(s, crtc_state,
 721						  (1 << 16) / 2048,
 722						  INT_MAX, true, true);
 723	if (ret || !s->visible)
 724		return ret;
 725
 726	hstate->src_x = s->src.x1;
 727	hstate->src_y = s->src.y1;
 728	hstate->src_w = drm_rect_width(&s->src);
 729	hstate->src_h = drm_rect_height(&s->src);
 730	hstate->crtc_x = s->dst.x1;
 731	hstate->crtc_y = s->dst.y1;
 732	hstate->crtc_w = drm_rect_width(&s->dst);
 733	hstate->crtc_h = drm_rect_height(&s->dst);
 734
 735	if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
 736	    SUBPIXEL_MASK)
 737		return -EINVAL;
 738
 739	hstate->src_x >>= 16;
 740	hstate->src_y >>= 16;
 741	hstate->src_w >>= 16;
 742	hstate->src_h >>= 16;
 743
 744	hstate->nplanes = fb->format->num_planes;
 745	if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
 746		return -EINVAL;
 747
 748	for (i = 0; i < hstate->nplanes; i++) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 749		unsigned int offset = 0;
 750		int xdiv = i ? fb->format->hsub : 1;
 751		int ydiv = i ? fb->format->vsub : 1;
 752
 753		hstate->bpp[i] = fb->format->cpp[i];
 754		if (!hstate->bpp[i])
 755			return -EINVAL;
 756
 757		switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
 758		case DRM_MODE_ROTATE_90:
 759			offset = (hstate->src_y / ydiv) *
 760				 fb->pitches[i];
 761			offset += ((hstate->src_x + hstate->src_w - 1) /
 762				   xdiv) * hstate->bpp[i];
 763			hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
 764					    fb->pitches[i]) -
 765					  (2 * hstate->bpp[i]);
 766			hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
 767			break;
 768		case DRM_MODE_ROTATE_180:
 769			offset = ((hstate->src_y + hstate->src_h - 1) /
 770				  ydiv) * fb->pitches[i];
 771			offset += ((hstate->src_x + hstate->src_w - 1) /
 772				   xdiv) * hstate->bpp[i];
 773			hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
 774					   hstate->bpp[i]) - fb->pitches[i];
 775			hstate->pstride[i] = -2 * hstate->bpp[i];
 776			break;
 777		case DRM_MODE_ROTATE_270:
 778			offset = ((hstate->src_y + hstate->src_h - 1) /
 779				  ydiv) * fb->pitches[i];
 780			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
 781			hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
 782					  fb->pitches[i];
 783			hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
 
 
 784			break;
 785		case DRM_MODE_ROTATE_0:
 786		default:
 787			offset = (hstate->src_y / ydiv) * fb->pitches[i];
 788			offset += (hstate->src_x / xdiv) * hstate->bpp[i];
 789			hstate->xstride[i] = fb->pitches[i] -
 790					  ((hstate->src_w / xdiv) *
 791					   hstate->bpp[i]);
 792			hstate->pstride[i] = 0;
 
 
 793			break;
 794		}
 795
 796		hstate->offsets[i] = offset + fb->offsets[i];
 797	}
 798
 799	/*
 800	 * Swap width and size in case of 90 or 270 degrees rotation
 801	 */
 802	if (drm_rotation_90_or_270(hstate->base.rotation)) {
 803		swap(hstate->src_w, hstate->src_h);
 804	}
 805
 806	if (!desc->layout.size &&
 807	    (mode->hdisplay != hstate->crtc_w ||
 808	     mode->vdisplay != hstate->crtc_h))
 809		return -EINVAL;
 810
 811	if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
 812	    (!desc->layout.memsize ||
 813	     hstate->base.fb->format->has_alpha))
 814		return -EINVAL;
 815
 816	return 0;
 817}
 818
 819static void atmel_hlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
 820{
 821	/* Disable interrupts */
 822	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
 823				    0xffffffff);
 824
 825	/* Disable the layer */
 826	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
 827				    ATMEL_HLCDC_LAYER_RST |
 828				    ATMEL_HLCDC_LAYER_A2Q |
 829				    ATMEL_HLCDC_LAYER_UPDATE);
 830
 831	/* Clear all pending interrupts */
 832	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 833}
 
 834
 835static void atmel_xlcdc_atomic_disable(struct atmel_hlcdc_plane *plane)
 836{
 837	/* Disable interrupts */
 838	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IDR,
 839				    0xffffffff);
 840
 841	/* Disable the layer */
 842	atmel_hlcdc_layer_write_reg(&plane->layer,
 843				    ATMEL_XLCDC_LAYER_ENR, 0);
 844
 845	/* Clear all pending interrupts */
 846	atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
 847}
 848
 849static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
 850					     struct drm_atomic_state *state)
 851{
 852	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 853	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
 
 
 854
 855	dc->desc->ops->lcdc_atomic_disable(plane);
 856}
 857
 858static void atmel_hlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
 859				      struct atmel_hlcdc_dc *dc)
 860{
 861	u32 sr;
 
 
 862
 863	/* Enable the overrun interrupts. */
 864	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
 865				    ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
 866				    ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
 867				    ATMEL_HLCDC_LAYER_OVR_IRQ(2));
 868
 869	/* Apply the new config at the next SOF event. */
 870	sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
 871	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
 872				    ATMEL_HLCDC_LAYER_UPDATE |
 873				    (sr & ATMEL_HLCDC_LAYER_EN ?
 874				    ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
 875}
 876
 877static void atmel_xlcdc_atomic_update(struct atmel_hlcdc_plane *plane,
 878				      struct atmel_hlcdc_dc *dc)
 879{
 880	/* Enable the overrun interrupts. */
 881	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_IER,
 882				    ATMEL_XLCDC_LAYER_OVR_IRQ(0) |
 883				    ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
 884				    ATMEL_XLCDC_LAYER_OVR_IRQ(2));
 885
 886	atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_XLCDC_LAYER_ENR,
 887				    ATMEL_XLCDC_LAYER_EN);
 
 888
 889	/*
 890	 * Updating XLCDC_xxxCFGx, XLCDC_xxxFBA and XLCDC_xxxEN,
 891	 * (where xxx indicates each layer) requires writing one to the
 892	 * Update Attribute field for each layer in LCDC_ATTRE register for SAM9X7.
 893	 */
 894	regmap_write(dc->hlcdc->regmap, ATMEL_XLCDC_ATTRE, ATMEL_XLCDC_BASE_UPDATE |
 895		     ATMEL_XLCDC_OVR1_UPDATE | ATMEL_XLCDC_OVR3_UPDATE |
 896		     ATMEL_XLCDC_HEO_UPDATE);
 897}
 898
 899static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
 900					    struct drm_atomic_state *state)
 901{
 902	struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
 903								       p);
 904	struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
 905	struct atmel_hlcdc_plane_state *hstate =
 906			drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
 907	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
 908
 909	if (!new_s->crtc || !new_s->fb)
 910		return;
 911
 912	if (!hstate->base.visible) {
 913		atmel_hlcdc_plane_atomic_disable(p, state);
 914		return;
 915	}
 916
 917	atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
 918	dc->desc->ops->lcdc_update_general_settings(plane, hstate);
 919	atmel_hlcdc_plane_update_format(plane, hstate);
 920	atmel_hlcdc_plane_update_clut(plane, hstate);
 921	atmel_hlcdc_plane_update_buffers(plane, hstate);
 922	atmel_hlcdc_plane_update_disc_area(plane, hstate);
 923
 924	dc->desc->ops->lcdc_atomic_update(plane, dc);
 925}
 926
 927static void atmel_hlcdc_csc_init(struct atmel_hlcdc_plane *plane,
 928				 const struct atmel_hlcdc_layer_desc *desc)
 
 
 929{
 930	/*
 931	 * TODO: declare a "yuv-to-rgb-conv-factors" property to let
 932	 * userspace modify these factors (using a BLOB property ?).
 933	 */
 934	static const u32 hlcdc_csc_coeffs[] = {
 935		0x4c900091,
 936		0x7a5f5090,
 937		0x40040890
 938	};
 939
 940	for (int i = 0; i < ARRAY_SIZE(hlcdc_csc_coeffs); i++) {
 941		atmel_hlcdc_layer_write_cfg(&plane->layer,
 942					    desc->layout.csc + i,
 943					    hlcdc_csc_coeffs[i]);
 944	}
 
 945}
 946
 947static void atmel_xlcdc_csc_init(struct atmel_hlcdc_plane *plane,
 948				 const struct atmel_hlcdc_layer_desc *desc)
 
 
 949{
 950	/*
 951	 * yuv-to-rgb-conv-factors are now defined from LCDC_HEOCFG16 to
 952	 * LCDC_HEOCFG21 registers in SAM9X7.
 953	 */
 954	static const u32 xlcdc_csc_coeffs[] = {
 955		0x00000488,
 956		0x00000648,
 957		0x1EA00480,
 958		0x00001D28,
 959		0x08100480,
 960		0x00000000,
 961		0x00000007
 962	};
 963
 964	for (int i = 0; i < ARRAY_SIZE(xlcdc_csc_coeffs); i++) {
 965		atmel_hlcdc_layer_write_cfg(&plane->layer,
 966					    desc->layout.csc + i,
 967					    xlcdc_csc_coeffs[i]);
 968	}
 969
 970	if (desc->layout.vxs_config && desc->layout.hxs_config) {
 971		/*
 972		 * Updating vxs.config and hxs.config fixes the
 973		 * Green Color Issue in SAM9X7 EGT Video Player App
 974		 */
 975		atmel_hlcdc_layer_write_cfg(&plane->layer,
 976					    desc->layout.vxs_config,
 977					    ATMEL_XLCDC_LAYER_VXSYCFG_ONE |
 978					    ATMEL_XLCDC_LAYER_VXSYTAP2_ENABLE |
 979					    ATMEL_XLCDC_LAYER_VXSCCFG_ONE |
 980					    ATMEL_XLCDC_LAYER_VXSCTAP2_ENABLE);
 981
 982		atmel_hlcdc_layer_write_cfg(&plane->layer,
 983					    desc->layout.hxs_config,
 984					    ATMEL_XLCDC_LAYER_HXSYCFG_ONE |
 985					    ATMEL_XLCDC_LAYER_HXSYTAP2_ENABLE |
 986					    ATMEL_XLCDC_LAYER_HXSCCFG_ONE |
 987					    ATMEL_XLCDC_LAYER_HXSCTAP2_ENABLE);
 988	}
 989}
 990
 991static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
 
 992{
 993	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
 994	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
 995
 996	if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
 997	    desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
 998		int ret;
 999
1000		ret = drm_plane_create_alpha_property(&plane->base);
1001		if (ret)
1002			return ret;
1003	}
1004
1005	if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
1006		int ret;
1007
1008		ret = drm_plane_create_rotation_property(&plane->base,
1009							 DRM_MODE_ROTATE_0,
1010							 DRM_MODE_ROTATE_0 |
1011							 DRM_MODE_ROTATE_90 |
1012							 DRM_MODE_ROTATE_180 |
1013							 DRM_MODE_ROTATE_270);
1014		if (ret)
1015			return ret;
1016	}
1017
1018	if (desc->layout.csc)
1019		dc->desc->ops->lcdc_csc_init(plane, desc);
 
 
 
 
 
 
 
 
 
 
 
 
 
1020
1021	return 0;
1022}
1023
1024static void atmel_hlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1025				const struct atmel_hlcdc_layer_desc *desc)
1026{
1027	u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
 
 
 
1028
1029	/*
1030	 * There's not much we can do in case of overrun except informing
1031	 * the user. However, we are in interrupt context here, hence the
1032	 * use of dev_dbg().
1033	 */
1034	if (isr &
1035	    (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
1036	     ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
1037		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
1038			desc->name);
1039}
1040
1041static void atmel_xlcdc_irq_dbg(struct atmel_hlcdc_plane *plane,
1042				const struct atmel_hlcdc_layer_desc *desc)
1043{
1044	u32 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_XLCDC_LAYER_ISR);
1045
1046	/*
1047	 * There's not much we can do in case of overrun except informing
1048	 * the user. However, we are in interrupt context here, hence the
1049	 * use of dev_dbg().
1050	 */
1051	if (isr &
1052	    (ATMEL_XLCDC_LAYER_OVR_IRQ(0) | ATMEL_XLCDC_LAYER_OVR_IRQ(1) |
1053	     ATMEL_XLCDC_LAYER_OVR_IRQ(2)))
1054		dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
1055			desc->name);
1056}
1057
1058void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
1059{
1060	const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
1061	struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
1062
1063	dc->desc->ops->lcdc_irq_dbg(plane, desc);
1064}
1065
1066const struct atmel_lcdc_dc_ops atmel_hlcdc_ops = {
1067	.plane_setup_scaler = atmel_hlcdc_plane_setup_scaler,
1068	.lcdc_update_buffers = atmel_hlcdc_update_buffers,
1069	.lcdc_atomic_disable = atmel_hlcdc_atomic_disable,
1070	.lcdc_update_general_settings = atmel_hlcdc_plane_update_general_settings,
1071	.lcdc_atomic_update = atmel_hlcdc_atomic_update,
1072	.lcdc_csc_init = atmel_hlcdc_csc_init,
1073	.lcdc_irq_dbg = atmel_hlcdc_irq_dbg,
1074};
1075
1076const struct atmel_lcdc_dc_ops atmel_xlcdc_ops = {
1077	.plane_setup_scaler = atmel_xlcdc_plane_setup_scaler,
1078	.lcdc_update_buffers = atmel_xlcdc_update_buffers,
1079	.lcdc_atomic_disable = atmel_xlcdc_atomic_disable,
1080	.lcdc_update_general_settings = atmel_xlcdc_plane_update_general_settings,
1081	.lcdc_atomic_update = atmel_xlcdc_atomic_update,
1082	.lcdc_csc_init = atmel_xlcdc_csc_init,
1083	.lcdc_irq_dbg = atmel_xlcdc_irq_dbg,
1084};
1085
1086static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
1087	.atomic_check = atmel_hlcdc_plane_atomic_check,
1088	.atomic_update = atmel_hlcdc_plane_atomic_update,
1089	.atomic_disable = atmel_hlcdc_plane_atomic_disable,
1090};
1091
1092static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
1093					 struct atmel_hlcdc_plane_state *state)
1094{
1095	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1096	int i;
1097
1098	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1099		struct atmel_hlcdc_dma_channel_dscr *dscr;
1100		dma_addr_t dscr_dma;
1101
1102		dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
1103		if (!dscr)
1104			goto err;
1105
1106		dscr->addr = 0;
1107		dscr->next = dscr_dma;
1108		dscr->self = dscr_dma;
1109		dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
1110
1111		state->dscrs[i] = dscr;
1112	}
1113
1114	return 0;
1115
1116err:
1117	for (i--; i >= 0; i--) {
1118		dma_pool_free(dc->dscrpool, state->dscrs[i],
1119			      state->dscrs[i]->self);
1120	}
1121
1122	return -ENOMEM;
1123}
1124
1125static void atmel_hlcdc_plane_reset(struct drm_plane *p)
1126{
1127	struct atmel_hlcdc_plane_state *state;
1128
1129	if (p->state) {
1130		state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1131
1132		if (state->base.fb)
1133			drm_framebuffer_put(state->base.fb);
1134
1135		kfree(state);
1136		p->state = NULL;
1137	}
1138
1139	state = kzalloc(sizeof(*state), GFP_KERNEL);
1140	if (state) {
1141		if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
1142			kfree(state);
1143			dev_err(p->dev->dev,
1144				"Failed to allocate initial plane state\n");
1145			return;
1146		}
1147		__drm_atomic_helper_plane_reset(p, &state->base);
 
 
 
1148	}
1149}
1150
1151static struct drm_plane_state *
1152atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
1153{
1154	struct atmel_hlcdc_plane_state *state =
1155			drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
1156	struct atmel_hlcdc_plane_state *copy;
1157
1158	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
1159	if (!copy)
1160		return NULL;
1161
1162	if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
1163		kfree(copy);
1164		return NULL;
1165	}
1166
1167	if (copy->base.fb)
1168		drm_framebuffer_get(copy->base.fb);
1169
1170	return &copy->base;
1171}
1172
1173static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
1174						   struct drm_plane_state *s)
1175{
1176	struct atmel_hlcdc_plane_state *state =
1177			drm_plane_state_to_atmel_hlcdc_plane_state(s);
1178	struct atmel_hlcdc_dc *dc = p->dev->dev_private;
1179	int i;
1180
1181	for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
1182		dma_pool_free(dc->dscrpool, state->dscrs[i],
1183			      state->dscrs[i]->self);
1184	}
1185
1186	if (s->fb)
1187		drm_framebuffer_put(s->fb);
1188
1189	kfree(state);
1190}
1191
1192static const struct drm_plane_funcs layer_plane_funcs = {
1193	.update_plane = drm_atomic_helper_update_plane,
1194	.disable_plane = drm_atomic_helper_disable_plane,
1195	.destroy = drm_plane_cleanup,
1196	.reset = atmel_hlcdc_plane_reset,
1197	.atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1198	.atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
 
 
1199};
1200
1201static int atmel_hlcdc_plane_create(struct drm_device *dev,
1202				    const struct atmel_hlcdc_layer_desc *desc)
 
1203{
1204	struct atmel_hlcdc_dc *dc = dev->dev_private;
1205	struct atmel_hlcdc_plane *plane;
1206	enum drm_plane_type type;
1207	int ret;
1208
1209	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1210	if (!plane)
1211		return -ENOMEM;
1212
1213	atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
 
1214
1215	if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1216		type = DRM_PLANE_TYPE_PRIMARY;
1217	else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1218		type = DRM_PLANE_TYPE_CURSOR;
1219	else
1220		type = DRM_PLANE_TYPE_OVERLAY;
1221
1222	ret = drm_universal_plane_init(dev, &plane->base, 0,
1223				       &layer_plane_funcs,
1224				       desc->formats->formats,
1225				       desc->formats->nformats,
1226				       NULL, type, NULL);
1227	if (ret)
1228		return ret;
1229
1230	drm_plane_helper_add(&plane->base,
1231			     &atmel_hlcdc_layer_plane_helper_funcs);
1232
1233	/* Set default property values*/
1234	ret = atmel_hlcdc_plane_init_properties(plane);
1235	if (ret)
1236		return ret;
1237
1238	dc->layers[desc->id] = &plane->layer;
1239
1240	return 0;
1241}
1242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1243int atmel_hlcdc_create_planes(struct drm_device *dev)
1244{
1245	struct atmel_hlcdc_dc *dc = dev->dev_private;
 
1246	const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1247	int nlayers = dc->desc->nlayers;
1248	int i, ret;
1249
 
 
 
 
1250	dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1251				sizeof(struct atmel_hlcdc_dma_channel_dscr),
1252				sizeof(u64), 0);
1253	if (!dc->dscrpool)
1254		return -ENOMEM;
1255
1256	for (i = 0; i < nlayers; i++) {
1257		if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1258		    descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1259		    descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1260			continue;
1261
1262		ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1263		if (ret)
1264			return ret;
1265	}
1266
1267	return 0;
1268}
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}