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