• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting
3  *
4  * Copyright (C) 2012 Renesas Electronics Corporation
5  *
6  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <drm/drmP.h>
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
19 
20 #include <video/sh_mobile_meram.h>
21 
22 #include "shmob_drm_crtc.h"
23 #include "shmob_drm_drv.h"
24 #include "shmob_drm_kms.h"
25 #include "shmob_drm_regs.h"
26 
27 /* -----------------------------------------------------------------------------
28  * Format helpers
29  */
30 
31 static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
32 	{
33 		.fourcc = DRM_FORMAT_RGB565,
34 		.bpp = 16,
35 		.yuv = false,
36 		.lddfr = LDDFR_PKF_RGB16,
37 		.meram = SH_MOBILE_MERAM_PF_RGB,
38 	}, {
39 		.fourcc = DRM_FORMAT_RGB888,
40 		.bpp = 24,
41 		.yuv = false,
42 		.lddfr = LDDFR_PKF_RGB24,
43 		.meram = SH_MOBILE_MERAM_PF_RGB,
44 	}, {
45 		.fourcc = DRM_FORMAT_ARGB8888,
46 		.bpp = 32,
47 		.yuv = false,
48 		.lddfr = LDDFR_PKF_ARGB32,
49 		.meram = SH_MOBILE_MERAM_PF_RGB,
50 	}, {
51 		.fourcc = DRM_FORMAT_NV12,
52 		.bpp = 12,
53 		.yuv = true,
54 		.lddfr = LDDFR_CC | LDDFR_YF_420,
55 		.meram = SH_MOBILE_MERAM_PF_NV,
56 	}, {
57 		.fourcc = DRM_FORMAT_NV21,
58 		.bpp = 12,
59 		.yuv = true,
60 		.lddfr = LDDFR_CC | LDDFR_YF_420,
61 		.meram = SH_MOBILE_MERAM_PF_NV,
62 	}, {
63 		.fourcc = DRM_FORMAT_NV16,
64 		.bpp = 16,
65 		.yuv = true,
66 		.lddfr = LDDFR_CC | LDDFR_YF_422,
67 		.meram = SH_MOBILE_MERAM_PF_NV,
68 	}, {
69 		.fourcc = DRM_FORMAT_NV61,
70 		.bpp = 16,
71 		.yuv = true,
72 		.lddfr = LDDFR_CC | LDDFR_YF_422,
73 		.meram = SH_MOBILE_MERAM_PF_NV,
74 	}, {
75 		.fourcc = DRM_FORMAT_NV24,
76 		.bpp = 24,
77 		.yuv = true,
78 		.lddfr = LDDFR_CC | LDDFR_YF_444,
79 		.meram = SH_MOBILE_MERAM_PF_NV24,
80 	}, {
81 		.fourcc = DRM_FORMAT_NV42,
82 		.bpp = 24,
83 		.yuv = true,
84 		.lddfr = LDDFR_CC | LDDFR_YF_444,
85 		.meram = SH_MOBILE_MERAM_PF_NV24,
86 	},
87 };
88 
shmob_drm_format_info(u32 fourcc)89 const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
90 {
91 	unsigned int i;
92 
93 	for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) {
94 		if (shmob_drm_format_infos[i].fourcc == fourcc)
95 			return &shmob_drm_format_infos[i];
96 	}
97 
98 	return NULL;
99 }
100 
101 /* -----------------------------------------------------------------------------
102  * Frame buffer
103  */
104 
105 static struct drm_framebuffer *
shmob_drm_fb_create(struct drm_device * dev,struct drm_file * file_priv,const struct drm_mode_fb_cmd2 * mode_cmd)106 shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
107 		    const struct drm_mode_fb_cmd2 *mode_cmd)
108 {
109 	const struct shmob_drm_format_info *format;
110 
111 	format = shmob_drm_format_info(mode_cmd->pixel_format);
112 	if (format == NULL) {
113 		dev_dbg(dev->dev, "unsupported pixel format %08x\n",
114 			mode_cmd->pixel_format);
115 		return ERR_PTR(-EINVAL);
116 	}
117 
118 	if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
119 		dev_dbg(dev->dev, "invalid pitch value %u\n",
120 			mode_cmd->pitches[0]);
121 		return ERR_PTR(-EINVAL);
122 	}
123 
124 	if (format->yuv) {
125 		unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
126 
127 		if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
128 			dev_dbg(dev->dev,
129 				"luma and chroma pitches do not match\n");
130 			return ERR_PTR(-EINVAL);
131 		}
132 	}
133 
134 	return drm_fb_cma_create(dev, file_priv, mode_cmd);
135 }
136 
137 static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
138 	.fb_create = shmob_drm_fb_create,
139 };
140 
shmob_drm_modeset_init(struct shmob_drm_device * sdev)141 int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
142 {
143 	drm_mode_config_init(sdev->ddev);
144 
145 	shmob_drm_crtc_create(sdev);
146 	shmob_drm_encoder_create(sdev);
147 	shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
148 
149 	drm_kms_helper_poll_init(sdev->ddev);
150 
151 	sdev->ddev->mode_config.min_width = 0;
152 	sdev->ddev->mode_config.min_height = 0;
153 	sdev->ddev->mode_config.max_width = 4095;
154 	sdev->ddev->mode_config.max_height = 4095;
155 	sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
156 
157 	drm_helper_disable_unused_functions(sdev->ddev);
158 
159 	return 0;
160 }
161