• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * g2d_rcq/g2d_driver/g2d.c
3  *
4  * Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
5  * Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
6  *
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  */
18 #include "g2d_driver_i.h"
19 #include "g2d_top.h"
20 #if defined(CONFIG_G2D_MIXER)
21 #include "g2d_mixer.h"
22 #endif
23 #if defined(CONFIG_G2D_ROTATE)
24 #include "g2d_rotate.h"
25 #endif
26 
27 /* alloc based on 4K byte */
28 #define G2D_BYTE_ALIGN(x) (((x + (4*1024-1)) >> 12) << 12)
29 static enum g2d_scan_order scan_order;
30 static struct mutex global_lock;
31 
32 static struct class *g2d_class;
33 static struct cdev *g2d_cdev;
34 static dev_t devid;
35 static struct device *g2d_dev;
36 static struct device *dmabuf_dev;
37 u32 g_time_info;
38 u32 g_func_runtime;
39 
40 __g2d_drv_t g2d_ext_hd;
41 __g2d_info_t para;
42 
43 __u32 dbg_info;
44 
45 static struct g2d_format_attr fmt_attr_tbl[] = {
46 /*
47 format  bits hor_rsample(u,v) ver_rsample(u,v) uvc interleave factor div
48 */
49 	{ G2D_FORMAT_ARGB8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
50 	{ G2D_FORMAT_ABGR8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
51 	{ G2D_FORMAT_RGBA8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
52 	{ G2D_FORMAT_BGRA8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
53 	{ G2D_FORMAT_XRGB8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
54 	{ G2D_FORMAT_XBGR8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
55 	{ G2D_FORMAT_RGBX8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
56 	{ G2D_FORMAT_BGRX8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
57 	{ G2D_FORMAT_RGB888, 8,  1, 1, 1, 1, 0, 1, 3, 1},
58 	{ G2D_FORMAT_BGR888, 8,  1, 1, 1, 1, 0, 1, 3, 1},
59 	{ G2D_FORMAT_RGB565, 8,  1, 1, 1, 1, 0, 1, 2, 1},
60 	{ G2D_FORMAT_BGR565, 8,  1, 1, 1, 1, 0, 1, 2, 1},
61 	{ G2D_FORMAT_ARGB4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
62 	{ G2D_FORMAT_ABGR4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
63 	{ G2D_FORMAT_RGBA4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
64 	{ G2D_FORMAT_BGRA4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
65 	{ G2D_FORMAT_ARGB1555, 8,  1, 1, 1, 1, 0, 1, 2, 1},
66 	{ G2D_FORMAT_ABGR1555, 8,  1, 1, 1, 1, 0, 1, 2, 1},
67 	{ G2D_FORMAT_RGBA5551, 8,  1, 1, 1, 1, 0, 1, 2, 1},
68 	{ G2D_FORMAT_BGRA5551, 8,  1, 1, 1, 1, 0, 1, 2, 1},
69 	{ G2D_FORMAT_ARGB2101010, 10, 1, 1, 1, 1, 0, 1, 4, 1},
70 	{ G2D_FORMAT_ABGR2101010, 10, 1, 1, 1, 1, 0, 1, 4, 1},
71 	{ G2D_FORMAT_RGBA1010102, 10, 1, 1, 1, 1, 0, 1, 4, 1},
72 	{ G2D_FORMAT_BGRA1010102, 10, 1, 1, 1, 1, 0, 1, 4, 1},
73 	{ G2D_FORMAT_IYUV422_V0Y1U0Y0, 8,  1, 1, 1, 1, 0, 1, 2, 1},
74 	{ G2D_FORMAT_IYUV422_Y1V0Y0U0, 8,  1, 1, 1, 1, 0, 1, 2, 1},
75 	{ G2D_FORMAT_IYUV422_U0Y1V0Y0, 8,  1, 1, 1, 1, 0, 1, 2, 1},
76 	{ G2D_FORMAT_IYUV422_Y1U0Y0V0, 8,  1, 1, 1, 1, 0, 1, 2, 1},
77 	{ G2D_FORMAT_YUV422_PLANAR, 8,  2, 2, 1, 1, 0, 0, 2, 1},
78 	{ G2D_FORMAT_YUV420_PLANAR, 8,  2, 2, 2, 2, 0, 0, 3, 2},
79 	{ G2D_FORMAT_YUV411_PLANAR, 8,  4, 4, 1, 1, 0, 0, 3, 2},
80 	{ G2D_FORMAT_YUV422UVC_U1V1U0V0, 8,  2, 2, 1, 1, 1, 0, 2, 1},
81 	{ G2D_FORMAT_YUV422UVC_V1U1V0U0, 8,  2, 2, 1, 1, 1, 0, 2, 1},
82 	{ G2D_FORMAT_YUV420UVC_U1V1U0V0, 8,  2, 2, 2, 2, 1, 0, 3, 2},
83 	{ G2D_FORMAT_YUV420UVC_V1U1V0U0, 8,  2, 2, 2, 2, 1, 0, 3, 2},
84 	{ G2D_FORMAT_YUV411UVC_U1V1U0V0, 8,  4, 4, 1, 1, 1, 0, 3, 2},
85 	{ G2D_FORMAT_YUV411UVC_V1U1V0U0, 8,  4, 4, 1, 1, 1, 0, 3, 2},
86 	{ G2D_FORMAT_Y8, 8,  1, 1, 1, 1, 0, 0, 1, 1},
87 	{ G2D_FORMAT_YVU10_444, 10, 1, 1, 1, 1, 0, 1, 4, 1},
88 	{ G2D_FORMAT_YUV10_444, 10, 1, 1, 1, 1, 0, 1, 4, 1},
89 	{ G2D_FORMAT_YVU10_P210, 10, 2, 2, 1, 1, 0, 0, 4, 1},
90 	{ G2D_FORMAT_YVU10_P010, 10, 2, 2, 2, 2, 0, 0, 3, 1},
91 };
92 
g2d_malloc(__u32 bytes_num,__u32 * phy_addr)93 void *g2d_malloc(__u32 bytes_num, __u32 *phy_addr)
94 {
95 	void *address = NULL;
96 
97 #if defined(CONFIG_ION)
98 	u32 actual_bytes;
99 
100 	if (bytes_num != 0) {
101 		actual_bytes = G2D_BYTE_ALIGN(bytes_num);
102 
103 		address = dma_alloc_coherent(para.dev, actual_bytes,
104 					     (dma_addr_t *) phy_addr,
105 					     GFP_KERNEL);
106 		if (address) {
107 			return address;
108 		}
109 		G2D_ERR_MSG("dma_alloc_coherent fail, size=0x%x\n", bytes_num);
110 		return NULL;
111 	}
112 	G2D_ERR_MSG("size is zero\n");
113 #else
114 	unsigned int map_size = 0;
115 	struct page *page;
116 
117 	if (bytes_num != 0) {
118 		map_size = PAGE_ALIGN(bytes_num);
119 		page = alloc_pages(GFP_KERNEL, get_order(map_size));
120 		if (page != NULL) {
121 			address = page_address(page);
122 			if (address == NULL) {
123 				free_pages((unsigned long)(page),
124 					   get_order(map_size));
125 				G2D_ERR_MSG("page_address fail!\n");
126 				return NULL;
127 			}
128 			*phy_addr = virt_to_phys(address);
129 			return address;
130 		}
131 		G2D_ERR_MSG("alloc_pages fail!\n");
132 		return NULL;
133 	}
134 	G2D_ERR_MSG("size is zero\n");
135 #endif
136 
137 	return NULL;
138 }
139 
g2d_free(void * virt_addr,void * phy_addr,unsigned int size)140 void g2d_free(void *virt_addr, void *phy_addr, unsigned int size)
141 {
142 #if defined(CONFIG_ION)
143 	u32 actual_bytes;
144 
145 	actual_bytes = PAGE_ALIGN(size);
146 	if (phy_addr && virt_addr)
147 		dma_free_coherent(para.dev, actual_bytes, virt_addr,
148 				  (dma_addr_t) phy_addr);
149 #else
150 	unsigned int map_size = PAGE_ALIGN(size);
151 	unsigned int page_size = map_size;
152 
153 	if (virt_addr == NULL)
154 		return;
155 
156 	free_pages((unsigned long)virt_addr, get_order(page_size));
157 #endif
158 }
159 
g2d_dma_map(int fd,struct dmabuf_item * item)160 int g2d_dma_map(int fd, struct dmabuf_item *item)
161 {
162 	struct dma_buf *dmabuf;
163 	struct dma_buf_attachment *attachment;
164 	struct sg_table *sgt;
165 	int ret = -1;
166 
167 	if (fd < 0) {
168 		pr_err("[G2D]dma_buf_id(%d) is invalid\n", fd);
169 		goto exit;
170 	}
171 	dmabuf = dma_buf_get(fd);
172 	if (IS_ERR(dmabuf)) {
173 		pr_err("[G2D]dma_buf_get failed, fd=%d\n", fd);
174 		goto exit;
175 	}
176 
177 	attachment = dma_buf_attach(dmabuf, dmabuf_dev);
178 	if (IS_ERR(attachment)) {
179 		pr_err("[G2D]dma_buf_attach failed\n");
180 		goto err_buf_put;
181 	}
182 	sgt = dma_buf_map_attachment(attachment, DMA_TO_DEVICE);
183 	if (IS_ERR_OR_NULL(sgt)) {
184 		pr_err("[G2D]dma_buf_map_attachment failed\n");
185 		goto err_buf_detach;
186 	}
187 
188 	item->fd = fd;
189 	item->buf = dmabuf;
190 	item->sgt = sgt;
191 	item->attachment = attachment;
192 	item->dma_addr = sg_dma_address(sgt->sgl);
193 	ret = 0;
194 	goto exit;
195 
196 err_buf_detach:
197 	dma_buf_detach(dmabuf, attachment);
198 err_buf_put:
199 	dma_buf_put(dmabuf);
200 exit:
201 	return ret;
202 }
203 
g2d_dma_unmap(struct dmabuf_item * item)204 void g2d_dma_unmap(struct dmabuf_item *item)
205 {
206 	dma_buf_unmap_attachment(item->attachment, item->sgt, DMA_TO_DEVICE);
207 	dma_buf_detach(item->buf, item->attachment);
208 	dma_buf_put(item->buf);
209 }
210 
g2d_set_info(g2d_image_enh * g2d_img,struct dmabuf_item * item)211 __s32 g2d_set_info(g2d_image_enh *g2d_img, struct dmabuf_item *item)
212 {
213 	__s32 ret = -1;
214 	__u32 i = 0;
215 	__u32 len = ARRAY_SIZE(fmt_attr_tbl);
216 	__u32 y_width, y_height, u_width, u_height;
217 	__u32 y_pitch, u_pitch;
218 	__u32 y_size, u_size;
219 
220 	g2d_img->laddr[0] = item->dma_addr;
221 
222 	if (g2d_img->format >= G2D_FORMAT_MAX) {
223 		G2D_ERR_MSG("format 0x%x is out of range\n", g2d_img->format);
224 		goto exit;
225 	}
226 
227 	for (i = 0; i < len; ++i) {
228 
229 		if (fmt_attr_tbl[i].format == g2d_img->format) {
230 			y_width = g2d_img->width;
231 			y_height = g2d_img->height;
232 			u_width = y_width/fmt_attr_tbl[i].hor_rsample_u;
233 			u_height = y_height/fmt_attr_tbl[i].ver_rsample_u;
234 
235 			y_pitch = G2DALIGN(y_width, g2d_img->align[0]);
236 			u_pitch = G2DALIGN(u_width * (fmt_attr_tbl[i].uvc + 1),
237 					g2d_img->align[1]);
238 
239 			y_size = y_pitch * y_height;
240 			u_size = u_pitch * u_height;
241 			g2d_img->laddr[1] = g2d_img->laddr[0] + y_size;
242 			g2d_img->laddr[2] = g2d_img->laddr[0] + y_size + u_size;
243 
244 			if (g2d_img->format == G2D_FORMAT_YUV420_PLANAR) {
245 				/* v */
246 				g2d_img->laddr[1] = g2d_img->laddr[0] + y_size + u_size;
247 				g2d_img->laddr[2] = g2d_img->laddr[0] + y_size; /* u */
248 			}
249 
250 			ret = 0;
251 			break;
252 		}
253 	}
254 	if (ret != 0)
255 		G2D_ERR_MSG("format 0x%x is invalid\n", g2d_img->format);
256 exit:
257 	return ret;
258 
259 }
260 
g2d_byte_cal(__u32 format,__u32 * ycnt,__u32 * ucnt,__u32 * vcnt)261 __s32 g2d_byte_cal(__u32 format, __u32 *ycnt, __u32 *ucnt, __u32 *vcnt)
262 {
263 	*ycnt = 0;
264 	*ucnt = 0;
265 	*vcnt = 0;
266 	if (format <= G2D_FORMAT_BGRX8888)
267 		*ycnt = 4;
268 
269 	else if (format <= G2D_FORMAT_BGR888)
270 		*ycnt = 3;
271 
272 	else if (format <= G2D_FORMAT_BGRA5551)
273 		*ycnt = 2;
274 
275 	else if (format <= G2D_FORMAT_BGRA1010102)
276 		*ycnt = 4;
277 
278 	else if (format <= 0x23) {
279 		*ycnt = 2;
280 	}
281 
282 	else if (format <= 0x25) {
283 		*ycnt = 1;
284 		*ucnt = 2;
285 	}
286 
287 	else if (format == 0x26) {
288 		*ycnt = 1;
289 		*ucnt = 1;
290 		*vcnt = 1;
291 	}
292 
293 	else if (format <= 0x29) {
294 		*ycnt = 1;
295 		*ucnt = 2;
296 	}
297 
298 	else if (format == 0x2a) {
299 		*ycnt = 1;
300 		*ucnt = 1;
301 		*vcnt = 1;
302 	}
303 
304 	else if (format <= 0x2d) {
305 		*ycnt = 1;
306 		*ucnt = 2;
307 	}
308 
309 	else if (format == 0x2e) {
310 		*ycnt = 1;
311 		*ucnt = 1;
312 		*vcnt = 1;
313 	}
314 
315 	else if (format == 0x30)
316 		*ycnt = 1;
317 
318 	else if (format <= 0x36) {
319 		*ycnt = 2;
320 		*ucnt = 4;
321 	}
322 
323 	else if (format <= 0x39)
324 		*ycnt = 6;
325 	return 0;
326 }
327 
328 
329 /**
330  */
cal_align(__u32 width,__u32 align)331 __u32 cal_align(__u32 width, __u32 align)
332 {
333 	switch (align) {
334 	case 0:
335 		return width;
336 	case 4:
337 		return (width + 3) >> 2 << 2;
338 	case 8:
339 		return (width + 7) >> 3 << 3;
340 	case 16:
341 		return (width + 15) >> 4 << 4;
342 	case 32:
343 		return (width + 31) >> 5 << 5;
344 	case 64:
345 		return (width + 63) >> 6 << 6;
346 	case 128:
347 		return (width + 127) >> 7 << 7;
348 	default:
349 		return (width + 31) >> 5 << 5;
350 	}
351 }
352 
353 
g2d_image_check(g2d_image_enh * p_image)354 __s32 g2d_image_check(g2d_image_enh *p_image)
355 {
356 	__s32 ret = -EINVAL;
357 
358 	if (!p_image) {
359 		G2D_ERR_MSG("NUll pointer!\n");
360 		goto OUT;
361 	}
362 
363 	if (((p_image->clip_rect.x < 0) &&
364 	     ((-p_image->clip_rect.x) > p_image->clip_rect.w)) ||
365 	    ((p_image->clip_rect.y < 0) &&
366 	     ((-p_image->clip_rect.y) > p_image->clip_rect.h)) ||
367 	    ((p_image->clip_rect.x > 0) &&
368 	     (p_image->clip_rect.x > p_image->width - 1)) ||
369 	    ((p_image->clip_rect.y > 0) &&
370 	     (p_image->clip_rect.y > p_image->height - 1))) {
371 		G2D_ERR_MSG("Invalid imager parameter setting\n");
372 		goto OUT;
373 	}
374 
375 	if (((p_image->clip_rect.x < 0) &&
376 				((-p_image->clip_rect.x) <
377 				 p_image->clip_rect.w))) {
378 		p_image->clip_rect.w =
379 			p_image->clip_rect.w +
380 			p_image->clip_rect.x;
381 		p_image->clip_rect.x = 0;
382 	} else if ((p_image->clip_rect.x +
383 				p_image->clip_rect.w)
384 			> p_image->width) {
385 		p_image->clip_rect.w =
386 			p_image->width -
387 			p_image->clip_rect.x;
388 	}
389 	if (((p_image->clip_rect.y < 0) &&
390 				((-p_image->clip_rect.y) <
391 				 p_image->clip_rect.h))) {
392 		p_image->clip_rect.h =
393 			p_image->clip_rect.h +
394 			p_image->clip_rect.y;
395 		p_image->clip_rect.y = 0;
396 	} else if ((p_image->clip_rect.y +
397 				p_image->clip_rect.h)
398 			> p_image->height) {
399 		p_image->clip_rect.h =
400 			p_image->height -
401 			p_image->clip_rect.y;
402 	}
403 
404 	p_image->bpremul = 0;
405 	p_image->bbuff = 1;
406 	ret = 0;
407 OUT:
408 	return ret;
409 
410 }
411 
g2d_clock_enable(__g2d_info_t * info)412 static int g2d_clock_enable(__g2d_info_t *info)
413 {
414 	int ret = 0;
415 
416 	if (info->reset) {
417 		ret = reset_control_deassert(info->reset);
418 		if (ret != 0) {
419 			pr_err("[G2D] deassert error\n");
420 			return ret;
421 		}
422 	}
423 
424 	if (info->bus_clk) {
425 		ret |=  clk_prepare_enable(info->bus_clk);
426 	}
427 
428 	if (info->clk) {
429 		if (info->clk_parent) {
430 			clk_set_parent(info->clk, info->clk_parent);
431 		}
432 		clk_set_rate(info->clk, 300000000);
433 		ret |= clk_prepare_enable(info->clk);
434 	}
435 	if (info->mbus_clk) {
436 		ret |= clk_prepare_enable(info->mbus_clk);
437 	}
438 	if (ret != 0)
439 		pr_err("[G2D] clock enable error\n");
440 
441 	return ret;
442 }
443 
g2d_clock_disable(const __g2d_info_t * info)444 static int g2d_clock_disable(const __g2d_info_t *info)
445 {
446 	if (info->clk)
447 		clk_disable(info->clk);
448 	if (info->bus_clk)
449 		clk_disable(info->bus_clk);
450 	if (info->mbus_clk)
451 		clk_disable(info->mbus_clk);
452 	if (info->reset)
453 		reset_control_assert(info->reset);
454 	return 0;
455 }
456 
g2d_open(struct inode * inode,struct file * file)457 int g2d_open(struct inode *inode, struct file *file)
458 {
459 	mutex_lock(&para.mutex);
460 	para.user_cnt++;
461 	if (para.user_cnt == 1) {
462 		g2d_clock_enable(&para);
463 		para.opened = true;
464 		g2d_bsp_open();
465 	}
466 
467 	mutex_unlock(&para.mutex);
468 	return 0;
469 }
470 EXPORT_SYMBOL_GPL(g2d_open);
471 
g2d_release(struct inode * inode,struct file * file)472 int g2d_release(struct inode *inode, struct file *file)
473 {
474 	mutex_lock(&para.mutex);
475 	para.user_cnt--;
476 	if (para.user_cnt == 0) {
477 		g2d_clock_disable(&para);
478 		para.opened = false;
479 		g2d_bsp_close();
480 	}
481 
482 	mutex_unlock(&para.mutex);
483 
484 	mutex_lock(&global_lock);
485 	scan_order = G2D_SM_TDLR;
486 	mutex_unlock(&global_lock);
487 
488 	return 0;
489 }
490 EXPORT_SYMBOL_GPL(g2d_release);
491 
g2d_blit_h(g2d_blt_h * para)492 int g2d_blit_h(g2d_blt_h *para)
493 {
494 	int ret = -1;
495 #if defined(CONFIG_G2D_ROTATE)
496 	ret = g2d_rotate_set_para(&para->src_image_h,
497 			    &para->dst_image_h,
498 			    para->flag_h);
499 #else
500 	G2D_ERR_MSG("Please enable CONFIG_G2D_ROTATE\n");
501 #endif
502 	return ret;
503 }
504 EXPORT_SYMBOL_GPL(g2d_blit_h);
505 
g2d_mmap(struct file * file,struct vm_area_struct * vma)506 int g2d_mmap(struct file *file, struct vm_area_struct *vma)
507 {
508 	unsigned long mypfn = vma->vm_pgoff;
509 	unsigned long vmsize = vma->vm_end - vma->vm_start;
510 
511 	vma->vm_pgoff = 0;
512 
513 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
514 	if (remap_pfn_range(vma, vma->vm_start, mypfn,
515 			    vmsize, vma->vm_page_prot))
516 		return -EAGAIN;
517 
518 	return 0;
519 }
520 
521 #if defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_ARCH_SUN20IW1)
522 extern void sunxi_reset_device_iommu(unsigned int master_id);
523 #endif
524 
g2d_wait_cmd_finish(unsigned int timeout)525 int g2d_wait_cmd_finish(unsigned int timeout)
526 {
527 	timeout = wait_event_timeout(g2d_ext_hd.queue,
528 				     g2d_ext_hd.finish_flag == 1,
529 				     msecs_to_jiffies(timeout));
530 	if (timeout == 0) {
531 		g2d_bsp_reset();
532 		G2D_ERR_MSG("G2D irq pending flag timeout\n");
533 
534 		/* reset iommu */
535 #if defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_ARCH_SUN20IW1)
536 		sunxi_reset_device_iommu(G2D_IOMMU_MASTER_ID);
537 #endif
538 		g2d_ext_hd.finish_flag = 1;
539 		wake_up(&g2d_ext_hd.queue);
540 		return -1;
541 	}
542 	g2d_ext_hd.finish_flag = 0;
543 
544 	return 0;
545 }
546 
g2d_handle_irq(int irq,void * dev_id)547 irqreturn_t g2d_handle_irq(int irq, void *dev_id)
548 {
549 
550 #if defined(CONFIG_G2D_MIXER)
551 #if G2D_MIXER_RCQ_USED == 1
552 	if (g2d_top_rcq_task_irq_query()) {
553 		g2d_top_mixer_reset();
554 		g2d_ext_hd.finish_flag = 1;
555 		wake_up(&g2d_ext_hd.queue);
556 		return IRQ_HANDLED;
557 	}
558 #else
559 	if (g2d_mixer_irq_query()) {
560 		g2d_top_mixer_reset();
561 		g2d_ext_hd.finish_flag = 1;
562 		wake_up(&g2d_ext_hd.queue);
563 		return IRQ_HANDLED;
564 	}
565 #endif
566 #endif
567 
568 
569 
570 #if defined(CONFIG_G2D_ROTATE)
571 	if (g2d_rot_irq_query()) {
572 		g2d_ext_hd.finish_flag = 1;
573 		wake_up(&g2d_ext_hd.queue);
574 		return IRQ_HANDLED;
575 	}
576 #endif
577 
578 	return IRQ_HANDLED;
579 }
g2d_ioctl_mutex_lock(void)580 void g2d_ioctl_mutex_lock(void)
581 {
582 	if (!mutex_trylock(&para.mutex))
583 		mutex_lock(&para.mutex);
584 }
585 EXPORT_SYMBOL_GPL(g2d_ioctl_mutex_lock);
586 
g2d_ioctl_mutex_unlock(void)587 void g2d_ioctl_mutex_unlock(void)
588 {
589 	mutex_unlock(&para.mutex);
590 }
591 EXPORT_SYMBOL_GPL(g2d_ioctl_mutex_unlock);
592 
g2d_ioctl(struct file * file,unsigned int cmd,unsigned long arg)593 long g2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
594 {
595 	int ret = -1;
596 	struct timespec64 test_start, test_end;
597 
598 
599 	if (g_time_info == 1)
600 		ktime_get_real_ts64(&test_start);
601 
602 	if (!mutex_trylock(&para.mutex))
603 		mutex_lock(&para.mutex);
604 
605 	g2d_ext_hd.finish_flag = 0;
606 	switch (cmd) {
607 	case G2D_CMD_MIXER_TASK:
608 		{
609 #if defined(CONFIG_G2D_MIXER)
610 		struct mixer_para *p_mixer_para = NULL;
611 		unsigned long karg[2];
612 		unsigned long ubuffer[2] = { 0 };
613 
614 		if (copy_from_user((void *)karg, (void __user *)arg,
615 				   sizeof(unsigned long) * 2)) {
616 			ret = -EFAULT;
617 			goto err_noput;
618 		}
619 		ubuffer[0] = *(unsigned long *)karg;
620 		ubuffer[1] = (*(unsigned long *)(karg + 1));
621 
622 		p_mixer_para = kmalloc(sizeof(struct mixer_para) * ubuffer[1],
623 			       GFP_KERNEL | __GFP_ZERO);
624 		if (!p_mixer_para)
625 			goto err_noput;
626 		if (copy_from_user(p_mixer_para, (void __user *)ubuffer[0],
627 				   sizeof(struct mixer_para) * ubuffer[1])) {
628 			ret = -EFAULT;
629 			goto err_noput;
630 		}
631 		ret  = mixer_task_process(&para, p_mixer_para, ubuffer[1]);
632 		kfree(p_mixer_para);
633 #endif
634 		break;
635 		}
636 	case G2D_CMD_CREATE_TASK:
637 		{
638 #if defined(CONFIG_G2D_MIXER)
639 			struct mixer_para *p_mixer_para = NULL;
640 			unsigned long karg[2];
641 			unsigned long ubuffer[2] = { 0 };
642 
643 			if (copy_from_user((void *)karg, (void __user *)arg,
644 					   sizeof(unsigned long) * 2)) {
645 				ret = -EFAULT;
646 				goto err_noput;
647 			}
648 			ubuffer[0] = *(unsigned long *)karg;
649 			ubuffer[1] = (*(unsigned long *)(karg + 1));
650 			p_mixer_para = kmalloc(sizeof(struct mixer_para) * ubuffer[1],
651 					       GFP_KERNEL | __GFP_ZERO);
652 			if (!p_mixer_para)
653 				goto err_noput;
654 			if (copy_from_user(p_mixer_para, (void __user *)ubuffer[0],
655 					   sizeof(struct mixer_para) * ubuffer[1])) {
656 				ret = -EFAULT;
657 				goto err_noput;
658 			}
659 			ret = create_mixer_task(&para, p_mixer_para, ubuffer[1]);
660 			if (copy_to_user((void __user *)ubuffer[0], p_mixer_para,
661 					 sizeof(struct mixer_para) * ubuffer[1])) {
662 				G2D_ERR_MSG("copy_to_user fail\n");
663 				return  -EFAULT;
664 			}
665 			kfree(p_mixer_para);
666 #endif
667 			break;
668 		}
669 	case G2D_CMD_TASK_APPLY:
670 		{
671 #if defined(CONFIG_G2D_MIXER)
672 			unsigned long karg[2];
673 			unsigned long ubuffer[2] = { 0 };
674 			struct mixer_para *p_mixer_para = NULL;
675 			struct g2d_mixer_task *p_task = NULL;
676 
677 			if (copy_from_user((void *)karg, (void __user *)arg,
678 					   sizeof(unsigned long) * 2)) {
679 				ret = -EFAULT;
680 				goto err_noput;
681 			}
682 			ubuffer[0] = *(unsigned long *)karg;
683 			ubuffer[1] = (*(unsigned long *)(karg + 1));
684 			p_task = g2d_mixer_get_inst(ubuffer[0]);
685 			if (!p_task) {
686 				ret = -EFAULT;
687 				goto err_noput;
688 			}
689 			p_mixer_para = kmalloc(sizeof(struct mixer_para) * p_task->frame_cnt,
690 					       GFP_KERNEL | __GFP_ZERO);
691 			if (!p_mixer_para)
692 				goto err_noput;
693 			if (copy_from_user(p_mixer_para, (void __user *)ubuffer[1],
694 					   sizeof(struct mixer_para) * p_task->frame_cnt)) {
695 				ret = -EFAULT;
696 				goto err_noput;
697 			}
698 			ret = p_task->apply(p_task, p_mixer_para);
699 			kfree(p_mixer_para);
700 #endif
701 			break;
702 		}
703 	case G2D_CMD_TASK_DESTROY:
704 		{
705 #if defined(CONFIG_G2D_MIXER)
706 			unsigned long karg[1];
707 			unsigned long ubuffer[1] = { 0 };
708 			struct g2d_mixer_task *p_task = NULL;
709 
710 			if (copy_from_user((void *)karg, (void __user *)arg,
711 					   sizeof(unsigned long))) {
712 				ret = -EFAULT;
713 				goto err_noput;
714 			}
715 			ubuffer[0] = *(unsigned long *)karg;
716 			p_task = g2d_mixer_get_inst(ubuffer[0]);
717 
718 			if (!p_task) {
719 				ret = -EFAULT;
720 				G2D_ERR_MSG("Fail to find mixer task inst:%lu\n", ubuffer[0]);
721 				goto err_noput;
722 			}
723 
724 			ret = p_task->destory(p_task);
725 #endif
726 			break;
727 		}
728 	case G2D_CMD_TASK_GET_PARA:
729 		{
730 #if defined(CONFIG_G2D_MIXER)
731 			struct g2d_mixer_task *p_task = NULL;
732 			unsigned long karg[2];
733 			unsigned long ubuffer[2] = { 0 };
734 
735 			if (copy_from_user((void *)karg, (void __user *)arg,
736 					   sizeof(unsigned long) * 2)) {
737 				ret = -EFAULT;
738 				goto err_noput;
739 			}
740 			ubuffer[0] = *(unsigned long *)karg;
741 			ubuffer[1] = (*(unsigned long *)(karg + 1));
742 
743 			p_task = g2d_mixer_get_inst(ubuffer[0]);
744 			if (!p_task || !ubuffer[1]) {
745 				ret = -EFAULT;
746 				goto err_noput;
747 			}
748 
749 			ret = copy_to_user(
750 			    (void __user *)ubuffer[1], p_task->p_para,
751 			    sizeof(struct mixer_para) * p_task->frame_cnt);
752 #endif
753 			break;
754 		}
755 	case G2D_CMD_BITBLT_H:
756 		{
757 		g2d_blt_h blit_para;
758 
759 		if (copy_from_user(&blit_para, (g2d_blt_h *) arg,
760 				   sizeof(g2d_blt_h))) {
761 			ret = -EFAULT;
762 			goto err_noput;
763 		}
764 
765 		if (blit_para.flag_h & 0xff00) {
766 			ret = g2d_blit_h(&blit_para);
767 		}
768 #if defined(CONFIG_G2D_MIXER)
769 		else {
770 			struct mixer_para mixer_blit_para;
771 			/*mixer module*/
772 			memset(&mixer_blit_para, 0, sizeof(struct mixer_para));
773 			memcpy(&mixer_blit_para.dst_image_h,
774 			       &blit_para.dst_image_h, sizeof(g2d_image_enh));
775 			memcpy(&mixer_blit_para.src_image_h,
776 			       &blit_para.src_image_h, sizeof(g2d_image_enh));
777 			mixer_blit_para.flag_h = blit_para.flag_h;
778 			mixer_blit_para.op_flag = OP_BITBLT;
779 			ret = mixer_task_process(&para, &mixer_blit_para, 1);
780 		}
781 
782 #endif
783 		break;
784 		}
785 	case G2D_CMD_LBC_ROT:
786 		{
787 			g2d_lbc_rot lbc_para;
788 
789 			if (copy_from_user(&lbc_para, (g2d_lbc_rot *)arg,
790 						sizeof(g2d_lbc_rot))) {
791 				ret = -EFAULT;
792 				goto err_noput;
793 			}
794 
795 			ret = g2d_lbc_rot_set_para(&lbc_para);
796 			break;
797 		}
798 
799 	case G2D_CMD_BLD_H:{
800 #if defined(CONFIG_G2D_MIXER)
801 			g2d_bld bld_para;
802 			struct mixer_para mixer_bld_para;
803 
804 			if (copy_from_user(&bld_para, (g2d_bld *) arg,
805 					   sizeof(g2d_bld))) {
806 				ret = -EFAULT;
807 				goto err_noput;
808 			}
809 			memset(&mixer_bld_para, 0, sizeof(struct mixer_para));
810 			memcpy(&mixer_bld_para.dst_image_h,
811 			       &bld_para.dst_image, sizeof(g2d_image_enh));
812 			memcpy(&mixer_bld_para.src_image_h,
813 			       &bld_para.src_image[0], sizeof(g2d_image_enh));
814 			/* ptn use as src  */
815 			memcpy(&mixer_bld_para.ptn_image_h,
816 			       &bld_para.src_image[1], sizeof(g2d_image_enh));
817 			memcpy(&mixer_bld_para.ck_para, &bld_para.ck_para,
818 			       sizeof(g2d_ck));
819 			mixer_bld_para.bld_cmd = bld_para.bld_cmd;
820 			mixer_bld_para.op_flag = OP_BLEND;
821 
822 			ret  = mixer_task_process(&para, &mixer_bld_para, 1);
823 #endif
824 			break;
825 		}
826 	case G2D_CMD_FILLRECT_H:{
827 #if defined(CONFIG_G2D_MIXER)
828 		g2d_fillrect_h fill_para;
829 		struct mixer_para mixer_fill_para;
830 
831 		if (copy_from_user(&fill_para, (g2d_fillrect_h *) arg,
832 				   sizeof(g2d_fillrect_h))) {
833 			ret = -EFAULT;
834 			goto err_noput;
835 		}
836 		memset(&mixer_fill_para, 0, sizeof(struct mixer_para));
837 		memcpy(&mixer_fill_para.dst_image_h,
838 		       &fill_para.dst_image_h, sizeof(g2d_image_enh));
839 		mixer_fill_para.op_flag = OP_FILLRECT;
840 
841 		ret  = mixer_task_process(&para, &mixer_fill_para, 1);
842 #endif
843 		break;
844 	}
845 	case G2D_CMD_MASK_H:{
846 #if defined(CONFIG_G2D_MIXER)
847 			g2d_maskblt mask_para;
848 			struct mixer_para mixer_mask_para;
849 
850 			if (copy_from_user(&mask_para, (g2d_maskblt *) arg,
851 					   sizeof(g2d_maskblt))) {
852 				ret = -EFAULT;
853 				goto err_noput;
854 			}
855 			memset(&mixer_mask_para, 0, sizeof(struct mixer_para));
856 			memcpy(&mixer_mask_para.ptn_image_h,
857 			       &mask_para.ptn_image_h, sizeof(g2d_image_enh));
858 			memcpy(&mixer_mask_para.mask_image_h,
859 			       &mask_para.mask_image_h, sizeof(g2d_image_enh));
860 			memcpy(&mixer_mask_para.dst_image_h,
861 			       &mask_para.dst_image_h, sizeof(g2d_image_enh));
862 			memcpy(&mixer_mask_para.src_image_h,
863 			       &mask_para.src_image_h, sizeof(g2d_image_enh));
864 			mixer_mask_para.back_flag = mask_para.back_flag;
865 			mixer_mask_para.fore_flag = mask_para.fore_flag;
866 			mixer_mask_para.op_flag = OP_MASK;
867 
868 			ret  = mixer_task_process(&para, &mixer_mask_para, 1);
869 #endif
870 			break;
871 		}
872 	case G2D_CMD_INVERTED_ORDER:
873 		{
874 			if (arg > G2D_SM_DTRL) {
875 				G2D_ERR_MSG("scan mode is err.\n");
876 				ret = -EINVAL;
877 				goto err_noput;
878 			}
879 
880 			mutex_lock(&global_lock);
881 			scan_order = arg;
882 			mutex_unlock(&global_lock);
883 			break;
884 		}
885 
886 	default:
887 		goto err_noput;
888 		break;
889 	}
890 
891 err_noput:
892 	mutex_unlock(&para.mutex);
893 	if (g_time_info == 1) {
894 		ktime_get_real_ts64(&test_end);
895 		g_func_runtime += (test_end.tv_sec - test_start.tv_sec) * 1000000 +
896 			(test_end.tv_nsec - test_start.tv_nsec) / NSEC_PER_USEC;
897 	}
898 	return ret;
899 }
900 
drv_g2d_init(void)901 __s32 drv_g2d_init(void)
902 {
903 	memset(&g2d_ext_hd, 0, sizeof(__g2d_drv_t));
904 	init_waitqueue_head(&g2d_ext_hd.queue);
905 	g2d_top_set_base((unsigned long) para.io);
906 
907 #if defined(CONFIG_G2D_ROTATE)
908 	g2d_rot_set_base((unsigned long) para.io);
909 #endif
910 	return 0;
911 }
912 
g2d_debug_show(struct device * dev,struct device_attribute * attr,char * buf)913 static ssize_t g2d_debug_show(struct device *dev,
914 			     struct device_attribute *attr, char *buf)
915 {
916 	return sprintf(buf, "debug=%d\n", dbg_info);
917 }
918 
g2d_debug_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)919 static ssize_t g2d_debug_store(struct device *dev,
920 			      struct device_attribute *attr,
921 			      const char *buf, size_t count)
922 {
923 	if (strncasecmp(buf, "1", 1) == 0)
924 		dbg_info = 1;
925 	else if (strncasecmp(buf, "0", 1) == 0)
926 		dbg_info = 0;
927 	else if (strncasecmp(buf, "2", 1) == 0)
928 		dbg_info = 2;
929 	else
930 		G2D_ERR_MSG("Error input!\n");
931 
932 	return count;
933 }
934 
935 static DEVICE_ATTR(debug, 0660,
936 		   g2d_debug_show, g2d_debug_store);
937 
g2d_func_runtime_show(struct device * dev,struct device_attribute * attr,char * buf)938 static ssize_t g2d_func_runtime_show(struct device *dev,
939 			     struct device_attribute *attr, char *buf)
940 {
941 	return sprintf(buf, "func_runtime = %d us\n", g_func_runtime);
942 }
943 
g2d_func_runtime_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)944 static ssize_t g2d_func_runtime_store(struct device *dev,
945 			      struct device_attribute *attr,
946 			      const char *buf, size_t count)
947 {
948 	g_func_runtime = 0;
949 	if (strncasecmp(buf, "1", 1) == 0)
950 		g_time_info = 1;
951 	else if (strncasecmp(buf, "0", 1) == 0)
952 		g_time_info = 0;
953 	else
954 		G2D_ERR_MSG("Error input!\n");
955 
956 	return count;
957 }
958 
959 static DEVICE_ATTR(func_runtime, 0660,
960 		   g2d_func_runtime_show, g2d_func_runtime_store);
961 
962 static struct attribute *g2d_attributes[] = {
963 	&dev_attr_debug.attr,
964 	&dev_attr_func_runtime.attr,
965 	NULL
966 };
967 
968 static struct attribute_group g2d_attribute_group = {
969 	.name = "attr",
970 	.attrs = g2d_attributes
971 };
972 
973 static u64 sunxi_g2d_dma_mask = DMA_BIT_MASK(32);
g2d_probe(struct platform_device * pdev)974 static int g2d_probe(struct platform_device *pdev)
975 {
976 	int ret = 0;
977 	__g2d_info_t *info = NULL;
978 
979 	info = &para;
980 	info->dev = &pdev->dev;
981 	dmabuf_dev = &pdev->dev;
982 	dmabuf_dev->dma_mask = &sunxi_g2d_dma_mask;
983 	dmabuf_dev->coherent_dma_mask = DMA_BIT_MASK(32);
984 	platform_set_drvdata(pdev, info);
985 
986 	info->io = of_iomap(pdev->dev.of_node, 0);
987 	if (info->io == NULL) {
988 		G2D_ERR_MSG("iormap() of register failed\n");
989 		ret = -ENXIO;
990 		goto dealloc_fb;
991 	}
992 
993 	info->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
994 	if (!info->irq) {
995 		G2D_ERR_MSG("irq_of_parse_and_map irq fail for transform\n");
996 		ret = -ENXIO;
997 		goto release_regs;
998 	}
999 
1000 	/* request the irq */
1001 	ret = request_irq(info->irq, g2d_handle_irq, 0,
1002 			  dev_name(&pdev->dev), NULL);
1003 	if (ret) {
1004 		G2D_ERR_MSG("failed to install irq resource\n");
1005 		goto release_regs;
1006 	}
1007 	/* clk init */
1008 	info->clk = devm_clk_get(&pdev->dev, "g2d");
1009 	if (IS_ERR(info->clk)) {
1010 		G2D_ERR_MSG("fail to get clk\n");
1011 		ret = -ENXIO;
1012 		goto out_dispose_mapping;
1013 	} else {
1014 		info->clk_parent = clk_get_parent(info->clk);
1015 		info->bus_clk = devm_clk_get(&pdev->dev, "bus");
1016 		info->mbus_clk = devm_clk_get(&pdev->dev, "mbus_g2d");
1017 		info->reset = devm_reset_control_get(&pdev->dev, NULL);
1018 	}
1019 
1020 	drv_g2d_init();
1021 	mutex_init(&info->mutex);
1022 	mutex_init(&global_lock);
1023 
1024 	ret = sysfs_create_group(&g2d_dev->kobj, &g2d_attribute_group);
1025 	if (ret < 0)
1026 		G2D_ERR_MSG("sysfs_create_file fail!\n");
1027 
1028 	return 0;
1029 
1030 out_dispose_mapping:
1031 	irq_dispose_mapping(info->irq);
1032 release_regs:
1033 	iounmap(info->io);
1034 dealloc_fb:
1035 	platform_set_drvdata(pdev, NULL);
1036 
1037 	return ret;
1038 }
1039 
1040 
1041 static const struct file_operations g2d_fops = {
1042 	.owner = THIS_MODULE,
1043 	.open = g2d_open,
1044 	.release = g2d_release,
1045 	.unlocked_ioctl = g2d_ioctl,
1046 	.mmap = g2d_mmap,
1047 };
1048 
g2d_remove(struct platform_device * pdev)1049 static int g2d_remove(struct platform_device *pdev)
1050 {
1051 	__g2d_info_t *info = platform_get_drvdata(pdev);
1052 
1053 	free_irq(info->irq, NULL);
1054 
1055 	platform_set_drvdata(pdev, NULL);
1056 
1057 	sysfs_remove_group(&g2d_dev->kobj, &g2d_attribute_group);
1058 
1059 	INFO("Driver unloaded succesfully.\n");
1060 	return 0;
1061 }
1062 
g2d_suspend(struct platform_device * pdev,pm_message_t state)1063 static int g2d_suspend(struct platform_device *pdev, pm_message_t state)
1064 {
1065 	INFO("%s.\n", __func__);
1066 	mutex_lock(&para.mutex);
1067 	if (para.opened) {
1068 		g2d_clock_disable(&para);
1069 		g2d_bsp_close();
1070 	}
1071 	mutex_unlock(&para.mutex);
1072 	INFO("g2d_suspend succesfully.\n");
1073 
1074 	return 0;
1075 }
1076 
g2d_resume(struct platform_device * pdev)1077 static int g2d_resume(struct platform_device *pdev)
1078 {
1079 	INFO("%s.\n", __func__);
1080 	mutex_lock(&para.mutex);
1081 	if (para.opened) {
1082 		g2d_clock_enable(&para);
1083 		g2d_bsp_open();
1084 	}
1085 	mutex_unlock(&para.mutex);
1086 	INFO("g2d_resume succesfully.\n");
1087 
1088 	return 0;
1089 }
1090 
1091 static const struct of_device_id sunxi_g2d_match[] = {
1092 	{.compatible = "allwinner,sunxi-g2d",},
1093 	{},
1094 };
1095 
1096 static struct platform_driver g2d_driver = {
1097 	.probe = g2d_probe,
1098 	.remove = g2d_remove,
1099 	.suspend = g2d_suspend,
1100 	.resume = g2d_resume,
1101 	.driver = {
1102 
1103 		   .owner = THIS_MODULE,
1104 		   .name = "g2d",
1105 		   .of_match_table = sunxi_g2d_match,
1106 		   },
1107 };
1108 
g2d_module_init(void)1109 int __init g2d_module_init(void)
1110 {
1111 	int ret = 0, err;
1112 
1113 	alloc_chrdev_region(&devid, 0, 1, "g2d_chrdev");
1114 	g2d_cdev = cdev_alloc();
1115 	cdev_init(g2d_cdev, &g2d_fops);
1116 	g2d_cdev->owner = THIS_MODULE;
1117 	err = cdev_add(g2d_cdev, devid, 1);
1118 	if (err) {
1119 		G2D_ERR_MSG("I was assigned major number %d.\n", MAJOR(devid));
1120 		return -1;
1121 	}
1122 
1123 	g2d_class = class_create(THIS_MODULE, "g2d");
1124 	if (IS_ERR(g2d_class)) {
1125 		G2D_ERR_MSG("create class error\n");
1126 		return -1;
1127 	}
1128 
1129 	g2d_dev = device_create(g2d_class, NULL, devid, NULL, "g2d");
1130 	if (ret == 0)
1131 		ret = platform_driver_register(&g2d_driver);
1132 
1133 	INFO("rcq version initialized.major:%d\n", MAJOR(devid));
1134 	return ret;
1135 }
1136 
g2d_module_exit(void)1137 static void __exit g2d_module_exit(void)
1138 {
1139 	INFO("g2d_module_exit\n");
1140 
1141 	platform_driver_unregister(&g2d_driver);
1142 	device_destroy(g2d_class, devid);
1143 	class_destroy(g2d_class);
1144 
1145 	cdev_del(g2d_cdev);
1146 }
1147 
1148 subsys_initcall_sync(g2d_module_init);
1149 module_exit(g2d_module_exit);
1150 
1151 MODULE_AUTHOR("zxb <zhengxiaobin@allwinnertech.com>");
1152 MODULE_DESCRIPTION("g2d(rcq) driver");
1153 MODULE_LICENSE("GPL");
1154