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