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 "type_support.h"
17 #include "math_support.h"
18 #include "sh_css_defs.h"
19 #include "ia_css_types.h"
20 #include "assert_support.h"
21 #include "ia_css_xnr3.host.h"
22 
23 /* Maximum value for alpha on ISP interface */
24 #define XNR_MAX_ALPHA  ((1 << (ISP_VEC_ELEMBITS - 1)) - 1)
25 
26 /* Minimum value for sigma on host interface. Lower values translate to
27  * max_alpha.
28  */
29 #define XNR_MIN_SIGMA  (IA_CSS_XNR3_SIGMA_SCALE / 100)
30 
31 /*
32  * division look-up table
33  * Refers to XNR3.0.5
34  */
35 #define XNR3_LOOK_UP_TABLE_POINTS 16
36 
37 static const s16 x[XNR3_LOOK_UP_TABLE_POINTS] = {
38 	1024, 1164, 1320, 1492, 1680, 1884, 2108, 2352,
39 	2616, 2900, 3208, 3540, 3896, 4276, 4684, 5120
40 };
41 
42 static const s16 a[XNR3_LOOK_UP_TABLE_POINTS] = {
43 	-7213, -5580, -4371, -3421, -2722, -2159, -6950, -5585,
44 	    -4529, -3697, -3010, -2485, -2070, -1727, -1428, 0
45     };
46 
47 static const s16 b[XNR3_LOOK_UP_TABLE_POINTS] = {
48 	4096, 3603, 3178, 2811, 2497, 2226, 1990, 1783,
49 	1603, 1446, 1307, 1185, 1077, 981, 895, 819
50 };
51 
52 static const s16 c[XNR3_LOOK_UP_TABLE_POINTS] = {
53 	1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
54 };
55 
56 /*
57  * Default kernel parameters. In general, default is bypass mode or as close
58  * to the ineffective values as possible. Due to the chroma down+upsampling,
59  * perfect bypass mode is not possible for xnr3 filter itself. Instead, the
60  * 'blending' parameter is used to create a bypass.
61  */
62 const struct ia_css_xnr3_config default_xnr3_config = {
63 	/* sigma */
64 	{ 0, 0, 0, 0, 0, 0 },
65 	/* coring */
66 	{ 0, 0, 0, 0 },
67 	/* blending */
68 	{ 0 }
69 };
70 
71 /*
72  * Compute an alpha value for the ISP kernel from sigma value on the host
73  * parameter interface as: alpha_scale * 1/(sigma/sigma_scale)
74  */
75 static int32_t
76 compute_alpha(int sigma)
77 {
78 	s32 alpha;
79 	int offset = sigma / 2;
80 
81 	if (sigma < XNR_MIN_SIGMA) {
82 		alpha = XNR_MAX_ALPHA;
83 	} else {
84 		alpha = ((IA_CSS_XNR3_SIGMA_SCALE * XNR_ALPHA_SCALE_FACTOR) + offset) / sigma;
85 
86 		if (alpha > XNR_MAX_ALPHA)
87 			alpha = XNR_MAX_ALPHA;
88 	}
89 
90 	return alpha;
91 }
92 
93 /*
94  * Compute the scaled coring value for the ISP kernel from the value on the
95  * host parameter interface.
96  */
97 static int32_t
98 compute_coring(int coring)
99 {
100 	s32 isp_coring;
101 	s32 isp_scale = XNR_CORING_SCALE_FACTOR;
102 	s32 host_scale = IA_CSS_XNR3_CORING_SCALE;
103 	s32 offset = host_scale / 2; /* fixed-point 0.5 */
104 
105 	/* Convert from public host-side scale factor to isp-side scale
106 	 * factor. Clip to [0, isp_scale-1).
107 	 */
108 	isp_coring = ((coring * isp_scale) + offset) / host_scale;
109 	return min(max(isp_coring, 0), isp_scale - 1);
110 }
111 
112 /*
113  * Compute the scaled blending strength for the ISP kernel from the value on
114  * the host parameter interface.
115  */
116 static int32_t
117 compute_blending(int strength)
118 {
119 	s32 isp_strength;
120 	s32 isp_scale = XNR_BLENDING_SCALE_FACTOR;
121 	s32 host_scale = IA_CSS_XNR3_BLENDING_SCALE;
122 	s32 offset = host_scale / 2; /* fixed-point 0.5 */
123 
124 	/* Convert from public host-side scale factor to isp-side scale
125 	 * factor. The blending factor is positive on the host side, but
126 	 * negative on the ISP side because +1.0 cannot be represented
127 	 * exactly as s0.11 fixed point, but -1.0 can.
128 	 */
129 	isp_strength = -(((strength * isp_scale) + offset) / host_scale);
130 	return MAX(MIN(isp_strength, 0), -isp_scale);
131 }
132 
133 void
134 ia_css_xnr3_encode(
135     struct sh_css_isp_xnr3_params *to,
136     const struct ia_css_xnr3_config *from,
137     unsigned int size)
138 {
139 	int kernel_size = XNR_FILTER_SIZE;
140 	/* The adjust factor is the next power of 2
141 	   w.r.t. the kernel size*/
142 	int adjust_factor = ceil_pow2(kernel_size);
143 	s32 max_diff = (1 << (ISP_VEC_ELEMBITS - 1)) - 1;
144 	s32 min_diff = -(1 << (ISP_VEC_ELEMBITS - 1));
145 
146 	s32 alpha_y0 = compute_alpha(from->sigma.y0);
147 	s32 alpha_y1 = compute_alpha(from->sigma.y1);
148 	s32 alpha_u0 = compute_alpha(from->sigma.u0);
149 	s32 alpha_u1 = compute_alpha(from->sigma.u1);
150 	s32 alpha_v0 = compute_alpha(from->sigma.v0);
151 	s32 alpha_v1 = compute_alpha(from->sigma.v1);
152 	s32 alpha_ydiff = (alpha_y1 - alpha_y0) * adjust_factor / kernel_size;
153 	s32 alpha_udiff = (alpha_u1 - alpha_u0) * adjust_factor / kernel_size;
154 	s32 alpha_vdiff = (alpha_v1 - alpha_v0) * adjust_factor / kernel_size;
155 
156 	s32 coring_u0 = compute_coring(from->coring.u0);
157 	s32 coring_u1 = compute_coring(from->coring.u1);
158 	s32 coring_v0 = compute_coring(from->coring.v0);
159 	s32 coring_v1 = compute_coring(from->coring.v1);
160 	s32 coring_udiff = (coring_u1 - coring_u0) * adjust_factor / kernel_size;
161 	s32 coring_vdiff = (coring_v1 - coring_v0) * adjust_factor / kernel_size;
162 
163 	s32 blending = compute_blending(from->blending.strength);
164 
165 	(void)size;
166 
167 	/* alpha's are represented in qN.5 format */
168 	to->alpha.y0 = alpha_y0;
169 	to->alpha.u0 = alpha_u0;
170 	to->alpha.v0 = alpha_v0;
171 	to->alpha.ydiff = min(max(alpha_ydiff, min_diff), max_diff);
172 	to->alpha.udiff = min(max(alpha_udiff, min_diff), max_diff);
173 	to->alpha.vdiff = min(max(alpha_vdiff, min_diff), max_diff);
174 
175 	/* coring parameters are expressed in q1.NN format */
176 	to->coring.u0 = coring_u0;
177 	to->coring.v0 = coring_v0;
178 	to->coring.udiff = min(max(coring_udiff, min_diff), max_diff);
179 	to->coring.vdiff = min(max(coring_vdiff, min_diff), max_diff);
180 
181 	/* blending strength is expressed in q1.NN format */
182 	to->blending.strength = blending;
183 }
184 
185 /* ISP2401 */
186 /* (void) = ia_css_xnr3_vmem_encode(*to, *from)
187  * -----------------------------------------------
188  * VMEM Encode Function to translate UV parameters from userspace into ISP space
189 */
190 void
191 ia_css_xnr3_vmem_encode(
192     struct sh_css_isp_xnr3_vmem_params *to,
193     const struct ia_css_xnr3_config *from,
194     unsigned int size)
195 {
196 	unsigned int i, j, base;
197 	const unsigned int total_blocks = 4;
198 	const unsigned int shuffle_block = 16;
199 
200 	(void)from;
201 	(void)size;
202 
203 	/* Init */
204 	for (i = 0; i < ISP_VEC_NELEMS; i++) {
205 		to->x[0][i] = 0;
206 		to->a[0][i] = 0;
207 		to->b[0][i] = 0;
208 		to->c[0][i] = 0;
209 	}
210 
211 	/* Constraints on "x":
212 	 * - values should be greater or equal to 0.
213 	 * - values should be ascending.
214 	 */
215 	assert(x[0] >= 0);
216 
217 	for (j = 1; j < XNR3_LOOK_UP_TABLE_POINTS; j++) {
218 		assert(x[j] >= 0);
219 		assert(x[j] > x[j - 1]);
220 	}
221 
222 	/* The implementation of the calulating 1/x is based on the availability
223 	 * of the OP_vec_shuffle16 operation.
224 	 * A 64 element vector is split up in 4 blocks of 16 element. Each array is copied to
225 	 * a vector 4 times, (starting at 0, 16, 32 and 48). All array elements are copied or
226 	 * initialised as described in the KFS. The remaining elements of a vector are set to 0.
227 	 */
228 	/* TODO: guard this code with above assumptions */
229 	for (i = 0; i < total_blocks; i++) {
230 		base = shuffle_block * i;
231 
232 		for (j = 0; j < XNR3_LOOK_UP_TABLE_POINTS; j++) {
233 			to->x[0][base + j] = x[j];
234 			to->a[0][base + j] = a[j];
235 			to->b[0][base + j] = b[j];
236 			to->c[0][base + j] = c[j];
237 		}
238 	}
239 }
240 
241 /* Dummy Function added as the tool expects it*/
242 void
243 ia_css_xnr3_debug_dtrace(
244     const struct ia_css_xnr3_config *config,
245     unsigned int level)
246 {
247 	(void)config;
248 	(void)level;
249 }
250