1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3 * Copyright (c) 2022 Rockchip Electronics Co., Ltd.
4 * Author: Sandy Huang <hjc@rock-chips.com>
5 */
6
7 #include <linux/delay.h>
8 #include <linux/init.h>
9 #include <linux/kthread.h>
10 #include <linux/module.h>
11 #include <linux/workqueue.h>
12
13 #include <drm/drm_atomic_uapi.h>
14
15 #include "rockchip_drm_drv.h"
16 #include "rockchip_drm_direct_show.h"
17 #include "rockchip_drm_display_pattern.h"
18
19 #include "kernel_logo_img.h"
20
21 #define USE_BUFFER_NUM 2
22 #define BUFFER_WIDTH 652
23 #define BUFFER_HEIGHT 268
24 #define BUFFER_FORMAT DRM_FORMAT_RGB565 /* DRM_FORMAT_RGB565/DRM_FORMAT_XRGB8888/DRM_FORMAT_NV12 */
25
26 struct rockchip_drm_self_test {
27 struct drm_device *dev;
28 struct work_struct commit_work;
29 struct workqueue_struct *workqueue;
30
31 struct drm_crtc *crtc;
32 struct drm_plane *plane;
33
34 struct rockchip_drm_direct_show_buffer *drm_buffer[USE_BUFFER_NUM];
35 };
36
37 static struct rockchip_drm_self_test rockchip_drm_st;
38
39 static void __maybe_unused
rockchip_drm_draw_white(struct rockchip_drm_direct_show_buffer * buffer)40 rockchip_drm_draw_white(struct rockchip_drm_direct_show_buffer *buffer)
41 {
42 if (buffer && buffer->vir_addr[0])
43 memset(buffer->vir_addr[0], 0xff, buffer->pitch[0] * buffer->height);
44 }
45
46 static void __maybe_unused
rockchip_drm_draw_gray128(struct rockchip_drm_direct_show_buffer * buffer)47 rockchip_drm_draw_gray128(struct rockchip_drm_direct_show_buffer *buffer)
48 {
49 if (buffer && buffer->vir_addr[0])
50 memset(buffer->vir_addr[0], 0x80, buffer->pitch[0] * buffer->height);
51 }
52
53 static void __maybe_unused
rockchip_drm_copy_bmp_file(struct rockchip_drm_direct_show_buffer * buffer)54 rockchip_drm_copy_bmp_file(struct rockchip_drm_direct_show_buffer *buffer)
55 {
56 int i = 0;
57 void *src, *dst;
58
59 if (!buffer || !buffer->vir_addr[0]) {
60 pr_info("%s[%d] buffer or buffer->vir_addr[0] is NULL\n", __func__, __LINE__);
61 return;
62 }
63
64 src = (void *)bmp_file;
65 dst = (void *)buffer->vir_addr[0];
66 for (i = 0; i < buffer->height; i++) {
67 memcpy(dst, src, buffer->pitch[0]);
68 src += BUFFER_WIDTH * buffer->bpp >> 3;
69 dst += buffer->pitch[0];
70 }
71 }
72
73 static void __maybe_unused
rockchip_drm_draw_color_bar(struct rockchip_drm_direct_show_buffer * buffer)74 rockchip_drm_draw_color_bar(struct rockchip_drm_direct_show_buffer *buffer)
75 {
76 if (buffer && buffer->vir_addr[0])
77 rockchip_drm_fill_color_bar(buffer->pixel_format,
78 buffer->vir_addr,
79 buffer->width,
80 buffer->height,
81 buffer->pitch[0]);
82 }
83
rockchip_drm_self_test_alloc_buffer(struct rockchip_drm_self_test * self_test)84 static int rockchip_drm_self_test_alloc_buffer(struct rockchip_drm_self_test *self_test)
85 {
86 int ret = 0, i = 0;
87 struct rockchip_drm_direct_show_buffer *buffer;
88
89 for (i = 0; i < USE_BUFFER_NUM; i++) {
90 buffer = kmalloc(sizeof(struct rockchip_drm_direct_show_buffer), GFP_KERNEL);
91 if (!buffer)
92 return -ENOMEM;
93 buffer->width = BUFFER_WIDTH;
94 buffer->height = BUFFER_HEIGHT;
95 buffer->pixel_format = BUFFER_FORMAT;
96 buffer->flag = ROCKCHIP_BO_CONTIG;
97 ret = rockchip_drm_direct_show_alloc_buffer(self_test->dev, buffer);
98 if (ret)
99 pr_info("failed to alloc drm buffer\n");
100 self_test->drm_buffer[i] = buffer;
101 }
102
103 return 0;
104 }
105
rockchip_drm_self_test_free_buffer(struct rockchip_drm_self_test * self_test)106 static int rockchip_drm_self_test_free_buffer(struct rockchip_drm_self_test *self_test)
107 {
108 int i = 0;
109
110 for (i = 0; i < USE_BUFFER_NUM; i++)
111 rockchip_drm_direct_show_free_buffer(self_test->dev, self_test->drm_buffer[i]);
112
113 return 0;
114 }
115
rockchip_drm_self_test_commit(struct work_struct * work)116 static void rockchip_drm_self_test_commit(struct work_struct *work)
117 {
118 struct rockchip_drm_self_test *self_test =
119 container_of(work, struct rockchip_drm_self_test, commit_work);
120 struct rockchip_drm_direct_show_commit_info commit_info;
121 int ret = 0;
122
123 if (!self_test->dev)
124 self_test->dev = rockchip_drm_get_dev();
125
126 /* drm is unready */
127 if (!self_test->dev) {
128 pr_info("%s[%d], drm is unready\n", __func__, __LINE__);
129 msleep(100);
130 queue_work(self_test->workqueue, &self_test->commit_work);
131
132 return;
133 }
134
135 /* alloc buffer */
136 if (!self_test->drm_buffer[0]) {
137 ret = rockchip_drm_self_test_alloc_buffer(self_test);
138 if (ret)
139 pr_info("error: drm self test alloc buffer error\n");
140 }
141
142 /* draw buffer */
143 rockchip_drm_copy_bmp_file(self_test->drm_buffer[0]);
144 /* rockchip_drm_draw_gray128(self_test->drm_buffer[1]); */
145 rockchip_drm_draw_color_bar(self_test->drm_buffer[1]);
146
147 /* get crtc and plane */
148 self_test->crtc = rockchip_drm_direct_show_get_crtc(self_test->dev, NULL);
149 if (self_test->crtc == NULL) {
150 pr_info("error: failed to get crtc\n");
151 goto free_buffer;
152 }
153
154 self_test->plane = rockchip_drm_direct_show_get_plane(self_test->dev, "Esmart0-win0");
155 if (self_test->plane == NULL) {
156 pr_info("error: failed to get plane\n");
157 goto free_buffer;
158 }
159
160 #if 1 /* for self test pattern */
161 /* commit to display */
162 do {
163 u32 i = 0;
164
165 commit_info.crtc = self_test->crtc;
166 commit_info.plane = self_test->plane;
167
168 commit_info.src_x = 0;
169 commit_info.src_y = 0;
170 commit_info.src_w = BUFFER_WIDTH;
171 commit_info.src_h = BUFFER_HEIGHT;
172
173 commit_info.dst_x = 0;
174 commit_info.dst_y = 0;
175 commit_info.dst_w = commit_info.src_w;
176 commit_info.dst_h = commit_info.src_h;
177
178 commit_info.top_zpos = true;
179
180 for (i = 0; i < 1000; i++) {
181 commit_info.buffer = self_test->drm_buffer[i % 2];/* two buffer ping pong */
182 rockchip_drm_direct_show_commit(self_test->dev, &commit_info);
183 mdelay(1000);
184 }
185 /* disable plane */
186 rockchip_drm_direct_show_disable_plane(self_test->dev, commit_info.plane);
187 /* free buffer */
188 rockchip_drm_self_test_free_buffer(self_test);
189 } while (0);
190 #else
191 /* for kernel logo display */
192 do {
193 int hdisplay = self_test->crtc->state->adjusted_mode.hdisplay;
194 int vdisplay = self_test->crtc->state->adjusted_mode.vdisplay;
195
196 commit_info.crtc = self_test->crtc;
197 commit_info.plane = self_test->plane;
198
199 commit_info.src_x = 0;
200 commit_info.src_y = 0;
201 commit_info.src_w = self_test->drm_buffer[0]->width;
202 commit_info.src_h = self_test->drm_buffer[0]->height;
203
204 if (1) {/* center display */
205 commit_info.dst_x = (hdisplay - BUFFER_WIDTH) / 2;
206 commit_info.dst_y = (vdisplay - BUFFER_HEIGHT) / 2;
207 commit_info.dst_w = commit_info.src_w;
208 commit_info.dst_h = commit_info.src_h;
209
210 } else {/* full screen display */
211 commit_info.dst_x = 0;
212 commit_info.dst_y = 0;
213 commit_info.dst_w = hdisplay;
214 commit_info.dst_h = vdisplay;
215 }
216
217 commit_info.buffer = self_test->drm_buffer[0];
218 rockchip_drm_direct_show_commit(self_test->dev, &commit_info);
219 } while (0);
220 #endif
221 return;
222
223 free_buffer:
224 /* free buffer */
225 rockchip_drm_self_test_free_buffer(self_test);
226 }
227
rockchip_drm_self_test_create_worker(struct rockchip_drm_self_test * slef_test)228 static int rockchip_drm_self_test_create_worker(struct rockchip_drm_self_test *slef_test)
229 {
230 struct workqueue_struct *wq = NULL;
231
232 wq = create_singlethread_workqueue("rockchip_drm_self_test");
233 if (!wq) {
234 pr_info("Failed to create rockchip_drm_self_test workqueue\n");
235 return -ENODEV;
236 }
237 slef_test->workqueue = wq;
238
239 return 0;
240 }
241
rockchip_drm_self_test_destory_worker(struct rockchip_drm_self_test * slef_test)242 static int __maybe_unused rockchip_drm_self_test_destory_worker(struct rockchip_drm_self_test *slef_test)
243 {
244 if (!slef_test)
245 return -ENODEV;
246
247 if (slef_test->workqueue)
248 destroy_workqueue(slef_test->workqueue);
249
250 return 0;
251 }
252
rockchip_drm_self_test_main(void * arg)253 static int rockchip_drm_self_test_main(void *arg)
254 {
255 rockchip_drm_self_test_create_worker(&rockchip_drm_st);
256 INIT_WORK(&rockchip_drm_st.commit_work, rockchip_drm_self_test_commit);
257 queue_work(rockchip_drm_st.workqueue, &rockchip_drm_st.commit_work);
258
259 return 0;
260 };
261
rockchip_drm_self_test(void)262 static int __init rockchip_drm_self_test(void)
263 {
264 kthread_run(rockchip_drm_self_test_main, NULL, "rockchip drm self test");
265
266 return 0;
267 }
268
269 subsys_initcall_sync(rockchip_drm_self_test);
270