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
36 static 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
41 static 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
46 static 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
51 static 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
56 static const s16 tcinv_x[NUMBER_OF_TCINV_POINTS] = {
57 0, 4, 11, 23, 42, 68, 102, 148, 205
58 };
59
60 static const s16 tcinv_a[NUMBER_OF_TCINV_POINTS] = {
61 -6364, -631, -126, -34, -13, -6, -4452, -2156, 0
62 };
63
64 static const s16 tcinv_b[NUMBER_OF_TCINV_POINTS] = {
65 8191, 1828, 726, 352, 197, 121, 80, 55, 40
66 };
67
68 static const s16 tcinv_c[NUMBER_OF_TCINV_POINTS] = {
69 1, 1, 1, 1, 1, 1, 0, 0, 0
70 };
71
72 static const s16 fcinv_x[NUMBER_OF_FCINV_POINTS] = {
73 0, 80, 216, 456, 824, 1344, 2040, 2952, 4096
74 };
75
76 static const s16 fcinv_a[NUMBER_OF_FCINV_POINTS] = {
77 -5244, -486, -86, -2849, -961, -400, -180, -86, 0
78 };
79
80 static const s16 fcinv_b[NUMBER_OF_FCINV_POINTS] = {
81 8191, 1637, 607, 287, 159, 98, 64, 44, 32
82 };
83
84 static const s16 fcinv_c[NUMBER_OF_FCINV_POINTS] = {
85 1, 1, 1, 0, 0, 0, 0, 0, 0
86 };
87
88 void
ia_css_eed1_8_vmem_encode(struct eed1_8_vmem_params * to,const struct ia_css_eed1_8_config * from,size_t size)89 ia_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 calculating 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] = clamp(from->dew_enhance_seg_x[j],
176 0, 8191);
177 to->e_dew_enh_y[0][base + j] = clamp(from->dew_enhance_seg_y[j],
178 -8192, 8191);
179 }
180
181 for (j = 0; j < (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1); j++) {
182 to->e_dew_enh_a[0][base + j] = clamp(from->dew_enhance_seg_slope[j],
183 -8192, 8191);
184 /* Convert dew_enhance_seg_exp to flag:
185 * 0 -> 0
186 * 1...13 -> 1
187 */
188 to->e_dew_enh_f[0][base + j] = clamp(from->dew_enhance_seg_exp[j],
189 0, 13) > 0;
190 }
191
192 /* Hard-coded to 0, in order to be able to handle out of
193 * range input in the same way as the other segments.
194 * See KFS for more details.
195 */
196 to->e_dew_enh_a[0][base + (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1)] = 0;
197 to->e_dew_enh_f[0][base + (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1)] = 0;
198
199 for (j = 0; j < NUMBER_OF_CHGRINV_POINTS; j++) {
200 to->chgrinv_x[0][base + j] = chgrinv_x[j];
201 to->chgrinv_a[0][base + j] = chgrinv_a[j];
202 to->chgrinv_b[0][base + j] = chgrinv_b[j];
203 to->chgrinv_c[0][base + j] = chgrinv_c[j];
204 }
205
206 for (j = 0; j < NUMBER_OF_TCINV_POINTS; j++) {
207 to->tcinv_x[0][base + j] = tcinv_x[j];
208 to->tcinv_a[0][base + j] = tcinv_a[j];
209 to->tcinv_b[0][base + j] = tcinv_b[j];
210 to->tcinv_c[0][base + j] = tcinv_c[j];
211 }
212
213 for (j = 0; j < NUMBER_OF_FCINV_POINTS; j++) {
214 to->fcinv_x[0][base + j] = fcinv_x[j];
215 to->fcinv_a[0][base + j] = fcinv_a[j];
216 to->fcinv_b[0][base + j] = fcinv_b[j];
217 to->fcinv_c[0][base + j] = fcinv_c[j];
218 }
219 }
220 }
221
222 void
ia_css_eed1_8_encode(struct eed1_8_dmem_params * to,const struct ia_css_eed1_8_config * from,size_t size)223 ia_css_eed1_8_encode(
224 struct eed1_8_dmem_params *to,
225 const struct ia_css_eed1_8_config *from,
226 size_t size)
227 {
228 int i;
229 int min_exp = 0;
230
231 (void)size;
232
233 to->rbzp_strength = from->rbzp_strength;
234
235 to->fcstrength = from->fcstrength;
236 to->fcthres_0 = from->fcthres_0;
237 to->fc_sat_coef = from->fc_sat_coef;
238 to->fc_coring_prm = from->fc_coring_prm;
239 to->fc_slope = from->fcthres_1 - from->fcthres_0;
240
241 to->aerel_thres0 = from->aerel_thres0;
242 to->aerel_gain0 = from->aerel_gain0;
243 to->aerel_thres_diff = from->aerel_thres1 - from->aerel_thres0;
244 to->aerel_gain_diff = from->aerel_gain1 - from->aerel_gain0;
245
246 to->derel_thres0 = from->derel_thres0;
247 to->derel_gain0 = from->derel_gain0;
248 to->derel_thres_diff = (from->derel_thres1 - from->derel_thres0);
249 to->derel_gain_diff = (from->derel_gain1 - from->derel_gain0);
250
251 to->coring_pos0 = from->coring_pos0;
252 to->coring_pos_diff = (from->coring_pos1 - from->coring_pos0);
253 to->coring_neg0 = from->coring_neg0;
254 to->coring_neg_diff = (from->coring_neg1 - from->coring_neg0);
255
256 /* Note: (ISP_VEC_ELEMBITS -1)
257 * TODO: currently the testbench does not support to use
258 * ISP_VEC_ELEMBITS. Investigate how to fix this
259 */
260 to->gain_exp = (13 - from->gain_exp);
261 to->gain_pos0 = from->gain_pos0;
262 to->gain_pos_diff = (from->gain_pos1 - from->gain_pos0);
263 to->gain_neg0 = from->gain_neg0;
264 to->gain_neg_diff = (from->gain_neg1 - from->gain_neg0);
265
266 to->margin_pos0 = from->pos_margin0;
267 to->margin_pos_diff = (from->pos_margin1 - from->pos_margin0);
268 to->margin_neg0 = from->neg_margin0;
269 to->margin_neg_diff = (from->neg_margin1 - from->neg_margin0);
270
271 /* Encode DEWEnhance exp (e_dew_enh_asr) */
272 for (i = 0; i < (IA_CSS_NUMBER_OF_DEW_ENHANCE_SEGMENTS - 1); i++) {
273 min_exp = max(min_exp, from->dew_enhance_seg_exp[i]);
274 }
275 to->e_dew_enh_asr = 13 - clamp(min_exp, 0, 13);
276
277 to->dedgew_max = from->dedgew_max;
278 }
279
280 void
ia_css_init_eed1_8_state(void * state,size_t size)281 ia_css_init_eed1_8_state(
282 void *state,
283 size_t size)
284 {
285 memset(state, 0, size);
286 }
287
288 #ifndef IA_CSS_NO_DEBUG
289 void
ia_css_eed1_8_debug_dtrace(const struct ia_css_eed1_8_config * eed,unsigned int level)290 ia_css_eed1_8_debug_dtrace(
291 const struct ia_css_eed1_8_config *eed,
292 unsigned int level)
293 {
294 if (!eed)
295 return;
296
297 ia_css_debug_dtrace(level, "Edge Enhancing Demosaic 1.8:\n");
298 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "rbzp_strength",
299 eed->rbzp_strength);
300 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcstrength", eed->fcstrength);
301 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcthres_0", eed->fcthres_0);
302 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fcthres_1", eed->fcthres_1);
303 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fc_sat_coef", eed->fc_sat_coef);
304 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "fc_coring_prm",
305 eed->fc_coring_prm);
306
307 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_thres0", eed->aerel_thres0);
308 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_gain0", eed->aerel_gain0);
309 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_thres1", eed->aerel_thres1);
310 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "aerel_gain1", eed->aerel_gain1);
311
312 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_thres0", eed->derel_thres0);
313 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_gain0", eed->derel_gain0);
314 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_thres1", eed->derel_thres1);
315 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "derel_gain1", eed->derel_gain1);
316
317 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_pos0", eed->coring_pos0);
318 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_pos1", eed->coring_pos1);
319 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_neg0", eed->coring_neg0);
320 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "coring_neg1", eed->coring_neg1);
321
322 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_exp", eed->gain_exp);
323 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_pos0", eed->gain_pos0);
324 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_pos1", eed->gain_pos1);
325 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_neg0", eed->gain_neg0);
326 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "gain_neg1", eed->gain_neg1);
327
328 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "pos_margin0", eed->pos_margin0);
329 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "pos_margin1", eed->pos_margin1);
330 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "neg_margin0", eed->neg_margin0);
331 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "neg_margin1", eed->neg_margin1);
332
333 ia_css_debug_dtrace(level, "\t%-32s = %d\n", "dedgew_max", eed->dedgew_max);
334 }
335 #endif
336