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#ifndef IA_CSS_NO_DEBUG
17#include "ia_css_debug.h"
18#endif
19
20#include "type_support.h"
21#include "assert_support.h"
22#include "math_support.h" /* for min and max */
23
24#include "ia_css_eed1_8.host.h"
25
26/* WARNING1: Number of inv points should be less or equal to 16,
27 * due to implementation limitation. See kernel design document
28 * for more details.
29 * WARNING2: Do not modify the number of inv points without correcting
30 * the EED1_8 kernel implementation assumptions.
31 */
32#define NUMBER_OF_CHGRINV_POINTS 15
33#define NUMBER_OF_TCINV_POINTS 9
34#define NUMBER_OF_FCINV_POINTS 9
35
36static const s16 chgrinv_x[NUMBER_OF_CHGRINV_POINTS] = {
37	0, 16, 64, 144, 272, 448, 672, 976,
38	1376, 1888, 2528, 3312, 4256, 5376, 6688
39};
40
41static const s16 chgrinv_a[NUMBER_OF_CHGRINV_POINTS] = {
42	-7171, -256, -29, -3456, -1071, -475, -189, -102,
43	    -48, -38, -10, -9, -7, -6, 0
44    };
45
46static const s16 chgrinv_b[NUMBER_OF_CHGRINV_POINTS] = {
47	8191, 1021, 256, 114, 60, 37, 24, 17,
48	12, 9, 6, 5, 4, 3, 2
49};
50
51static const s16 chgrinv_c[NUMBER_OF_CHGRINV_POINTS] = {
52	1, 1, 1, 0, 0, 0, 0, 0,
53	0, 0, 0, 0, 0, 0, 0
54};
55
56static const s16 tcinv_x[NUMBER_OF_TCINV_POINTS] = {
57	0, 4, 11, 23, 42, 68, 102, 148, 205
58};
59
60static const s16 tcinv_a[NUMBER_OF_TCINV_POINTS] = {
61	-6364, -631, -126, -34, -13, -6, -4452, -2156, 0
62    };
63
64static const s16 tcinv_b[NUMBER_OF_TCINV_POINTS] = {
65	8191, 1828, 726, 352, 197, 121, 80, 55, 40
66};
67
68static const s16 tcinv_c[NUMBER_OF_TCINV_POINTS] = {
69	1, 1, 1, 1, 1, 1, 0, 0, 0
70};
71
72static const s16 fcinv_x[NUMBER_OF_FCINV_POINTS] = {
73	0, 80, 216, 456, 824, 1344, 2040, 2952, 4096
74};
75
76static const s16 fcinv_a[NUMBER_OF_FCINV_POINTS] = {
77	-5244, -486, -86, -2849, -961, -400, -180, -86, 0
78    };
79
80static const s16 fcinv_b[NUMBER_OF_FCINV_POINTS] = {
81	8191, 1637, 607, 287, 159, 98, 64, 44, 32
82};
83
84static const s16 fcinv_c[NUMBER_OF_FCINV_POINTS] = {
85	1, 1, 1, 0, 0, 0, 0, 0, 0
86};
87
88void
89ia_css_eed1_8_vmem_encode(
90    struct eed1_8_vmem_params *to,
91    const struct ia_css_eed1_8_config *from,
92    size_t size)
93{
94	unsigned int i, j, base;
95	const unsigned int total_blocks = 4;
96	const unsigned int shuffle_block = 16;
97
98	(void)size;
99
100	/* Init */
101	for (i = 0; i < ISP_VEC_NELEMS; i++) {
102		to->e_dew_enh_x[0][i] = 0;
103		to->e_dew_enh_y[0][i] = 0;
104		to->e_dew_enh_a[0][i] = 0;
105		to->e_dew_enh_f[0][i] = 0;
106		to->chgrinv_x[0][i] = 0;
107		to->chgrinv_a[0][i] = 0;
108		to->chgrinv_b[0][i] = 0;
109		to->chgrinv_c[0][i] = 0;
110		to->tcinv_x[0][i] = 0;
111		to->tcinv_a[0][i] = 0;
112		to->tcinv_b[0][i] = 0;
113		to->tcinv_c[0][i] = 0;
114		to->fcinv_x[0][i] = 0;
115		to->fcinv_a[0][i] = 0;
116		to->fcinv_b[0][i] = 0;
117		to->fcinv_c[0][i] = 0;
118	}
119
120	/* Constraints on dew_enhance_seg_x and dew_enhance_seg_y:
121	 * - values should be greater or equal to 0.
122	 * - values should be ascending.
123	 * - value of index zero is equal to 0.
124	 */
125
126	/* Checking constraints: */
127	/* TODO: investigate if an assert is the right way to report that
128	 * the constraints are violated.
129	 */
130	for (j = 0; j < IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS; j++) {
131		assert(from->dew_enhance_seg_x[j] > -1);
132		assert(from->dew_enhance_seg_y[j] > -1);
133	}
134
135	for (j = 1; j < IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS; j++) {
136		assert(from->dew_enhance_seg_x[j] > from->dew_enhance_seg_x[j - 1]);
137		assert(from->dew_enhance_seg_y[j] > from->dew_enhance_seg_y[j - 1]);
138	}
139
140	assert(from->dew_enhance_seg_x[0] == 0);
141	assert(from->dew_enhance_seg_y[0] == 0);
142
143	/* Constraints on chgrinv_x, tcinv_x and fcinv_x:
144	 * - values should be greater or equal to 0.
145	 * - values should be ascending.
146	 * - value of index zero is equal to 0.
147	 */
148	assert(chgrinv_x[0] == 0);
149	assert(tcinv_x[0] == 0);
150	assert(fcinv_x[0] == 0);
151
152	for (j = 1; j < NUMBER_OF_CHGRINV_POINTS; j++) {
153		assert(chgrinv_x[j] > chgrinv_x[j - 1]);
154	}
155
156	for (j = 1; j < NUMBER_OF_TCINV_POINTS; j++) {
157		assert(tcinv_x[j] > tcinv_x[j - 1]);
158	}
159
160	for (j = 1; j < NUMBER_OF_FCINV_POINTS; j++) {
161		assert(fcinv_x[j] > fcinv_x[j - 1]);
162	}
163
164	/* The implementation of the calulating 1/x is based on the availability
165	 * of the OP_vec_shuffle16 operation.
166	 * A 64 element vector is split up in 4 blocks of 16 element. Each array is copied to
167	 * a vector 4 times, (starting at 0, 16, 32 and 48). All array elements are copied or
168	 * initialised as described in the KFS. The remaining elements of a vector are set to 0.
169	 */
170	/* TODO: guard this code with above assumptions */
171	for (i = 0; i < total_blocks; i++) {
172		base = shuffle_block * i;
173
174		for (j = 0; j < IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS; j++) {
175			to->e_dew_enh_x[0][base + j] = min_t(int, max_t(int,
176							     from->dew_enhance_seg_x[j], 0),
177							     8191);
178			to->e_dew_enh_y[0][base + j] = min_t(int, max_t(int,
179							     from->dew_enhance_seg_y[j], -8192),
180							     8191);
181		}
182
183		for (j = 0; j < (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1); j++) {
184			to->e_dew_enh_a[0][base + j] = min_t(int, max_t(int,
185							     from->dew_enhance_seg_slope[j],
186							     -8192), 8191);
187			/* Convert dew_enhance_seg_exp to flag:
188			 * 0 -> 0
189			 * 1...13 -> 1
190			 */
191			to->e_dew_enh_f[0][base + j] = (min_t(int, max_t(int,
192							      from->dew_enhance_seg_exp[j],
193							      0), 13) > 0);
194		}
195
196		/* Hard-coded to 0, in order to be able to handle out of
197		 * range input in the same way as the other segments.
198		 * See KFS for more details.
199		 */
200		to->e_dew_enh_a[0][base + (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1)] = 0;
201		to->e_dew_enh_f[0][base + (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1)] = 0;
202
203		for (j = 0; j < NUMBER_OF_CHGRINV_POINTS; j++) {
204			to->chgrinv_x[0][base + j] = chgrinv_x[j];
205			to->chgrinv_a[0][base + j] = chgrinv_a[j];
206			to->chgrinv_b[0][base + j] = chgrinv_b[j];
207			to->chgrinv_c[0][base + j] = chgrinv_c[j];
208		}
209
210		for (j = 0; j < NUMBER_OF_TCINV_POINTS; j++) {
211			to->tcinv_x[0][base + j] = tcinv_x[j];
212			to->tcinv_a[0][base + j] = tcinv_a[j];
213			to->tcinv_b[0][base + j] = tcinv_b[j];
214			to->tcinv_c[0][base + j] = tcinv_c[j];
215		}
216
217		for (j = 0; j < NUMBER_OF_FCINV_POINTS; j++) {
218			to->fcinv_x[0][base + j] = fcinv_x[j];
219			to->fcinv_a[0][base + j] = fcinv_a[j];
220			to->fcinv_b[0][base + j] = fcinv_b[j];
221			to->fcinv_c[0][base + j] = fcinv_c[j];
222		}
223	}
224}
225
226void
227ia_css_eed1_8_encode(
228    struct eed1_8_dmem_params *to,
229    const struct ia_css_eed1_8_config *from,
230    size_t size)
231{
232	int i;
233	int min_exp = 0;
234
235	(void)size;
236
237	to->rbzp_strength = from->rbzp_strength;
238
239	to->fcstrength = from->fcstrength;
240	to->fcthres_0 = from->fcthres_0;
241	to->fc_sat_coef = from->fc_sat_coef;
242	to->fc_coring_prm = from->fc_coring_prm;
243	to->fc_slope = from->fcthres_1 - from->fcthres_0;
244
245	to->aerel_thres0 = from->aerel_thres0;
246	to->aerel_gain0 = from->aerel_gain0;
247	to->aerel_thres_diff = from->aerel_thres1 - from->aerel_thres0;
248	to->aerel_gain_diff = from->aerel_gain1 - from->aerel_gain0;
249
250	to->derel_thres0 = from->derel_thres0;
251	to->derel_gain0 = from->derel_gain0;
252	to->derel_thres_diff = (from->derel_thres1 - from->derel_thres0);
253	to->derel_gain_diff = (from->derel_gain1 - from->derel_gain0);
254
255	to->coring_pos0 = from->coring_pos0;
256	to->coring_pos_diff = (from->coring_pos1 - from->coring_pos0);
257	to->coring_neg0 = from->coring_neg0;
258	to->coring_neg_diff = (from->coring_neg1 - from->coring_neg0);
259
260	/* Note: (ISP_VEC_ELEMBITS -1)
261	 * TODO: currently the testbench does not support to use
262	 * ISP_VEC_ELEMBITS. Investigate how to fix this
263	 */
264	to->gain_exp = (13 - from->gain_exp);
265	to->gain_pos0 = from->gain_pos0;
266	to->gain_pos_diff = (from->gain_pos1 - from->gain_pos0);
267	to->gain_neg0 = from->gain_neg0;
268	to->gain_neg_diff = (from->gain_neg1 - from->gain_neg0);
269
270	to->margin_pos0 = from->pos_margin0;
271	to->margin_pos_diff = (from->pos_margin1 - from->pos_margin0);
272	to->margin_neg0 = from->neg_margin0;
273	to->margin_neg_diff = (from->neg_margin1 - from->neg_margin0);
274
275	/* Encode DEWEnhance exp (e_dew_enh_asr) */
276	for (i = 0; i < (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1); i++) {
277		min_exp = max(min_exp, from->dew_enhance_seg_exp[i]);
278	}
279	to->e_dew_enh_asr = 13 - min(max(min_exp, 0), 13);
280
281	to->dedgew_max = from->dedgew_max;
282}
283
284void
285ia_css_init_eed1_8_state(
286    void *state,
287    size_t size)
288{
289	memset(state, 0, size);
290}
291
292#ifndef IA_CSS_NO_DEBUG
293void
294ia_css_eed1_8_debug_dtrace(
295    const struct ia_css_eed1_8_config *eed,
296    unsigned int level)
297{
298	if (!eed)
299		return;
300
301	ia_css_debug_dtrace(level, "Edge Enhancing Demosaic 1.8:\n");
302	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "rbzp_strength",
303			    eed->rbzp_strength);
304	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcstrength", eed->fcstrength);
305	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcthres_0", eed->fcthres_0);
306	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcthres_1", eed->fcthres_1);
307	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fc_sat_coef", eed->fc_sat_coef);
308	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fc_coring_prm",
309			    eed->fc_coring_prm);
310
311	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_thres0", eed->aerel_thres0);
312	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_gain0", eed->aerel_gain0);
313	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_thres1", eed->aerel_thres1);
314	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_gain1", eed->aerel_gain1);
315
316	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_thres0", eed->derel_thres0);
317	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_gain0", eed->derel_gain0);
318	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_thres1", eed->derel_thres1);
319	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_gain1", eed->derel_gain1);
320
321	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_pos0", eed->coring_pos0);
322	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_pos1", eed->coring_pos1);
323	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_neg0", eed->coring_neg0);
324	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_neg1", eed->coring_neg1);
325
326	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_exp", eed->gain_exp);
327	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_pos0", eed->gain_pos0);
328	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_pos1", eed->gain_pos1);
329	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_neg0", eed->gain_neg0);
330	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_neg1", eed->gain_neg1);
331
332	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "pos_margin0", eed->pos_margin0);
333	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "pos_margin1", eed->pos_margin1);
334	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "neg_margin0", eed->neg_margin0);
335	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "neg_margin1", eed->neg_margin1);
336
337	ia_css_debug_dtrace(level, "\t%-32s = %d\n", "dedgew_max", eed->dedgew_max);
338}
339#endif
340