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 "ia_css_types.h"
17#include "sh_css_defs.h"
18#include "assert_support.h"
19
20#include "ia_css_ctc2.host.h"
21
22#define INEFFECTIVE_VAL 4096
23#define BASIC_VAL 819
24
25/*Default configuration of parameters for Ctc2*/
26const struct ia_css_ctc2_config default_ctc2_config = {
27	INEFFECTIVE_VAL, INEFFECTIVE_VAL, INEFFECTIVE_VAL,
28	INEFFECTIVE_VAL, INEFFECTIVE_VAL, INEFFECTIVE_VAL,
29	BASIC_VAL * 2, BASIC_VAL * 4, BASIC_VAL * 6,
30	BASIC_VAL * 8, INEFFECTIVE_VAL, INEFFECTIVE_VAL,
31	BASIC_VAL >> 1, BASIC_VAL
32};
33
34/* (dydx) = ctc2_slope(y1, y0, x1, x0)
35 * -----------------------------------------------
36 * Calculation of the Slope of a Line = ((y1 - y0) >> 8)/(x1 - x0)
37 *
38 * Note: y1, y0 , x1 & x0 must lie within the range 0 <-> 8191
39 */
40static int ctc2_slope(int y1, int y0, int x1, int x0)
41{
42	const int shift_val = 8;
43	const int max_slope = (1 << IA_CSS_CTC_COEF_SHIFT) - 1;
44	int dy = y1 - y0;
45	int dx = x1 - x0;
46	int rounding = (dx + 1) >> 1;
47	int dy_shift = dy << shift_val;
48	int slope, dydx;
49
50	/*Protection for parameter values, & avoiding zero divisions*/
51	assert(y0 >= 0 && y0 <= max_slope);
52	assert(y1 >= 0 && y1 <= max_slope);
53	assert(x0 >= 0 && x0 <= max_slope);
54	assert(x1 > 0 && x1 <= max_slope);
55	assert(dx > 0);
56
57	if (dy < 0)
58		rounding = -rounding;
59	slope = (int)(dy_shift + rounding) / dx;
60
61	/*the slope must lie within the range
62	  (-max_slope-1) >= (dydx) >= (max_slope)
63	*/
64	if (slope <= -max_slope - 1) {
65		dydx = -max_slope - 1;
66	} else if (slope >= max_slope) {
67		dydx = max_slope;
68	} else {
69		dydx = slope;
70	}
71
72	return dydx;
73}
74
75/* (void) = ia_css_ctc2_vmem_encode(*to, *from)
76 * -----------------------------------------------
77 * VMEM Encode Function to translate Y parameters from userspace into ISP space
78 */
79void ia_css_ctc2_vmem_encode(struct ia_css_isp_ctc2_vmem_params *to,
80			     const struct ia_css_ctc2_config *from,
81			     size_t size)
82{
83	unsigned int i, j;
84	const unsigned int shffl_blck = 4;
85	const unsigned int length_zeros = 11;
86	short dydx0, dydx1, dydx2, dydx3, dydx4;
87
88	(void)size;
89	/*
90	*  Calculation of slopes of lines interconnecting
91	*  0.0 -> y_x1 -> y_x2 -> y _x3 -> y_x4 -> 1.0
92	*/
93	dydx0 = ctc2_slope(from->y_y1, from->y_y0,
94			   from->y_x1, 0);
95	dydx1 = ctc2_slope(from->y_y2, from->y_y1,
96			   from->y_x2, from->y_x1);
97	dydx2 = ctc2_slope(from->y_y3, from->y_y2,
98			   from->y_x3, from->y_x2);
99	dydx3 = ctc2_slope(from->y_y4, from->y_y3,
100			   from->y_x4, from->y_x3);
101	dydx4 = ctc2_slope(from->y_y5, from->y_y4,
102			   SH_CSS_BAYER_MAXVAL, from->y_x4);
103
104	/*Fill 3 arrays with:
105	 * - Luma input gain values y_y0, y_y1, y_y2, y_3, y_y4
106	 * - Luma kneepoints 0, y_x1, y_x2, y_x3, y_x4
107	 * - Calculated slopes dydx0, dyxd1, dydx2, dydx3, dydx4
108	 *
109	 * - Each 64-element array is divided in blocks of 16 elements:
110	 *   the 5 parameters + zeros in the remaining 11 positions
111	 * - All blocks of the same array will contain the same data
112	 */
113	for (i = 0; i < shffl_blck; i++) {
114		to->y_x[0][(i << shffl_blck)]     = 0;
115		to->y_x[0][(i << shffl_blck) + 1] = from->y_x1;
116		to->y_x[0][(i << shffl_blck) + 2] = from->y_x2;
117		to->y_x[0][(i << shffl_blck) + 3] = from->y_x3;
118		to->y_x[0][(i << shffl_blck) + 4] = from->y_x4;
119
120		to->y_y[0][(i << shffl_blck)]     = from->y_y0;
121		to->y_y[0][(i << shffl_blck) + 1] = from->y_y1;
122		to->y_y[0][(i << shffl_blck) + 2] = from->y_y2;
123		to->y_y[0][(i << shffl_blck) + 3] = from->y_y3;
124		to->y_y[0][(i << shffl_blck) + 4] = from->y_y4;
125
126		to->e_y_slope[0][(i << shffl_blck)]    = dydx0;
127		to->e_y_slope[0][(i << shffl_blck) + 1] = dydx1;
128		to->e_y_slope[0][(i << shffl_blck) + 2] = dydx2;
129		to->e_y_slope[0][(i << shffl_blck) + 3] = dydx3;
130		to->e_y_slope[0][(i << shffl_blck) + 4] = dydx4;
131
132		for (j = 0; j < length_zeros; j++) {
133			to->y_x[0][(i << shffl_blck) + 5 + j] = 0;
134			to->y_y[0][(i << shffl_blck) + 5 + j] = 0;
135			to->e_y_slope[0][(i << shffl_blck) + 5 + j] = 0;
136		}
137	}
138}
139
140/* (void) = ia_css_ctc2_encode(*to, *from)
141 * -----------------------------------------------
142 * DMEM Encode Function to translate UV parameters from userspace into ISP space
143 */
144void ia_css_ctc2_encode(struct ia_css_isp_ctc2_dmem_params *to,
145			struct ia_css_ctc2_config *from,
146			size_t size)
147{
148	(void)size;
149
150	to->uv_y0 = from->uv_y0;
151	to->uv_y1 = from->uv_y1;
152	to->uv_x0 = from->uv_x0;
153	to->uv_x1 = from->uv_x1;
154
155	/*Slope Calculation*/
156	to->uv_dydx = ctc2_slope(from->uv_y1, from->uv_y0,
157				 from->uv_x1, from->uv_x0);
158}
159