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 "assert_support.h"
18 #include "ia_css_debug.h"
19 #include "ia_css_sdis_types.h"
20 #include "sdis/common/ia_css_sdis_common.host.h"
21 #include "ia_css_sdis.host.h"
22 
23 const struct ia_css_dvs_coefficients default_sdis_config = {
24 	.grid = { 0, 0, 0, 0, 0, 0, 0, 0 },
25 	.hor_coefs = NULL,
26 	.ver_coefs = NULL
27 };
28 
29 static void
30 fill_row(short *private, const short *public, unsigned int width,
31 	 unsigned int padding)
32 {
33 	assert((int)width >= 0);
34 	assert((int)padding >= 0);
35 	memcpy(private, public, width * sizeof(short));
36 	memset(&private[width], 0, padding * sizeof(short));
37 }
38 
39 void ia_css_sdis_horicoef_vmem_encode(
40     struct sh_css_isp_sdis_hori_coef_tbl *to,
41     const struct ia_css_dvs_coefficients *from,
42     unsigned int size)
43 {
44 	unsigned int aligned_width = from->grid.aligned_width *
45 				     from->grid.bqs_per_grid_cell;
46 	unsigned int width         = from->grid.num_hor_coefs;
47 	int      padding       = aligned_width - width;
48 	unsigned int stride        = size / IA_CSS_DVS_NUM_COEF_TYPES / sizeof(short);
49 	unsigned int total_bytes   = aligned_width * IA_CSS_DVS_NUM_COEF_TYPES * sizeof(
50 					 short);
51 	short   *public        = from->hor_coefs;
52 	short   *private       = (short *)to;
53 	unsigned int type;
54 
55 	/* Copy the table, add padding */
56 	assert(padding >= 0);
57 	assert(total_bytes <= size);
58 	assert(size % (IA_CSS_DVS_NUM_COEF_TYPES * ISP_VEC_NELEMS * sizeof(
59 			   short)) == 0);
60 
61 	for (type = 0; type < IA_CSS_DVS_NUM_COEF_TYPES; type++) {
62 		fill_row(&private[type * stride], &public[type * width], width, padding);
63 	}
64 }
65 
66 void ia_css_sdis_vertcoef_vmem_encode(
67     struct sh_css_isp_sdis_vert_coef_tbl *to,
68     const struct ia_css_dvs_coefficients *from,
69     unsigned int size)
70 {
71 	unsigned int aligned_height = from->grid.aligned_height *
72 				      from->grid.bqs_per_grid_cell;
73 	unsigned int height         = from->grid.num_ver_coefs;
74 	int      padding        = aligned_height - height;
75 	unsigned int stride         = size / IA_CSS_DVS_NUM_COEF_TYPES / sizeof(short);
76 	unsigned int total_bytes    = aligned_height * IA_CSS_DVS_NUM_COEF_TYPES *
77 				      sizeof(short);
78 	short   *public         = from->ver_coefs;
79 	short   *private        = (short *)to;
80 	unsigned int type;
81 
82 	/* Copy the table, add padding */
83 	assert(padding >= 0);
84 	assert(total_bytes <= size);
85 	assert(size % (IA_CSS_DVS_NUM_COEF_TYPES * ISP_VEC_NELEMS * sizeof(
86 			   short)) == 0);
87 
88 	for (type = 0; type < IA_CSS_DVS_NUM_COEF_TYPES; type++) {
89 		fill_row(&private[type * stride], &public[type * height], height, padding);
90 	}
91 }
92 
93 void ia_css_sdis_horiproj_encode(
94     struct sh_css_isp_sdis_hori_proj_tbl *to,
95     const struct ia_css_dvs_coefficients *from,
96     unsigned int size)
97 {
98 	(void)to;
99 	(void)from;
100 	(void)size;
101 }
102 
103 void ia_css_sdis_vertproj_encode(
104     struct sh_css_isp_sdis_vert_proj_tbl *to,
105     const struct ia_css_dvs_coefficients *from,
106     unsigned int size)
107 {
108 	(void)to;
109 	(void)from;
110 	(void)size;
111 }
112 
113 void ia_css_get_isp_dis_coefficients(
114     struct ia_css_stream *stream,
115     short *horizontal_coefficients,
116     short *vertical_coefficients)
117 {
118 	struct ia_css_isp_parameters *params;
119 	unsigned int hor_num_isp, ver_num_isp;
120 	unsigned int hor_num_3a,  ver_num_3a;
121 	int i;
122 	struct ia_css_binary *dvs_binary;
123 
124 	IA_CSS_ENTER("void");
125 
126 	assert(horizontal_coefficients);
127 	assert(vertical_coefficients);
128 
129 	params = stream->isp_params_configs;
130 
131 	/* Only video pipe supports DVS */
132 	dvs_binary = ia_css_stream_get_dvs_binary(stream);
133 	if (!dvs_binary)
134 		return;
135 
136 	hor_num_isp = dvs_binary->dis.coef.pad.width;
137 	ver_num_isp = dvs_binary->dis.coef.pad.height;
138 	hor_num_3a  = dvs_binary->dis.coef.dim.width;
139 	ver_num_3a  = dvs_binary->dis.coef.dim.height;
140 
141 	for (i = 0; i < IA_CSS_DVS_NUM_COEF_TYPES; i++) {
142 		fill_row(&horizontal_coefficients[i * hor_num_isp],
143 			 &params->dvs_coefs.hor_coefs[i * hor_num_3a], hor_num_3a,
144 			 hor_num_isp - hor_num_3a);
145 	}
146 	for (i = 0; i < SH_CSS_DIS_VER_NUM_COEF_TYPES(dvs_binary); i++) {
147 		fill_row(&vertical_coefficients[i * ver_num_isp],
148 			 &params->dvs_coefs.ver_coefs[i * ver_num_3a], ver_num_3a,
149 			 ver_num_isp - ver_num_3a);
150 	}
151 
152 	IA_CSS_LEAVE("void");
153 }
154 
155 size_t
156 ia_css_sdis_hor_coef_tbl_bytes(
157     const struct ia_css_binary *binary)
158 {
159 	if (binary->info->sp.pipeline.isp_pipe_version == 1)
160 		return sizeof(short) * IA_CSS_DVS_NUM_COEF_TYPES  * binary->dis.coef.pad.width;
161 	else
162 		return sizeof(short) * IA_CSS_DVS2_NUM_COEF_TYPES * binary->dis.coef.pad.width;
163 }
164 
165 size_t
166 ia_css_sdis_ver_coef_tbl_bytes(
167     const struct ia_css_binary *binary)
168 {
169 	return sizeof(short) * SH_CSS_DIS_VER_NUM_COEF_TYPES(binary) *
170 	       binary->dis.coef.pad.height;
171 }
172 
173 void
174 ia_css_sdis_init_info(
175     struct ia_css_sdis_info *dis,
176     unsigned int sc_3a_dis_width,
177     unsigned int sc_3a_dis_padded_width,
178     unsigned int sc_3a_dis_height,
179     unsigned int isp_pipe_version,
180     unsigned int enabled)
181 {
182 	if (!enabled) {
183 		*dis = (struct ia_css_sdis_info) { };
184 		return;
185 	}
186 
187 	dis->deci_factor_log2 = SH_CSS_DIS_DECI_FACTOR_LOG2;
188 
189 	dis->grid.dim.width  =
190 	    _ISP_BQS(sc_3a_dis_width) >> SH_CSS_DIS_DECI_FACTOR_LOG2;
191 	dis->grid.dim.height =
192 	    _ISP_BQS(sc_3a_dis_height) >> SH_CSS_DIS_DECI_FACTOR_LOG2;
193 	dis->grid.pad.width  =
194 	    CEIL_SHIFT(_ISP_BQS(sc_3a_dis_padded_width), SH_CSS_DIS_DECI_FACTOR_LOG2);
195 	dis->grid.pad.height =
196 	    CEIL_SHIFT(_ISP_BQS(sc_3a_dis_height), SH_CSS_DIS_DECI_FACTOR_LOG2);
197 
198 	dis->coef.dim.width  =
199 	    (_ISP_BQS(sc_3a_dis_width)  >> SH_CSS_DIS_DECI_FACTOR_LOG2) <<
200 	    SH_CSS_DIS_DECI_FACTOR_LOG2;
201 	dis->coef.dim.height =
202 	    (_ISP_BQS(sc_3a_dis_height) >> SH_CSS_DIS_DECI_FACTOR_LOG2) <<
203 	    SH_CSS_DIS_DECI_FACTOR_LOG2;
204 	dis->coef.pad.width  =
205 	    __ISP_SDIS_HOR_COEF_NUM_VECS(sc_3a_dis_padded_width) * ISP_VEC_NELEMS;
206 	dis->coef.pad.height =
207 	    __ISP_SDIS_VER_COEF_NUM_VECS(sc_3a_dis_height) * ISP_VEC_NELEMS;
208 	if (isp_pipe_version == 1) {
209 		dis->proj.dim.width  =
210 		    _ISP_BQS(sc_3a_dis_height) >> SH_CSS_DIS_DECI_FACTOR_LOG2;
211 		dis->proj.dim.height =
212 		    _ISP_BQS(sc_3a_dis_width)  >> SH_CSS_DIS_DECI_FACTOR_LOG2;
213 	} else {
214 		dis->proj.dim.width  =
215 		    (_ISP_BQS(sc_3a_dis_width)  >> SH_CSS_DIS_DECI_FACTOR_LOG2) *
216 		    (_ISP_BQS(sc_3a_dis_height) >> SH_CSS_DIS_DECI_FACTOR_LOG2);
217 		dis->proj.dim.height =
218 		    (_ISP_BQS(sc_3a_dis_width)  >> SH_CSS_DIS_DECI_FACTOR_LOG2) *
219 		    (_ISP_BQS(sc_3a_dis_height) >> SH_CSS_DIS_DECI_FACTOR_LOG2);
220 	}
221 	dis->proj.pad.width  =
222 	    __ISP_SDIS_HOR_PROJ_NUM_ISP(sc_3a_dis_padded_width,
223 					sc_3a_dis_height,
224 					SH_CSS_DIS_DECI_FACTOR_LOG2,
225 					isp_pipe_version);
226 	dis->proj.pad.height =
227 	    __ISP_SDIS_VER_PROJ_NUM_ISP(sc_3a_dis_padded_width,
228 					SH_CSS_DIS_DECI_FACTOR_LOG2);
229 }
230 
231 void ia_css_sdis_clear_coefficients(
232     struct ia_css_dvs_coefficients *dvs_coefs)
233 {
234 	dvs_coefs->hor_coefs = NULL;
235 	dvs_coefs->ver_coefs = NULL;
236 }
237 
238 int
239 ia_css_get_dvs_statistics(
240     struct ia_css_dvs_statistics	       *host_stats,
241     const struct ia_css_isp_dvs_statistics *isp_stats) {
242 	struct ia_css_isp_dvs_statistics_map *map;
243 	int ret = 0;
244 
245 	IA_CSS_ENTER("host_stats=%p, isp_stats=%p", host_stats, isp_stats);
246 
247 	assert(host_stats);
248 	assert(isp_stats);
249 
250 	map = ia_css_isp_dvs_statistics_map_allocate(isp_stats, NULL);
251 	if (map)
252 	{
253 		hmm_load(isp_stats->data_ptr, map->data_ptr, isp_stats->size);
254 		ia_css_translate_dvs_statistics(host_stats, map);
255 		ia_css_isp_dvs_statistics_map_free(map);
256 	} else
257 	{
258 		IA_CSS_ERROR("out of memory");
259 		ret = -ENOMEM;
260 	}
261 
262 	IA_CSS_LEAVE_ERR(ret);
263 	return ret;
264 }
265 
266 void
267 ia_css_translate_dvs_statistics(
268     struct ia_css_dvs_statistics               *host_stats,
269     const struct ia_css_isp_dvs_statistics_map *isp_stats)
270 {
271 	unsigned int hor_num_isp, ver_num_isp, hor_num_dvs, ver_num_dvs, i;
272 	s32 *hor_ptr_dvs, *ver_ptr_dvs, *hor_ptr_isp, *ver_ptr_isp;
273 
274 	assert(host_stats);
275 	assert(host_stats->hor_proj);
276 	assert(host_stats->ver_proj);
277 	assert(isp_stats);
278 	assert(isp_stats->hor_proj);
279 	assert(isp_stats->ver_proj);
280 
281 	IA_CSS_ENTER("hproj=%p, vproj=%p, haddr=%p, vaddr=%p",
282 		     host_stats->hor_proj, host_stats->ver_proj,
283 		     isp_stats->hor_proj, isp_stats->ver_proj);
284 
285 	hor_num_isp = host_stats->grid.aligned_height;
286 	ver_num_isp = host_stats->grid.aligned_width;
287 	hor_ptr_isp = isp_stats->hor_proj;
288 	ver_ptr_isp = isp_stats->ver_proj;
289 	hor_num_dvs = host_stats->grid.height;
290 	ver_num_dvs = host_stats->grid.width;
291 	hor_ptr_dvs = host_stats->hor_proj;
292 	ver_ptr_dvs = host_stats->ver_proj;
293 
294 	for (i = 0; i < IA_CSS_DVS_NUM_COEF_TYPES; i++) {
295 		memcpy(hor_ptr_dvs, hor_ptr_isp, hor_num_dvs * sizeof(int32_t));
296 		hor_ptr_isp += hor_num_isp;
297 		hor_ptr_dvs += hor_num_dvs;
298 
299 		memcpy(ver_ptr_dvs, ver_ptr_isp, ver_num_dvs * sizeof(int32_t));
300 		ver_ptr_isp += ver_num_isp;
301 		ver_ptr_dvs += ver_num_dvs;
302 	}
303 
304 	IA_CSS_LEAVE("void");
305 }
306 
307 struct ia_css_isp_dvs_statistics *
308 ia_css_isp_dvs_statistics_allocate(
309     const struct ia_css_dvs_grid_info *grid)
310 {
311 	struct ia_css_isp_dvs_statistics *me;
312 	int hor_size, ver_size;
313 
314 	assert(grid);
315 
316 	IA_CSS_ENTER("grid=%p", grid);
317 
318 	if (!grid->enable)
319 		return NULL;
320 
321 	me = kvcalloc(1, sizeof(*me), GFP_KERNEL);
322 	if (!me)
323 		goto err;
324 
325 	hor_size = CEIL_MUL(sizeof(int) * IA_CSS_DVS_NUM_COEF_TYPES *
326 			    grid->aligned_height,
327 			    HIVE_ISP_DDR_WORD_BYTES);
328 	ver_size = CEIL_MUL(sizeof(int) * IA_CSS_DVS_NUM_COEF_TYPES *
329 			    grid->aligned_width,
330 			    HIVE_ISP_DDR_WORD_BYTES);
331 
332 	me->size = hor_size + ver_size;
333 	me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0);
334 	if (me->data_ptr == mmgr_NULL)
335 		goto err;
336 	me->hor_size = hor_size;
337 	me->hor_proj = me->data_ptr;
338 	me->ver_size = ver_size;
339 	me->ver_proj = me->data_ptr + hor_size;
340 
341 	IA_CSS_LEAVE("return=%p", me);
342 
343 	return me;
344 err:
345 	ia_css_isp_dvs_statistics_free(me);
346 
347 	IA_CSS_LEAVE("return=%p", NULL);
348 
349 	return NULL;
350 }
351 
352 struct ia_css_isp_dvs_statistics_map *
353 ia_css_isp_dvs_statistics_map_allocate(
354     const struct ia_css_isp_dvs_statistics *isp_stats,
355     void *data_ptr)
356 {
357 	struct ia_css_isp_dvs_statistics_map *me;
358 	/* Windows compiler does not like adding sizes to a void *
359 	 * so we use a local char * instead. */
360 	char *base_ptr;
361 
362 	me = kvmalloc(sizeof(*me), GFP_KERNEL);
363 	if (!me) {
364 		IA_CSS_LOG("cannot allocate memory");
365 		goto err;
366 	}
367 
368 	me->data_ptr = data_ptr;
369 	me->data_allocated = !data_ptr;
370 
371 	if (!me->data_ptr) {
372 		me->data_ptr = kvmalloc(isp_stats->size, GFP_KERNEL);
373 		if (!me->data_ptr) {
374 			IA_CSS_LOG("cannot allocate memory");
375 			goto err;
376 		}
377 	}
378 	base_ptr = me->data_ptr;
379 
380 	me->size = isp_stats->size;
381 	/* GCC complains when we assign a char * to a void *, so these
382 	 * casts are necessary unfortunately. */
383 	me->hor_proj = (void *)base_ptr;
384 	me->ver_proj = (void *)(base_ptr + isp_stats->hor_size);
385 
386 	return me;
387 err:
388 	if (me)
389 		kvfree(me);
390 	return NULL;
391 }
392 
393 void
394 ia_css_isp_dvs_statistics_map_free(struct ia_css_isp_dvs_statistics_map *me)
395 {
396 	if (me) {
397 		if (me->data_allocated)
398 			kvfree(me->data_ptr);
399 		kvfree(me);
400 	}
401 }
402 
403 void
404 ia_css_isp_dvs_statistics_free(struct ia_css_isp_dvs_statistics *me)
405 {
406 	if (me) {
407 		hmm_free(me->data_ptr);
408 		kvfree(me);
409 	}
410 }
411 
412 void ia_css_sdis_horicoef_debug_dtrace(
413     const struct ia_css_dvs_coefficients *config, unsigned int level)
414 {
415 	(void)config;
416 	(void)level;
417 }
418 
419 void ia_css_sdis_vertcoef_debug_dtrace(
420     const struct ia_css_dvs_coefficients *config, unsigned int level)
421 {
422 	(void)config;
423 	(void)level;
424 }
425 
426 void ia_css_sdis_horiproj_debug_dtrace(
427     const struct ia_css_dvs_coefficients *config, unsigned int level)
428 {
429 	(void)config;
430 	(void)level;
431 }
432 
433 void ia_css_sdis_vertproj_debug_dtrace(
434     const struct ia_css_dvs_coefficients *config, unsigned int level)
435 {
436 	(void)config;
437 	(void)level;
438 }
439