| 
									
										
										
										
											2012-04-26 13:53:59 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-02-06 18:13:52 +01:00
										 |  |  |  * Copyright (C) 2012 Renesas Electronics Corporation | 
					
						
							| 
									
										
										
										
											2012-04-26 13:53:59 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 <video/sh_mobile_meram.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "shmob_drm_crtc.h"
 | 
					
						
							|  |  |  | #include "shmob_drm_drv.h"
 | 
					
						
							|  |  |  | #include "shmob_drm_kms.h"
 | 
					
						
							|  |  |  | #include "shmob_drm_regs.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------------
 | 
					
						
							|  |  |  |  * Format helpers | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct shmob_drm_format_info shmob_drm_format_infos[] = { | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_RGB565, | 
					
						
							|  |  |  | 		.bpp = 16, | 
					
						
							|  |  |  | 		.yuv = false, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_PKF_RGB16, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_RGB, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_RGB888, | 
					
						
							|  |  |  | 		.bpp = 24, | 
					
						
							|  |  |  | 		.yuv = false, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_PKF_RGB24, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_RGB, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_ARGB8888, | 
					
						
							|  |  |  | 		.bpp = 32, | 
					
						
							|  |  |  | 		.yuv = false, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_PKF_ARGB32, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_RGB, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV12, | 
					
						
							|  |  |  | 		.bpp = 12, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_420, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV21, | 
					
						
							|  |  |  | 		.bpp = 12, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_420, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV16, | 
					
						
							|  |  |  | 		.bpp = 16, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_422, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV61, | 
					
						
							|  |  |  | 		.bpp = 16, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_422, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV24, | 
					
						
							|  |  |  | 		.bpp = 24, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_444, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV24, | 
					
						
							|  |  |  | 	}, { | 
					
						
							|  |  |  | 		.fourcc = DRM_FORMAT_NV42, | 
					
						
							|  |  |  | 		.bpp = 24, | 
					
						
							|  |  |  | 		.yuv = true, | 
					
						
							|  |  |  | 		.lddfr = LDDFR_CC | LDDFR_YF_444, | 
					
						
							|  |  |  | 		.meram = SH_MOBILE_MERAM_PF_NV24, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) { | 
					
						
							|  |  |  | 		if (shmob_drm_format_infos[i].fourcc == fourcc) | 
					
						
							|  |  |  | 			return &shmob_drm_format_infos[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* -----------------------------------------------------------------------------
 | 
					
						
							|  |  |  |  * Frame buffer | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct drm_framebuffer * | 
					
						
							|  |  |  | shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, | 
					
						
							|  |  |  | 		    struct drm_mode_fb_cmd2 *mode_cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct shmob_drm_format_info *format; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	format = shmob_drm_format_info(mode_cmd->pixel_format); | 
					
						
							|  |  |  | 	if (format == NULL) { | 
					
						
							|  |  |  | 		dev_dbg(dev->dev, "unsupported pixel format %08x\n", | 
					
						
							|  |  |  | 			mode_cmd->pixel_format); | 
					
						
							|  |  |  | 		return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) { | 
					
						
							| 
									
										
										
										
											2012-12-11 14:53:42 +01:00
										 |  |  | 		dev_dbg(dev->dev, "invalid pitch value %u\n", | 
					
						
							| 
									
										
										
										
											2012-04-26 13:53:59 +02:00
										 |  |  | 			mode_cmd->pitches[0]); | 
					
						
							|  |  |  | 		return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (format->yuv) { | 
					
						
							|  |  |  | 		unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) { | 
					
						
							|  |  |  | 			dev_dbg(dev->dev, | 
					
						
							|  |  |  | 				"luma and chroma pitches do not match\n"); | 
					
						
							|  |  |  | 			return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return drm_fb_cma_create(dev, file_priv, mode_cmd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = { | 
					
						
							|  |  |  | 	.fb_create = shmob_drm_fb_create, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int shmob_drm_modeset_init(struct shmob_drm_device *sdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	drm_mode_config_init(sdev->ddev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	shmob_drm_crtc_create(sdev); | 
					
						
							|  |  |  | 	shmob_drm_encoder_create(sdev); | 
					
						
							|  |  |  | 	shmob_drm_connector_create(sdev, &sdev->encoder.encoder); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	drm_kms_helper_poll_init(sdev->ddev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdev->ddev->mode_config.min_width = 0; | 
					
						
							|  |  |  | 	sdev->ddev->mode_config.min_height = 0; | 
					
						
							|  |  |  | 	sdev->ddev->mode_config.max_width = 4095; | 
					
						
							|  |  |  | 	sdev->ddev->mode_config.max_height = 4095; | 
					
						
							|  |  |  | 	sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	drm_helper_disable_unused_functions(sdev->ddev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |