1*11696c5eSBiju Das // SPDX-License-Identifier: GPL-2.0+
2*11696c5eSBiju Das /*
3*11696c5eSBiju Das  * shmob_drm_kms.c  --  SH Mobile DRM Mode Setting
4*11696c5eSBiju Das  *
5*11696c5eSBiju Das  * Copyright (C) 2012 Renesas Electronics Corporation
6*11696c5eSBiju Das  *
7*11696c5eSBiju Das  * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8*11696c5eSBiju Das  */
9*11696c5eSBiju Das 
10*11696c5eSBiju Das #include <drm/drm_crtc.h>
11*11696c5eSBiju Das #include <drm/drm_crtc_helper.h>
12*11696c5eSBiju Das #include <drm/drm_fourcc.h>
13*11696c5eSBiju Das #include <drm/drm_gem_dma_helper.h>
14*11696c5eSBiju Das #include <drm/drm_gem_framebuffer_helper.h>
15*11696c5eSBiju Das #include <drm/drm_probe_helper.h>
16*11696c5eSBiju Das 
17*11696c5eSBiju Das #include "shmob_drm_crtc.h"
18*11696c5eSBiju Das #include "shmob_drm_drv.h"
19*11696c5eSBiju Das #include "shmob_drm_kms.h"
20*11696c5eSBiju Das #include "shmob_drm_regs.h"
21*11696c5eSBiju Das 
22*11696c5eSBiju Das /* -----------------------------------------------------------------------------
23*11696c5eSBiju Das  * Format helpers
24*11696c5eSBiju Das  */
25*11696c5eSBiju Das 
26*11696c5eSBiju Das static const struct shmob_drm_format_info shmob_drm_format_infos[] = {
27*11696c5eSBiju Das 	{
28*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_RGB565,
29*11696c5eSBiju Das 		.bpp = 16,
30*11696c5eSBiju Das 		.yuv = false,
31*11696c5eSBiju Das 		.lddfr = LDDFR_PKF_RGB16,
32*11696c5eSBiju Das 	}, {
33*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_RGB888,
34*11696c5eSBiju Das 		.bpp = 24,
35*11696c5eSBiju Das 		.yuv = false,
36*11696c5eSBiju Das 		.lddfr = LDDFR_PKF_RGB24,
37*11696c5eSBiju Das 	}, {
38*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_ARGB8888,
39*11696c5eSBiju Das 		.bpp = 32,
40*11696c5eSBiju Das 		.yuv = false,
41*11696c5eSBiju Das 		.lddfr = LDDFR_PKF_ARGB32,
42*11696c5eSBiju Das 	}, {
43*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_XRGB8888,
44*11696c5eSBiju Das 		.bpp = 32,
45*11696c5eSBiju Das 		.yuv = false,
46*11696c5eSBiju Das 		.lddfr = LDDFR_PKF_ARGB32,
47*11696c5eSBiju Das 	}, {
48*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV12,
49*11696c5eSBiju Das 		.bpp = 12,
50*11696c5eSBiju Das 		.yuv = true,
51*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_420,
52*11696c5eSBiju Das 	}, {
53*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV21,
54*11696c5eSBiju Das 		.bpp = 12,
55*11696c5eSBiju Das 		.yuv = true,
56*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_420,
57*11696c5eSBiju Das 	}, {
58*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV16,
59*11696c5eSBiju Das 		.bpp = 16,
60*11696c5eSBiju Das 		.yuv = true,
61*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_422,
62*11696c5eSBiju Das 	}, {
63*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV61,
64*11696c5eSBiju Das 		.bpp = 16,
65*11696c5eSBiju Das 		.yuv = true,
66*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_422,
67*11696c5eSBiju Das 	}, {
68*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV24,
69*11696c5eSBiju Das 		.bpp = 24,
70*11696c5eSBiju Das 		.yuv = true,
71*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_444,
72*11696c5eSBiju Das 	}, {
73*11696c5eSBiju Das 		.fourcc = DRM_FORMAT_NV42,
74*11696c5eSBiju Das 		.bpp = 24,
75*11696c5eSBiju Das 		.yuv = true,
76*11696c5eSBiju Das 		.lddfr = LDDFR_CC | LDDFR_YF_444,
77*11696c5eSBiju Das 	},
78*11696c5eSBiju Das };
79*11696c5eSBiju Das 
shmob_drm_format_info(u32 fourcc)80*11696c5eSBiju Das const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc)
81*11696c5eSBiju Das {
82*11696c5eSBiju Das 	unsigned int i;
83*11696c5eSBiju Das 
84*11696c5eSBiju Das 	for (i = 0; i < ARRAY_SIZE(shmob_drm_format_infos); ++i) {
85*11696c5eSBiju Das 		if (shmob_drm_format_infos[i].fourcc == fourcc)
86*11696c5eSBiju Das 			return &shmob_drm_format_infos[i];
87*11696c5eSBiju Das 	}
88*11696c5eSBiju Das 
89*11696c5eSBiju Das 	return NULL;
90*11696c5eSBiju Das }
91*11696c5eSBiju Das 
92*11696c5eSBiju Das /* -----------------------------------------------------------------------------
93*11696c5eSBiju Das  * Frame buffer
94*11696c5eSBiju Das  */
95*11696c5eSBiju Das 
96*11696c5eSBiju Das 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)97*11696c5eSBiju Das shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
98*11696c5eSBiju Das 		    const struct drm_mode_fb_cmd2 *mode_cmd)
99*11696c5eSBiju Das {
100*11696c5eSBiju Das 	const struct shmob_drm_format_info *format;
101*11696c5eSBiju Das 
102*11696c5eSBiju Das 	format = shmob_drm_format_info(mode_cmd->pixel_format);
103*11696c5eSBiju Das 	if (format == NULL) {
104*11696c5eSBiju Das 		dev_dbg(dev->dev, "unsupported pixel format %p4cc\n",
105*11696c5eSBiju Das 			&mode_cmd->pixel_format);
106*11696c5eSBiju Das 		return ERR_PTR(-EINVAL);
107*11696c5eSBiju Das 	}
108*11696c5eSBiju Das 
109*11696c5eSBiju Das 	if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
110*11696c5eSBiju Das 		dev_dbg(dev->dev, "invalid pitch value %u\n",
111*11696c5eSBiju Das 			mode_cmd->pitches[0]);
112*11696c5eSBiju Das 		return ERR_PTR(-EINVAL);
113*11696c5eSBiju Das 	}
114*11696c5eSBiju Das 
115*11696c5eSBiju Das 	if (format->yuv) {
116*11696c5eSBiju Das 		unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;
117*11696c5eSBiju Das 
118*11696c5eSBiju Das 		if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
119*11696c5eSBiju Das 			dev_dbg(dev->dev,
120*11696c5eSBiju Das 				"luma and chroma pitches do not match\n");
121*11696c5eSBiju Das 			return ERR_PTR(-EINVAL);
122*11696c5eSBiju Das 		}
123*11696c5eSBiju Das 	}
124*11696c5eSBiju Das 
125*11696c5eSBiju Das 	return drm_gem_fb_create(dev, file_priv, mode_cmd);
126*11696c5eSBiju Das }
127*11696c5eSBiju Das 
128*11696c5eSBiju Das static const struct drm_mode_config_funcs shmob_drm_mode_config_funcs = {
129*11696c5eSBiju Das 	.fb_create = shmob_drm_fb_create,
130*11696c5eSBiju Das };
131*11696c5eSBiju Das 
shmob_drm_modeset_init(struct shmob_drm_device * sdev)132*11696c5eSBiju Das int shmob_drm_modeset_init(struct shmob_drm_device *sdev)
133*11696c5eSBiju Das {
134*11696c5eSBiju Das 	int ret;
135*11696c5eSBiju Das 
136*11696c5eSBiju Das 	ret = drmm_mode_config_init(sdev->ddev);
137*11696c5eSBiju Das 	if (ret)
138*11696c5eSBiju Das 		return ret;
139*11696c5eSBiju Das 
140*11696c5eSBiju Das 	shmob_drm_crtc_create(sdev);
141*11696c5eSBiju Das 	shmob_drm_encoder_create(sdev);
142*11696c5eSBiju Das 	shmob_drm_connector_create(sdev, &sdev->encoder.encoder);
143*11696c5eSBiju Das 
144*11696c5eSBiju Das 	drm_kms_helper_poll_init(sdev->ddev);
145*11696c5eSBiju Das 
146*11696c5eSBiju Das 	sdev->ddev->mode_config.min_width = 0;
147*11696c5eSBiju Das 	sdev->ddev->mode_config.min_height = 0;
148*11696c5eSBiju Das 	sdev->ddev->mode_config.max_width = 4095;
149*11696c5eSBiju Das 	sdev->ddev->mode_config.max_height = 4095;
150*11696c5eSBiju Das 	sdev->ddev->mode_config.funcs = &shmob_drm_mode_config_funcs;
151*11696c5eSBiju Das 
152*11696c5eSBiju Das 	drm_helper_disable_unused_functions(sdev->ddev);
153*11696c5eSBiju Das 
154*11696c5eSBiju Das 	return 0;
155*11696c5eSBiju Das }
156