| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * rcar_du_plane.c  --  R-Car Display Unit Planes | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2013 Renesas Corporation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <drm/drmP.h>
 | 
					
						
							|  |  |  | #include <drm/drm_crtc.h>
 | 
					
						
							|  |  |  | #include <drm/drm_crtc_helper.h>
 | 
					
						
							|  |  |  | #include <drm/drm_fb_cma_helper.h>
 | 
					
						
							|  |  |  | #include <drm/drm_gem_cma_helper.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "rcar_du_drv.h"
 | 
					
						
							|  |  |  | #include "rcar_du_kms.h"
 | 
					
						
							|  |  |  | #include "rcar_du_plane.h"
 | 
					
						
							|  |  |  | #include "rcar_du_regs.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define RCAR_DU_COLORKEY_NONE		(0 << 24)
 | 
					
						
							|  |  |  | #define RCAR_DU_COLORKEY_SOURCE		(1 << 24)
 | 
					
						
							|  |  |  | #define RCAR_DU_COLORKEY_MASK		(1 << 24)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct rcar_du_kms_plane { | 
					
						
							|  |  |  | 	struct drm_plane plane; | 
					
						
							|  |  |  | 	struct rcar_du_plane *hwplane; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | static u32 rcar_du_plane_read(struct rcar_du_group *rgrp, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 			      unsigned int index, u32 reg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	return rcar_du_read(rgrp->dev, | 
					
						
							|  |  |  | 			    rgrp->mmio_offset + index * PLANE_OFF + reg); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | static void rcar_du_plane_write(struct rcar_du_group *rgrp, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 				unsigned int index, u32 reg, u32 data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg, | 
					
						
							|  |  |  | 		      data); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int rcar_du_plane_reserve(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 			  const struct rcar_du_format_info *format) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = plane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 	int ret = -EBUSY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_lock(&rgrp->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	for (i = 0; i < ARRAY_SIZE(rgrp->planes.planes); ++i) { | 
					
						
							|  |  |  | 		if (!(rgrp->planes.free & (1 << i))) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (format->planes == 1 || | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		    rgrp->planes.free & (1 << ((i + 1) % 8))) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	if (i == ARRAY_SIZE(rgrp->planes.planes)) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rgrp->planes.free &= ~(1 << i); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	if (format->planes == 2) | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rgrp->planes.free &= ~(1 << ((i + 1) % 8)); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	plane->hwindex = i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_unlock(&rgrp->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void rcar_du_plane_release(struct rcar_du_plane *plane) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = plane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (plane->hwindex == -1) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_lock(&rgrp->planes.lock); | 
					
						
							|  |  |  | 	rgrp->planes.free |= 1 << plane->hwindex; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	if (plane->format->planes == 2) | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rgrp->planes.free |= 1 << ((plane->hwindex + 1) % 8); | 
					
						
							|  |  |  | 	mutex_unlock(&rgrp->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	plane->hwindex = -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void rcar_du_plane_update_base(struct rcar_du_plane *plane) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = plane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	unsigned int index = plane->hwindex; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 20:54:16 +02:00
										 |  |  | 	/* The Y position is expressed in raster line units and must be doubled
 | 
					
						
							|  |  |  | 	 * for 32bpp formats, according to the R8A7790 datasheet. No mention of | 
					
						
							|  |  |  | 	 * doubling the Y position is found in the R8A7779 datasheet, but the | 
					
						
							|  |  |  | 	 * rule seems to apply there as well. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Similarly, for the second plane, NV12 and NV21 formats seem to | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	 * require a halved Y position value. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 			    (plane->format->bpp == 32 ? 2 : 1)); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (plane->format->planes == 2) { | 
					
						
							|  |  |  | 		index = (index + 1) % 8; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x); | 
					
						
							|  |  |  | 		rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 				    (plane->format->bpp == 16 ? 2 : 1) / 2); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[1]); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void rcar_du_plane_compute_base(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 				struct drm_framebuffer *fb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct drm_gem_cma_object *gem; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gem = drm_fb_cma_get_gem_obj(fb, 0); | 
					
						
							|  |  |  | 	plane->dma[0] = gem->paddr + fb->offsets[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (plane->format->planes == 2) { | 
					
						
							|  |  |  | 		gem = drm_fb_cma_get_gem_obj(fb, 1); | 
					
						
							|  |  |  | 		plane->dma[1] = gem->paddr + fb->offsets[1]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 				     unsigned int index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = plane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	u32 colorkey; | 
					
						
							|  |  |  | 	u32 pnmr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* The PnALPHAR register controls alpha-blending in 16bpp formats
 | 
					
						
							|  |  |  | 	 * (ARGB1555 and XRGB1555). | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * For ARGB, set the alpha value to 0, and enable alpha-blending when | 
					
						
							|  |  |  | 	 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * For XRGB, set the alpha value to the plane-wide alpha value and | 
					
						
							|  |  |  | 	 * enable alpha-blending regardless of the X bit value. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (plane->format->fourcc != DRM_FORMAT_XRGB1555) | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnALPHAR, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 				    PnALPHAR_ABIT_X | plane->alpha); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pnmr = PnMR_BM_MD | plane->format->pnmr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable color keying when requested. YUV formats have the
 | 
					
						
							|  |  |  | 	 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying | 
					
						
							|  |  |  | 	 * automatically. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if ((plane->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE) | 
					
						
							|  |  |  | 		pnmr |= PnMR_SPIM_TP_OFF; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* For packed YUV formats we need to select the U/V order. */ | 
					
						
							|  |  |  | 	if (plane->format->fourcc == DRM_FORMAT_YUYV) | 
					
						
							|  |  |  | 		pnmr |= PnMR_YCDF_YUYV; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnMR, pnmr); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (plane->format->fourcc) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB565: | 
					
						
							|  |  |  | 		colorkey = ((plane->colorkey & 0xf80000) >> 8) | 
					
						
							|  |  |  | 			 | ((plane->colorkey & 0x00fc00) >> 5) | 
					
						
							|  |  |  | 			 | ((plane->colorkey & 0x0000f8) >> 3); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case DRM_FORMAT_ARGB1555: | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB1555: | 
					
						
							|  |  |  | 		colorkey = ((plane->colorkey & 0xf80000) >> 9) | 
					
						
							|  |  |  | 			 | ((plane->colorkey & 0x00f800) >> 6) | 
					
						
							|  |  |  | 			 | ((plane->colorkey & 0x0000f8) >> 3); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 	case DRM_FORMAT_ARGB8888: | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		rcar_du_plane_write(rgrp, index, PnTC3R, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 				    PnTC3R_CODE | (plane->colorkey & 0xffffff)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __rcar_du_plane_setup(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 				  unsigned int index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = plane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	u32 ddcr2 = PnDDCR2_CODE; | 
					
						
							|  |  |  | 	u32 ddcr4; | 
					
						
							|  |  |  | 	u32 mwr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Data format
 | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * The data format is selected by the DDDF field in PnMR and the EDF | 
					
						
							|  |  |  | 	 * field in DDCR4. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	ddcr4 = rcar_du_plane_read(rgrp, index, PnDDCR4); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	ddcr4 &= ~PnDDCR4_EDF_MASK; | 
					
						
							|  |  |  | 	ddcr4 |= plane->format->edf | PnDDCR4_CODE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_setup_mode(plane, index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (plane->format->planes == 2) { | 
					
						
							|  |  |  | 		if (plane->hwindex != index) { | 
					
						
							|  |  |  | 			if (plane->format->fourcc == DRM_FORMAT_NV12 || | 
					
						
							|  |  |  | 			    plane->format->fourcc == DRM_FORMAT_NV21) | 
					
						
							|  |  |  | 				ddcr2 |= PnDDCR2_Y420; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (plane->format->fourcc == DRM_FORMAT_NV21) | 
					
						
							|  |  |  | 				ddcr2 |= PnDDCR2_NV21; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ddcr2 |= PnDDCR2_DIVU; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ddcr2 |= PnDDCR2_DIVY; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Memory pitch (expressed in pixels) */ | 
					
						
							|  |  |  | 	if (plane->format->planes == 2) | 
					
						
							|  |  |  | 		mwr = plane->pitch; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		mwr = plane->pitch * 8 / plane->format->bpp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnMWR, mwr); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Destination position and size */ | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnDSXR, plane->width); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnDSYR, plane->height); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnDPXR, plane->dst_x); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnDPYR, plane->dst_y); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Wrap-around and blinking, disabled */ | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	rcar_du_plane_write(rgrp, index, PnWASPR, 0); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnWAMWR, 4095); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnBTR, 0); | 
					
						
							|  |  |  | 	rcar_du_plane_write(rgrp, index, PnMLR, 0); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void rcar_du_plane_setup(struct rcar_du_plane *plane) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	__rcar_du_plane_setup(plane, plane->hwindex); | 
					
						
							|  |  |  | 	if (plane->format->planes == 2) | 
					
						
							|  |  |  | 		__rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_update_base(plane); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | 
					
						
							|  |  |  | 		       struct drm_framebuffer *fb, int crtc_x, int crtc_y, | 
					
						
							|  |  |  | 		       unsigned int crtc_w, unsigned int crtc_h, | 
					
						
							|  |  |  | 		       uint32_t src_x, uint32_t src_y, | 
					
						
							|  |  |  | 		       uint32_t src_w, uint32_t src_h) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct rcar_du_plane *rplane = to_rcar_plane(plane); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_device *rcdu = rplane->group->dev; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	const struct rcar_du_format_info *format; | 
					
						
							|  |  |  | 	unsigned int nplanes; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	format = rcar_du_format_info(fb->pixel_format); | 
					
						
							|  |  |  | 	if (format == NULL) { | 
					
						
							|  |  |  | 		dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__, | 
					
						
							|  |  |  | 			fb->pixel_format); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) { | 
					
						
							|  |  |  | 		dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nplanes = rplane->format ? rplane->format->planes : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Reallocate hardware planes if the number of required planes has
 | 
					
						
							|  |  |  | 	 * changed. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (format->planes != nplanes) { | 
					
						
							|  |  |  | 		rcar_du_plane_release(rplane); | 
					
						
							|  |  |  | 		ret = rcar_du_plane_reserve(rplane, format); | 
					
						
							|  |  |  | 		if (ret < 0) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rplane->crtc = crtc; | 
					
						
							|  |  |  | 	rplane->format = format; | 
					
						
							|  |  |  | 	rplane->pitch = fb->pitches[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rplane->src_x = src_x >> 16; | 
					
						
							|  |  |  | 	rplane->src_y = src_y >> 16; | 
					
						
							|  |  |  | 	rplane->dst_x = crtc_x; | 
					
						
							|  |  |  | 	rplane->dst_y = crtc_y; | 
					
						
							|  |  |  | 	rplane->width = crtc_w; | 
					
						
							|  |  |  | 	rplane->height = crtc_h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_compute_base(rplane, fb); | 
					
						
							|  |  |  | 	rcar_du_plane_setup(rplane); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_lock(&rplane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	rplane->enabled = true; | 
					
						
							|  |  |  | 	rcar_du_crtc_update_planes(rplane->crtc); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_unlock(&rplane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rcar_du_plane_disable(struct drm_plane *plane) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct rcar_du_plane *rplane = to_rcar_plane(plane); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rplane->enabled) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_lock(&rplane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	rplane->enabled = false; | 
					
						
							|  |  |  | 	rcar_du_crtc_update_planes(rplane->crtc); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_unlock(&rplane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_release(rplane); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rplane->crtc = NULL; | 
					
						
							|  |  |  | 	rplane->format = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Both the .set_property and the .update_plane operations are called with the
 | 
					
						
							|  |  |  |  * mode_config lock held. There is this no need to explicitly protect access to | 
					
						
							|  |  |  |  * the alpha and colorkey fields and the mode register. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void rcar_du_plane_set_alpha(struct rcar_du_plane *plane, u32 alpha) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (plane->alpha == alpha) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	plane->alpha = alpha; | 
					
						
							|  |  |  | 	if (!plane->enabled || plane->format->fourcc != DRM_FORMAT_XRGB1555) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_setup_mode(plane, plane->hwindex); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 				       u32 colorkey) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (plane->colorkey == colorkey) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	plane->colorkey = colorkey; | 
					
						
							|  |  |  | 	if (!plane->enabled) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_plane_setup_mode(plane, plane->hwindex); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane, | 
					
						
							|  |  |  | 				   unsigned int zpos) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_lock(&plane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	if (plane->zpos == zpos) | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	plane->zpos = zpos; | 
					
						
							|  |  |  | 	if (!plane->enabled) | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcar_du_crtc_update_planes(plane->crtc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_unlock(&plane->group->planes.lock); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int rcar_du_plane_set_property(struct drm_plane *plane, | 
					
						
							|  |  |  | 				      struct drm_property *property, | 
					
						
							|  |  |  | 				      uint64_t value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct rcar_du_plane *rplane = to_rcar_plane(plane); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_group *rgrp = rplane->group; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	if (property == rgrp->planes.alpha) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		rcar_du_plane_set_alpha(rplane, value); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	else if (property == rgrp->planes.colorkey) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		rcar_du_plane_set_colorkey(rplane, value); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	else if (property == rgrp->planes.zpos) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		rcar_du_plane_set_zpos(rplane, value); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct drm_plane_funcs rcar_du_plane_funcs = { | 
					
						
							|  |  |  | 	.update_plane = rcar_du_plane_update, | 
					
						
							|  |  |  | 	.disable_plane = rcar_du_plane_disable, | 
					
						
							|  |  |  | 	.set_property = rcar_du_plane_set_property, | 
					
						
							|  |  |  | 	.destroy = drm_plane_cleanup, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const uint32_t formats[] = { | 
					
						
							|  |  |  | 	DRM_FORMAT_RGB565, | 
					
						
							|  |  |  | 	DRM_FORMAT_ARGB1555, | 
					
						
							|  |  |  | 	DRM_FORMAT_XRGB1555, | 
					
						
							|  |  |  | 	DRM_FORMAT_XRGB8888, | 
					
						
							|  |  |  | 	DRM_FORMAT_ARGB8888, | 
					
						
							|  |  |  | 	DRM_FORMAT_UYVY, | 
					
						
							|  |  |  | 	DRM_FORMAT_YUYV, | 
					
						
							|  |  |  | 	DRM_FORMAT_NV12, | 
					
						
							|  |  |  | 	DRM_FORMAT_NV21, | 
					
						
							|  |  |  | 	DRM_FORMAT_NV16, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | int rcar_du_planes_init(struct rcar_du_group *rgrp) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_planes *planes = &rgrp->planes; | 
					
						
							|  |  |  | 	struct rcar_du_device *rcdu = rgrp->dev; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	mutex_init(&planes->lock); | 
					
						
							|  |  |  | 	planes->free = 0xff; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	planes->alpha = | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	if (planes->alpha == NULL) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* The color key is expressed as an RGB888 triplet stored in a 32-bit
 | 
					
						
							|  |  |  | 	 * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0) | 
					
						
							|  |  |  | 	 * or enable source color keying (1). | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	planes->colorkey = | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		drm_property_create_range(rcdu->ddev, 0, "colorkey", | 
					
						
							|  |  |  | 					  0, 0x01ffffff); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	if (planes->colorkey == NULL) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	planes->zpos = | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7); | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	if (planes->zpos == NULL) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	for (i = 0; i < ARRAY_SIZE(planes->planes); ++i) { | 
					
						
							|  |  |  | 		struct rcar_du_plane *plane = &planes->planes[i]; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		plane->group = rgrp; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		plane->hwindex = -1; | 
					
						
							|  |  |  | 		plane->alpha = 255; | 
					
						
							|  |  |  | 		plane->colorkey = RCAR_DU_COLORKEY_NONE; | 
					
						
							|  |  |  | 		plane->zpos = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | int rcar_du_planes_register(struct rcar_du_group *rgrp) | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 	struct rcar_du_planes *planes = &rgrp->planes; | 
					
						
							|  |  |  | 	struct rcar_du_device *rcdu = rgrp->dev; | 
					
						
							| 
									
										
										
										
											2013-06-17 00:29:25 +02:00
										 |  |  | 	unsigned int crtcs; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 00:29:25 +02:00
										 |  |  | 	crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { | 
					
						
							|  |  |  | 		struct rcar_du_kms_plane *plane; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		plane = devm_kzalloc(rcdu->dev, sizeof(*plane), GFP_KERNEL); | 
					
						
							|  |  |  | 		if (plane == NULL) | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 		plane->hwplane = &planes->planes[i + 2]; | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		plane->hwplane->zpos = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 00:29:25 +02:00
										 |  |  | 		ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 				     &rcar_du_plane_funcs, formats, | 
					
						
							|  |  |  | 				     ARRAY_SIZE(formats), false); | 
					
						
							|  |  |  | 		if (ret < 0) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		drm_object_attach_property(&plane->plane.base, | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 					   planes->alpha, 255); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 		drm_object_attach_property(&plane->plane.base, | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 					   planes->colorkey, | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 					   RCAR_DU_COLORKEY_NONE); | 
					
						
							|  |  |  | 		drm_object_attach_property(&plane->plane.base, | 
					
						
							| 
									
										
										
										
											2013-06-16 21:01:02 +02:00
										 |  |  | 					   planes->zpos, 1); | 
					
						
							| 
									
										
										
										
											2013-06-19 13:54:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |