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_sdis2.host.h"
21
22const struct ia_css_dvs2_coefficients default_sdis2_config = {
23	.grid = { 0, 0, 0, 0, 0, 0, 0, 0 },
24	.hor_coefs = { NULL, NULL, NULL, NULL },
25	.ver_coefs = { NULL, NULL, NULL, NULL },
26};
27
28static void
29fill_row(short *private, const short *public, unsigned int width,
30	 unsigned int padding)
31{
32	memcpy(private, public, width * sizeof(short));
33	memset(&private[width], 0, padding * sizeof(short));
34}
35
36void ia_css_sdis2_horicoef_vmem_encode(
37    struct sh_css_isp_sdis_hori_coef_tbl *to,
38    const struct ia_css_dvs2_coefficients *from,
39    unsigned int size)
40{
41	unsigned int aligned_width = from->grid.aligned_width *
42				     from->grid.bqs_per_grid_cell;
43	unsigned int width         = from->grid.num_hor_coefs;
44	int      padding       = aligned_width - width;
45	unsigned int stride        = size / IA_CSS_DVS2_NUM_COEF_TYPES / sizeof(short);
46	unsigned int total_bytes   = aligned_width * IA_CSS_DVS2_NUM_COEF_TYPES *
47				     sizeof(short);
48	short   *private       = (short *)to;
49
50	/* Copy the table, add padding */
51	assert(padding >= 0);
52	assert(total_bytes <= size);
53	assert(size % (IA_CSS_DVS2_NUM_COEF_TYPES * ISP_VEC_NELEMS * sizeof(
54			   short)) == 0);
55	fill_row(&private[0 * stride], from->hor_coefs.odd_real,  width, padding);
56	fill_row(&private[1 * stride], from->hor_coefs.odd_imag,  width, padding);
57	fill_row(&private[2 * stride], from->hor_coefs.even_real, width, padding);
58	fill_row(&private[3 * stride], from->hor_coefs.even_imag, width, padding);
59}
60
61void ia_css_sdis2_vertcoef_vmem_encode(
62    struct sh_css_isp_sdis_vert_coef_tbl *to,
63    const struct ia_css_dvs2_coefficients *from,
64    unsigned int size)
65{
66	unsigned int aligned_height = from->grid.aligned_height *
67				      from->grid.bqs_per_grid_cell;
68	unsigned int height         = from->grid.num_ver_coefs;
69	int      padding        = aligned_height - height;
70	unsigned int stride         = size / IA_CSS_DVS2_NUM_COEF_TYPES / sizeof(short);
71	unsigned int total_bytes    = aligned_height * IA_CSS_DVS2_NUM_COEF_TYPES *
72				      sizeof(short);
73	short   *private        = (short *)to;
74
75	/* Copy the table, add padding */
76	assert(padding >= 0);
77	assert(total_bytes <= size);
78	assert(size % (IA_CSS_DVS2_NUM_COEF_TYPES * ISP_VEC_NELEMS * sizeof(
79			   short)) == 0);
80	fill_row(&private[0 * stride], from->ver_coefs.odd_real,  height, padding);
81	fill_row(&private[1 * stride], from->ver_coefs.odd_imag,  height, padding);
82	fill_row(&private[2 * stride], from->ver_coefs.even_real, height, padding);
83	fill_row(&private[3 * stride], from->ver_coefs.even_imag, height, padding);
84}
85
86void ia_css_sdis2_horiproj_encode(
87    struct sh_css_isp_sdis_hori_proj_tbl *to,
88    const struct ia_css_dvs2_coefficients *from,
89    unsigned int size)
90{
91	(void)to;
92	(void)from;
93	(void)size;
94}
95
96void ia_css_sdis2_vertproj_encode(
97    struct sh_css_isp_sdis_vert_proj_tbl *to,
98    const struct ia_css_dvs2_coefficients *from,
99    unsigned int size)
100{
101	(void)to;
102	(void)from;
103	(void)size;
104}
105
106void ia_css_get_isp_dvs2_coefficients(
107    struct ia_css_stream *stream,
108    short *hor_coefs_odd_real,
109    short *hor_coefs_odd_imag,
110    short *hor_coefs_even_real,
111    short *hor_coefs_even_imag,
112    short *ver_coefs_odd_real,
113    short *ver_coefs_odd_imag,
114    short *ver_coefs_even_real,
115    short *ver_coefs_even_imag)
116{
117	struct ia_css_isp_parameters *params;
118	unsigned int hor_num_3a, ver_num_3a;
119	struct ia_css_binary *dvs_binary;
120
121	IA_CSS_ENTER("void");
122
123	assert(stream);
124	assert(hor_coefs_odd_real);
125	assert(hor_coefs_odd_imag);
126	assert(hor_coefs_even_real);
127	assert(hor_coefs_even_imag);
128	assert(ver_coefs_odd_real);
129	assert(ver_coefs_odd_imag);
130	assert(ver_coefs_even_real);
131	assert(ver_coefs_even_imag);
132
133	params = stream->isp_params_configs;
134
135	/* Only video pipe supports DVS */
136	dvs_binary = ia_css_stream_get_dvs_binary(stream);
137	if (!dvs_binary)
138		return;
139
140	hor_num_3a  = dvs_binary->dis.coef.dim.width;
141	ver_num_3a  = dvs_binary->dis.coef.dim.height;
142
143	memcpy(hor_coefs_odd_real,  params->dvs2_coefs.hor_coefs.odd_real,
144	       hor_num_3a * sizeof(short));
145	memcpy(hor_coefs_odd_imag,  params->dvs2_coefs.hor_coefs.odd_imag,
146	       hor_num_3a * sizeof(short));
147	memcpy(hor_coefs_even_real, params->dvs2_coefs.hor_coefs.even_real,
148	       hor_num_3a * sizeof(short));
149	memcpy(hor_coefs_even_imag, params->dvs2_coefs.hor_coefs.even_imag,
150	       hor_num_3a * sizeof(short));
151	memcpy(ver_coefs_odd_real,  params->dvs2_coefs.ver_coefs.odd_real,
152	       ver_num_3a * sizeof(short));
153	memcpy(ver_coefs_odd_imag,  params->dvs2_coefs.ver_coefs.odd_imag,
154	       ver_num_3a * sizeof(short));
155	memcpy(ver_coefs_even_real, params->dvs2_coefs.ver_coefs.even_real,
156	       ver_num_3a * sizeof(short));
157	memcpy(ver_coefs_even_imag, params->dvs2_coefs.ver_coefs.even_imag,
158	       ver_num_3a * sizeof(short));
159
160	IA_CSS_LEAVE("void");
161}
162
163void ia_css_sdis2_clear_coefficients(
164    struct ia_css_dvs2_coefficients *dvs2_coefs)
165{
166	dvs2_coefs->hor_coefs.odd_real  = NULL;
167	dvs2_coefs->hor_coefs.odd_imag  = NULL;
168	dvs2_coefs->hor_coefs.even_real = NULL;
169	dvs2_coefs->hor_coefs.even_imag = NULL;
170	dvs2_coefs->ver_coefs.odd_real  = NULL;
171	dvs2_coefs->ver_coefs.odd_imag  = NULL;
172	dvs2_coefs->ver_coefs.even_real = NULL;
173	dvs2_coefs->ver_coefs.even_imag = NULL;
174}
175
176int
177ia_css_get_dvs2_statistics(
178    struct ia_css_dvs2_statistics          *host_stats,
179    const struct ia_css_isp_dvs_statistics *isp_stats) {
180	struct ia_css_isp_dvs_statistics_map *map;
181	int ret = 0;
182
183	IA_CSS_ENTER("host_stats=%p, isp_stats=%p", host_stats, isp_stats);
184
185	assert(host_stats);
186	assert(isp_stats);
187
188	map = ia_css_isp_dvs_statistics_map_allocate(isp_stats, NULL);
189	if (map)
190	{
191		hmm_load(isp_stats->data_ptr, map->data_ptr, isp_stats->size);
192		ia_css_translate_dvs2_statistics(host_stats, map);
193		ia_css_isp_dvs_statistics_map_free(map);
194	} else
195	{
196		IA_CSS_ERROR("out of memory");
197		ret = -ENOMEM;
198	}
199
200	IA_CSS_LEAVE_ERR(ret);
201	return ret;
202}
203
204void
205ia_css_translate_dvs2_statistics(
206    struct ia_css_dvs2_statistics		   *host_stats,
207    const struct ia_css_isp_dvs_statistics_map *isp_stats)
208{
209	unsigned int size_bytes, table_width, table_size, height;
210	unsigned int src_offset = 0, dst_offset = 0;
211	s32 *htemp_ptr, *vtemp_ptr;
212
213	assert(host_stats);
214	assert(host_stats->hor_prod.odd_real);
215	assert(host_stats->hor_prod.odd_imag);
216	assert(host_stats->hor_prod.even_real);
217	assert(host_stats->hor_prod.even_imag);
218	assert(host_stats->ver_prod.odd_real);
219	assert(host_stats->ver_prod.odd_imag);
220	assert(host_stats->ver_prod.even_real);
221	assert(host_stats->ver_prod.even_imag);
222	assert(isp_stats);
223	assert(isp_stats->hor_proj);
224	assert(isp_stats->ver_proj);
225
226	IA_CSS_ENTER("hor_coefs.odd_real=%p, hor_coefs.odd_imag=%p, hor_coefs.even_real=%p, hor_coefs.even_imag=%p, ver_coefs.odd_real=%p, ver_coefs.odd_imag=%p, ver_coefs.even_real=%p, ver_coefs.even_imag=%p, haddr=%p, vaddr=%p",
227		     host_stats->hor_prod.odd_real, host_stats->hor_prod.odd_imag,
228		     host_stats->hor_prod.even_real, host_stats->hor_prod.even_imag,
229		     host_stats->ver_prod.odd_real, host_stats->ver_prod.odd_imag,
230		     host_stats->ver_prod.even_real, host_stats->ver_prod.even_imag,
231		     isp_stats->hor_proj, isp_stats->ver_proj);
232
233	/* Host side: reflecting the true width in bytes */
234	size_bytes = host_stats->grid.aligned_width * sizeof(*htemp_ptr);
235
236	/* DDR side: need to be aligned to the system bus width */
237	/* statistics table width in terms of 32-bit words*/
238	table_width = CEIL_MUL(size_bytes,
239			       HIVE_ISP_DDR_WORD_BYTES) / sizeof(*htemp_ptr);
240	table_size = table_width * host_stats->grid.aligned_height;
241
242	htemp_ptr = isp_stats->hor_proj; /* horizontal stats */
243	vtemp_ptr = isp_stats->ver_proj; /* vertical stats */
244	for (height = 0; height < host_stats->grid.aligned_height; height++) {
245		/* hor stats */
246		memcpy(host_stats->hor_prod.odd_real + dst_offset,
247		       &htemp_ptr[0 * table_size + src_offset], size_bytes);
248		memcpy(host_stats->hor_prod.odd_imag + dst_offset,
249		       &htemp_ptr[1 * table_size + src_offset], size_bytes);
250		memcpy(host_stats->hor_prod.even_real + dst_offset,
251		       &htemp_ptr[2 * table_size + src_offset], size_bytes);
252		memcpy(host_stats->hor_prod.even_imag + dst_offset,
253		       &htemp_ptr[3 * table_size + src_offset], size_bytes);
254
255		/* ver stats */
256		memcpy(host_stats->ver_prod.odd_real + dst_offset,
257		       &vtemp_ptr[0 * table_size + src_offset], size_bytes);
258		memcpy(host_stats->ver_prod.odd_imag + dst_offset,
259		       &vtemp_ptr[1 * table_size + src_offset], size_bytes);
260		memcpy(host_stats->ver_prod.even_real + dst_offset,
261		       &vtemp_ptr[2 * table_size + src_offset], size_bytes);
262		memcpy(host_stats->ver_prod.even_imag + dst_offset,
263		       &vtemp_ptr[3 * table_size + src_offset], size_bytes);
264
265		src_offset += table_width; /* aligned table width */
266		dst_offset += host_stats->grid.aligned_width;
267	}
268
269	IA_CSS_LEAVE("void");
270}
271
272struct ia_css_isp_dvs_statistics *
273ia_css_isp_dvs2_statistics_allocate(
274    const struct ia_css_dvs_grid_info *grid)
275{
276	struct ia_css_isp_dvs_statistics *me;
277	int size;
278
279	assert(grid);
280
281	IA_CSS_ENTER("grid=%p", grid);
282
283	if (!grid->enable)
284		return NULL;
285
286	me = kvcalloc(1, sizeof(*me), GFP_KERNEL);
287	if (!me)
288		goto err;
289
290	/* on ISP 2 SDIS DMA model, every row of projection table width must be
291	   aligned to HIVE_ISP_DDR_WORD_BYTES
292	*/
293	size = CEIL_MUL(sizeof(int) * grid->aligned_width, HIVE_ISP_DDR_WORD_BYTES)
294	       * grid->aligned_height * IA_CSS_DVS2_NUM_COEF_TYPES;
295
296	me->size = 2 * size;
297	me->data_ptr = hmm_alloc(me->size);
298	if (me->data_ptr == mmgr_NULL)
299		goto err;
300	me->hor_proj = me->data_ptr;
301	me->hor_size = size;
302	me->ver_proj = me->data_ptr + size;
303	me->ver_size = size;
304
305	IA_CSS_LEAVE("return=%p", me);
306	return me;
307err:
308	ia_css_isp_dvs2_statistics_free(me);
309	IA_CSS_LEAVE("return=%p", NULL);
310
311	return NULL;
312}
313
314void
315ia_css_isp_dvs2_statistics_free(struct ia_css_isp_dvs_statistics *me)
316{
317	if (me) {
318		hmm_free(me->data_ptr);
319		kvfree(me);
320	}
321}
322
323void ia_css_sdis2_horicoef_debug_dtrace(
324    const struct ia_css_dvs2_coefficients *config, unsigned int level)
325{
326	(void)config;
327	(void)level;
328}
329
330void ia_css_sdis2_vertcoef_debug_dtrace(
331    const struct ia_css_dvs2_coefficients *config, unsigned int level)
332{
333	(void)config;
334	(void)level;
335}
336
337void ia_css_sdis2_horiproj_debug_dtrace(
338    const struct ia_css_dvs2_coefficients *config, unsigned int level)
339{
340	(void)config;
341	(void)level;
342}
343
344void ia_css_sdis2_vertproj_debug_dtrace(
345    const struct ia_css_dvs2_coefficients *config, unsigned int level)
346{
347	(void)config;
348	(void)level;
349}
350