1 /*
2  * g2d_ovl_v.c
3  *
4  * Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
5  * Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17 #include <stdlib.h>
18 #include "g2d_ovl_v.h"
19 
g2d_ovl_v_calc_coarse(struct ovl_v_submodule * p_ovl_v,__u32 format,__u32 inw,__u32 inh,__u32 outw,__u32 outh,__u32 * midw,__u32 * midh)20 __s32 g2d_ovl_v_calc_coarse(struct ovl_v_submodule *p_ovl_v, __u32 format, __u32 inw,
21 		      __u32 inh, __u32 outw, __u32 outh, __u32 *midw,
22 		      __u32 *midh)
23 {
24 	__u32 tmp;
25 	__s32 ret = -1;
26 	struct g2d_mixer_ovl_v_reg *p_reg = p_ovl_v->get_reg(p_ovl_v);
27 
28 	if (!p_reg)
29 		goto OUT;
30 
31 	switch (format) {
32 	case G2D_FORMAT_IYUV422_V0Y1U0Y0:
33 	case G2D_FORMAT_IYUV422_Y1V0Y0U0:
34 	case G2D_FORMAT_IYUV422_U0Y1V0Y0:
35 	case G2D_FORMAT_IYUV422_Y1U0Y0V0: {
36 		/* interleaved YUV422 format */
37 		*midw = inw;
38 		*midh = inh;
39 		break;
40 	}
41 	case G2D_FORMAT_YUV422UVC_V1U1V0U0:
42 	case G2D_FORMAT_YUV422UVC_U1V1U0V0:
43 	case G2D_FORMAT_YUV422_PLANAR: {
44 		if (inw >= (outw << 3)) {
45 			*midw = outw << 3;
46 			tmp = (*midw << 16) | inw;
47 			p_reg->hor_down_sample0.dwval = tmp;
48 			tmp = (*midw << 15) | ((inw + 1) >> 1);
49 			p_reg->hor_down_sample1.dwval = tmp;
50 		} else
51 			*midw = inw;
52 		if (inh >= (outh << 2)) {
53 			*midh = (outh << 2);
54 			tmp = (*midh << 16) | inh;
55 			p_reg->ver_down_sample0.dwval = tmp;
56 			p_reg->ver_down_sample1.dwval = tmp;
57 		} else
58 			*midh = inh;
59 		break;
60 	}
61 	case G2D_FORMAT_Y8:
62 	case G2D_FORMAT_YUV420_PLANAR:
63 	case G2D_FORMAT_YUV420UVC_V1U1V0U0:
64 	case G2D_FORMAT_YUV420UVC_U1V1U0V0: {
65 		if (inw >= (outw << 3)) {
66 			*midw = outw << 3;
67 			tmp = (*midw << 16) | inw;
68 			p_reg->hor_down_sample0.dwval = tmp;
69 			tmp = (*midw << 15) | ((inw + 1) >> 1);
70 			p_reg->hor_down_sample1.dwval = tmp;
71 		} else
72 			*midw = inw;
73 		if (inh >= (outh << 2)) {
74 			*midh = (outh << 2);
75 			tmp = (*midh << 16) | inh;
76 			p_reg->ver_down_sample0.dwval = tmp;
77 			tmp = (*midh << 15) | ((inh + 1) >> 1);
78 			p_reg->ver_down_sample1.dwval = tmp;
79 		} else
80 			*midh = inh;
81 		break;
82 	}
83 	case G2D_FORMAT_YUV411_PLANAR:
84 	case G2D_FORMAT_YUV411UVC_V1U1V0U0:
85 	case G2D_FORMAT_YUV411UVC_U1V1U0V0: {
86 		if (inw >= (outw << 3)) {
87 			*midw = outw << 3;
88 			tmp = ((*midw) << 16) | inw;
89 			p_reg->hor_down_sample0.dwval = tmp;
90 			tmp = ((*midw) << 14) | ((inw + 3) >> 2);
91 			p_reg->hor_down_sample1.dwval = tmp;
92 		} else
93 			*midw = inw;
94 		if (inh >= (outh << 2)) {
95 			*midh = (outh << 2);
96 			tmp = ((*midh) << 16) | inh;
97 			p_reg->ver_down_sample0.dwval = tmp;
98 			p_reg->ver_down_sample1.dwval = tmp;
99 		} else
100 			*midh = inh;
101 		break;
102 	}
103 	default:
104 		if (inw >= (outw << 3)) {
105 			*midw = outw << 3;
106 			tmp = ((*midw) << 16) | inw;
107 			p_reg->hor_down_sample0.dwval = tmp;
108 			p_reg->hor_down_sample1.dwval = tmp;
109 		} else
110 			*midw = inw;
111 		if (inh >= (outh << 2)) {
112 			*midh = (outh << 2);
113 			tmp = ((*midh) << 16) | inh;
114 			p_reg->ver_down_sample0.dwval = tmp;
115 			p_reg->ver_down_sample1.dwval = tmp;
116 		} else
117 			*midh = inh;
118 		break;
119 	}
120 	p_ovl_v->set_block_dirty(p_ovl_v, 0, 1);
121 	ret = 0;
122 OUT:
123 	return ret;
124 }
125 
126 /**
127  * fillcolor set
128  * @color_value:fill color value
129  */
g2d_ovl_v_fc_set(struct ovl_v_submodule * p_ovl_v,__u32 color_value)130 __s32 g2d_ovl_v_fc_set(struct ovl_v_submodule *p_ovl_v, __u32 color_value)
131 {
132 	__s32 ret = -1;
133 	struct g2d_mixer_ovl_v_reg *p_reg = p_ovl_v->get_reg(p_ovl_v);
134 	if (!p_reg)
135 		goto OUT;
136 
137 	p_reg->ovl_attr.bits.lay_fillcolor_en = 1;
138 	p_reg->ovl_fill_color = color_value;
139 	p_ovl_v->set_block_dirty(p_ovl_v, 0, 1);
140 	ret = 0;
141 
142 OUT:
143 	return ret;
144 }
145 
146 /**
147  * @sel:layer no.
148  * @para avoid_flag is a sign of whether or not to avoid the black point bug cause by g2d
149  */
g2d_vlayer_set(struct ovl_v_submodule * p_ovl_v,__u32 sel,g2d_image_enh * p_image,u8 avoid_flag)150 __s32 g2d_vlayer_set(struct ovl_v_submodule *p_ovl_v, __u32 sel, g2d_image_enh *p_image, u8 avoid_flag)
151 {
152 	unsigned long long addr0, addr1, addr2;
153 	__u32 tmp;
154 	__u32 ycnt, ucnt, vcnt;
155 	__u32 pitch0, pitch1, pitch2;
156 	__u32 ch, cw, cy, cx;
157 	__s32 ret = -1;
158 	struct g2d_mixer_ovl_v_reg *p_reg = p_ovl_v->get_reg(p_ovl_v);
159 
160 	if (!p_reg)
161 		goto OUT;
162 
163 	p_reg->ovl_attr.bits.lay_fbfmt = p_image->format;
164 	p_reg->ovl_attr.bits.alpha_mode = p_image->mode;
165 
166 	/**
167 	 * except for the scaler function, bpremul is equal to 0,
168 	 * the code under if is only used by the scaler function
169 	 */
170 	if (p_image->bpremul)
171 		p_reg->ovl_attr.bits.lay_premul_ctl = 1;
172 	if (avoid_flag)
173 		p_reg->ovl_attr.bits.lay_premul_ctl = 0;
174 	p_reg->ovl_attr.bits.lay_glbalpha = p_image->alpha & 0xff;
175 	p_reg->ovl_attr.bits.lay_en = 1;
176 
177 	p_reg->ovl_mem.bits.lay_width =
178 	    (p_image->clip_rect.w == 0 ? 0 : p_image->clip_rect.w - 1) & 0x1fff;
179 	p_reg->ovl_mem.bits.lay_height =
180 	    (p_image->clip_rect.h == 0 ? 0 : p_image->clip_rect.h - 1) & 0x1fff;
181 
182 	p_reg->ovl_winsize.bits.width =
183 	    (p_image->clip_rect.w == 0 ? 0 : p_image->clip_rect.w - 1) & 0x1fff;
184 	p_reg->ovl_winsize.bits.height =
185 	    (p_image->clip_rect.h == 0 ? 0 : p_image->clip_rect.h - 1) & 0x1fff;
186 
187 	/* offset is set to 0, ovl size is set to layer size */
188 	p_reg->ovl_mem_coor.dwval = 0;
189 	if ((p_image->format >= G2D_FORMAT_YUV422UVC_V1U1V0U0)
190 	      && (p_image->format <= G2D_FORMAT_YUV422_PLANAR)) {
191 		cw = p_image->width >> 1;
192 		ch = p_image->height;
193 		cx = p_image->clip_rect.x >> 1;
194 		cy = p_image->clip_rect.y;
195 	}
196 
197 	else if ((p_image->format >= G2D_FORMAT_YUV420UVC_V1U1V0U0)
198 		 && (p_image->format <= G2D_FORMAT_YUV420_PLANAR)) {
199 		cw = p_image->width >> 1;
200 		ch = p_image->height >> 1;
201 		cx = p_image->clip_rect.x >> 1;
202 		cy = p_image->clip_rect.y >> 1;
203 	}
204 
205 	else if ((p_image->format >= G2D_FORMAT_YUV411UVC_V1U1V0U0)
206 		 && (p_image->format <= G2D_FORMAT_YUV411_PLANAR)) {
207 		cw = p_image->width >> 2;
208 		ch = p_image->height;
209 		cx = p_image->clip_rect.x >> 2;
210 		cy = p_image->clip_rect.y;
211 	}
212 
213 	else {
214 		cw = 0;
215 		ch = 0;
216 		cx = 0;
217 		cy = 0;
218 	}
219 	g2d_byte_cal(p_image->format, &ycnt, &ucnt, &vcnt);
220 	pitch0 = cal_align(ycnt * p_image->width, p_image->align[0]);
221 	p_reg->ovl_mem_pitch0 = pitch0;
222 	pitch1 = cal_align(ucnt * cw, p_image->align[1]);
223 	p_reg->ovl_mem_pitch1 = pitch1;
224 	pitch2 = cal_align(vcnt * cw, p_image->align[2]);
225 	p_reg->ovl_mem_pitch2 = pitch2;
226 	addr0 =
227 	    p_image->laddr[0] + ((__u64) p_image->haddr[0] << 32) +
228 	    pitch0 * p_image->clip_rect.y + ycnt * p_image->clip_rect.x;
229 	p_reg->ovl_mem_low_addr0 = addr0 & 0xffffffff;
230 	addr1 =
231 	    p_image->laddr[1] + ((__u64) p_image->haddr[1] << 32) + pitch1 * cy +
232 	    ucnt * cx;
233 	p_reg->ovl_mem_low_addr1 = addr1 & 0xffffffff;
234 	addr2 =
235 	    p_image->laddr[2] + ((__u64) p_image->haddr[2] << 32) + pitch2 * cy +
236 	    vcnt * cx;
237 	p_reg->ovl_mem_low_addr2 = addr2 & 0xffffffff;
238 	tmp = ((addr0 >> 32) & 0xff) | ((addr1 >> 32) & 0xff) << 8 |
239 	    ((addr2 >> 32) & 0xff) << 16;
240 	p_reg->ovl_mem_high_addr.dwval = tmp;
241 	if (p_image->bbuff == 0)
242 		g2d_ovl_v_fc_set(p_ovl_v, p_image->color);
243 	p_ovl_v->set_block_dirty(p_ovl_v, 0, 1);
244 	ret = 0;
245 OUT:
246 	return ret;
247 }
248 
g2d_vlayer_overlay_set(struct ovl_v_submodule * p_ovl_v,__u32 sel,g2d_coor * coor,__u32 w,__u32 h)249 __s32 g2d_vlayer_overlay_set(struct ovl_v_submodule *p_ovl_v, __u32 sel,
250 					g2d_coor *coor,  __u32 w, __u32 h)
251 {
252 	__s32 ret = -1;
253 	struct g2d_mixer_ovl_v_reg *p_reg = p_ovl_v->get_reg(p_ovl_v);
254 
255 	if (!p_reg)
256 		goto OUT;
257 
258 	p_reg->ovl_winsize.bits.width = (w - 1) & 0x1fff;
259 	p_reg->ovl_winsize.bits.height = (h - 1) & 0x1fff;
260 
261 	p_reg->ovl_mem_coor.bits.lay_xcoor = coor->x;
262 	p_reg->ovl_mem_coor.bits.lay_ycoor = coor->y;
263 	ret = 0;
264 OUT:
265 	return ret;
266 }
267 
ovl_v_rcq_setup(struct ovl_v_submodule * p_ovl_v,u8 * base,struct g2d_rcq_mem_info * p_rcq_info)268 static int ovl_v_rcq_setup(struct ovl_v_submodule *p_ovl_v, u8 *base,
269 			   struct g2d_rcq_mem_info *p_rcq_info)
270 {
271 	u8 *reg_base = base + G2D_V0;
272 	int ret = -1;
273 
274 	if (!p_ovl_v) {
275 		G2D_ERR_MSG("Null pointer!\n");
276 		goto OUT;
277 	}
278 
279 	p_ovl_v->reg_info->size = sizeof(struct g2d_mixer_ovl_v_reg);
280 	p_ovl_v->reg_info->vir_addr = (u8 *)g2d_top_reg_memory_alloc(
281 	    p_ovl_v->reg_info->size, (void *)&(p_ovl_v->reg_info->phy_addr),
282 	    p_rcq_info);
283 
284 	if (!p_ovl_v->reg_info->vir_addr) {
285 		G2D_ERR_MSG("Malloc writeback reg rcq memory fail!\n");
286 		goto OUT;
287 	}
288 
289 	p_ovl_v->reg_blks->vir_addr = p_ovl_v->reg_info->vir_addr;
290 	p_ovl_v->reg_blks->phy_addr = p_ovl_v->reg_info->phy_addr;
291 	p_ovl_v->reg_blks->size = p_ovl_v->reg_info->size;
292 	p_ovl_v->reg_blks->reg_addr = reg_base;
293 	ret = 0;
294 
295 OUT:
296 	return ret;
297 }
298 
ovl_v_get_reg_block_num(struct ovl_v_submodule * p_ovl_v)299 static __u32 ovl_v_get_reg_block_num(struct ovl_v_submodule *p_ovl_v)
300 {
301 	if (p_ovl_v)
302 		return p_ovl_v->reg_blk_num;
303 	return 0;
304 }
305 
ovl_v_get_reg_block(struct ovl_v_submodule * p_ovl_v,struct g2d_reg_block ** blks)306 static __s32 ovl_v_get_reg_block(struct ovl_v_submodule *p_ovl_v,
307 			    struct g2d_reg_block **blks)
308 {
309 	int i = 0;
310 	if (p_ovl_v) {
311 		for (i = 0; i < p_ovl_v->reg_blk_num; ++i)
312 			blks[i] = p_ovl_v->reg_blks + i;
313 	}
314 	return 0;
315 }
316 
ovl_v_get_reg(struct ovl_v_submodule * p_ovl_v)317 static struct g2d_mixer_ovl_v_reg *ovl_v_get_reg(struct ovl_v_submodule *p_ovl_v)
318 {
319 #if G2D_MIXER_RCQ_USED == 1
320 	return (struct g2d_mixer_ovl_v_reg *)(p_ovl_v->reg_blks
321 						   ->vir_addr);
322 #else
323 	return (struct g2d_mixer_ovl_v_reg *)(p_ovl_v->reg_blks
324 						   ->reg_addr);
325 #endif
326 	return NULL;
327 }
328 
ovl_v_set_block_dirty(struct ovl_v_submodule * p_ovl_v,__u32 blk_id,__u32 dirty)329 static void ovl_v_set_block_dirty(struct ovl_v_submodule *p_ovl_v, __u32 blk_id, __u32 dirty)
330 {
331 #if G2D_MIXER_RCQ_USED == 1
332 	if (p_ovl_v && p_ovl_v->reg_blks->rcq_hd)
333 		p_ovl_v->reg_blks->rcq_hd->dirty.bits.dirty = dirty;
334 	else
335 		G2D_ERR_MSG("Null pointer!\n");
336 #else
337 
338 	if (p_ovl_v)
339 		p_ovl_v->reg_blks->dirty = dirty;
340 	else
341 		G2D_ERR_MSG("Null pointer!\n");
342 #endif
343 }
344 
345 
ovl_v_get_rcq_mem_size(struct ovl_v_submodule * p_ovl_v)346 static __u32 ovl_v_get_rcq_mem_size(struct ovl_v_submodule *p_ovl_v)
347 {
348 	return G2D_RCQ_BYTE_ALIGN(sizeof(struct g2d_mixer_ovl_v_reg));
349 }
350 
ovl_v_destory(struct ovl_v_submodule * p_ovl_v)351 static __s32 ovl_v_destory(struct ovl_v_submodule *p_ovl_v)
352 {
353 	if (p_ovl_v) {
354 		free(p_ovl_v->reg_blks);
355 		p_ovl_v->reg_blks = NULL;
356 
357 		free(p_ovl_v->reg_info);
358 		p_ovl_v->reg_info = NULL;
359 		free(p_ovl_v);
360 	}
361 
362 	return 0;
363 }
364 
365 struct ovl_v_submodule *
g2d_ovl_v_submodule_setup(struct g2d_mixer_frame * p_frame)366 g2d_ovl_v_submodule_setup(struct g2d_mixer_frame *p_frame)
367 {
368 	struct ovl_v_submodule *p_ovl_v = NULL;
369 
370 	p_ovl_v = hal_malloc(sizeof(struct ovl_v_submodule));
371 
372 	if (!p_ovl_v) {
373 		G2D_ERR_MSG("malloc wb submodule fail!\n");
374 		return NULL;
375 	}
376 	memset(p_ovl_v, 0, sizeof(struct ovl_v_submodule));
377 	p_ovl_v->rcq_setup = ovl_v_rcq_setup;
378 	p_ovl_v->reg_blk_num = VI_LAYER_NUMBER;
379 	p_ovl_v->get_reg_block_num = ovl_v_get_reg_block_num;
380 	p_ovl_v->get_reg_block = ovl_v_get_reg_block;
381 	p_ovl_v->get_reg = ovl_v_get_reg;
382 	p_ovl_v->set_block_dirty = ovl_v_set_block_dirty;
383 	p_ovl_v->get_rcq_mem_size = ovl_v_get_rcq_mem_size;
384 	p_ovl_v->destory = ovl_v_destory;
385 
386 	p_ovl_v->reg_blks =
387 	    hal_malloc(sizeof(struct g2d_reg_block) * p_ovl_v->reg_blk_num);
388 	p_ovl_v->reg_info =
389 	    hal_malloc(sizeof(struct g2d_reg_mem_info));
390 
391 	if (!p_ovl_v->reg_blks || !p_ovl_v->reg_info) {
392 		G2D_ERR_MSG("malloc wb reg info fail!\n");
393 		goto FREE_WB;
394 	}
395 	memset(p_ovl_v->reg_blks, 0, sizeof(struct g2d_reg_block) * p_ovl_v->reg_blk_num);
396 	memset(p_ovl_v->reg_info, 0, sizeof(struct g2d_reg_mem_info));
397 
398 	return p_ovl_v;
399 FREE_WB:
400 	free(p_ovl_v->reg_blks);
401 	free(p_ovl_v->reg_info);
402 	free(p_ovl_v);
403 
404 	return NULL;
405 }
406