xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/rockchip_drm_self_test.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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