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