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
24const 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
30static void
31fill_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
40void 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
67void 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
94void 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
104void 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
114void 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
156size_t
157ia_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
166size_t
167ia_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
174void
175ia_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
232void 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
239int
240ia_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
267void
268ia_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
308struct ia_css_isp_dvs_statistics *
309ia_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;
345err:
346	ia_css_isp_dvs_statistics_free(me);
347
348	IA_CSS_LEAVE("return=%p", NULL);
349
350	return NULL;
351}
352
353struct ia_css_isp_dvs_statistics_map *
354ia_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;
388err:
389	kvfree(me);
390	return NULL;
391}
392
393void
394ia_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
403void
404ia_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
412void 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
419void 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
426void 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
433void 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