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 "sh_css_param_dvs.h"
17 #include <assert_support.h>
18 #include <type_support.h>
19 #include <ia_css_err.h>
20 #include <ia_css_types.h>
21 #include "ia_css_debug.h"
22 
23 static struct ia_css_dvs_6axis_config *
alloc_dvs_6axis_table(const struct ia_css_resolution * frame_res,struct ia_css_dvs_6axis_config * dvs_config_src)24 alloc_dvs_6axis_table(const struct ia_css_resolution *frame_res,
25 		      struct ia_css_dvs_6axis_config  *dvs_config_src)
26 {
27 	unsigned int width_y = 0;
28 	unsigned int height_y = 0;
29 	unsigned int width_uv = 0;
30 	unsigned int height_uv = 0;
31 	int err = 0;
32 	struct ia_css_dvs_6axis_config  *dvs_config = NULL;
33 
34 	dvs_config = kvmalloc(sizeof(struct ia_css_dvs_6axis_config),
35 			      GFP_KERNEL);
36 	if (!dvs_config)	{
37 		IA_CSS_ERROR("out of memory");
38 		err = -ENOMEM;
39 	} else {
40 		/*Initialize new struct with latest config settings*/
41 		if (dvs_config_src) {
42 			dvs_config->width_y = width_y = dvs_config_src->width_y;
43 			dvs_config->height_y = height_y = dvs_config_src->height_y;
44 			dvs_config->width_uv = width_uv = dvs_config_src->width_uv;
45 			dvs_config->height_uv = height_uv = dvs_config_src->height_uv;
46 			IA_CSS_LOG("alloc_dvs_6axis_table Y: W %d H %d", width_y, height_y);
47 		} else if (frame_res) {
48 			dvs_config->width_y = width_y = DVS_TABLE_IN_BLOCKDIM_X_LUMA(frame_res->width);
49 			dvs_config->height_y = height_y = DVS_TABLE_IN_BLOCKDIM_Y_LUMA(
50 							      frame_res->height);
51 			dvs_config->width_uv = width_uv = DVS_TABLE_IN_BLOCKDIM_X_CHROMA(
52 							      frame_res->width /
53 							      2); /* UV = Y/2, depens on colour format YUV 4.2.0*/
54 			dvs_config->height_uv = height_uv = DVS_TABLE_IN_BLOCKDIM_Y_CHROMA(
55 								frame_res->height /
56 								2);/* UV = Y/2, depens on colour format YUV 4.2.0*/
57 			IA_CSS_LOG("alloc_dvs_6axis_table Y: W %d H %d", width_y, height_y);
58 		}
59 
60 		/* Generate Y buffers  */
61 		dvs_config->xcoords_y = kvmalloc(width_y * height_y * sizeof(uint32_t),
62 						 GFP_KERNEL);
63 		if (!dvs_config->xcoords_y) {
64 			IA_CSS_ERROR("out of memory");
65 			err = -ENOMEM;
66 			goto exit;
67 		}
68 
69 		dvs_config->ycoords_y = kvmalloc(width_y * height_y * sizeof(uint32_t),
70 						 GFP_KERNEL);
71 		if (!dvs_config->ycoords_y) {
72 			IA_CSS_ERROR("out of memory");
73 			err = -ENOMEM;
74 			goto exit;
75 		}
76 
77 		/* Generate UV buffers  */
78 		IA_CSS_LOG("UV W %d H %d", width_uv, height_uv);
79 
80 		dvs_config->xcoords_uv = kvmalloc(width_uv * height_uv * sizeof(uint32_t),
81 						  GFP_KERNEL);
82 		if (!dvs_config->xcoords_uv) {
83 			IA_CSS_ERROR("out of memory");
84 			err = -ENOMEM;
85 			goto exit;
86 		}
87 
88 		dvs_config->ycoords_uv = kvmalloc(width_uv * height_uv * sizeof(uint32_t),
89 						  GFP_KERNEL);
90 		if (!dvs_config->ycoords_uv) {
91 			IA_CSS_ERROR("out of memory");
92 			err = -ENOMEM;
93 		}
94 exit:
95 		if (err) {
96 			free_dvs_6axis_table(
97 			    &dvs_config); /* we might have allocated some memory, release this */
98 			dvs_config = NULL;
99 		}
100 	}
101 
102 	IA_CSS_LEAVE("dvs_config=%p", dvs_config);
103 	return dvs_config;
104 }
105 
106 static void
init_dvs_6axis_table_from_default(struct ia_css_dvs_6axis_config * dvs_config,const struct ia_css_resolution * dvs_offset)107 init_dvs_6axis_table_from_default(struct ia_css_dvs_6axis_config *dvs_config,
108 				  const struct ia_css_resolution *dvs_offset)
109 {
110 	unsigned int x, y;
111 	unsigned int width_y = dvs_config->width_y;
112 	unsigned int height_y = dvs_config->height_y;
113 	unsigned int width_uv = dvs_config->width_uv;
114 	unsigned int height_uv = dvs_config->height_uv;
115 
116 	IA_CSS_LOG("Env_X=%d, Env_Y=%d, width_y=%d, height_y=%d",
117 		   dvs_offset->width, dvs_offset->height, width_y, height_y);
118 	for (y = 0; y < height_y; y++) {
119 		for (x = 0; x < width_y; x++) {
120 			dvs_config->xcoords_y[y * width_y + x] =  (dvs_offset->width + x *
121 				DVS_BLOCKDIM_X) << DVS_COORD_FRAC_BITS;
122 		}
123 	}
124 
125 	for (y = 0; y < height_y; y++) {
126 		for (x = 0; x < width_y; x++) {
127 			dvs_config->ycoords_y[y * width_y + x] =  (dvs_offset->height + y *
128 				DVS_BLOCKDIM_Y_LUMA) << DVS_COORD_FRAC_BITS;
129 		}
130 	}
131 
132 	for (y = 0; y < height_uv; y++) {
133 		for (x = 0; x < width_uv;
134 		     x++) { /* Envelope dimensions set in Ypixels hence offset UV = offset Y/2 */
135 			dvs_config->xcoords_uv[y * width_uv + x] =  ((dvs_offset->width / 2) + x *
136 				DVS_BLOCKDIM_X) << DVS_COORD_FRAC_BITS;
137 		}
138 	}
139 
140 	for (y = 0; y < height_uv; y++) {
141 		for (x = 0; x < width_uv;
142 		     x++) { /* Envelope dimensions set in Ypixels hence offset UV = offset Y/2 */
143 			dvs_config->ycoords_uv[y * width_uv + x] =  ((dvs_offset->height / 2) + y *
144 				DVS_BLOCKDIM_Y_CHROMA) <<
145 				DVS_COORD_FRAC_BITS;
146 		}
147 	}
148 }
149 
150 static void
init_dvs_6axis_table_from_config(struct ia_css_dvs_6axis_config * dvs_config,struct ia_css_dvs_6axis_config * dvs_config_src)151 init_dvs_6axis_table_from_config(struct ia_css_dvs_6axis_config *dvs_config,
152 				 struct ia_css_dvs_6axis_config  *dvs_config_src)
153 {
154 	unsigned int width_y = dvs_config->width_y;
155 	unsigned int height_y = dvs_config->height_y;
156 	unsigned int width_uv = dvs_config->width_uv;
157 	unsigned int height_uv = dvs_config->height_uv;
158 
159 	memcpy(dvs_config->xcoords_y, dvs_config_src->xcoords_y,
160 	       (width_y * height_y * sizeof(uint32_t)));
161 	memcpy(dvs_config->ycoords_y, dvs_config_src->ycoords_y,
162 	       (width_y * height_y * sizeof(uint32_t)));
163 	memcpy(dvs_config->xcoords_uv, dvs_config_src->xcoords_uv,
164 	       (width_uv * height_uv * sizeof(uint32_t)));
165 	memcpy(dvs_config->ycoords_uv, dvs_config_src->ycoords_uv,
166 	       (width_uv * height_uv * sizeof(uint32_t)));
167 }
168 
169 struct ia_css_dvs_6axis_config *
generate_dvs_6axis_table(const struct ia_css_resolution * frame_res,const struct ia_css_resolution * dvs_offset)170 generate_dvs_6axis_table(const struct ia_css_resolution *frame_res,
171 			 const struct ia_css_resolution *dvs_offset)
172 {
173 	struct ia_css_dvs_6axis_config *dvs_6axis_table;
174 
175 	assert(frame_res);
176 	assert(dvs_offset);
177 
178 	dvs_6axis_table = alloc_dvs_6axis_table(frame_res, NULL);
179 	if (dvs_6axis_table) {
180 		init_dvs_6axis_table_from_default(dvs_6axis_table, dvs_offset);
181 		return dvs_6axis_table;
182 	}
183 	return NULL;
184 }
185 
186 struct ia_css_dvs_6axis_config *
generate_dvs_6axis_table_from_config(struct ia_css_dvs_6axis_config * dvs_config_src)187 generate_dvs_6axis_table_from_config(struct ia_css_dvs_6axis_config
188 				     *dvs_config_src)
189 {
190 	struct ia_css_dvs_6axis_config *dvs_6axis_table;
191 
192 	assert(dvs_config_src);
193 
194 	dvs_6axis_table = alloc_dvs_6axis_table(NULL, dvs_config_src);
195 	if (dvs_6axis_table) {
196 		init_dvs_6axis_table_from_config(dvs_6axis_table, dvs_config_src);
197 		return dvs_6axis_table;
198 	}
199 	return NULL;
200 }
201 
202 void
free_dvs_6axis_table(struct ia_css_dvs_6axis_config ** dvs_6axis_config)203 free_dvs_6axis_table(struct ia_css_dvs_6axis_config  **dvs_6axis_config)
204 {
205 	if ((dvs_6axis_config) && (*dvs_6axis_config)) {
206 		IA_CSS_ENTER_PRIVATE("dvs_6axis_config %p", (*dvs_6axis_config));
207 		if ((*dvs_6axis_config)->xcoords_y) {
208 			kvfree((*dvs_6axis_config)->xcoords_y);
209 			(*dvs_6axis_config)->xcoords_y = NULL;
210 		}
211 
212 		if ((*dvs_6axis_config)->ycoords_y) {
213 			kvfree((*dvs_6axis_config)->ycoords_y);
214 			(*dvs_6axis_config)->ycoords_y = NULL;
215 		}
216 
217 		/* Free up UV buffers */
218 		if ((*dvs_6axis_config)->xcoords_uv) {
219 			kvfree((*dvs_6axis_config)->xcoords_uv);
220 			(*dvs_6axis_config)->xcoords_uv = NULL;
221 		}
222 
223 		if ((*dvs_6axis_config)->ycoords_uv) {
224 			kvfree((*dvs_6axis_config)->ycoords_uv);
225 			(*dvs_6axis_config)->ycoords_uv = NULL;
226 		}
227 
228 		IA_CSS_LEAVE_PRIVATE("dvs_6axis_config %p", (*dvs_6axis_config));
229 		kvfree(*dvs_6axis_config);
230 		*dvs_6axis_config = NULL;
231 	}
232 }
233 
copy_dvs_6axis_table(struct ia_css_dvs_6axis_config * dvs_config_dst,const struct ia_css_dvs_6axis_config * dvs_config_src)234 void copy_dvs_6axis_table(struct ia_css_dvs_6axis_config *dvs_config_dst,
235 			  const struct ia_css_dvs_6axis_config *dvs_config_src)
236 {
237 	unsigned int width_y;
238 	unsigned int height_y;
239 	unsigned int width_uv;
240 	unsigned int height_uv;
241 
242 	assert(dvs_config_src);
243 	assert(dvs_config_dst);
244 	assert(dvs_config_src->xcoords_y);
245 	assert(dvs_config_src->xcoords_uv);
246 	assert(dvs_config_src->ycoords_y);
247 	assert(dvs_config_src->ycoords_uv);
248 	assert(dvs_config_src->width_y == dvs_config_dst->width_y);
249 	assert(dvs_config_src->width_uv == dvs_config_dst->width_uv);
250 	assert(dvs_config_src->height_y == dvs_config_dst->height_y);
251 	assert(dvs_config_src->height_uv == dvs_config_dst->height_uv);
252 
253 	width_y = dvs_config_src->width_y;
254 	height_y = dvs_config_src->height_y;
255 	width_uv =
256 	    dvs_config_src->width_uv; /* = Y/2, depens on colour format YUV 4.2.0*/
257 	height_uv = dvs_config_src->height_uv;
258 
259 	memcpy(dvs_config_dst->xcoords_y, dvs_config_src->xcoords_y,
260 	       (width_y * height_y * sizeof(uint32_t)));
261 	memcpy(dvs_config_dst->ycoords_y, dvs_config_src->ycoords_y,
262 	       (width_y * height_y * sizeof(uint32_t)));
263 
264 	memcpy(dvs_config_dst->xcoords_uv, dvs_config_src->xcoords_uv,
265 	       (width_uv * height_uv * sizeof(uint32_t)));
266 	memcpy(dvs_config_dst->ycoords_uv, dvs_config_src->ycoords_uv,
267 	       (width_uv * height_uv * sizeof(uint32_t)));
268 }
269 
270 void
ia_css_dvs_statistics_get(enum dvs_statistics_type type,union ia_css_dvs_statistics_host * host_stats,const union ia_css_dvs_statistics_isp * isp_stats)271 ia_css_dvs_statistics_get(enum dvs_statistics_type type,
272 			  union ia_css_dvs_statistics_host  *host_stats,
273 			  const union ia_css_dvs_statistics_isp *isp_stats)
274 {
275 	if (type == DVS_STATISTICS) {
276 		ia_css_get_dvs_statistics(host_stats->p_dvs_statistics_host,
277 					  isp_stats->p_dvs_statistics_isp);
278 	} else if (type == DVS2_STATISTICS) {
279 		ia_css_get_dvs2_statistics(host_stats->p_dvs2_statistics_host,
280 					   isp_stats->p_dvs_statistics_isp);
281 	}
282 	return;
283 }
284