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