1 /*
2  * Support for Intel Camera Imaging ISP subsystem.
3  * Copyright (c) 2015, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  */
14 
15 #include "hmm.h"
16 
17 #include "ia_css_frame_public.h"
18 #define IA_CSS_INCLUDE_CONFIGURATIONS
19 #include "ia_css_isp_configs.h"
20 
21 #include "ia_css_types.h"
22 #include "ia_css_host_data.h"
23 #include "sh_css_param_dvs.h"
24 #include "sh_css_params.h"
25 #include "ia_css_binary.h"
26 #include "ia_css_debug.h"
27 #include "assert_support.h"
28 
29 #include "ia_css_dvs.host.h"
30 
31 static const struct ia_css_dvs_configuration default_config = {
32 	.info = (struct ia_css_frame_info *)NULL,
33 };
34 
35 void
36 ia_css_dvs_config(
37     struct sh_css_isp_dvs_isp_config *to,
38     const struct ia_css_dvs_configuration  *from,
39     unsigned int size)
40 {
41 	(void)size;
42 	to->num_horizontal_blocks =
43 	    DVS_NUM_BLOCKS_X(from->info->res.width);
44 	to->num_vertical_blocks =
45 	    DVS_NUM_BLOCKS_Y(from->info->res.height);
46 }
47 
48 void
49 ia_css_dvs_configure(
50     const struct ia_css_binary     *binary,
51     const struct ia_css_frame_info *info)
52 {
53 	struct ia_css_dvs_configuration config = default_config;
54 
55 	config.info = info;
56 
57 	ia_css_configure_dvs(binary, &config);
58 }
59 
60 static void
61 convert_coords_to_ispparams(
62     struct ia_css_host_data *gdc_warp_table,
63     const struct ia_css_dvs_6axis_config *config,
64     unsigned int i_stride,
65     unsigned int o_width,
66     unsigned int o_height,
67     unsigned int uv_flag)
68 {
69 	unsigned int i, j;
70 	gdc_warp_param_mem_t s = { 0 };
71 	unsigned int x00, x01, x10, x11,
72 		 y00, y01, y10, y11;
73 
74 	unsigned int xmin, ymin, xmax, ymax;
75 	unsigned int topleft_x, topleft_y, bottom_x, bottom_y,
76 		 topleft_x_frac, topleft_y_frac;
77 	unsigned int dvs_interp_envelope = (DVS_GDC_INTERP_METHOD == HRT_GDC_BLI_MODE ?
78 					    DVS_GDC_BLI_INTERP_ENVELOPE : DVS_GDC_BCI_INTERP_ENVELOPE);
79 
80 	/* number of blocks per height and width */
81 	unsigned int num_blocks_y =  (uv_flag ? DVS_NUM_BLOCKS_Y_CHROMA(
82 					  o_height) : DVS_NUM_BLOCKS_Y(o_height));
83 	unsigned int num_blocks_x =  (uv_flag ? DVS_NUM_BLOCKS_X_CHROMA(
84 					  o_width)  : DVS_NUM_BLOCKS_X(
85 					  o_width)); // round num_x up to blockdim_x, if it concerns the Y0Y1 block (uv_flag==0) round up to even
86 
87 	unsigned int in_stride = i_stride * DVS_INPUT_BYTES_PER_PIXEL;
88 	unsigned int width, height;
89 	unsigned int *xbuff = NULL;
90 	unsigned int *ybuff = NULL;
91 	struct gdc_warp_param_mem_s *ptr;
92 
93 	assert(config);
94 	assert(gdc_warp_table);
95 	assert(gdc_warp_table->address);
96 
97 	ptr = (struct gdc_warp_param_mem_s *)gdc_warp_table->address;
98 
99 	ptr += (2 * uv_flag); /* format is Y0 Y1 UV, so UV starts at 3rd position */
100 
101 	if (uv_flag == 0) {
102 		xbuff = config->xcoords_y;
103 		ybuff = config->ycoords_y;
104 		width = config->width_y;
105 		height = config->height_y;
106 	} else {
107 		xbuff = config->xcoords_uv;
108 		ybuff = config->ycoords_uv;
109 		width = config->width_uv;
110 		height = config->height_uv;
111 	}
112 
113 	IA_CSS_LOG("blockdim_x %d blockdim_y %d",
114 		   DVS_BLOCKDIM_X, DVS_BLOCKDIM_Y_LUMA >> uv_flag);
115 	IA_CSS_LOG("num_blocks_x %d num_blocks_y %d", num_blocks_x, num_blocks_y);
116 	IA_CSS_LOG("width %d height %d", width, height);
117 
118 	assert(width == num_blocks_x +
119 	       1); // the width and height of the provided morphing table should be 1 more than the number of blocks
120 	assert(height == num_blocks_y + 1);
121 
122 	for (j = 0; j < num_blocks_y; j++) {
123 		for (i = 0; i < num_blocks_x; i++) {
124 			x00 = xbuff[j * width + i];
125 			x01 = xbuff[j * width + (i + 1)];
126 			x10 = xbuff[(j + 1) * width + i];
127 			x11 = xbuff[(j + 1) * width + (i + 1)];
128 
129 			y00 = ybuff[j * width + i];
130 			y01 = ybuff[j * width + (i + 1)];
131 			y10 = ybuff[(j + 1) * width + i];
132 			y11 = ybuff[(j + 1) * width + (i + 1)];
133 
134 			xmin = min(x00, x10);
135 			xmax = max(x01, x11);
136 			ymin = min(y00, y01);
137 			ymax = max(y10, y11);
138 
139 			/* Assert that right column's X is greater */
140 			assert(x01 >= xmin);
141 			assert(x11 >= xmin);
142 			/* Assert that bottom row's Y is greater */
143 			assert(y10 >= ymin);
144 			assert(y11 >= ymin);
145 
146 			topleft_y = ymin >> DVS_COORD_FRAC_BITS;
147 			topleft_x = ((xmin >> DVS_COORD_FRAC_BITS)
148 				     >> XMEM_ALIGN_LOG2)
149 				    << (XMEM_ALIGN_LOG2);
150 			s.in_addr_offset = topleft_y * in_stride + topleft_x;
151 
152 			/* similar to topleft_y calculation, but round up if ymax
153 			 * has any fraction bits */
154 			bottom_y = CEIL_DIV(ymax, 1 << DVS_COORD_FRAC_BITS);
155 			s.in_block_height = bottom_y - topleft_y + dvs_interp_envelope;
156 
157 			bottom_x = CEIL_DIV(xmax, 1 << DVS_COORD_FRAC_BITS);
158 			s.in_block_width = bottom_x - topleft_x + dvs_interp_envelope;
159 
160 			topleft_x_frac = topleft_x << (DVS_COORD_FRAC_BITS);
161 			topleft_y_frac = topleft_y << (DVS_COORD_FRAC_BITS);
162 
163 			s.p0_x = x00 - topleft_x_frac;
164 			s.p1_x = x01 - topleft_x_frac;
165 			s.p2_x = x10 - topleft_x_frac;
166 			s.p3_x = x11 - topleft_x_frac;
167 
168 			s.p0_y = y00 - topleft_y_frac;
169 			s.p1_y = y01 - topleft_y_frac;
170 			s.p2_y = y10 - topleft_y_frac;
171 			s.p3_y = y11 - topleft_y_frac;
172 
173 			// block should fit within the boundingbox.
174 			assert(s.p0_x < (s.in_block_width << DVS_COORD_FRAC_BITS));
175 			assert(s.p1_x < (s.in_block_width << DVS_COORD_FRAC_BITS));
176 			assert(s.p2_x < (s.in_block_width << DVS_COORD_FRAC_BITS));
177 			assert(s.p3_x < (s.in_block_width << DVS_COORD_FRAC_BITS));
178 			assert(s.p0_y < (s.in_block_height << DVS_COORD_FRAC_BITS));
179 			assert(s.p1_y < (s.in_block_height << DVS_COORD_FRAC_BITS));
180 			assert(s.p2_y < (s.in_block_height << DVS_COORD_FRAC_BITS));
181 			assert(s.p3_y < (s.in_block_height << DVS_COORD_FRAC_BITS));
182 
183 			// block size should be greater than zero.
184 			assert(s.p0_x < s.p1_x);
185 			assert(s.p2_x < s.p3_x);
186 			assert(s.p0_y < s.p2_y);
187 			assert(s.p1_y < s.p3_y);
188 
189 #if 0
190 			printf("j: %d\ti:%d\n", j, i);
191 			printf("offset: %d\n", s.in_addr_offset);
192 			printf("p0_x: %d\n", s.p0_x);
193 			printf("p0_y: %d\n", s.p0_y);
194 			printf("p1_x: %d\n", s.p1_x);
195 			printf("p1_y: %d\n", s.p1_y);
196 			printf("p2_x: %d\n", s.p2_x);
197 			printf("p2_y: %d\n", s.p2_y);
198 			printf("p3_x: %d\n", s.p3_x);
199 			printf("p3_y: %d\n", s.p3_y);
200 
201 			printf("p0_x_nofrac[0]: %d\n", s.p0_x >> DVS_COORD_FRAC_BITS);
202 			printf("p0_y_nofrac[1]: %d\n", s.p0_y >> DVS_COORD_FRAC_BITS);
203 			printf("p1_x_nofrac[2]: %d\n", s.p1_x >> DVS_COORD_FRAC_BITS);
204 			printf("p1_y_nofrac[3]: %d\n", s.p1_y >> DVS_COORD_FRAC_BITS);
205 			printf("p2_x_nofrac[0]: %d\n", s.p2_x >> DVS_COORD_FRAC_BITS);
206 			printf("p2_y_nofrac[1]: %d\n", s.p2_y >> DVS_COORD_FRAC_BITS);
207 			printf("p3_x_nofrac[2]: %d\n", s.p3_x >> DVS_COORD_FRAC_BITS);
208 			printf("p3_y_nofrac[3]: %d\n", s.p3_y >> DVS_COORD_FRAC_BITS);
209 			printf("\n");
210 #endif
211 
212 			*ptr = s;
213 
214 			// storage format:
215 			// Y0 Y1 UV0 Y2 Y3 UV1
216 			/* if uv_flag equals true increment with 2 incase x is odd, this to
217 			skip the uv position. */
218 			if (uv_flag)
219 				ptr += 3;
220 			else
221 				ptr += (1 + (i & 1));
222 		}
223 	}
224 }
225 
226 struct ia_css_host_data *
227 convert_allocate_dvs_6axis_config(
228     const struct ia_css_dvs_6axis_config *dvs_6axis_config,
229     const struct ia_css_binary *binary,
230     const struct ia_css_frame_info *dvs_in_frame_info)
231 {
232 	unsigned int i_stride;
233 	unsigned int o_width;
234 	unsigned int o_height;
235 	struct ia_css_host_data *me;
236 	struct gdc_warp_param_mem_s *isp_data_ptr;
237 
238 	assert(binary);
239 	assert(dvs_6axis_config);
240 	assert(dvs_in_frame_info);
241 
242 	me = ia_css_host_data_allocate((size_t)((DVS_6AXIS_BYTES(binary) / 2) * 3));
243 
244 	if (!me)
245 		return NULL;
246 
247 	/*DVS only supports input frame of YUV420 or NV12. Fail for all other cases*/
248 	assert((dvs_in_frame_info->format == IA_CSS_FRAME_FORMAT_NV12)
249 	       || (dvs_in_frame_info->format == IA_CSS_FRAME_FORMAT_YUV420));
250 
251 	isp_data_ptr = (struct gdc_warp_param_mem_s *)me->address;
252 
253 	i_stride  = dvs_in_frame_info->padded_width;
254 
255 	o_width  = binary->out_frame_info[0].res.width;
256 	o_height = binary->out_frame_info[0].res.height;
257 
258 	/* Y plane */
259 	convert_coords_to_ispparams(me, dvs_6axis_config,
260 				    i_stride, o_width, o_height, 0);
261 
262 	if (dvs_in_frame_info->format == IA_CSS_FRAME_FORMAT_YUV420) {
263 		/*YUV420 has half the stride for U/V plane*/
264 		i_stride /= 2;
265 	}
266 
267 	/* UV plane (packed inside the y plane) */
268 	convert_coords_to_ispparams(me, dvs_6axis_config,
269 				    i_stride, o_width / 2, o_height / 2, 1);
270 
271 	return me;
272 }
273 
274 int
275 store_dvs_6axis_config(
276     const struct ia_css_dvs_6axis_config *dvs_6axis_config,
277     const struct ia_css_binary *binary,
278     const struct ia_css_frame_info *dvs_in_frame_info,
279     ia_css_ptr ddr_addr_y) {
280 	struct ia_css_host_data *me;
281 
282 	assert(dvs_6axis_config);
283 	assert(ddr_addr_y != mmgr_NULL);
284 	assert(dvs_in_frame_info);
285 
286 	me = convert_allocate_dvs_6axis_config(dvs_6axis_config,
287 					       binary,
288 					       dvs_in_frame_info);
289 
290 	if (!me)
291 	{
292 		IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM);
293 		return -ENOMEM;
294 	}
295 
296 	ia_css_params_store_ia_css_host_data(
297 	    ddr_addr_y,
298 	    me);
299 	ia_css_host_data_free(me);
300 
301 	return 0;
302 }
303