• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Allwinner SoCs display driver.
3  *
4  * Copyright (C) 2016 Allwinner.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10 
11 #include "disp_private.h"
12 #include "../dev_disp.h"
13 #include "../disp_trace.h"
14 
15 extern struct disp_drv_info g_disp_drv;
16 
17 #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED)
18 
disp_delay_ms(u32 ms)19 s32 disp_delay_ms(u32 ms)
20 {
21 #if defined(__LINUX_PLAT__)
22 	mdelay(ms);
23 #endif
24 #ifdef __UBOOT_PLAT__
25 	__msdelay(ms);
26 #endif
27 	return 0;
28 }
29 
30 #else
31 
disp_delay_ms(u32 ms)32 s32 disp_delay_ms(u32 ms)
33 {
34 #if defined(__LINUX_PLAT__)
35 	u32 timeout = msecs_to_jiffies(ms);
36 
37 	set_current_state(TASK_UNINTERRUPTIBLE);
38 	schedule_timeout(timeout);
39 #endif
40 #ifdef __UBOOT_PLAT__
41 	__msdelay(ms);
42 #endif
43 	return 0;
44 }
45 
46 #endif				/*endif SUPPORT_EINK */
47 
disp_delay_us(u32 us)48 s32 disp_delay_us(u32 us)
49 {
50 	udelay(us);
51 
52 	return 0;
53 }
54 
dump_layer_config(struct disp_layer_config_data * data)55 u32 dump_layer_config(struct disp_layer_config_data *data)
56 {
57 	u32 count = 0;
58 	char buf[512];
59 
60 	count +=
61 	    sprintf(buf + count, " %6s ",
62 		    (data->config.info.mode == LAYER_MODE_BUFFER) ?
63 		    "buffer" : "color");
64 	count +=
65 	    sprintf(buf + count, " %8s ",
66 		    (data->config.enable == 1) ? "enable" : "disable");
67 	count += sprintf(buf + count, "ch[%1d] ", data->config.channel);
68 	count += sprintf(buf + count, "lyr[%1d] ", data->config.layer_id);
69 	count += sprintf(buf + count, "z[%1d] ", data->config.info.zorder);
70 	count +=
71 	    sprintf(buf + count, "pre_m[%1s] ",
72 		    (data->config.info.fb.pre_multiply) ? "Y" : "N");
73 	count +=
74 	    sprintf(buf + count, "alpha[%5s %3d] ",
75 		    (data->config.info.alpha_mode) ? "globl" : "pixel",
76 		    data->config.info.alpha_value);
77 	count += sprintf(buf + count, "fmt[%3d] ", data->config.info.fb.format);
78 	count +=
79 	    sprintf(buf + count, "size[%4d,%4d;%4d,%4d;%4d,%4d] ",
80 		    data->config.info.fb.size[0].width,
81 		    data->config.info.fb.size[0].height,
82 		    data->config.info.fb.size[0].width,
83 		    data->config.info.fb.size[0].height,
84 		    data->config.info.fb.size[0].width,
85 		    data->config.info.fb.size[0].height);
86 	count +=
87 	    sprintf(buf + count, "crop[%4d,%4d,%4d,%4d] ",
88 		    (u32) (data->config.info.fb.crop.x >> 32),
89 		    (u32) (data->config.info.fb.crop.y >> 32),
90 		    (u32) (data->config.info.fb.crop.width >> 32),
91 		    (u32) (data->config.info.fb.crop.height >> 32));
92 	count +=
93 	    sprintf(buf + count, "frame[%4d,%4d,%4d,%4d] ",
94 		    data->config.info.screen_win.x,
95 		    data->config.info.screen_win.y,
96 		    data->config.info.screen_win.width,
97 		    data->config.info.screen_win.height);
98 	count +=
99 	    sprintf(buf + count, "addr[%8llx,%8llx,%8llx] ",
100 		    data->config.info.fb.addr[0], data->config.info.fb.addr[1],
101 		    data->config.info.fb.addr[2]);
102 	count += sprintf(buf + count, "flag[0x%8x] ", data->flag);
103 	count += sprintf(buf + count, "\n");
104 
105 	DE_WRN("%s", buf);
106 	return count;
107 }
108 
disp_vmap(unsigned long phys_addr,unsigned long size)109 void *disp_vmap(unsigned long phys_addr, unsigned long size)
110 {
111 	int npages = PAGE_ALIGN(size) / PAGE_SIZE;
112 	struct page **pages = vmalloc(sizeof(struct page *) * npages);
113 	struct page **tmp = pages;
114 	struct page *cur_page = phys_to_page(phys_addr);
115 	pgprot_t pgprot;
116 	void *vaddr = NULL;
117 	int i;
118 
119 	if (!pages)
120 		return NULL;
121 
122 	for (i = 0; i < npages; i++)
123 		*(tmp++) = cur_page++;
124 
125 	pgprot = PAGE_KERNEL;
126 	vaddr = vmap(pages, npages, VM_MAP, pgprot);
127 
128 	vfree(pages);
129 	return vaddr;
130 }
131 
disp_vunmap(const void * vaddr)132 void disp_vunmap(const void *vaddr)
133 {
134 	vunmap(vaddr);
135 }
136 
disp_dma_map_core(int fd,struct dmabuf_item * item)137 static int disp_dma_map_core(int fd, struct dmabuf_item *item)
138 {
139 #if defined(__LINUX_PLAT__)
140 	struct dma_buf *dmabuf;
141 	struct dma_buf_attachment *attachment;
142 	struct sg_table *sgt;
143 	int ret = -1;
144 
145 	if (fd < 0) {
146 		DE_WRN("dma_buf_id(%d) is invalid\n", fd);
147 		goto exit;
148 	}
149 	dmabuf = dma_buf_get(fd);
150 	if (IS_ERR(dmabuf)) {
151 		DE_WRN("dma_buf_get failed, fd=%d\n", fd);
152 		goto exit;
153 	}
154 	attachment = dma_buf_attach(dmabuf, g_disp_drv.dev);
155 	if (IS_ERR(attachment)) {
156 		DE_WRN("dma_buf_attach failed\n");
157 		goto err_buf_put;
158 	}
159 	sgt = dma_buf_map_attachment(attachment, DMA_FROM_DEVICE);
160 	if (IS_ERR_OR_NULL(sgt)) {
161 		DE_WRN("dma_buf_map_attachment failed\n");
162 		goto err_buf_detach;
163 	}
164 
165 	item->dmabuf = dmabuf;
166 	item->sgt = sgt;
167 	item->attachment = attachment;
168 	item->dma_addr = sg_dma_address(sgt->sgl);
169 	ret = 0;
170 
171 	goto exit;
172 
173 	/* unmap attachment sgt, not sgt_bak, cause it's not alloc yet! */
174 	dma_buf_unmap_attachment(attachment, sgt, DMA_FROM_DEVICE);
175 err_buf_detach:
176 	dma_buf_detach(dmabuf, attachment);
177 err_buf_put:
178 	dma_buf_put(dmabuf);
179 exit:
180 	return ret;
181 #endif
182 	return 0;
183 }
184 
disp_dma_unmap_core(struct dmabuf_item * item)185 static void disp_dma_unmap_core(struct dmabuf_item *item)
186 {
187 #if defined(__LINUX_PLAT__)
188 	dma_buf_unmap_attachment(item->attachment, item->sgt, DMA_FROM_DEVICE);
189 	dma_buf_detach(item->dmabuf, item->attachment);
190 	dma_buf_put(item->dmabuf);
191 #endif
192 }
193 
disp_dma_map(int fd)194 struct dmabuf_item *disp_dma_map(int fd)
195 {
196 #if defined(__LINUX_PLAT__)
197 	struct dmabuf_item *item = NULL;
198 
199 	DISP_TRACE_BEGIN("disp_dma_map");
200 	item = kmalloc(sizeof(struct dmabuf_item),
201 			      GFP_KERNEL | __GFP_ZERO);
202 
203 	if (item == NULL) {
204 		DE_WRN("malloc memory of size %d fail!\n",
205 		       (unsigned int)sizeof(struct dmabuf_item));
206 		goto exit;
207 	}
208 	if (disp_dma_map_core(fd, item) != 0) {
209 		kfree(item);
210 		item = NULL;
211 	}
212 
213 exit:
214 	DISP_TRACE_END("disp_dma_map");
215 	return item;
216 #else
217 
218 	return NULL;
219 #endif
220 }
221 
disp_dma_unmap(struct dmabuf_item * item)222 void disp_dma_unmap(struct dmabuf_item *item)
223 {
224 #if defined(__LINUX_PLAT__)
225 	DISP_TRACE_BEGIN("disp_dma_unmap");
226 	disp_dma_unmap_core(item);
227 	kfree(item);
228 	DISP_TRACE_END("disp_dma_unmap");
229 #endif
230 }
231 
232 static struct disp_format_attr fmt_attr_tbl[] = {
233 	/* format                            bits */
234 	/* hor_rsample(u,v) */
235 	/* ver_rsample(u,v) */
236 	/* uvc */
237 	/* interleave */
238 	/* factor */
239 	/* div */
240 
241 	{ DISP_FORMAT_ARGB_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
242 	{ DISP_FORMAT_ABGR_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
243 	{ DISP_FORMAT_RGBA_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
244 	{ DISP_FORMAT_BGRA_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
245 	{ DISP_FORMAT_XRGB_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
246 	{ DISP_FORMAT_XBGR_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
247 	{ DISP_FORMAT_RGBX_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
248 	{ DISP_FORMAT_BGRX_8888, 8,  1, 1, 1, 1, 0, 1, 4, 1},
249 	{ DISP_FORMAT_RGB_888, 8,  1, 1, 1, 1, 0, 1, 3, 1},
250 	{ DISP_FORMAT_BGR_888, 8,  1, 1, 1, 1, 0, 1, 3, 1},
251 	{ DISP_FORMAT_RGB_565, 8,  1, 1, 1, 1, 0, 1, 2, 1},
252 	{ DISP_FORMAT_BGR_565, 8,  1, 1, 1, 1, 0, 1, 2, 1},
253 	{ DISP_FORMAT_ARGB_4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
254 	{ DISP_FORMAT_ABGR_4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
255 	{ DISP_FORMAT_RGBA_4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
256 	{ DISP_FORMAT_BGRA_4444, 8,  1, 1, 1, 1, 0, 1, 2, 1},
257 	{ DISP_FORMAT_ARGB_1555, 8,  1, 1, 1, 1, 0, 1, 2, 1},
258 	{ DISP_FORMAT_ABGR_1555, 8,  1, 1, 1, 1, 0, 1, 2, 1},
259 	{ DISP_FORMAT_RGBA_5551, 8,  1, 1, 1, 1, 0, 1, 2, 1},
260 	{ DISP_FORMAT_BGRA_5551, 8,  1, 1, 1, 1, 0, 1, 2, 1},
261 	{ DISP_FORMAT_A2R10G10B10, 10, 1, 1, 1, 1, 0, 1, 4, 1},
262 	{ DISP_FORMAT_A2B10G10R10, 10, 1, 1, 1, 1, 0, 1, 4, 1},
263 	{ DISP_FORMAT_R10G10B10A2, 10, 1, 1, 1, 1, 0, 1, 4, 1},
264 	{ DISP_FORMAT_B10G10R10A2, 10, 1, 1, 1, 1, 0, 1, 4, 1},
265 	{ DISP_FORMAT_YUV444_I_AYUV, 8,  1, 1, 1, 1, 0, 1, 3, 1},
266 	{ DISP_FORMAT_YUV444_I_VUYA, 8,  1, 1, 1, 1, 0, 1, 3, 1},
267 	{ DISP_FORMAT_YUV422_I_YVYU, 8,  1, 1, 1, 1, 0, 1, 2, 1},
268 	{ DISP_FORMAT_YUV422_I_YUYV, 8,  1, 1, 1, 1, 0, 1, 2, 1},
269 	{ DISP_FORMAT_YUV422_I_UYVY, 8,  1, 1, 1, 1, 0, 1, 2, 1},
270 	{ DISP_FORMAT_YUV422_I_VYUY, 8,  1, 1, 1, 1, 0, 1, 2, 1},
271 	{ DISP_FORMAT_YUV444_P, 8,  1, 1, 1, 1, 0, 1, 1, 1},
272 	{ DISP_FORMAT_YUV422_P, 8,  2, 2, 1, 1, 0, 0, 2, 1},
273 	{ DISP_FORMAT_YUV420_P, 8,  2, 2, 2, 2, 0, 0, 3, 2},
274 	{ DISP_FORMAT_YUV411_P, 8,  4, 4, 1, 1, 0, 0, 3, 2},
275 	{ DISP_FORMAT_YUV422_SP_UVUV, 8,  2, 2, 1, 1, 1, 0, 2, 1},
276 	{ DISP_FORMAT_YUV422_SP_VUVU, 8,  2, 2, 1, 1, 1, 0, 2, 1},
277 	{ DISP_FORMAT_YUV420_SP_UVUV, 8,  2, 2, 2, 2, 1, 0, 3, 2},
278 	{ DISP_FORMAT_YUV420_SP_VUVU, 8,  2, 2, 2, 2, 1, 0, 3, 2},
279 	{ DISP_FORMAT_YUV411_SP_UVUV, 8,  4, 4, 1, 1, 1, 0, 3, 2},
280 	{ DISP_FORMAT_YUV411_SP_VUVU, 8,  4, 4, 1, 1, 1, 0, 3, 2},
281 	{ DISP_FORMAT_8BIT_GRAY, 8,  1, 1, 1, 1, 0, 0, 1, 1},
282 	{ DISP_FORMAT_YUV444_I_AYUV_10BIT, 10, 1, 1, 1, 1, 0, 1, 4, 1},
283 	{ DISP_FORMAT_YUV444_I_VUYA_10BIT, 10, 1, 1, 1, 1, 0, 1, 4, 1},
284 	{ DISP_FORMAT_YUV422_I_YVYU_10BIT, 10, 1, 1, 1, 1, 0, 1, 3, 1},
285 	{ DISP_FORMAT_YUV422_I_YUYV_10BIT, 10, 1, 1, 1, 1, 0, 1, 3, 1},
286 	{ DISP_FORMAT_YUV422_I_UYVY_10BIT, 10, 1, 1, 1, 1, 0, 1, 3, 1},
287 	{ DISP_FORMAT_YUV422_I_VYUY_10BIT, 10, 1, 1, 1, 1, 0, 1, 3, 1},
288 	{ DISP_FORMAT_YUV444_P_10BIT, 10, 1, 1, 1, 1, 0, 0, 6, 1},
289 	{ DISP_FORMAT_YUV422_P_10BIT, 10, 2, 2, 1, 1, 0, 0, 4, 1},
290 	{ DISP_FORMAT_YUV420_P_10BIT, 10, 2, 2, 2, 2, 0, 0, 3, 1},
291 	{ DISP_FORMAT_YUV411_P_10BIT, 10, 4, 4, 1, 1, 0, 0, 3, 1},
292 	{ DISP_FORMAT_YUV422_SP_UVUV_10BIT, 10, 2, 2, 1, 1, 1, 0, 4, 1},
293 	{ DISP_FORMAT_YUV422_SP_VUVU_10BIT, 10, 2, 2, 1, 1, 1, 0, 4, 1},
294 	{ DISP_FORMAT_YUV420_SP_UVUV_10BIT, 10, 2, 2, 2, 2, 1, 0, 3, 1},
295 	{ DISP_FORMAT_YUV420_SP_VUVU_10BIT, 10, 2, 2, 2, 2, 1, 0, 3, 1},
296 	{ DISP_FORMAT_YUV411_SP_UVUV_10BIT, 10, 4, 4, 1, 1, 1, 0, 3, 1},
297 	{ DISP_FORMAT_YUV411_SP_VUVU_10BIT, 10, 4, 4, 1, 1, 1, 0, 3, 1},
298 };
299 
300 /* @left_eye: indicate left eye buffer when true */
disp_set_fb_info(struct fb_address_transfer * fb,bool left_eye)301 s32 disp_set_fb_info(struct fb_address_transfer *fb, bool left_eye)
302 {
303 	s32 ret = -1;
304 	u32 i = 0;
305 	u32 len = ARRAY_SIZE(fmt_attr_tbl);
306 	u32 y_width, y_height, u_width, u_height;
307 	u32 y_pitch, u_pitch;
308 	u32 y_size, u_size;
309 	unsigned long long fb_addr[3];
310 
311 
312 	y_width = fb->size[0].width;
313 	y_height = fb->size[0].height;
314 	u_width = fb->size[1].width;
315 	u_height = fb->size[1].height;
316 	u_width = (u_width == 0) ? y_width : u_width;
317 	u_height = (u_height == 0) ? y_height : u_height;
318 
319 	fb_addr[0] = fb->dma_addr;
320 
321 	if (fb->format >= DISP_FORMAT_MAX) {
322 		DE_WRN("%s, format 0x%x is out of range\n", __func__,
323 			fb->format);
324 		goto exit;
325 	}
326 
327 	for (i = 0; i < len; ++i) {
328 
329 		if (fmt_attr_tbl[i].format == fb->format) {
330 			y_pitch = y_width *
331 			    ((fmt_attr_tbl[i].bits == 8) ? 1 : 2);
332 			u_pitch = u_width *
333 			    ((fmt_attr_tbl[i].bits == 8) ? 1 : 2) *
334 			    (fmt_attr_tbl[i].uvc + 1);
335 
336 			y_pitch = DISPALIGN(y_pitch, fb->align[0]);
337 			u_pitch = DISPALIGN(u_pitch, fb->align[1]);
338 			y_size = y_pitch * y_height;
339 			u_size = u_pitch * u_height;
340 
341 			fb_addr[1] = fb->dma_addr + y_size; /* u */
342 			fb_addr[2] = fb->dma_addr + y_size + u_size; /* v */
343 
344 			if (fb->format == DISP_FORMAT_YUV420_P ||
345 				fb->format == DISP_FORMAT_YUV420_P_10BIT) {
346 				/* v */
347 				fb_addr[1] = fb->dma_addr + y_size + u_size;
348 				fb_addr[2] = fb->dma_addr + y_size; /* u */
349 			}
350 			ret = 0;
351 			break;
352 		}
353 	}
354 	if (fb->format >= DISP_FORMAT_1bpp_palette_LE && fb->format <= DISP_FORMAT_8bpp_palette_LE) {
355 		fb_addr[0] = fb->dma_addr;
356 		fb_addr[1] = fb->dma_addr;
357 		fb_addr[2] = fb->dma_addr;
358 		ret = 0;
359 	}
360 	if (ret != 0) {
361 		DE_WRN("%s, format 0x%x is invalid\n", __func__,
362 			fb->format);
363 	} else {
364 		if (left_eye) {
365 			fb->addr[0] = fb_addr[0];
366 			fb->addr[1] = fb_addr[1];
367 			fb->addr[2] = fb_addr[2];
368 			fb->trd_right_addr[0] = fb_addr[0];
369 			fb->trd_right_addr[1] = fb_addr[1];
370 			fb->trd_right_addr[2] = fb_addr[2];
371 		} else {
372 			fb->trd_right_addr[0] = fb_addr[0];
373 			fb->trd_right_addr[1] = fb_addr[1];
374 			fb->trd_right_addr[2] = fb_addr[2];
375 		}
376 	}
377 exit:
378 	return ret;
379 }
380 EXPORT_SYMBOL(disp_set_fb_info);
381 
disp_set_fb_base_on_depth(struct fb_address_transfer * fb)382 s32 disp_set_fb_base_on_depth(struct fb_address_transfer *fb)
383 {
384 	s32 ret = -1;
385 	u32 i = 0;
386 	u32 len = ARRAY_SIZE(fmt_attr_tbl);
387 	int depth = fb->depth;
388 	unsigned long long abs_depth = (depth > 0) ?
389 				  depth : (-depth);
390 	/*
391 	 * 1: left & right move closer, right buffer address move right
392 	 * 0: in opposite direction
393 	 */
394 	unsigned int direction = (depth > 0) ? 1 : 0;
395 	unsigned int offset = 0;
396 
397 	if (fb->format >= DISP_FORMAT_MAX) {
398 		DE_WRN("%s, format 0x%x is out of range\n", __func__,
399 			fb->format);
400 		goto exit;
401 	}
402 
403 	for (i = 0; i < len; ++i) {
404 		if (fmt_attr_tbl[i].format == fb->format) {
405 			offset = fmt_attr_tbl[i].factor / fmt_attr_tbl[i].div;
406 			offset = offset * (unsigned int)abs_depth;
407 
408 			ret = 0;
409 			break;
410 		}
411 	}
412 	if (ret != 0) {
413 		DE_WRN("%s, format 0x%x is invalid\n", __func__,
414 			fb->format);
415 	} else {
416 		if (direction == 0) {
417 			fb->addr[0] += offset;
418 			fb->addr[1] += offset;
419 			fb->addr[2] += offset;
420 		} else {
421 			fb->trd_right_addr[0] += offset;
422 			fb->trd_right_addr[1] += offset;
423 			fb->trd_right_addr[2] += offset;
424 		}
425 	}
426 exit:
427 	return ret;
428 }
429 
430 /* *********************** disp irq util begin ********************* */
431 struct disp_irq_util {
432 	s32 num;
433 	u32 irq_no;
434 	u32 irq_en;
435 	struct disp_irq_info *irq_info[DISP_SCREEN_NUM + DISP_WB_NUM + DISP_SCREEN_NUM];
436 };
437 
438 static struct disp_irq_util s_irq_util;
439 static DEFINE_SPINLOCK(s_irq_lock);
440 
disp_init_irq_util(u32 irq_no)441 s32 disp_init_irq_util(u32 irq_no)
442 {
443 	s_irq_util.irq_no = irq_no;
444 	return 0;
445 }
446 
disp_irq_handler(int irq,void * parg)447 static s32 disp_irq_handler(int irq, void *parg)
448 {
449 	unsigned long flags;
450 	const u32 total_num = sizeof(s_irq_util.irq_info)
451 		/ sizeof(s_irq_util.irq_info[0]);
452 	u32 id;
453 
454 	for (id = 0; id < total_num; id++) {
455 		struct disp_irq_info *irq_info;
456 
457 		spin_lock_irqsave(&s_irq_lock, flags);
458 		irq_info = s_irq_util.irq_info[id];
459 		spin_unlock_irqrestore(&s_irq_lock, flags);
460 
461 		if (irq_info)
462 			irq_info->irq_handler(irq_info->sel,
463 				irq_info->irq_flag, irq_info->ptr);
464 	}
465 
466 	return DISP_IRQ_RETURN;
467 }
468 
disp_register_irq(u32 id,struct disp_irq_info * irq_info)469 s32 disp_register_irq(u32 id, struct disp_irq_info *irq_info)
470 {
471 	/*unsigned long flags;*/
472 	const u32 max_id = sizeof(s_irq_util.irq_info)
473 		/ sizeof(s_irq_util.irq_info[0]);
474 
475 	if ((irq_info == NULL) || (id >= max_id)) {
476 		__wrn("invalid pare: irq_info=%p, id=%d\n",
477 			irq_info, id);
478 		return -1;
479 	}
480 
481 	__inf("id=%d, irq_info:sel=%d,irq_flag=0x%x\n", id,
482 		irq_info->sel, irq_info->irq_flag);
483 
484 	/*spin_lock_irqsave(&s_irq_lock, flags);*/
485 	if (s_irq_util.irq_info[id] == NULL) {
486 		s_irq_util.irq_info[id] = irq_info;
487 		s_irq_util.num++;
488 		if ((s_irq_util.num > 0)
489 			&& (s_irq_util.irq_en == 0)) {
490 			disp_sys_register_irq(s_irq_util.irq_no, 0,
491 				disp_irq_handler, NULL, 0, 0);
492 			disp_sys_enable_irq(s_irq_util.irq_no);
493 			s_irq_util.irq_en = 1;
494 		}
495 	} else {
496 		__wrn("irq for %d already registered\n", id);
497 	}
498 	/*spin_unlock_irqrestore(&s_irq_lock, flags);*/
499 
500 	return 0;
501 }
502 
disp_unregister_irq(u32 id,struct disp_irq_info * irq_info)503 s32 disp_unregister_irq(u32 id, struct disp_irq_info *irq_info)
504 {
505 	/*unsigned long flags;*/
506 	const u32 max_id = sizeof(s_irq_util.irq_info)
507 		/ sizeof(s_irq_util.irq_info[0]);
508 
509 	if ((irq_info == NULL) || (id >= max_id)) {
510 		__wrn("invalid pare: irq_info=%p, id=%d\n",
511 			irq_info, id);
512 		return -1;
513 	}
514 
515 	/*spin_lock_irqsave(&s_irq_lock, flags);*/
516 	if (s_irq_util.irq_info[id] == irq_info) {
517 		s_irq_util.irq_info[id] = NULL;
518 		s_irq_util.num--;
519 		if ((s_irq_util.num == 0)
520 			&& (s_irq_util.irq_en != 0)) {
521 			disp_sys_disable_irq(s_irq_util.irq_no);
522 			disp_sys_unregister_irq(s_irq_util.irq_no,
523 				disp_irq_handler, NULL);
524 			s_irq_util.irq_en = 0;
525 		}
526 	} else {
527 		__wrn("irq for %d already unregistered\n", id);
528 	}
529 	/*spin_unlock_irqrestore(&s_irq_lock, flags);*/
530 	return 0;
531 }
532 /* *********************** disp irq util end ********************** */
533