1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Clovertrail PNW Camera Imaging ISP subsystem.
4  *
5  * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version
9  * 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  *
17  */
18 
19 #include <media/videobuf-vmalloc.h>
20 #include <media/v4l2-dev.h>
21 #include <media/v4l2-event.h>
22 
23 #include "mmu/isp_mmu.h"
24 #include "mmu/sh_mmu_mrfld.h"
25 #include "hmm/hmm_bo.h"
26 #include "hmm/hmm.h"
27 
28 #include "atomisp_compat.h"
29 #include "atomisp_internal.h"
30 #include "atomisp_cmd.h"
31 #include "atomisp-regs.h"
32 #include "atomisp_fops.h"
33 #include "atomisp_ioctl.h"
34 
35 #include "ia_css_debug.h"
36 #include "ia_css_isp_param.h"
37 #include "sh_css_hrt.h"
38 #include "ia_css_isys.h"
39 
40 #include <linux/io.h>
41 #include <linux/pm_runtime.h>
42 
43 /* Assume max number of ACC stages */
44 #define MAX_ACC_STAGES	20
45 
46 /* Ideally, this should come from CSS headers */
47 #define NO_LINK -1
48 
49 /*
50  * to serialize MMIO access , this is due to ISP2400 silicon issue Sighting
51  * #4684168, if concurrency access happened, system may hard hang.
52  */
53 static DEFINE_SPINLOCK(mmio_lock);
54 
55 enum frame_info_type {
56 	ATOMISP_CSS_VF_FRAME,
57 	ATOMISP_CSS_SECOND_VF_FRAME,
58 	ATOMISP_CSS_OUTPUT_FRAME,
59 	ATOMISP_CSS_SECOND_OUTPUT_FRAME,
60 	ATOMISP_CSS_RAW_FRAME,
61 };
62 
63 struct bayer_ds_factor {
64 	unsigned int numerator;
65 	unsigned int denominator;
66 };
67 
68 static void atomisp_css2_hw_store_8(hrt_address addr, uint8_t data)
69 {
70 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
71 	unsigned long flags;
72 
73 	spin_lock_irqsave(&mmio_lock, flags);
74 	writeb(data, isp->base + (addr & 0x003FFFFF));
75 	spin_unlock_irqrestore(&mmio_lock, flags);
76 }
77 
78 static void atomisp_css2_hw_store_16(hrt_address addr, uint16_t data)
79 {
80 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
81 	unsigned long flags;
82 
83 	spin_lock_irqsave(&mmio_lock, flags);
84 	writew(data, isp->base + (addr & 0x003FFFFF));
85 	spin_unlock_irqrestore(&mmio_lock, flags);
86 }
87 
88 void atomisp_css2_hw_store_32(hrt_address addr, uint32_t data)
89 {
90 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
91 	unsigned long flags;
92 
93 	spin_lock_irqsave(&mmio_lock, flags);
94 	writel(data, isp->base + (addr & 0x003FFFFF));
95 	spin_unlock_irqrestore(&mmio_lock, flags);
96 }
97 
98 static uint8_t atomisp_css2_hw_load_8(hrt_address addr)
99 {
100 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
101 	unsigned long flags;
102 	u8 ret;
103 
104 	spin_lock_irqsave(&mmio_lock, flags);
105 	ret = readb(isp->base + (addr & 0x003FFFFF));
106 	spin_unlock_irqrestore(&mmio_lock, flags);
107 	return ret;
108 }
109 
110 static uint16_t atomisp_css2_hw_load_16(hrt_address addr)
111 {
112 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
113 	unsigned long flags;
114 	u16 ret;
115 
116 	spin_lock_irqsave(&mmio_lock, flags);
117 	ret = readw(isp->base + (addr & 0x003FFFFF));
118 	spin_unlock_irqrestore(&mmio_lock, flags);
119 	return ret;
120 }
121 
122 static uint32_t atomisp_css2_hw_load_32(hrt_address addr)
123 {
124 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
125 	unsigned long flags;
126 	u32 ret;
127 
128 	spin_lock_irqsave(&mmio_lock, flags);
129 	ret = readl(isp->base + (addr & 0x003FFFFF));
130 	spin_unlock_irqrestore(&mmio_lock, flags);
131 	return ret;
132 }
133 
134 static void atomisp_css2_hw_store(hrt_address addr, const void *from, uint32_t n)
135 {
136 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
137 	unsigned long flags;
138 	unsigned int i;
139 
140 	addr &= 0x003FFFFF;
141 	spin_lock_irqsave(&mmio_lock, flags);
142 	for (i = 0; i < n; i++, from++)
143 		writeb(*(s8 *)from, isp->base + addr + i);
144 
145 	spin_unlock_irqrestore(&mmio_lock, flags);
146 }
147 
148 static void atomisp_css2_hw_load(hrt_address addr, void *to, uint32_t n)
149 {
150 	struct atomisp_device *isp = dev_get_drvdata(atomisp_dev);
151 	unsigned long flags;
152 	unsigned int i;
153 
154 	addr &= 0x003FFFFF;
155 	spin_lock_irqsave(&mmio_lock, flags);
156 	for (i = 0; i < n; i++, to++)
157 		*(s8 *)to = readb(isp->base + addr + i);
158 	spin_unlock_irqrestore(&mmio_lock, flags);
159 }
160 
161 static int  __printf(1, 0) atomisp_vprintk(const char *fmt, va_list args)
162 {
163 	vprintk(fmt, args);
164 	return 0;
165 }
166 
167 void atomisp_load_uint32(hrt_address addr, uint32_t *data)
168 {
169 	*data = atomisp_css2_hw_load_32(addr);
170 }
171 
172 static int hmm_get_mmu_base_addr(struct device *dev, unsigned int *mmu_base_addr)
173 {
174 	if (!sh_mmu_mrfld.get_pd_base) {
175 		dev_err(dev, "get mmu base address failed.\n");
176 		return -EINVAL;
177 	}
178 
179 	*mmu_base_addr = sh_mmu_mrfld.get_pd_base(&bo_device.mmu,
180 			 bo_device.mmu.base_address);
181 	return 0;
182 }
183 
184 static void __dump_pipe_config(struct atomisp_sub_device *asd,
185 			       struct atomisp_stream_env *stream_env,
186 			       unsigned int pipe_id)
187 {
188 	struct atomisp_device *isp = asd->isp;
189 
190 	if (stream_env->pipes[pipe_id]) {
191 		struct ia_css_pipe_config *p_config;
192 		struct ia_css_pipe_extra_config *pe_config;
193 
194 		p_config = &stream_env->pipe_configs[pipe_id];
195 		pe_config = &stream_env->pipe_extra_configs[pipe_id];
196 		dev_dbg(isp->dev, "dumping pipe[%d] config:\n", pipe_id);
197 		dev_dbg(isp->dev,
198 			"pipe_config.pipe_mode:%d.\n", p_config->mode);
199 		dev_dbg(isp->dev,
200 			"pipe_config.output_info[0] w=%d, h=%d.\n",
201 			p_config->output_info[0].res.width,
202 			p_config->output_info[0].res.height);
203 		dev_dbg(isp->dev,
204 			"pipe_config.vf_pp_in_res w=%d, h=%d.\n",
205 			p_config->vf_pp_in_res.width,
206 			p_config->vf_pp_in_res.height);
207 		dev_dbg(isp->dev,
208 			"pipe_config.capt_pp_in_res w=%d, h=%d.\n",
209 			p_config->capt_pp_in_res.width,
210 			p_config->capt_pp_in_res.height);
211 		dev_dbg(isp->dev,
212 			"pipe_config.output.padded w=%d.\n",
213 			p_config->output_info[0].padded_width);
214 		dev_dbg(isp->dev,
215 			"pipe_config.vf_output_info[0] w=%d, h=%d.\n",
216 			p_config->vf_output_info[0].res.width,
217 			p_config->vf_output_info[0].res.height);
218 		dev_dbg(isp->dev,
219 			"pipe_config.bayer_ds_out_res w=%d, h=%d.\n",
220 			p_config->bayer_ds_out_res.width,
221 			p_config->bayer_ds_out_res.height);
222 		dev_dbg(isp->dev,
223 			"pipe_config.envelope w=%d, h=%d.\n",
224 			p_config->dvs_envelope.width,
225 			p_config->dvs_envelope.height);
226 		dev_dbg(isp->dev,
227 			"pipe_config.dvs_frame_delay=%d.\n",
228 			p_config->dvs_frame_delay);
229 		dev_dbg(isp->dev,
230 			"pipe_config.isp_pipe_version:%d.\n",
231 			p_config->isp_pipe_version);
232 		dev_dbg(isp->dev,
233 			"pipe_config.default_capture_config.capture_mode=%d.\n",
234 			p_config->default_capture_config.mode);
235 		dev_dbg(isp->dev,
236 			"pipe_config.enable_dz=%d.\n",
237 			p_config->enable_dz);
238 		dev_dbg(isp->dev,
239 			"pipe_config.default_capture_config.enable_xnr=%d.\n",
240 			p_config->default_capture_config.enable_xnr);
241 		dev_dbg(isp->dev,
242 			"dumping pipe[%d] extra config:\n", pipe_id);
243 		dev_dbg(isp->dev,
244 			"pipe_extra_config.enable_raw_binning:%d.\n",
245 			pe_config->enable_raw_binning);
246 		dev_dbg(isp->dev,
247 			"pipe_extra_config.enable_yuv_ds:%d.\n",
248 			pe_config->enable_yuv_ds);
249 		dev_dbg(isp->dev,
250 			"pipe_extra_config.enable_high_speed:%d.\n",
251 			pe_config->enable_high_speed);
252 		dev_dbg(isp->dev,
253 			"pipe_extra_config.enable_dvs_6axis:%d.\n",
254 			pe_config->enable_dvs_6axis);
255 		dev_dbg(isp->dev,
256 			"pipe_extra_config.enable_reduced_pipe:%d.\n",
257 			pe_config->enable_reduced_pipe);
258 		dev_dbg(isp->dev,
259 			"pipe_(extra_)config.enable_dz:%d.\n",
260 			p_config->enable_dz);
261 		dev_dbg(isp->dev,
262 			"pipe_extra_config.disable_vf_pp:%d.\n",
263 			pe_config->disable_vf_pp);
264 	}
265 }
266 
267 static void __dump_stream_config(struct atomisp_sub_device *asd,
268 				 struct atomisp_stream_env *stream_env)
269 {
270 	struct atomisp_device *isp = asd->isp;
271 	struct ia_css_stream_config *s_config;
272 	int j;
273 	bool valid_stream = false;
274 
275 	for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
276 		if (stream_env->pipes[j]) {
277 			__dump_pipe_config(asd, stream_env, j);
278 			valid_stream = true;
279 		}
280 	}
281 	if (!valid_stream)
282 		return;
283 	s_config = &stream_env->stream_config;
284 	dev_dbg(isp->dev, "stream_config.mode=%d.\n", s_config->mode);
285 
286 	if (s_config->mode == IA_CSS_INPUT_MODE_SENSOR ||
287 	    s_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
288 		dev_dbg(isp->dev, "stream_config.source.port.port=%d.\n",
289 			s_config->source.port.port);
290 		dev_dbg(isp->dev, "stream_config.source.port.num_lanes=%d.\n",
291 			s_config->source.port.num_lanes);
292 		dev_dbg(isp->dev, "stream_config.source.port.timeout=%d.\n",
293 			s_config->source.port.timeout);
294 		dev_dbg(isp->dev, "stream_config.source.port.rxcount=0x%x.\n",
295 			s_config->source.port.rxcount);
296 		dev_dbg(isp->dev, "stream_config.source.port.compression.type=%d.\n",
297 			s_config->source.port.compression.type);
298 		dev_dbg(isp->dev,
299 			"stream_config.source.port.compression.compressed_bits_per_pixel=%d.\n",
300 			s_config->source.port.compression.
301 			compressed_bits_per_pixel);
302 		dev_dbg(isp->dev,
303 			"stream_config.source.port.compression.uncompressed_bits_per_pixel=%d.\n",
304 			s_config->source.port.compression.
305 			uncompressed_bits_per_pixel);
306 	} else if (s_config->mode == IA_CSS_INPUT_MODE_TPG) {
307 		dev_dbg(isp->dev, "stream_config.source.tpg.id=%d.\n",
308 			s_config->source.tpg.id);
309 		dev_dbg(isp->dev, "stream_config.source.tpg.mode=%d.\n",
310 			s_config->source.tpg.mode);
311 		dev_dbg(isp->dev, "stream_config.source.tpg.x_mask=%d.\n",
312 			s_config->source.tpg.x_mask);
313 		dev_dbg(isp->dev, "stream_config.source.tpg.x_delta=%d.\n",
314 			s_config->source.tpg.x_delta);
315 		dev_dbg(isp->dev, "stream_config.source.tpg.y_mask=%d.\n",
316 			s_config->source.tpg.y_mask);
317 		dev_dbg(isp->dev, "stream_config.source.tpg.y_delta=%d.\n",
318 			s_config->source.tpg.y_delta);
319 		dev_dbg(isp->dev, "stream_config.source.tpg.xy_mask=%d.\n",
320 			s_config->source.tpg.xy_mask);
321 	} else if (s_config->mode == IA_CSS_INPUT_MODE_PRBS) {
322 		dev_dbg(isp->dev, "stream_config.source.prbs.id=%d.\n",
323 			s_config->source.prbs.id);
324 		dev_dbg(isp->dev, "stream_config.source.prbs.h_blank=%d.\n",
325 			s_config->source.prbs.h_blank);
326 		dev_dbg(isp->dev, "stream_config.source.prbs.v_blank=%d.\n",
327 			s_config->source.prbs.v_blank);
328 		dev_dbg(isp->dev, "stream_config.source.prbs.seed=%d.\n",
329 			s_config->source.prbs.seed);
330 		dev_dbg(isp->dev, "stream_config.source.prbs.seed1=%d.\n",
331 			s_config->source.prbs.seed1);
332 	}
333 
334 	for (j = 0; j < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; j++) {
335 		dev_dbg(isp->dev, "stream_configisys_config[%d].input_res w=%d, h=%d.\n",
336 			j,
337 			s_config->isys_config[j].input_res.width,
338 			s_config->isys_config[j].input_res.height);
339 
340 		dev_dbg(isp->dev, "stream_configisys_config[%d].linked_isys_stream_id=%d\n",
341 			j,
342 			s_config->isys_config[j].linked_isys_stream_id);
343 
344 		dev_dbg(isp->dev, "stream_configisys_config[%d].format=%d\n",
345 			j,
346 			s_config->isys_config[j].format);
347 
348 		dev_dbg(isp->dev, "stream_configisys_config[%d].valid=%d.\n",
349 			j,
350 			s_config->isys_config[j].valid);
351 	}
352 
353 	dev_dbg(isp->dev, "stream_config.input_config.input_res w=%d, h=%d.\n",
354 		s_config->input_config.input_res.width,
355 		s_config->input_config.input_res.height);
356 
357 	dev_dbg(isp->dev, "stream_config.input_config.effective_res w=%d, h=%d.\n",
358 		s_config->input_config.effective_res.width,
359 		s_config->input_config.effective_res.height);
360 
361 	dev_dbg(isp->dev, "stream_config.input_config.format=%d\n",
362 		s_config->input_config.format);
363 
364 	dev_dbg(isp->dev, "stream_config.input_config.bayer_order=%d.\n",
365 		s_config->input_config.bayer_order);
366 
367 	dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n",
368 		s_config->pixels_per_clock);
369 	dev_dbg(isp->dev, "stream_config.online=%d.\n", s_config->online);
370 	dev_dbg(isp->dev, "stream_config.continuous=%d.\n",
371 		s_config->continuous);
372 	dev_dbg(isp->dev, "stream_config.disable_cont_viewfinder=%d.\n",
373 		s_config->disable_cont_viewfinder);
374 	dev_dbg(isp->dev, "stream_config.channel_id=%d.\n",
375 		s_config->channel_id);
376 	dev_dbg(isp->dev, "stream_config.init_num_cont_raw_buf=%d.\n",
377 		s_config->init_num_cont_raw_buf);
378 	dev_dbg(isp->dev, "stream_config.target_num_cont_raw_buf=%d.\n",
379 		s_config->target_num_cont_raw_buf);
380 	dev_dbg(isp->dev, "stream_config.left_padding=%d.\n",
381 		s_config->left_padding);
382 	dev_dbg(isp->dev, "stream_config.sensor_binning_factor=%d.\n",
383 		s_config->sensor_binning_factor);
384 	dev_dbg(isp->dev, "stream_config.pixels_per_clock=%d.\n",
385 		s_config->pixels_per_clock);
386 	dev_dbg(isp->dev, "stream_config.pack_raw_pixels=%d.\n",
387 		s_config->pack_raw_pixels);
388 	dev_dbg(isp->dev, "stream_config.flash_gpio_pin=%d.\n",
389 		s_config->flash_gpio_pin);
390 	dev_dbg(isp->dev, "stream_config.mipi_buffer_config.size_mem_words=%d.\n",
391 		s_config->mipi_buffer_config.size_mem_words);
392 	dev_dbg(isp->dev, "stream_config.mipi_buffer_config.contiguous=%d.\n",
393 		s_config->mipi_buffer_config.contiguous);
394 	dev_dbg(isp->dev, "stream_config.metadata_config.data_type=%d.\n",
395 		s_config->metadata_config.data_type);
396 	dev_dbg(isp->dev, "stream_config.metadata_config.resolution w=%d, h=%d.\n",
397 		s_config->metadata_config.resolution.width,
398 		s_config->metadata_config.resolution.height);
399 }
400 
401 static int __destroy_stream(struct atomisp_sub_device *asd,
402 			    struct atomisp_stream_env *stream_env)
403 {
404 	struct atomisp_device *isp = asd->isp;
405 	unsigned long timeout;
406 
407 	if (!stream_env->stream)
408 		return 0;
409 
410 	if (stream_env->stream_state == CSS_STREAM_STARTED
411 	    && ia_css_stream_stop(stream_env->stream) != 0) {
412 		dev_err(isp->dev, "stop stream failed.\n");
413 		return -EINVAL;
414 	}
415 
416 	if (stream_env->stream_state == CSS_STREAM_STARTED) {
417 		timeout = jiffies + msecs_to_jiffies(40);
418 		while (1) {
419 			if (ia_css_stream_has_stopped(stream_env->stream))
420 				break;
421 
422 			if (time_after(jiffies, timeout)) {
423 				dev_warn(isp->dev, "stop stream timeout.\n");
424 				break;
425 			}
426 
427 			usleep_range(100, 200);
428 		}
429 	}
430 
431 	stream_env->stream_state = CSS_STREAM_STOPPED;
432 
433 	if (ia_css_stream_destroy(stream_env->stream)) {
434 		dev_err(isp->dev, "destroy stream failed.\n");
435 		return -EINVAL;
436 	}
437 	stream_env->stream_state = CSS_STREAM_UNINIT;
438 	stream_env->stream = NULL;
439 
440 	return 0;
441 }
442 
443 static int __destroy_streams(struct atomisp_sub_device *asd)
444 {
445 	int ret, i;
446 
447 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
448 		ret = __destroy_stream(asd, &asd->stream_env[i]);
449 		if (ret)
450 			return ret;
451 	}
452 	asd->stream_prepared = false;
453 	return 0;
454 }
455 
456 static int __create_stream(struct atomisp_sub_device *asd,
457 			   struct atomisp_stream_env *stream_env)
458 {
459 	int pipe_index = 0, i;
460 	struct ia_css_pipe *multi_pipes[IA_CSS_PIPE_ID_NUM];
461 
462 	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
463 		if (stream_env->pipes[i])
464 			multi_pipes[pipe_index++] = stream_env->pipes[i];
465 	}
466 	if (pipe_index == 0)
467 		return 0;
468 
469 	stream_env->stream_config.target_num_cont_raw_buf =
470 	    asd->continuous_raw_buffer_size->val;
471 	stream_env->stream_config.channel_id = stream_env->ch_id;
472 	stream_env->stream_config.ia_css_enable_raw_buffer_locking =
473 	    asd->enable_raw_buffer_lock->val;
474 
475 	__dump_stream_config(asd, stream_env);
476 	if (ia_css_stream_create(&stream_env->stream_config,
477 				 pipe_index, multi_pipes, &stream_env->stream) != 0)
478 		return -EINVAL;
479 	if (ia_css_stream_get_info(stream_env->stream,
480 				   &stream_env->stream_info) != 0) {
481 		ia_css_stream_destroy(stream_env->stream);
482 		stream_env->stream = NULL;
483 		return -EINVAL;
484 	}
485 
486 	stream_env->stream_state = CSS_STREAM_CREATED;
487 	return 0;
488 }
489 
490 static int __create_streams(struct atomisp_sub_device *asd)
491 {
492 	int ret, i;
493 
494 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
495 		ret = __create_stream(asd, &asd->stream_env[i]);
496 		if (ret)
497 			goto rollback;
498 	}
499 	asd->stream_prepared = true;
500 	return 0;
501 rollback:
502 	for (i--; i >= 0; i--)
503 		__destroy_stream(asd, &asd->stream_env[i]);
504 	return ret;
505 }
506 
507 static int __destroy_stream_pipes(struct atomisp_sub_device *asd,
508 				  struct atomisp_stream_env *stream_env)
509 {
510 	struct atomisp_device *isp = asd->isp;
511 	int ret = 0;
512 	int i;
513 
514 	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
515 		if (!stream_env->pipes[i])
516 			continue;
517 		if (ia_css_pipe_destroy(stream_env->pipes[i])
518 		    != 0) {
519 			dev_err(isp->dev,
520 				"destroy pipe[%d]failed.cannot recover.\n", i);
521 			ret = -EINVAL;
522 		}
523 		stream_env->pipes[i] = NULL;
524 		stream_env->update_pipe[i] = false;
525 	}
526 	return ret;
527 }
528 
529 static int __destroy_pipes(struct atomisp_sub_device *asd)
530 {
531 	struct atomisp_device *isp = asd->isp;
532 	int i;
533 	int ret = 0;
534 
535 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
536 		if (asd->stream_env[i].stream) {
537 			dev_err(isp->dev,
538 				"cannot destroy css pipes for stream[%d].\n",
539 				i);
540 			continue;
541 		}
542 
543 		ret = __destroy_stream_pipes(asd, &asd->stream_env[i]);
544 		if (ret)
545 			return ret;
546 	}
547 
548 	return 0;
549 }
550 
551 void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd)
552 {
553 	if (__destroy_streams(asd))
554 		dev_warn(asd->isp->dev, "destroy stream failed.\n");
555 
556 	if (__destroy_pipes(asd))
557 		dev_warn(asd->isp->dev, "destroy pipe failed.\n");
558 }
559 
560 static void __apply_additional_pipe_config(
561     struct atomisp_sub_device *asd,
562     struct atomisp_stream_env *stream_env,
563     enum ia_css_pipe_id pipe_id)
564 {
565 	struct atomisp_device *isp = asd->isp;
566 
567 	if (pipe_id < 0 || pipe_id >= IA_CSS_PIPE_ID_NUM) {
568 		dev_err(isp->dev,
569 			"wrong pipe_id for additional pipe config.\n");
570 		return;
571 	}
572 
573 	/* apply default pipe config */
574 	stream_env->pipe_configs[pipe_id].isp_pipe_version = 2;
575 	stream_env->pipe_configs[pipe_id].enable_dz =
576 	    asd->disable_dz->val ? false : true;
577 	/* apply isp 2.2 specific config for baytrail*/
578 	switch (pipe_id) {
579 	case IA_CSS_PIPE_ID_CAPTURE:
580 		/* enable capture pp/dz manually or digital zoom would
581 		 * fail*/
582 		if (stream_env->pipe_configs[pipe_id].
583 		    default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW)
584 			stream_env->pipe_configs[pipe_id].enable_dz = false;
585 		break;
586 	case IA_CSS_PIPE_ID_VIDEO:
587 		/* enable reduced pipe to have binary
588 		 * video_dz_2_min selected*/
589 		stream_env->pipe_extra_configs[pipe_id]
590 		.enable_reduced_pipe = true;
591 		stream_env->pipe_configs[pipe_id]
592 		.enable_dz = false;
593 
594 		if (asd->params.video_dis_en) {
595 			stream_env->pipe_extra_configs[pipe_id]
596 			.enable_dvs_6axis = true;
597 			stream_env->pipe_configs[pipe_id]
598 			.dvs_frame_delay =
599 			    ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
600 		}
601 		break;
602 	case IA_CSS_PIPE_ID_PREVIEW:
603 		break;
604 	case IA_CSS_PIPE_ID_YUVPP:
605 	case IA_CSS_PIPE_ID_COPY:
606 		stream_env->pipe_configs[pipe_id].enable_dz = false;
607 		break;
608 	default:
609 		break;
610 	}
611 }
612 
613 static bool is_pipe_valid_to_current_run_mode(struct atomisp_sub_device *asd,
614 	enum ia_css_pipe_id pipe_id)
615 {
616 	if (!asd)
617 		return false;
618 
619 	if (pipe_id == IA_CSS_PIPE_ID_YUVPP)
620 		return true;
621 
622 	if (asd->vfpp) {
623 		if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
624 			if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
625 				return true;
626 			else
627 				return false;
628 		} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
629 			if (pipe_id == IA_CSS_PIPE_ID_CAPTURE)
630 				return true;
631 			else
632 				return false;
633 		}
634 	}
635 
636 	if (!asd->run_mode)
637 		return false;
638 
639 	if (asd->copy_mode && pipe_id == IA_CSS_PIPE_ID_COPY)
640 		return true;
641 
642 	switch (asd->run_mode->val) {
643 	case ATOMISP_RUN_MODE_STILL_CAPTURE:
644 		if (pipe_id == IA_CSS_PIPE_ID_CAPTURE)
645 			return true;
646 
647 		return false;
648 	case ATOMISP_RUN_MODE_PREVIEW:
649 		if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
650 			return true;
651 
652 		return false;
653 	case ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE:
654 		if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
655 		    pipe_id == IA_CSS_PIPE_ID_PREVIEW)
656 			return true;
657 
658 		return false;
659 	case ATOMISP_RUN_MODE_VIDEO:
660 		if (pipe_id == IA_CSS_PIPE_ID_VIDEO || pipe_id == IA_CSS_PIPE_ID_YUVPP)
661 			return true;
662 
663 		return false;
664 	case ATOMISP_RUN_MODE_SDV:
665 		if (pipe_id == IA_CSS_PIPE_ID_CAPTURE ||
666 		    pipe_id == IA_CSS_PIPE_ID_VIDEO)
667 			return true;
668 
669 		return false;
670 	}
671 
672 	return false;
673 }
674 
675 static int __create_pipe(struct atomisp_sub_device *asd,
676 			 struct atomisp_stream_env *stream_env,
677 			 enum ia_css_pipe_id pipe_id)
678 {
679 	struct atomisp_device *isp = asd->isp;
680 	struct ia_css_pipe_extra_config extra_config;
681 	int ret;
682 
683 	if (pipe_id >= IA_CSS_PIPE_ID_NUM)
684 		return -EINVAL;
685 
686 	if (!stream_env->pipe_configs[pipe_id].output_info[0].res.width)
687 		return 0;
688 
689 	if (!is_pipe_valid_to_current_run_mode(asd, pipe_id))
690 		return 0;
691 
692 	ia_css_pipe_extra_config_defaults(&extra_config);
693 
694 	__apply_additional_pipe_config(asd, stream_env, pipe_id);
695 	if (!memcmp(&extra_config,
696 		    &stream_env->pipe_extra_configs[pipe_id],
697 		    sizeof(extra_config)))
698 		ret = ia_css_pipe_create(
699 			  &stream_env->pipe_configs[pipe_id],
700 			  &stream_env->pipes[pipe_id]);
701 	else
702 		ret = ia_css_pipe_create_extra(
703 			  &stream_env->pipe_configs[pipe_id],
704 			  &stream_env->pipe_extra_configs[pipe_id],
705 			  &stream_env->pipes[pipe_id]);
706 	if (ret)
707 		dev_err(isp->dev, "create pipe[%d] error.\n", pipe_id);
708 	return ret;
709 }
710 
711 static int __create_pipes(struct atomisp_sub_device *asd)
712 {
713 	int ret;
714 	int i, j;
715 
716 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
717 		for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
718 			ret = __create_pipe(asd, &asd->stream_env[i], j);
719 			if (ret)
720 				break;
721 		}
722 		if (j < IA_CSS_PIPE_ID_NUM)
723 			goto pipe_err;
724 	}
725 	return 0;
726 pipe_err:
727 	for (; i >= 0; i--) {
728 		for (j--; j >= 0; j--) {
729 			if (asd->stream_env[i].pipes[j]) {
730 				ia_css_pipe_destroy(asd->stream_env[i].pipes[j]);
731 				asd->stream_env[i].pipes[j] = NULL;
732 			}
733 		}
734 		j = IA_CSS_PIPE_ID_NUM;
735 	}
736 	return -EINVAL;
737 }
738 
739 int atomisp_create_pipes_stream(struct atomisp_sub_device *asd)
740 {
741 	int ret;
742 
743 	ret = __create_pipes(asd);
744 	if (ret) {
745 		dev_err(asd->isp->dev, "create pipe failed %d.\n", ret);
746 		return ret;
747 	}
748 
749 	ret = __create_streams(asd);
750 	if (ret) {
751 		dev_warn(asd->isp->dev, "create stream failed %d.\n", ret);
752 		__destroy_pipes(asd);
753 		return ret;
754 	}
755 
756 	return 0;
757 }
758 
759 int atomisp_css_update_stream(struct atomisp_sub_device *asd)
760 {
761 	atomisp_destroy_pipes_stream_force(asd);
762 	return atomisp_create_pipes_stream(asd);
763 }
764 
765 int atomisp_css_init(struct atomisp_device *isp)
766 {
767 	unsigned int mmu_base_addr;
768 	int ret;
769 	int err;
770 
771 	ret = hmm_get_mmu_base_addr(isp->dev, &mmu_base_addr);
772 	if (ret)
773 		return ret;
774 
775 	/* Init ISP */
776 	err = ia_css_init(isp->dev, &isp->css_env.isp_css_env, NULL,
777 			  (uint32_t)mmu_base_addr, IA_CSS_IRQ_TYPE_PULSE);
778 	if (err) {
779 		dev_err(isp->dev, "css init failed --- bad firmware?\n");
780 		return -EINVAL;
781 	}
782 	ia_css_enable_isys_event_queue(true);
783 
784 	isp->css_initialized = true;
785 	dev_dbg(isp->dev, "sh_css_init success\n");
786 
787 	return 0;
788 }
789 
790 static inline int __set_css_print_env(struct atomisp_device *isp, int opt)
791 {
792 	int ret = 0;
793 
794 	if (opt == 0)
795 		isp->css_env.isp_css_env.print_env.debug_print = NULL;
796 	else if (opt == 1)
797 		isp->css_env.isp_css_env.print_env.debug_print = atomisp_vprintk;
798 	else
799 		ret = -EINVAL;
800 
801 	return ret;
802 }
803 
804 int atomisp_css_load_firmware(struct atomisp_device *isp)
805 {
806 	int err;
807 
808 	/* set css env */
809 	isp->css_env.isp_css_fw.data = (void *)isp->firmware->data;
810 	isp->css_env.isp_css_fw.bytes = isp->firmware->size;
811 
812 	isp->css_env.isp_css_env.hw_access_env.store_8 =
813 	    atomisp_css2_hw_store_8;
814 	isp->css_env.isp_css_env.hw_access_env.store_16 =
815 	    atomisp_css2_hw_store_16;
816 	isp->css_env.isp_css_env.hw_access_env.store_32 =
817 	    atomisp_css2_hw_store_32;
818 
819 	isp->css_env.isp_css_env.hw_access_env.load_8 = atomisp_css2_hw_load_8;
820 	isp->css_env.isp_css_env.hw_access_env.load_16 =
821 	    atomisp_css2_hw_load_16;
822 	isp->css_env.isp_css_env.hw_access_env.load_32 =
823 	    atomisp_css2_hw_load_32;
824 
825 	isp->css_env.isp_css_env.hw_access_env.load = atomisp_css2_hw_load;
826 	isp->css_env.isp_css_env.hw_access_env.store = atomisp_css2_hw_store;
827 
828 	__set_css_print_env(isp, dbg_func);
829 
830 	isp->css_env.isp_css_env.print_env.error_print = atomisp_vprintk;
831 
832 	/* load isp fw into ISP memory */
833 	err = ia_css_load_firmware(isp->dev, &isp->css_env.isp_css_env,
834 				   &isp->css_env.isp_css_fw);
835 	if (err) {
836 		dev_err(isp->dev, "css load fw failed.\n");
837 		return -EINVAL;
838 	}
839 
840 	return 0;
841 }
842 
843 void atomisp_css_uninit(struct atomisp_device *isp)
844 {
845 	isp->css_initialized = false;
846 	ia_css_uninit();
847 }
848 
849 int atomisp_css_irq_translate(struct atomisp_device *isp,
850 			      unsigned int *infos)
851 {
852 	int err;
853 
854 	err = ia_css_irq_translate(infos);
855 	if (err) {
856 		dev_warn(isp->dev,
857 			 "%s:failed to translate irq (err = %d,infos = %d)\n",
858 			 __func__, err, *infos);
859 		return -EINVAL;
860 	}
861 
862 	return 0;
863 }
864 
865 void atomisp_css_rx_get_irq_info(enum mipi_port_id port,
866 				 unsigned int *infos)
867 {
868 #ifndef ISP2401
869 	ia_css_isys_rx_get_irq_info(port, infos);
870 #else
871 	*infos = 0;
872 #endif
873 }
874 
875 void atomisp_css_rx_clear_irq_info(enum mipi_port_id port,
876 				   unsigned int infos)
877 {
878 #ifndef ISP2401
879 	ia_css_isys_rx_clear_irq_info(port, infos);
880 #endif
881 }
882 
883 int atomisp_css_irq_enable(struct atomisp_device *isp,
884 			   enum ia_css_irq_info info, bool enable)
885 {
886 	dev_dbg(isp->dev, "%s: css irq info 0x%08x: %s (%d).\n",
887 		__func__, info,
888 		enable ? "enable" : "disable", enable);
889 	if (ia_css_irq_enable(info, enable)) {
890 		dev_warn(isp->dev, "%s:Invalid irq info: 0x%08x when %s.\n",
891 			 __func__, info,
892 			 enable ? "enabling" : "disabling");
893 		return -EINVAL;
894 	}
895 
896 	return 0;
897 }
898 
899 void atomisp_css_init_struct(struct atomisp_sub_device *asd)
900 {
901 	int i, j;
902 
903 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
904 		asd->stream_env[i].stream = NULL;
905 		for (j = 0; j < IA_CSS_PIPE_MODE_NUM; j++) {
906 			asd->stream_env[i].pipes[j] = NULL;
907 			asd->stream_env[i].update_pipe[j] = false;
908 			ia_css_pipe_config_defaults(
909 			    &asd->stream_env[i].pipe_configs[j]);
910 			ia_css_pipe_extra_config_defaults(
911 			    &asd->stream_env[i].pipe_extra_configs[j]);
912 		}
913 		ia_css_stream_config_defaults(&asd->stream_env[i].stream_config);
914 	}
915 }
916 
917 int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
918 				  struct ia_css_frame *frame,
919 				  enum atomisp_input_stream_id stream_id,
920 				  enum ia_css_buffer_type css_buf_type,
921 				  enum ia_css_pipe_id css_pipe_id)
922 {
923 	struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
924 	struct ia_css_buffer css_buf = {0};
925 	int err;
926 
927 	css_buf.type = css_buf_type;
928 	css_buf.data.frame = frame;
929 
930 	err = ia_css_pipe_enqueue_buffer(
931 		  stream_env->pipes[css_pipe_id], &css_buf);
932 	if (err)
933 		return -EINVAL;
934 
935 	return 0;
936 }
937 
938 int atomisp_q_metadata_buffer_to_css(struct atomisp_sub_device *asd,
939 				     struct atomisp_metadata_buf *metadata_buf,
940 				     enum atomisp_input_stream_id stream_id,
941 				     enum ia_css_pipe_id css_pipe_id)
942 {
943 	struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
944 	struct ia_css_buffer buffer = {0};
945 	struct atomisp_device *isp = asd->isp;
946 
947 	buffer.type = IA_CSS_BUFFER_TYPE_METADATA;
948 	buffer.data.metadata = metadata_buf->metadata;
949 	if (ia_css_pipe_enqueue_buffer(stream_env->pipes[css_pipe_id],
950 				       &buffer)) {
951 		dev_err(isp->dev, "failed to q meta data buffer\n");
952 		return -EINVAL;
953 	}
954 
955 	return 0;
956 }
957 
958 int atomisp_q_s3a_buffer_to_css(struct atomisp_sub_device *asd,
959 				struct atomisp_s3a_buf *s3a_buf,
960 				enum atomisp_input_stream_id stream_id,
961 				enum ia_css_pipe_id css_pipe_id)
962 {
963 	struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
964 	struct ia_css_buffer buffer = {0};
965 	struct atomisp_device *isp = asd->isp;
966 
967 	buffer.type = IA_CSS_BUFFER_TYPE_3A_STATISTICS;
968 	buffer.data.stats_3a = s3a_buf->s3a_data;
969 	if (ia_css_pipe_enqueue_buffer(
970 		stream_env->pipes[css_pipe_id],
971 		&buffer)) {
972 		dev_dbg(isp->dev, "failed to q s3a stat buffer\n");
973 		return -EINVAL;
974 	}
975 
976 	return 0;
977 }
978 
979 int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd,
980 				struct atomisp_dis_buf *dis_buf,
981 				enum atomisp_input_stream_id stream_id,
982 				enum ia_css_pipe_id css_pipe_id)
983 {
984 	struct atomisp_stream_env *stream_env = &asd->stream_env[stream_id];
985 	struct ia_css_buffer buffer = {0};
986 	struct atomisp_device *isp = asd->isp;
987 
988 	buffer.type = IA_CSS_BUFFER_TYPE_DIS_STATISTICS;
989 	buffer.data.stats_dvs = dis_buf->dis_data;
990 	if (ia_css_pipe_enqueue_buffer(
991 		stream_env->pipes[css_pipe_id],
992 		&buffer)) {
993 		dev_dbg(isp->dev, "failed to q dvs stat buffer\n");
994 		return -EINVAL;
995 	}
996 
997 	return 0;
998 }
999 
1000 int atomisp_css_start(struct atomisp_sub_device *asd,
1001 		      enum ia_css_pipe_id pipe_id, bool in_reset)
1002 {
1003 	struct atomisp_device *isp = asd->isp;
1004 	bool sp_is_started = false;
1005 	int ret = 0, i = 0;
1006 
1007 	if (in_reset) {
1008 		ret = atomisp_css_update_stream(asd);
1009 		if (ret)
1010 			return ret;
1011 
1012 		/* Invalidate caches. FIXME: should flush only necessary buffers */
1013 		wbinvd();
1014 	}
1015 
1016 	/*
1017 	 * For dual steam case, it is possible that:
1018 	 * 1: for this stream, it is at the stage that:
1019 	 * - after set_fmt is called
1020 	 * - before stream on is called
1021 	 * 2: for the other stream, the stream off is called which css reset
1022 	 * has been done.
1023 	 *
1024 	 * Thus the stream created in set_fmt get destroyed and need to be
1025 	 * recreated in the next stream on.
1026 	 */
1027 	if (!asd->stream_prepared) {
1028 		ret = atomisp_create_pipes_stream(asd);
1029 		if (ret)
1030 			return ret;
1031 	}
1032 	/*
1033 	 * SP can only be started one time
1034 	 * if atomisp_subdev_streaming_count() tell there already has some
1035 	 * subdev at streamming, then SP should already be started previously,
1036 	 * so need to skip start sp procedure
1037 	 */
1038 	if (atomisp_streaming_count(isp)) {
1039 		dev_dbg(isp->dev, "skip start sp\n");
1040 	} else {
1041 		if (!sh_css_hrt_system_is_idle())
1042 			dev_err(isp->dev, "CSS HW not idle before starting SP\n");
1043 		if (ia_css_start_sp()) {
1044 			dev_err(isp->dev, "start sp error.\n");
1045 			ret = -EINVAL;
1046 			goto start_err;
1047 		} else {
1048 			sp_is_started = true;
1049 		}
1050 	}
1051 
1052 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1053 		if (asd->stream_env[i].stream) {
1054 			if (ia_css_stream_start(asd->stream_env[i]
1055 						.stream) != 0) {
1056 				dev_err(isp->dev, "stream[%d] start error.\n", i);
1057 				ret = -EINVAL;
1058 				goto start_err;
1059 			} else {
1060 				asd->stream_env[i].stream_state = CSS_STREAM_STARTED;
1061 				dev_dbg(isp->dev, "stream[%d] started.\n", i);
1062 			}
1063 		}
1064 	}
1065 
1066 	return 0;
1067 
1068 start_err:
1069 	atomisp_destroy_pipes_stream_force(asd);
1070 
1071 	/* css 2.0 API limitation: ia_css_stop_sp() could be only called after
1072 	 * destroy all pipes
1073 	 */
1074 	/*
1075 	 * SP can not be stop if other streams are in use
1076 	 */
1077 	if ((atomisp_streaming_count(isp) == 0) && sp_is_started)
1078 		ia_css_stop_sp();
1079 
1080 	return ret;
1081 }
1082 
1083 void atomisp_css_update_isp_params(struct atomisp_sub_device *asd)
1084 {
1085 	/*
1086 	 * FIXME!
1087 	 * for ISP2401 new input system, this api is under development.
1088 	 * Calling it would cause kernel panic.
1089 	 *
1090 	 * VIED BZ: 1458
1091 	 *
1092 	 * Check if it is Cherry Trail and also new input system
1093 	 */
1094 	if (asd->copy_mode) {
1095 		dev_warn(asd->isp->dev,
1096 			 "%s: ia_css_stream_set_isp_config() not supported in copy mode!.\n",
1097 			 __func__);
1098 		return;
1099 	}
1100 
1101 	ia_css_stream_set_isp_config(
1102 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
1103 	    &asd->params.config);
1104 	memset(&asd->params.config, 0, sizeof(asd->params.config));
1105 }
1106 
1107 void atomisp_css_update_isp_params_on_pipe(struct atomisp_sub_device *asd,
1108 	struct ia_css_pipe *pipe)
1109 {
1110 	int ret;
1111 
1112 	if (!pipe) {
1113 		atomisp_css_update_isp_params(asd);
1114 		return;
1115 	}
1116 
1117 	dev_dbg(asd->isp->dev,
1118 		"%s: apply parameter for ia_css_frame %p with isp_config_id %d on pipe %p.\n",
1119 		__func__, asd->params.config.output_frame,
1120 		asd->params.config.isp_config_id, pipe);
1121 
1122 	ret = ia_css_stream_set_isp_config_on_pipe(
1123 		  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
1124 		  &asd->params.config, pipe);
1125 	if (ret)
1126 		dev_warn(asd->isp->dev, "%s: ia_css_stream_set_isp_config_on_pipe failed %d\n",
1127 			 __func__, ret);
1128 	memset(&asd->params.config, 0, sizeof(asd->params.config));
1129 }
1130 
1131 int atomisp_css_queue_buffer(struct atomisp_sub_device *asd,
1132 			     enum atomisp_input_stream_id stream_id,
1133 			     enum ia_css_pipe_id pipe_id,
1134 			     enum ia_css_buffer_type buf_type,
1135 			     struct atomisp_css_buffer *isp_css_buffer)
1136 {
1137 	if (ia_css_pipe_enqueue_buffer(
1138 		asd->stream_env[stream_id].pipes[pipe_id],
1139 		&isp_css_buffer->css_buffer)
1140 	    != 0)
1141 		return -EINVAL;
1142 
1143 	return 0;
1144 }
1145 
1146 int atomisp_css_dequeue_buffer(struct atomisp_sub_device *asd,
1147 			       enum atomisp_input_stream_id stream_id,
1148 			       enum ia_css_pipe_id pipe_id,
1149 			       enum ia_css_buffer_type buf_type,
1150 			       struct atomisp_css_buffer *isp_css_buffer)
1151 {
1152 	struct atomisp_device *isp = asd->isp;
1153 	int err;
1154 
1155 	err = ia_css_pipe_dequeue_buffer(
1156 		  asd->stream_env[stream_id].pipes[pipe_id],
1157 		  &isp_css_buffer->css_buffer);
1158 	if (err) {
1159 		dev_err(isp->dev,
1160 			"ia_css_pipe_dequeue_buffer failed: 0x%x\n", err);
1161 		return -EINVAL;
1162 	}
1163 
1164 	return 0;
1165 }
1166 
1167 int atomisp_css_allocate_stat_buffers(struct atomisp_sub_device   *asd,
1168 				      u16 stream_id,
1169 				      struct atomisp_s3a_buf      *s3a_buf,
1170 				      struct atomisp_dis_buf      *dis_buf,
1171 				      struct atomisp_metadata_buf *md_buf)
1172 {
1173 	struct atomisp_device *isp = asd->isp;
1174 	struct ia_css_dvs_grid_info *dvs_grid_info =
1175 	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1176 
1177 	if (s3a_buf && asd->params.curr_grid_info.s3a_grid.enable) {
1178 		void *s3a_ptr;
1179 
1180 		s3a_buf->s3a_data = ia_css_isp_3a_statistics_allocate(
1181 					&asd->params.curr_grid_info.s3a_grid);
1182 		if (!s3a_buf->s3a_data) {
1183 			dev_err(isp->dev, "3a buf allocation failed.\n");
1184 			return -EINVAL;
1185 		}
1186 
1187 		s3a_ptr = hmm_vmap(s3a_buf->s3a_data->data_ptr, true);
1188 		s3a_buf->s3a_map = ia_css_isp_3a_statistics_map_allocate(
1189 				       s3a_buf->s3a_data, s3a_ptr);
1190 	}
1191 
1192 	if (dis_buf && dvs_grid_info && dvs_grid_info->enable) {
1193 		void *dvs_ptr;
1194 
1195 		dis_buf->dis_data = ia_css_isp_dvs2_statistics_allocate(
1196 					dvs_grid_info);
1197 		if (!dis_buf->dis_data) {
1198 			dev_err(isp->dev, "dvs buf allocation failed.\n");
1199 			if (s3a_buf)
1200 				ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1201 			return -EINVAL;
1202 		}
1203 
1204 		dvs_ptr = hmm_vmap(dis_buf->dis_data->data_ptr, true);
1205 		dis_buf->dvs_map = ia_css_isp_dvs_statistics_map_allocate(
1206 				       dis_buf->dis_data, dvs_ptr);
1207 	}
1208 
1209 	if (asd->stream_env[stream_id].stream_info.
1210 	    metadata_info.size && md_buf) {
1211 		md_buf->metadata = ia_css_metadata_allocate(
1212 				       &asd->stream_env[stream_id].stream_info.metadata_info);
1213 		if (!md_buf->metadata) {
1214 			if (s3a_buf)
1215 				ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1216 			if (dis_buf)
1217 				ia_css_isp_dvs2_statistics_free(dis_buf->dis_data);
1218 			dev_err(isp->dev, "metadata buf allocation failed.\n");
1219 			return -EINVAL;
1220 		}
1221 		md_buf->md_vptr = hmm_vmap(md_buf->metadata->address, false);
1222 	}
1223 
1224 	return 0;
1225 }
1226 
1227 void atomisp_css_free_3a_buffer(struct atomisp_s3a_buf *s3a_buf)
1228 {
1229 	if (s3a_buf->s3a_data)
1230 		hmm_vunmap(s3a_buf->s3a_data->data_ptr);
1231 
1232 	ia_css_isp_3a_statistics_map_free(s3a_buf->s3a_map);
1233 	s3a_buf->s3a_map = NULL;
1234 	ia_css_isp_3a_statistics_free(s3a_buf->s3a_data);
1235 }
1236 
1237 void atomisp_css_free_dis_buffer(struct atomisp_dis_buf *dis_buf)
1238 {
1239 	if (dis_buf->dis_data)
1240 		hmm_vunmap(dis_buf->dis_data->data_ptr);
1241 
1242 	ia_css_isp_dvs_statistics_map_free(dis_buf->dvs_map);
1243 	dis_buf->dvs_map = NULL;
1244 	ia_css_isp_dvs2_statistics_free(dis_buf->dis_data);
1245 }
1246 
1247 void atomisp_css_free_metadata_buffer(struct atomisp_metadata_buf *metadata_buf)
1248 {
1249 	if (metadata_buf->md_vptr) {
1250 		hmm_vunmap(metadata_buf->metadata->address);
1251 		metadata_buf->md_vptr = NULL;
1252 	}
1253 	ia_css_metadata_free(metadata_buf->metadata);
1254 }
1255 
1256 void atomisp_css_free_stat_buffers(struct atomisp_sub_device *asd)
1257 {
1258 	struct atomisp_s3a_buf *s3a_buf, *_s3a_buf;
1259 	struct atomisp_dis_buf *dis_buf, *_dis_buf;
1260 	struct atomisp_metadata_buf *md_buf, *_md_buf;
1261 	struct ia_css_dvs_grid_info *dvs_grid_info =
1262 	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1263 	unsigned int i;
1264 
1265 	/* 3A statistics use vmalloc, DIS use kmalloc */
1266 	if (dvs_grid_info && dvs_grid_info->enable) {
1267 		ia_css_dvs2_coefficients_free(asd->params.css_param.dvs2_coeff);
1268 		ia_css_dvs2_statistics_free(asd->params.dvs_stat);
1269 		asd->params.css_param.dvs2_coeff = NULL;
1270 		asd->params.dvs_stat = NULL;
1271 		asd->params.dvs_hor_proj_bytes = 0;
1272 		asd->params.dvs_ver_proj_bytes = 0;
1273 		asd->params.dvs_hor_coef_bytes = 0;
1274 		asd->params.dvs_ver_coef_bytes = 0;
1275 		asd->params.dis_proj_data_valid = false;
1276 		list_for_each_entry_safe(dis_buf, _dis_buf,
1277 					 &asd->dis_stats, list) {
1278 			atomisp_css_free_dis_buffer(dis_buf);
1279 			list_del(&dis_buf->list);
1280 			kfree(dis_buf);
1281 		}
1282 		list_for_each_entry_safe(dis_buf, _dis_buf,
1283 					 &asd->dis_stats_in_css, list) {
1284 			atomisp_css_free_dis_buffer(dis_buf);
1285 			list_del(&dis_buf->list);
1286 			kfree(dis_buf);
1287 		}
1288 	}
1289 	if (asd->params.curr_grid_info.s3a_grid.enable) {
1290 		ia_css_3a_statistics_free(asd->params.s3a_user_stat);
1291 		asd->params.s3a_user_stat = NULL;
1292 		asd->params.s3a_output_bytes = 0;
1293 		list_for_each_entry_safe(s3a_buf, _s3a_buf,
1294 					 &asd->s3a_stats, list) {
1295 			atomisp_css_free_3a_buffer(s3a_buf);
1296 			list_del(&s3a_buf->list);
1297 			kfree(s3a_buf);
1298 		}
1299 		list_for_each_entry_safe(s3a_buf, _s3a_buf,
1300 					 &asd->s3a_stats_in_css, list) {
1301 			atomisp_css_free_3a_buffer(s3a_buf);
1302 			list_del(&s3a_buf->list);
1303 			kfree(s3a_buf);
1304 		}
1305 		list_for_each_entry_safe(s3a_buf, _s3a_buf,
1306 					 &asd->s3a_stats_ready, list) {
1307 			atomisp_css_free_3a_buffer(s3a_buf);
1308 			list_del(&s3a_buf->list);
1309 			kfree(s3a_buf);
1310 		}
1311 	}
1312 
1313 	if (asd->params.css_param.dvs_6axis) {
1314 		ia_css_dvs2_6axis_config_free(asd->params.css_param.dvs_6axis);
1315 		asd->params.css_param.dvs_6axis = NULL;
1316 	}
1317 
1318 	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1319 		list_for_each_entry_safe(md_buf, _md_buf,
1320 					 &asd->metadata[i], list) {
1321 			atomisp_css_free_metadata_buffer(md_buf);
1322 			list_del(&md_buf->list);
1323 			kfree(md_buf);
1324 		}
1325 		list_for_each_entry_safe(md_buf, _md_buf,
1326 					 &asd->metadata_in_css[i], list) {
1327 			atomisp_css_free_metadata_buffer(md_buf);
1328 			list_del(&md_buf->list);
1329 			kfree(md_buf);
1330 		}
1331 		list_for_each_entry_safe(md_buf, _md_buf,
1332 					 &asd->metadata_ready[i], list) {
1333 			atomisp_css_free_metadata_buffer(md_buf);
1334 			list_del(&md_buf->list);
1335 			kfree(md_buf);
1336 		}
1337 	}
1338 	asd->params.metadata_width_size = 0;
1339 	atomisp_free_metadata_output_buf(asd);
1340 }
1341 
1342 int atomisp_css_get_grid_info(struct atomisp_sub_device *asd,
1343 			      enum ia_css_pipe_id pipe_id,
1344 			      int source_pad)
1345 {
1346 	struct ia_css_pipe_info p_info;
1347 	struct ia_css_grid_info old_info;
1348 	struct atomisp_device *isp = asd->isp;
1349 	int md_width = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
1350 		       stream_config.metadata_config.resolution.width;
1351 
1352 	memset(&p_info, 0, sizeof(struct ia_css_pipe_info));
1353 	memset(&old_info, 0, sizeof(struct ia_css_grid_info));
1354 
1355 	if (ia_css_pipe_get_info(
1356 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id],
1357 		&p_info) != 0) {
1358 		dev_err(isp->dev, "ia_css_pipe_get_info failed\n");
1359 		return -EINVAL;
1360 	}
1361 
1362 	memcpy(&old_info, &asd->params.curr_grid_info,
1363 	       sizeof(struct ia_css_grid_info));
1364 	memcpy(&asd->params.curr_grid_info, &p_info.grid_info,
1365 	       sizeof(struct ia_css_grid_info));
1366 	/*
1367 	 * Record which css pipe enables s3a_grid.
1368 	 * Currently would have one css pipe that need it
1369 	 */
1370 	if (asd->params.curr_grid_info.s3a_grid.enable) {
1371 		if (asd->params.s3a_enabled_pipe != IA_CSS_PIPE_ID_NUM)
1372 			dev_dbg(isp->dev, "css pipe %d enabled s3a grid replaced by: %d.\n",
1373 				asd->params.s3a_enabled_pipe, pipe_id);
1374 		asd->params.s3a_enabled_pipe = pipe_id;
1375 	}
1376 
1377 	/* If the grid info has not changed and the buffers for 3A and
1378 	 * DIS statistics buffers are allocated or buffer size would be zero
1379 	 * then no need to do anything. */
1380 	if (((!memcmp(&old_info, &asd->params.curr_grid_info, sizeof(old_info))
1381 	      && asd->params.s3a_user_stat && asd->params.dvs_stat)
1382 	     || asd->params.curr_grid_info.s3a_grid.width == 0
1383 	     || asd->params.curr_grid_info.s3a_grid.height == 0)
1384 	    && asd->params.metadata_width_size == md_width) {
1385 		dev_dbg(isp->dev,
1386 			"grid info change escape. memcmp=%d, s3a_user_stat=%d,dvs_stat=%d, s3a.width=%d, s3a.height=%d, metadata width =%d\n",
1387 			!memcmp(&old_info, &asd->params.curr_grid_info,
1388 				sizeof(old_info)),
1389 			!!asd->params.s3a_user_stat, !!asd->params.dvs_stat,
1390 			asd->params.curr_grid_info.s3a_grid.width,
1391 			asd->params.curr_grid_info.s3a_grid.height,
1392 			asd->params.metadata_width_size);
1393 		return -EINVAL;
1394 	}
1395 	asd->params.metadata_width_size = md_width;
1396 
1397 	return 0;
1398 }
1399 
1400 int atomisp_alloc_3a_output_buf(struct atomisp_sub_device *asd)
1401 {
1402 	if (!asd->params.curr_grid_info.s3a_grid.width ||
1403 	    !asd->params.curr_grid_info.s3a_grid.height)
1404 		return 0;
1405 
1406 	asd->params.s3a_user_stat = ia_css_3a_statistics_allocate(
1407 					&asd->params.curr_grid_info.s3a_grid);
1408 	if (!asd->params.s3a_user_stat)
1409 		return -ENOMEM;
1410 	/* 3A statistics. These can be big, so we use vmalloc. */
1411 	asd->params.s3a_output_bytes =
1412 	    asd->params.curr_grid_info.s3a_grid.width *
1413 	    asd->params.curr_grid_info.s3a_grid.height *
1414 	    sizeof(*asd->params.s3a_user_stat->data);
1415 
1416 	return 0;
1417 }
1418 
1419 int atomisp_alloc_dis_coef_buf(struct atomisp_sub_device *asd)
1420 {
1421 	struct ia_css_dvs_grid_info *dvs_grid =
1422 	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
1423 
1424 	if (!dvs_grid)
1425 		return 0;
1426 
1427 	if (!dvs_grid->enable) {
1428 		dev_dbg(asd->isp->dev, "%s: dvs_grid not enabled.\n", __func__);
1429 		return 0;
1430 	}
1431 
1432 	/* DIS coefficients. */
1433 	asd->params.css_param.dvs2_coeff = ia_css_dvs2_coefficients_allocate(
1434 					       dvs_grid);
1435 	if (!asd->params.css_param.dvs2_coeff)
1436 		return -ENOMEM;
1437 
1438 	asd->params.dvs_hor_coef_bytes = dvs_grid->num_hor_coefs *
1439 					 sizeof(*asd->params.css_param.dvs2_coeff->hor_coefs.odd_real);
1440 
1441 	asd->params.dvs_ver_coef_bytes = dvs_grid->num_ver_coefs *
1442 					 sizeof(*asd->params.css_param.dvs2_coeff->ver_coefs.odd_real);
1443 
1444 	/* DIS projections. */
1445 	asd->params.dis_proj_data_valid = false;
1446 	asd->params.dvs_stat = ia_css_dvs2_statistics_allocate(dvs_grid);
1447 	if (!asd->params.dvs_stat)
1448 		return -ENOMEM;
1449 
1450 	asd->params.dvs_hor_proj_bytes =
1451 	    dvs_grid->aligned_height * dvs_grid->aligned_width *
1452 	    sizeof(*asd->params.dvs_stat->hor_prod.odd_real);
1453 
1454 	asd->params.dvs_ver_proj_bytes =
1455 	    dvs_grid->aligned_height * dvs_grid->aligned_width *
1456 	    sizeof(*asd->params.dvs_stat->ver_prod.odd_real);
1457 
1458 	return 0;
1459 }
1460 
1461 int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd)
1462 {
1463 	int i;
1464 
1465 	/* We allocate the cpu-side buffer used for communication with user
1466 	 * space */
1467 	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1468 		asd->params.metadata_user[i] = kvmalloc(
1469 						   asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
1470 						   stream_info.metadata_info.size, GFP_KERNEL);
1471 		if (!asd->params.metadata_user[i]) {
1472 			while (--i >= 0) {
1473 				kvfree(asd->params.metadata_user[i]);
1474 				asd->params.metadata_user[i] = NULL;
1475 			}
1476 			return -ENOMEM;
1477 		}
1478 	}
1479 
1480 	return 0;
1481 }
1482 
1483 void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd)
1484 {
1485 	unsigned int i;
1486 
1487 	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1488 		if (asd->params.metadata_user[i]) {
1489 			kvfree(asd->params.metadata_user[i]);
1490 			asd->params.metadata_user[i] = NULL;
1491 		}
1492 	}
1493 }
1494 
1495 void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd,
1496 				      struct atomisp_css_event *current_event)
1497 {
1498 	/*
1499 	 * FIXME!
1500 	 * Pipe ID reported in CSS event is not correct for new system's
1501 	 * copy pipe.
1502 	 * VIED BZ: 1463
1503 	 */
1504 	ia_css_temp_pipe_to_pipe_id(current_event->event.pipe,
1505 				    &current_event->pipe);
1506 	if (asd && asd->copy_mode &&
1507 	    current_event->pipe == IA_CSS_PIPE_ID_CAPTURE)
1508 		current_event->pipe = IA_CSS_PIPE_ID_COPY;
1509 }
1510 
1511 int atomisp_css_isys_set_resolution(struct atomisp_sub_device *asd,
1512 				    enum atomisp_input_stream_id stream_id,
1513 				    struct v4l2_mbus_framefmt *ffmt,
1514 				    int isys_stream)
1515 {
1516 	struct ia_css_stream_config *s_config =
1517 		    &asd->stream_env[stream_id].stream_config;
1518 
1519 	if (isys_stream >= IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH)
1520 		return -EINVAL;
1521 
1522 	s_config->isys_config[isys_stream].input_res.width = ffmt->width;
1523 	s_config->isys_config[isys_stream].input_res.height = ffmt->height;
1524 	return 0;
1525 }
1526 
1527 int atomisp_css_input_set_resolution(struct atomisp_sub_device *asd,
1528 				     enum atomisp_input_stream_id stream_id,
1529 				     struct v4l2_mbus_framefmt *ffmt)
1530 {
1531 	struct ia_css_stream_config *s_config =
1532 		    &asd->stream_env[stream_id].stream_config;
1533 
1534 	s_config->input_config.input_res.width = ffmt->width;
1535 	s_config->input_config.input_res.height = ffmt->height;
1536 	return 0;
1537 }
1538 
1539 void atomisp_css_input_set_binning_factor(struct atomisp_sub_device *asd,
1540 	enum atomisp_input_stream_id stream_id,
1541 	unsigned int bin_factor)
1542 {
1543 	asd->stream_env[stream_id]
1544 	.stream_config.sensor_binning_factor = bin_factor;
1545 }
1546 
1547 void atomisp_css_input_set_bayer_order(struct atomisp_sub_device *asd,
1548 				       enum atomisp_input_stream_id stream_id,
1549 				       enum ia_css_bayer_order bayer_order)
1550 {
1551 	struct ia_css_stream_config *s_config =
1552 		    &asd->stream_env[stream_id].stream_config;
1553 	s_config->input_config.bayer_order = bayer_order;
1554 }
1555 
1556 void atomisp_css_isys_set_link(struct atomisp_sub_device *asd,
1557 			       enum atomisp_input_stream_id stream_id,
1558 			       int link,
1559 			       int isys_stream)
1560 {
1561 	struct ia_css_stream_config *s_config =
1562 		    &asd->stream_env[stream_id].stream_config;
1563 
1564 	s_config->isys_config[isys_stream].linked_isys_stream_id = link;
1565 }
1566 
1567 void atomisp_css_isys_set_valid(struct atomisp_sub_device *asd,
1568 				enum atomisp_input_stream_id stream_id,
1569 				bool valid,
1570 				int isys_stream)
1571 {
1572 	struct ia_css_stream_config *s_config =
1573 		    &asd->stream_env[stream_id].stream_config;
1574 
1575 	s_config->isys_config[isys_stream].valid = valid;
1576 }
1577 
1578 void atomisp_css_isys_set_format(struct atomisp_sub_device *asd,
1579 				 enum atomisp_input_stream_id stream_id,
1580 				 enum atomisp_input_format format,
1581 				 int isys_stream)
1582 {
1583 	struct ia_css_stream_config *s_config =
1584 		    &asd->stream_env[stream_id].stream_config;
1585 
1586 	s_config->isys_config[isys_stream].format = format;
1587 }
1588 
1589 void atomisp_css_input_set_format(struct atomisp_sub_device *asd,
1590 				  enum atomisp_input_stream_id stream_id,
1591 				  enum atomisp_input_format format)
1592 {
1593 	struct ia_css_stream_config *s_config =
1594 		    &asd->stream_env[stream_id].stream_config;
1595 
1596 	s_config->input_config.format = format;
1597 }
1598 
1599 int atomisp_css_set_default_isys_config(struct atomisp_sub_device *asd,
1600 					enum atomisp_input_stream_id stream_id,
1601 					struct v4l2_mbus_framefmt *ffmt)
1602 {
1603 	int i;
1604 	struct ia_css_stream_config *s_config =
1605 		    &asd->stream_env[stream_id].stream_config;
1606 	/*
1607 	 * Set all isys configs to not valid.
1608 	 * Currently we support only one stream per channel
1609 	 */
1610 	for (i = IA_CSS_STREAM_ISYS_STREAM_0;
1611 	     i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++)
1612 		s_config->isys_config[i].valid = false;
1613 
1614 	atomisp_css_isys_set_resolution(asd, stream_id, ffmt,
1615 					IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1616 	atomisp_css_isys_set_format(asd, stream_id,
1617 				    s_config->input_config.format,
1618 				    IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1619 	atomisp_css_isys_set_link(asd, stream_id, NO_LINK,
1620 				  IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1621 	atomisp_css_isys_set_valid(asd, stream_id, true,
1622 				   IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
1623 
1624 	return 0;
1625 }
1626 
1627 int atomisp_css_isys_two_stream_cfg(struct atomisp_sub_device *asd,
1628 				    enum atomisp_input_stream_id stream_id,
1629 				    enum atomisp_input_format input_format)
1630 {
1631 	struct ia_css_stream_config *s_config =
1632 		    &asd->stream_env[stream_id].stream_config;
1633 
1634 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width =
1635 	    s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width;
1636 
1637 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height =
1638 	    s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height / 2;
1639 
1640 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id
1641 	    = IA_CSS_STREAM_ISYS_STREAM_0;
1642 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format =
1643 	    ATOMISP_INPUT_FORMAT_USER_DEF1;
1644 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format =
1645 	    ATOMISP_INPUT_FORMAT_USER_DEF2;
1646 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true;
1647 	return 0;
1648 }
1649 
1650 void atomisp_css_isys_two_stream_cfg_update_stream1(
1651     struct atomisp_sub_device *asd,
1652     enum atomisp_input_stream_id stream_id,
1653     enum atomisp_input_format input_format,
1654     unsigned int width, unsigned int height)
1655 {
1656 	struct ia_css_stream_config *s_config =
1657 		    &asd->stream_env[stream_id].stream_config;
1658 
1659 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.width =
1660 	    width;
1661 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].input_res.height =
1662 	    height;
1663 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].format =
1664 	    input_format;
1665 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_0].valid = true;
1666 }
1667 
1668 void atomisp_css_isys_two_stream_cfg_update_stream2(
1669     struct atomisp_sub_device *asd,
1670     enum atomisp_input_stream_id stream_id,
1671     enum atomisp_input_format input_format,
1672     unsigned int width, unsigned int height)
1673 {
1674 	struct ia_css_stream_config *s_config =
1675 		    &asd->stream_env[stream_id].stream_config;
1676 
1677 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.width =
1678 	    width;
1679 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].input_res.height =
1680 	    height;
1681 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].linked_isys_stream_id
1682 	    = IA_CSS_STREAM_ISYS_STREAM_0;
1683 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].format =
1684 	    input_format;
1685 	s_config->isys_config[IA_CSS_STREAM_ISYS_STREAM_1].valid = true;
1686 }
1687 
1688 int atomisp_css_input_set_effective_resolution(
1689     struct atomisp_sub_device *asd,
1690     enum atomisp_input_stream_id stream_id,
1691     unsigned int width, unsigned int height)
1692 {
1693 	struct ia_css_stream_config *s_config =
1694 		    &asd->stream_env[stream_id].stream_config;
1695 	s_config->input_config.effective_res.width = width;
1696 	s_config->input_config.effective_res.height = height;
1697 	return 0;
1698 }
1699 
1700 void atomisp_css_video_set_dis_envelope(struct atomisp_sub_device *asd,
1701 					unsigned int dvs_w, unsigned int dvs_h)
1702 {
1703 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1704 	.pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.width = dvs_w;
1705 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1706 	.pipe_configs[IA_CSS_PIPE_ID_VIDEO].dvs_envelope.height = dvs_h;
1707 }
1708 
1709 void atomisp_css_input_set_two_pixels_per_clock(
1710     struct atomisp_sub_device *asd,
1711     bool two_ppc)
1712 {
1713 	int i;
1714 
1715 	if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1716 	    .stream_config.pixels_per_clock == (two_ppc ? 2 : 1))
1717 		return;
1718 
1719 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1720 	.stream_config.pixels_per_clock = (two_ppc ? 2 : 1);
1721 	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1722 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1723 		.update_pipe[i] = true;
1724 }
1725 
1726 void atomisp_css_enable_dz(struct atomisp_sub_device *asd, bool enable)
1727 {
1728 	int i;
1729 
1730 	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1731 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1732 		.pipe_configs[i].enable_dz = enable;
1733 }
1734 
1735 void atomisp_css_capture_set_mode(struct atomisp_sub_device *asd,
1736 				  enum ia_css_capture_mode mode)
1737 {
1738 	struct atomisp_stream_env *stream_env =
1739 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1740 
1741 	if (stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE]
1742 	    .default_capture_config.mode == mode)
1743 		return;
1744 
1745 	stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
1746 	default_capture_config.mode = mode;
1747 	stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
1748 }
1749 
1750 void atomisp_css_input_set_mode(struct atomisp_sub_device *asd,
1751 				enum ia_css_input_mode mode)
1752 {
1753 	int i;
1754 	struct atomisp_device *isp = asd->isp;
1755 	unsigned int size_mem_words;
1756 
1757 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++)
1758 		asd->stream_env[i].stream_config.mode = mode;
1759 
1760 	if (isp->inputs[asd->input_curr].type == TEST_PATTERN) {
1761 		struct ia_css_stream_config *s_config =
1762 			    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_config;
1763 		s_config->mode = IA_CSS_INPUT_MODE_TPG;
1764 		s_config->source.tpg.mode = IA_CSS_TPG_MODE_CHECKERBOARD;
1765 		s_config->source.tpg.x_mask = (1 << 4) - 1;
1766 		s_config->source.tpg.x_delta = -2;
1767 		s_config->source.tpg.y_mask = (1 << 4) - 1;
1768 		s_config->source.tpg.y_delta = 3;
1769 		s_config->source.tpg.xy_mask = (1 << 8) - 1;
1770 		return;
1771 	}
1772 
1773 	if (mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
1774 		return;
1775 
1776 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1777 		/*
1778 		 * TODO: sensor needs to export the embedded_data_size_words
1779 		 * information to atomisp for each setting.
1780 		 * Here using a large safe value.
1781 		 */
1782 		struct ia_css_stream_config *s_config =
1783 			    &asd->stream_env[i].stream_config;
1784 
1785 		if (s_config->input_config.input_res.width == 0)
1786 			continue;
1787 
1788 		if (ia_css_mipi_frame_calculate_size(
1789 			s_config->input_config.input_res.width,
1790 			s_config->input_config.input_res.height,
1791 			s_config->input_config.format,
1792 			true,
1793 			0x13000,
1794 			&size_mem_words) != 0) {
1795 			if (IS_MRFD)
1796 				size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_2;
1797 			else
1798 				size_mem_words = CSS_MIPI_FRAME_BUFFER_SIZE_1;
1799 			dev_warn(asd->isp->dev,
1800 				 "ia_css_mipi_frame_calculate_size failed,applying pre-defined MIPI buffer size %u.\n",
1801 				 size_mem_words);
1802 		}
1803 		s_config->mipi_buffer_config.size_mem_words = size_mem_words;
1804 		s_config->mipi_buffer_config.nof_mipi_buffers = 2;
1805 	}
1806 }
1807 
1808 void atomisp_css_capture_enable_online(struct atomisp_sub_device *asd,
1809 				       unsigned short stream_index, bool enable)
1810 {
1811 	struct atomisp_stream_env *stream_env =
1812 		    &asd->stream_env[stream_index];
1813 
1814 	if (stream_env->stream_config.online == !!enable)
1815 		return;
1816 
1817 	stream_env->stream_config.online = !!enable;
1818 	stream_env->update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
1819 }
1820 
1821 void atomisp_css_preview_enable_online(struct atomisp_sub_device *asd,
1822 				       unsigned short stream_index, bool enable)
1823 {
1824 	struct atomisp_stream_env *stream_env =
1825 		    &asd->stream_env[stream_index];
1826 	int i;
1827 
1828 	if (stream_env->stream_config.online != !!enable) {
1829 		stream_env->stream_config.online = !!enable;
1830 		for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1831 			stream_env->update_pipe[i] = true;
1832 	}
1833 }
1834 
1835 void atomisp_css_video_enable_online(struct atomisp_sub_device *asd,
1836 				     bool enable)
1837 {
1838 	struct atomisp_stream_env *stream_env =
1839 		    &asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO];
1840 	int i;
1841 
1842 	if (stream_env->stream_config.online != enable) {
1843 		stream_env->stream_config.online = enable;
1844 		for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1845 			stream_env->update_pipe[i] = true;
1846 	}
1847 }
1848 
1849 void atomisp_css_enable_continuous(struct atomisp_sub_device *asd,
1850 				   bool enable)
1851 {
1852 	struct atomisp_stream_env *stream_env =
1853 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1854 	int i;
1855 
1856 	if (stream_env->stream_config.continuous != !!enable) {
1857 		stream_env->stream_config.continuous = !!enable;
1858 		stream_env->stream_config.pack_raw_pixels = true;
1859 		for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1860 			stream_env->update_pipe[i] = true;
1861 	}
1862 }
1863 
1864 void atomisp_css_enable_cvf(struct atomisp_sub_device *asd,
1865 			    bool enable)
1866 {
1867 	struct atomisp_stream_env *stream_env =
1868 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1869 	int i;
1870 
1871 	if (stream_env->stream_config.disable_cont_viewfinder != !enable) {
1872 		stream_env->stream_config.disable_cont_viewfinder = !enable;
1873 		for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
1874 			stream_env->update_pipe[i] = true;
1875 	}
1876 }
1877 
1878 int atomisp_css_input_configure_port(
1879     struct atomisp_sub_device *asd,
1880     enum mipi_port_id port,
1881     unsigned int num_lanes,
1882     unsigned int timeout,
1883     unsigned int mipi_freq,
1884     enum atomisp_input_format metadata_format,
1885     unsigned int metadata_width,
1886     unsigned int metadata_height)
1887 {
1888 	int i;
1889 	struct atomisp_stream_env *stream_env;
1890 	/*
1891 	 * Calculate rx_count as follows:
1892 	 * Input: mipi_freq                 : CSI-2 bus frequency in Hz
1893 	 * UI = 1 / (2 * mipi_freq)         : period of one bit on the bus
1894 	 * min = 85e-9 + 6 * UI             : Limits for rx_count in seconds
1895 	 * max = 145e-9 + 10 * UI
1896 	 * rxcount0 = min / (4 / mipi_freq) : convert seconds to byte clocks
1897 	 * rxcount = rxcount0 - 2           : adjust for better results
1898 	 * The formula below is simplified version of the above with
1899 	 * 10-bit fixed points for improved accuracy.
1900 	 */
1901 	const unsigned int rxcount =
1902 	    min(((mipi_freq / 46000) - 1280) >> 10, 0xffU) * 0x01010101U;
1903 
1904 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1905 		stream_env = &asd->stream_env[i];
1906 		stream_env->stream_config.source.port.port = port;
1907 		stream_env->stream_config.source.port.num_lanes = num_lanes;
1908 		stream_env->stream_config.source.port.timeout = timeout;
1909 		if (mipi_freq)
1910 			stream_env->stream_config.source.port.rxcount = rxcount;
1911 		stream_env->stream_config.
1912 		metadata_config.data_type = metadata_format;
1913 		stream_env->stream_config.
1914 		metadata_config.resolution.width = metadata_width;
1915 		stream_env->stream_config.
1916 		metadata_config.resolution.height = metadata_height;
1917 	}
1918 
1919 	return 0;
1920 }
1921 
1922 void atomisp_css_stop(struct atomisp_sub_device *asd,
1923 		      enum ia_css_pipe_id pipe_id, bool in_reset)
1924 {
1925 	struct atomisp_device *isp = asd->isp;
1926 	unsigned long irqflags;
1927 	unsigned int i;
1928 
1929 	/* if is called in atomisp_reset(), force destroy streams and pipes */
1930 	atomisp_destroy_pipes_stream_force(asd);
1931 
1932 	atomisp_init_raw_buffer_bitmap(asd);
1933 
1934 	/*
1935 	 * SP can not be stop if other streams are in use
1936 	 */
1937 	if (atomisp_streaming_count(isp) == 0)
1938 		ia_css_stop_sp();
1939 
1940 	if (!in_reset) {
1941 		struct atomisp_stream_env *stream_env;
1942 		int i, j;
1943 
1944 		for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
1945 			stream_env = &asd->stream_env[i];
1946 			for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
1947 				ia_css_pipe_config_defaults(
1948 				    &stream_env->pipe_configs[j]);
1949 				ia_css_pipe_extra_config_defaults(
1950 				    &stream_env->pipe_extra_configs[j]);
1951 			}
1952 			ia_css_stream_config_defaults(
1953 			    &stream_env->stream_config);
1954 		}
1955 		memset(&asd->params.config, 0, sizeof(asd->params.config));
1956 		asd->params.css_update_params_needed = false;
1957 	}
1958 
1959 	/* move stats buffers to free queue list */
1960 	list_splice_init(&asd->s3a_stats_in_css, &asd->s3a_stats);
1961 	list_splice_init(&asd->s3a_stats_ready, &asd->s3a_stats);
1962 
1963 	spin_lock_irqsave(&asd->dis_stats_lock, irqflags);
1964 	list_splice_init(&asd->dis_stats_in_css, &asd->dis_stats);
1965 	asd->params.dis_proj_data_valid = false;
1966 	spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags);
1967 
1968 	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
1969 		list_splice_init(&asd->metadata_in_css[i], &asd->metadata[i]);
1970 		list_splice_init(&asd->metadata_ready[i], &asd->metadata[i]);
1971 	}
1972 
1973 	atomisp_flush_params_queue(&asd->video_out_capture);
1974 	atomisp_flush_params_queue(&asd->video_out_vf);
1975 	atomisp_flush_params_queue(&asd->video_out_preview);
1976 	atomisp_flush_params_queue(&asd->video_out_video_capture);
1977 	atomisp_free_css_parameters(&asd->params.css_param);
1978 	memset(&asd->params.css_param, 0, sizeof(asd->params.css_param));
1979 }
1980 
1981 void atomisp_css_continuous_set_num_raw_frames(
1982      struct atomisp_sub_device *asd,
1983      int num_frames)
1984 {
1985 	if (asd->enable_raw_buffer_lock->val) {
1986 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1987 		.stream_config.init_num_cont_raw_buf =
1988 		    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN;
1989 		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
1990 		    asd->params.video_dis_en)
1991 			asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1992 			.stream_config.init_num_cont_raw_buf +=
1993 			    ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
1994 	} else {
1995 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1996 		.stream_config.init_num_cont_raw_buf =
1997 		    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES;
1998 	}
1999 
2000 	if (asd->params.video_dis_en)
2001 		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2002 		.stream_config.init_num_cont_raw_buf +=
2003 		    ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
2004 
2005 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2006 	.stream_config.target_num_cont_raw_buf = num_frames;
2007 }
2008 
2009 static enum ia_css_pipe_mode __pipe_id_to_pipe_mode(
2010     struct atomisp_sub_device *asd,
2011     enum ia_css_pipe_id pipe_id)
2012 {
2013 	struct atomisp_device *isp = asd->isp;
2014 	struct camera_mipi_info *mipi_info = atomisp_to_sensor_mipi_info(
2015 		isp->inputs[asd->input_curr].camera);
2016 
2017 	switch (pipe_id) {
2018 	case IA_CSS_PIPE_ID_COPY:
2019 		/* Currently only YUVPP mode supports YUV420_Legacy format.
2020 		 * Revert this when other pipe modes can support
2021 		 * YUV420_Legacy format.
2022 		 */
2023 		if (mipi_info && mipi_info->input_format ==
2024 		    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY)
2025 			return IA_CSS_PIPE_MODE_YUVPP;
2026 		return IA_CSS_PIPE_MODE_COPY;
2027 	case IA_CSS_PIPE_ID_PREVIEW:
2028 		return IA_CSS_PIPE_MODE_PREVIEW;
2029 	case IA_CSS_PIPE_ID_CAPTURE:
2030 		return IA_CSS_PIPE_MODE_CAPTURE;
2031 	case IA_CSS_PIPE_ID_VIDEO:
2032 		return IA_CSS_PIPE_MODE_VIDEO;
2033 	case IA_CSS_PIPE_ID_YUVPP:
2034 		return IA_CSS_PIPE_MODE_YUVPP;
2035 	default:
2036 		WARN_ON(1);
2037 		return IA_CSS_PIPE_MODE_PREVIEW;
2038 	}
2039 }
2040 
2041 static void __configure_output(struct atomisp_sub_device *asd,
2042 			       unsigned int stream_index,
2043 			       unsigned int width, unsigned int height,
2044 			       unsigned int min_width,
2045 			       enum ia_css_frame_format format,
2046 			       enum ia_css_pipe_id pipe_id)
2047 {
2048 	struct atomisp_device *isp = asd->isp;
2049 	struct atomisp_stream_env *stream_env =
2050 		    &asd->stream_env[stream_index];
2051 	struct ia_css_stream_config *s_config = &stream_env->stream_config;
2052 
2053 	stream_env->pipe_configs[pipe_id].mode =
2054 	    __pipe_id_to_pipe_mode(asd, pipe_id);
2055 	stream_env->update_pipe[pipe_id] = true;
2056 
2057 	stream_env->pipe_configs[pipe_id].output_info[0].res.width = width;
2058 	stream_env->pipe_configs[pipe_id].output_info[0].res.height = height;
2059 	stream_env->pipe_configs[pipe_id].output_info[0].format = format;
2060 	stream_env->pipe_configs[pipe_id].output_info[0].padded_width = min_width;
2061 
2062 	/* isp binary 2.2 specific setting*/
2063 	if (width > s_config->input_config.effective_res.width ||
2064 	    height > s_config->input_config.effective_res.height) {
2065 		s_config->input_config.effective_res.width = width;
2066 		s_config->input_config.effective_res.height = height;
2067 	}
2068 
2069 	dev_dbg(isp->dev, "configuring pipe[%d] output info w=%d.h=%d.f=%d.\n",
2070 		pipe_id, width, height, format);
2071 }
2072 
2073 /*
2074  * For CSS2.1, capture pipe uses capture_pp_in_res to configure yuv
2075  * downscaling input resolution.
2076  */
2077 static void __configure_capture_pp_input(struct atomisp_sub_device *asd,
2078 	unsigned int width, unsigned int height,
2079 	enum ia_css_pipe_id pipe_id)
2080 {
2081 	struct atomisp_device *isp = asd->isp;
2082 	struct atomisp_stream_env *stream_env =
2083 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2084 	struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2085 	struct ia_css_pipe_config *pipe_configs =
2086 		    &stream_env->pipe_configs[pipe_id];
2087 	struct ia_css_pipe_extra_config *pipe_extra_configs =
2088 		    &stream_env->pipe_extra_configs[pipe_id];
2089 	unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
2090 
2091 	if (width == 0 && height == 0)
2092 		return;
2093 
2094 	if (width * 9 / 10 < pipe_configs->output_info[0].res.width ||
2095 	    height * 9 / 10 < pipe_configs->output_info[0].res.height)
2096 		return;
2097 	/* here just copy the calculation in css */
2098 	hor_ds_factor = CEIL_DIV(width >> 1,
2099 				 pipe_configs->output_info[0].res.width);
2100 	ver_ds_factor = CEIL_DIV(height >> 1,
2101 				 pipe_configs->output_info[0].res.height);
2102 
2103 	if ((asd->isp->media_dev.hw_revision <
2104 	     (ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT) ||
2105 	     IS_CHT) && hor_ds_factor != ver_ds_factor) {
2106 		dev_warn(asd->isp->dev,
2107 			 "Cropping for capture due to FW limitation");
2108 		return;
2109 	}
2110 
2111 	pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2112 	stream_env->update_pipe[pipe_id] = true;
2113 
2114 	pipe_extra_configs->enable_yuv_ds = true;
2115 
2116 	pipe_configs->capt_pp_in_res.width =
2117 	    stream_config->input_config.effective_res.width;
2118 	pipe_configs->capt_pp_in_res.height =
2119 	    stream_config->input_config.effective_res.height;
2120 
2121 	dev_dbg(isp->dev, "configuring pipe[%d]capture pp input w=%d.h=%d.\n",
2122 		pipe_id, width, height);
2123 }
2124 
2125 /*
2126  * For CSS2.1, preview pipe could support bayer downscaling, yuv decimation and
2127  * yuv downscaling, which needs addtional configurations.
2128  */
2129 static void __configure_preview_pp_input(struct atomisp_sub_device *asd,
2130 	unsigned int width, unsigned int height,
2131 	enum ia_css_pipe_id pipe_id)
2132 {
2133 	struct atomisp_device *isp = asd->isp;
2134 	int out_width, out_height, yuv_ds_in_width, yuv_ds_in_height;
2135 	struct atomisp_stream_env *stream_env =
2136 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2137 	struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2138 	struct ia_css_pipe_config *pipe_configs =
2139 		    &stream_env->pipe_configs[pipe_id];
2140 	struct ia_css_pipe_extra_config *pipe_extra_configs =
2141 		    &stream_env->pipe_extra_configs[pipe_id];
2142 	struct ia_css_resolution *bayer_ds_out_res =
2143 		    &pipe_configs->bayer_ds_out_res;
2144 	struct ia_css_resolution *vf_pp_in_res =
2145 		    &pipe_configs->vf_pp_in_res;
2146 	struct ia_css_resolution  *effective_res =
2147 		    &stream_config->input_config.effective_res;
2148 
2149 	static const struct bayer_ds_factor bds_fct[] = {{2, 1}, {3, 2}, {5, 4} };
2150 	/*
2151 	 * BZ201033: YUV decimation factor of 4 causes couple of rightmost
2152 	 * columns to be shaded. Remove this factor to work around the CSS bug.
2153 	 * const unsigned int yuv_dec_fct[] = {4, 2};
2154 	 */
2155 	static const unsigned int yuv_dec_fct[] = { 2 };
2156 	unsigned int i;
2157 
2158 	if (width == 0 && height == 0)
2159 		return;
2160 
2161 	pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2162 	stream_env->update_pipe[pipe_id] = true;
2163 
2164 	out_width = pipe_configs->output_info[0].res.width;
2165 	out_height = pipe_configs->output_info[0].res.height;
2166 
2167 	/*
2168 	 * The ISP could do bayer downscaling, yuv decimation and yuv
2169 	 * downscaling:
2170 	 * 1: Bayer Downscaling: between effective resolution and
2171 	 * bayer_ds_res_out;
2172 	 * 2: YUV Decimation: between bayer_ds_res_out and vf_pp_in_res;
2173 	 * 3: YUV Downscaling: between vf_pp_in_res and final vf output
2174 	 *
2175 	 * Rule for Bayer Downscaling: support factor 2, 1.5 and 1.25
2176 	 * Rule for YUV Decimation: support factor 2, 4
2177 	 * Rule for YUV Downscaling: arbitrary value below 2
2178 	 *
2179 	 * General rule of factor distribution among these stages:
2180 	 * 1: try to do Bayer downscaling first if not in online mode.
2181 	 * 2: try to do maximum of 2 for YUV downscaling
2182 	 * 3: the remainling for YUV decimation
2183 	 *
2184 	 * Note:
2185 	 * Do not configure bayer_ds_out_res if:
2186 	 * online == 1 or continuous == 0 or raw_binning = 0
2187 	 */
2188 	if (stream_config->online || !stream_config->continuous ||
2189 	    !pipe_extra_configs->enable_raw_binning) {
2190 		bayer_ds_out_res->width = 0;
2191 		bayer_ds_out_res->height = 0;
2192 	} else {
2193 		bayer_ds_out_res->width = effective_res->width;
2194 		bayer_ds_out_res->height = effective_res->height;
2195 
2196 		for (i = 0; i < ARRAY_SIZE(bds_fct); i++) {
2197 			if (effective_res->width >= out_width *
2198 			    bds_fct[i].numerator / bds_fct[i].denominator &&
2199 			    effective_res->height >= out_height *
2200 			    bds_fct[i].numerator / bds_fct[i].denominator) {
2201 				bayer_ds_out_res->width =
2202 				    effective_res->width *
2203 				    bds_fct[i].denominator /
2204 				    bds_fct[i].numerator;
2205 				bayer_ds_out_res->height =
2206 				    effective_res->height *
2207 				    bds_fct[i].denominator /
2208 				    bds_fct[i].numerator;
2209 				break;
2210 			}
2211 		}
2212 	}
2213 	/*
2214 	 * calculate YUV Decimation, YUV downscaling facor:
2215 	 * YUV Downscaling factor must not exceed 2.
2216 	 * YUV Decimation factor could be 2, 4.
2217 	 */
2218 	/* first decide the yuv_ds input resolution */
2219 	if (bayer_ds_out_res->width == 0) {
2220 		yuv_ds_in_width = effective_res->width;
2221 		yuv_ds_in_height = effective_res->height;
2222 	} else {
2223 		yuv_ds_in_width = bayer_ds_out_res->width;
2224 		yuv_ds_in_height = bayer_ds_out_res->height;
2225 	}
2226 
2227 	vf_pp_in_res->width = yuv_ds_in_width;
2228 	vf_pp_in_res->height = yuv_ds_in_height;
2229 
2230 	/* find out the yuv decimation factor */
2231 	for (i = 0; i < ARRAY_SIZE(yuv_dec_fct); i++) {
2232 		if (yuv_ds_in_width >= out_width * yuv_dec_fct[i] &&
2233 		    yuv_ds_in_height >= out_height * yuv_dec_fct[i]) {
2234 			vf_pp_in_res->width = yuv_ds_in_width / yuv_dec_fct[i];
2235 			vf_pp_in_res->height = yuv_ds_in_height / yuv_dec_fct[i];
2236 			break;
2237 		}
2238 	}
2239 
2240 	if (vf_pp_in_res->width == out_width &&
2241 	    vf_pp_in_res->height == out_height) {
2242 		pipe_extra_configs->enable_yuv_ds = false;
2243 		vf_pp_in_res->width = 0;
2244 		vf_pp_in_res->height = 0;
2245 	} else {
2246 		pipe_extra_configs->enable_yuv_ds = true;
2247 	}
2248 
2249 	dev_dbg(isp->dev, "configuring pipe[%d]preview pp input w=%d.h=%d.\n",
2250 		pipe_id, width, height);
2251 }
2252 
2253 /*
2254  * For CSS2.1, offline video pipe could support bayer decimation, and
2255  * yuv downscaling, which needs addtional configurations.
2256  */
2257 static void __configure_video_pp_input(struct atomisp_sub_device *asd,
2258 				       unsigned int width, unsigned int height,
2259 				       enum ia_css_pipe_id pipe_id)
2260 {
2261 	struct atomisp_device *isp = asd->isp;
2262 	int out_width, out_height;
2263 	struct atomisp_stream_env *stream_env =
2264 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2265 	struct ia_css_stream_config *stream_config = &stream_env->stream_config;
2266 	struct ia_css_pipe_config *pipe_configs =
2267 		    &stream_env->pipe_configs[pipe_id];
2268 	struct ia_css_pipe_extra_config *pipe_extra_configs =
2269 		    &stream_env->pipe_extra_configs[pipe_id];
2270 	struct ia_css_resolution *bayer_ds_out_res =
2271 		    &pipe_configs->bayer_ds_out_res;
2272 	struct ia_css_resolution  *effective_res =
2273 		    &stream_config->input_config.effective_res;
2274 
2275 	static const struct bayer_ds_factor bds_factors[] = {
2276 		{8, 1}, {6, 1}, {4, 1}, {3, 1}, {2, 1}, {3, 2}
2277 	};
2278 	unsigned int i;
2279 
2280 	if (width == 0 && height == 0)
2281 		return;
2282 
2283 	pipe_configs->mode = __pipe_id_to_pipe_mode(asd, pipe_id);
2284 	stream_env->update_pipe[pipe_id] = true;
2285 
2286 	pipe_extra_configs->enable_yuv_ds = false;
2287 
2288 	/*
2289 	 * If DVS is enabled,  video binary will take care the dvs envelope
2290 	 * and usually the bayer_ds_out_res should be larger than 120% of
2291 	 * destination resolution, the extra 20% will be cropped as DVS
2292 	 * envelope. But,  if the bayer_ds_out_res is less than 120% of the
2293 	 * destination. The ISP can still work,  but DVS quality is not good.
2294 	 */
2295 	/* taking at least 10% as envelope */
2296 	if (asd->params.video_dis_en) {
2297 		out_width = pipe_configs->output_info[0].res.width * 110 / 100;
2298 		out_height = pipe_configs->output_info[0].res.height * 110 / 100;
2299 	} else {
2300 		out_width = pipe_configs->output_info[0].res.width;
2301 		out_height = pipe_configs->output_info[0].res.height;
2302 	}
2303 
2304 	/*
2305 	 * calculate bayer decimate factor:
2306 	 * 1: only 1.5, 2, 4 and 8 get supported
2307 	 * 2: Do not configure bayer_ds_out_res if:
2308 	 *    online == 1 or continuous == 0 or raw_binning = 0
2309 	 */
2310 	if (stream_config->online || !stream_config->continuous) {
2311 		bayer_ds_out_res->width = 0;
2312 		bayer_ds_out_res->height = 0;
2313 		goto done;
2314 	}
2315 
2316 	pipe_extra_configs->enable_raw_binning = true;
2317 	bayer_ds_out_res->width = effective_res->width;
2318 	bayer_ds_out_res->height = effective_res->height;
2319 
2320 	for (i = 0; i < sizeof(bds_factors) / sizeof(struct bayer_ds_factor);
2321 	     i++) {
2322 		if (effective_res->width >= out_width *
2323 		    bds_factors[i].numerator / bds_factors[i].denominator &&
2324 		    effective_res->height >= out_height *
2325 		    bds_factors[i].numerator / bds_factors[i].denominator) {
2326 			bayer_ds_out_res->width = effective_res->width *
2327 						  bds_factors[i].denominator /
2328 						  bds_factors[i].numerator;
2329 			bayer_ds_out_res->height = effective_res->height *
2330 						   bds_factors[i].denominator /
2331 						   bds_factors[i].numerator;
2332 			break;
2333 		}
2334 	}
2335 
2336 	/*
2337 	 * DVS is cropped from BDS output, so we do not really need to set the
2338 	 * envelope to 20% of output resolution here. always set it to 12x12
2339 	 * per firmware requirement.
2340 	 */
2341 	pipe_configs->dvs_envelope.width = 12;
2342 	pipe_configs->dvs_envelope.height = 12;
2343 
2344 done:
2345 	if (pipe_id == IA_CSS_PIPE_ID_YUVPP)
2346 		stream_config->left_padding = -1;
2347 	else
2348 		stream_config->left_padding = 12;
2349 	dev_dbg(isp->dev, "configuring pipe[%d]video pp input w=%d.h=%d.\n",
2350 		pipe_id, width, height);
2351 }
2352 
2353 static void __configure_vf_output(struct atomisp_sub_device *asd,
2354 				  unsigned int width, unsigned int height,
2355 				  unsigned int min_width,
2356 				  enum ia_css_frame_format format,
2357 				  enum ia_css_pipe_id pipe_id)
2358 {
2359 	struct atomisp_device *isp = asd->isp;
2360 	struct atomisp_stream_env *stream_env =
2361 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2362 	stream_env->pipe_configs[pipe_id].mode =
2363 	    __pipe_id_to_pipe_mode(asd, pipe_id);
2364 	stream_env->update_pipe[pipe_id] = true;
2365 
2366 	stream_env->pipe_configs[pipe_id].vf_output_info[0].res.width = width;
2367 	stream_env->pipe_configs[pipe_id].vf_output_info[0].res.height = height;
2368 	stream_env->pipe_configs[pipe_id].vf_output_info[0].format = format;
2369 	stream_env->pipe_configs[pipe_id].vf_output_info[0].padded_width =
2370 	    min_width;
2371 	dev_dbg(isp->dev,
2372 		"configuring pipe[%d] vf output info w=%d.h=%d.f=%d.\n",
2373 		pipe_id, width, height, format);
2374 }
2375 
2376 static int __get_frame_info(struct atomisp_sub_device *asd,
2377 			    unsigned int stream_index,
2378 			    struct ia_css_frame_info *info,
2379 			    enum frame_info_type type,
2380 			    enum ia_css_pipe_id pipe_id)
2381 {
2382 	struct atomisp_device *isp = asd->isp;
2383 	int ret;
2384 	struct ia_css_pipe_info p_info;
2385 
2386 	/* FIXME! No need to destroy/recreate all streams */
2387 	ret = atomisp_css_update_stream(asd);
2388 	if (ret)
2389 		return ret;
2390 
2391 	ret = ia_css_pipe_get_info(asd->stream_env[stream_index].pipes[pipe_id],
2392 				   &p_info);
2393 	if (ret) {
2394 		dev_err(isp->dev, "can't get info from pipe\n");
2395 		goto get_info_err;
2396 	}
2397 
2398 	switch (type) {
2399 	case ATOMISP_CSS_VF_FRAME:
2400 		*info = p_info.vf_output_info[0];
2401 		dev_dbg(isp->dev, "getting vf frame info.\n");
2402 		break;
2403 	case ATOMISP_CSS_SECOND_VF_FRAME:
2404 		*info = p_info.vf_output_info[1];
2405 		dev_dbg(isp->dev, "getting second vf frame info.\n");
2406 		break;
2407 	case ATOMISP_CSS_OUTPUT_FRAME:
2408 		*info = p_info.output_info[0];
2409 		dev_dbg(isp->dev, "getting main frame info.\n");
2410 		break;
2411 	case ATOMISP_CSS_SECOND_OUTPUT_FRAME:
2412 		*info = p_info.output_info[1];
2413 		dev_dbg(isp->dev, "getting second main frame info.\n");
2414 		break;
2415 	default:
2416 	case ATOMISP_CSS_RAW_FRAME:
2417 		*info = p_info.raw_output_info;
2418 		dev_dbg(isp->dev, "getting raw frame info.\n");
2419 		break;
2420 	}
2421 	dev_dbg(isp->dev, "get frame info: w=%d, h=%d, num_invalid_frames %d.\n",
2422 		info->res.width, info->res.height, p_info.num_invalid_frames);
2423 
2424 	return 0;
2425 
2426 get_info_err:
2427 	atomisp_destroy_pipes_stream_force(asd);
2428 	return -EINVAL;
2429 }
2430 
2431 static unsigned int atomisp_get_pipe_index(struct atomisp_sub_device *asd,
2432 	uint16_t source_pad)
2433 {
2434 	struct atomisp_device *isp = asd->isp;
2435 
2436 	switch (source_pad) {
2437 	case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
2438 		if (asd->copy_mode)
2439 			return IA_CSS_PIPE_ID_COPY;
2440 		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO
2441 		    || asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER)
2442 			return IA_CSS_PIPE_ID_VIDEO;
2443 
2444 		return IA_CSS_PIPE_ID_CAPTURE;
2445 	case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
2446 		if (asd->copy_mode)
2447 			return IA_CSS_PIPE_ID_COPY;
2448 
2449 		return IA_CSS_PIPE_ID_CAPTURE;
2450 	case ATOMISP_SUBDEV_PAD_SOURCE_VF:
2451 		if (!atomisp_is_mbuscode_raw(asd->fmt[asd->capture_pad].fmt.code)) {
2452 			return IA_CSS_PIPE_ID_CAPTURE;
2453 		}
2454 		fallthrough;
2455 	case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
2456 		if (asd->copy_mode)
2457 			return IA_CSS_PIPE_ID_COPY;
2458 		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
2459 			return IA_CSS_PIPE_ID_VIDEO;
2460 
2461 		return IA_CSS_PIPE_ID_PREVIEW;
2462 	}
2463 	dev_warn(isp->dev,
2464 		 "invalid source pad:%d, return default preview pipe index.\n",
2465 		 source_pad);
2466 	return IA_CSS_PIPE_ID_PREVIEW;
2467 }
2468 
2469 int atomisp_get_css_frame_info(struct atomisp_sub_device *asd,
2470 			       u16 source_pad,
2471 			       struct ia_css_frame_info *frame_info)
2472 {
2473 	struct ia_css_pipe_info info;
2474 	int pipe_index = atomisp_get_pipe_index(asd, source_pad);
2475 	int stream_index;
2476 	struct atomisp_device *isp = asd->isp;
2477 
2478 	stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ?
2479 			       ATOMISP_INPUT_STREAM_VIDEO :
2480 			       ATOMISP_INPUT_STREAM_GENERAL;
2481 
2482 	if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index]
2483 		.pipes[pipe_index], &info)) {
2484 		dev_dbg(isp->dev, "ia_css_pipe_get_info FAILED");
2485 		return -EINVAL;
2486 	}
2487 
2488 	switch (source_pad) {
2489 	case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE:
2490 		*frame_info = info.output_info[0];
2491 		break;
2492 	case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO:
2493 		*frame_info = info.output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2494 		break;
2495 	case ATOMISP_SUBDEV_PAD_SOURCE_VF:
2496 		if (stream_index == ATOMISP_INPUT_STREAM_POSTVIEW)
2497 			*frame_info = info.output_info[0];
2498 		else
2499 			*frame_info = info.vf_output_info[0];
2500 		break;
2501 	case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW:
2502 		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
2503 		    (pipe_index == IA_CSS_PIPE_ID_VIDEO ||
2504 		     pipe_index == IA_CSS_PIPE_ID_YUVPP))
2505 			*frame_info = info.vf_output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2506 		else
2507 			*frame_info =
2508 			    info.output_info[ATOMISP_CSS_OUTPUT_DEFAULT_INDEX];
2509 
2510 		break;
2511 	default:
2512 		frame_info = NULL;
2513 		break;
2514 	}
2515 	return frame_info ? 0 : -EINVAL;
2516 }
2517 
2518 int atomisp_css_copy_configure_output(struct atomisp_sub_device *asd,
2519 				      unsigned int stream_index,
2520 				      unsigned int width, unsigned int height,
2521 				      unsigned int padded_width,
2522 				      enum ia_css_frame_format format)
2523 {
2524 	asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_COPY].
2525 	default_capture_config.mode =
2526 	    IA_CSS_CAPTURE_MODE_RAW;
2527 
2528 	__configure_output(asd, stream_index, width, height, padded_width,
2529 			   format, IA_CSS_PIPE_ID_COPY);
2530 	return 0;
2531 }
2532 
2533 int atomisp_css_yuvpp_configure_output(struct atomisp_sub_device *asd,
2534 				       unsigned int stream_index,
2535 				       unsigned int width, unsigned int height,
2536 				       unsigned int padded_width,
2537 				       enum ia_css_frame_format format)
2538 {
2539 	asd->stream_env[stream_index].pipe_configs[IA_CSS_PIPE_ID_YUVPP].
2540 	default_capture_config.mode =
2541 	    IA_CSS_CAPTURE_MODE_RAW;
2542 
2543 	__configure_output(asd, stream_index, width, height, padded_width,
2544 			   format, IA_CSS_PIPE_ID_YUVPP);
2545 	return 0;
2546 }
2547 
2548 int atomisp_css_yuvpp_get_output_frame_info(
2549     struct atomisp_sub_device *asd,
2550     unsigned int stream_index,
2551     struct ia_css_frame_info *info)
2552 {
2553 	return __get_frame_info(asd, stream_index, info,
2554 				ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_YUVPP);
2555 }
2556 
2557 int atomisp_css_yuvpp_get_viewfinder_frame_info(
2558     struct atomisp_sub_device *asd,
2559     unsigned int stream_index,
2560     struct ia_css_frame_info *info)
2561 {
2562 	return __get_frame_info(asd, stream_index, info,
2563 				ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_YUVPP);
2564 }
2565 
2566 int atomisp_css_preview_configure_output(struct atomisp_sub_device *asd,
2567 	unsigned int width, unsigned int height,
2568 	unsigned int min_width,
2569 	enum ia_css_frame_format format)
2570 {
2571 	__configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2572 			   min_width, format, IA_CSS_PIPE_ID_PREVIEW);
2573 	return 0;
2574 }
2575 
2576 int atomisp_css_capture_configure_output(struct atomisp_sub_device *asd,
2577 	unsigned int width, unsigned int height,
2578 	unsigned int min_width,
2579 	enum ia_css_frame_format format)
2580 {
2581 	__configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2582 			   min_width, format, IA_CSS_PIPE_ID_CAPTURE);
2583 	return 0;
2584 }
2585 
2586 int atomisp_css_video_configure_output(struct atomisp_sub_device *asd,
2587 				       unsigned int width, unsigned int height,
2588 				       unsigned int min_width,
2589 				       enum ia_css_frame_format format)
2590 {
2591 	__configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, width, height,
2592 			   min_width, format, IA_CSS_PIPE_ID_VIDEO);
2593 	return 0;
2594 }
2595 
2596 int atomisp_css_video_configure_viewfinder(
2597     struct atomisp_sub_device *asd,
2598     unsigned int width, unsigned int height,
2599     unsigned int min_width,
2600     enum ia_css_frame_format format)
2601 {
2602 	__configure_vf_output(asd, width, height, min_width, format,
2603 			      IA_CSS_PIPE_ID_VIDEO);
2604 	return 0;
2605 }
2606 
2607 int atomisp_css_capture_configure_viewfinder(
2608     struct atomisp_sub_device *asd,
2609     unsigned int width, unsigned int height,
2610     unsigned int min_width,
2611     enum ia_css_frame_format format)
2612 {
2613 	__configure_vf_output(asd, width, height, min_width, format, IA_CSS_PIPE_ID_CAPTURE);
2614 	return 0;
2615 }
2616 
2617 int atomisp_css_video_get_viewfinder_frame_info(
2618     struct atomisp_sub_device *asd,
2619     struct ia_css_frame_info *info)
2620 {
2621 	return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2622 				ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_VIDEO);
2623 }
2624 
2625 int atomisp_css_capture_get_viewfinder_frame_info(
2626     struct atomisp_sub_device *asd,
2627     struct ia_css_frame_info *info)
2628 {
2629 	return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2630 				ATOMISP_CSS_VF_FRAME, IA_CSS_PIPE_ID_CAPTURE);
2631 }
2632 
2633 int atomisp_css_copy_get_output_frame_info(
2634     struct atomisp_sub_device *asd,
2635     unsigned int stream_index,
2636     struct ia_css_frame_info *info)
2637 {
2638 	return __get_frame_info(asd, stream_index, info,
2639 				ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_COPY);
2640 }
2641 
2642 int atomisp_css_preview_get_output_frame_info(
2643     struct atomisp_sub_device *asd,
2644     struct ia_css_frame_info *info)
2645 {
2646 	return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2647 				ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_PREVIEW);
2648 }
2649 
2650 int atomisp_css_capture_get_output_frame_info(
2651     struct atomisp_sub_device *asd,
2652     struct ia_css_frame_info *info)
2653 {
2654 	return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2655 				ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_CAPTURE);
2656 }
2657 
2658 int atomisp_css_video_get_output_frame_info(
2659     struct atomisp_sub_device *asd,
2660     struct ia_css_frame_info *info)
2661 {
2662 	return __get_frame_info(asd, ATOMISP_INPUT_STREAM_GENERAL, info,
2663 				ATOMISP_CSS_OUTPUT_FRAME, IA_CSS_PIPE_ID_VIDEO);
2664 }
2665 
2666 int atomisp_css_preview_configure_pp_input(
2667     struct atomisp_sub_device *asd,
2668     unsigned int width, unsigned int height)
2669 {
2670 	struct atomisp_stream_env *stream_env =
2671 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2672 	__configure_preview_pp_input(asd, width, height, IA_CSS_PIPE_ID_PREVIEW);
2673 
2674 	if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
2675 	    capt_pp_in_res.width)
2676 		__configure_capture_pp_input(asd, width, height, IA_CSS_PIPE_ID_CAPTURE);
2677 
2678 	return 0;
2679 }
2680 
2681 int atomisp_css_capture_configure_pp_input(
2682     struct atomisp_sub_device *asd,
2683     unsigned int width, unsigned int height)
2684 {
2685 	__configure_capture_pp_input(asd, width, height, IA_CSS_PIPE_ID_CAPTURE);
2686 	return 0;
2687 }
2688 
2689 int atomisp_css_video_configure_pp_input(
2690     struct atomisp_sub_device *asd,
2691     unsigned int width, unsigned int height)
2692 {
2693 	struct atomisp_stream_env *stream_env =
2694 		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2695 
2696 	__configure_video_pp_input(asd, width, height, IA_CSS_PIPE_ID_VIDEO);
2697 
2698 	if (width > stream_env->pipe_configs[IA_CSS_PIPE_ID_CAPTURE].
2699 	    capt_pp_in_res.width)
2700 		__configure_capture_pp_input(asd, width, height, IA_CSS_PIPE_ID_CAPTURE);
2701 
2702 	return 0;
2703 }
2704 
2705 int atomisp_css_offline_capture_configure(struct atomisp_sub_device *asd,
2706 	int num_captures, unsigned int skip, int offset)
2707 {
2708 	int ret;
2709 
2710 	dev_dbg(asd->isp->dev, "%s num_capture:%d skip:%d offset:%d\n",
2711 		__func__, num_captures, skip, offset);
2712 
2713 	ret = ia_css_stream_capture(
2714 		  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
2715 		  num_captures, skip, offset);
2716 	if (ret)
2717 		return -EINVAL;
2718 
2719 	return 0;
2720 }
2721 
2722 int atomisp_css_exp_id_capture(struct atomisp_sub_device *asd, int exp_id)
2723 {
2724 	int ret;
2725 
2726 	ret = ia_css_stream_capture_frame(
2727 		  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
2728 		  exp_id);
2729 	if (ret == -ENOBUFS) {
2730 		/* capture cmd queue is full */
2731 		return -EBUSY;
2732 	} else if (ret) {
2733 		return -EIO;
2734 	}
2735 
2736 	return 0;
2737 }
2738 
2739 int atomisp_css_exp_id_unlock(struct atomisp_sub_device *asd, int exp_id)
2740 {
2741 	int ret;
2742 
2743 	ret = ia_css_unlock_raw_frame(
2744 		  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
2745 		  exp_id);
2746 	if (ret == -ENOBUFS)
2747 		return -EAGAIN;
2748 	else if (ret)
2749 		return -EIO;
2750 
2751 	return 0;
2752 }
2753 
2754 int atomisp_css_capture_enable_xnr(struct atomisp_sub_device *asd,
2755 				   bool enable)
2756 {
2757 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2758 	.pipe_configs[IA_CSS_PIPE_ID_CAPTURE]
2759 	.default_capture_config.enable_xnr = enable;
2760 	asd->params.capture_config.enable_xnr = enable;
2761 	asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2762 	.update_pipe[IA_CSS_PIPE_ID_CAPTURE] = true;
2763 
2764 	return 0;
2765 }
2766 
2767 void atomisp_css_set_ctc_table(struct atomisp_sub_device *asd,
2768 			       struct ia_css_ctc_table *ctc_table)
2769 {
2770 	int i;
2771 	u16 *vamem_ptr = ctc_table->data.vamem_1;
2772 	int data_size = IA_CSS_VAMEM_1_CTC_TABLE_SIZE;
2773 	bool valid = false;
2774 
2775 	/* workaround: if ctc_table is all 0, do not apply it */
2776 	if (ctc_table->vamem_type == IA_CSS_VAMEM_TYPE_2) {
2777 		vamem_ptr = ctc_table->data.vamem_2;
2778 		data_size = IA_CSS_VAMEM_2_CTC_TABLE_SIZE;
2779 	}
2780 
2781 	for (i = 0; i < data_size; i++) {
2782 		if (*(vamem_ptr + i)) {
2783 			valid = true;
2784 			break;
2785 		}
2786 	}
2787 
2788 	if (valid)
2789 		asd->params.config.ctc_table = ctc_table;
2790 	else
2791 		dev_warn(asd->isp->dev, "Bypass the invalid ctc_table.\n");
2792 }
2793 
2794 void atomisp_css_set_anr_thres(struct atomisp_sub_device *asd,
2795 			       struct ia_css_anr_thres *anr_thres)
2796 {
2797 	asd->params.config.anr_thres = anr_thres;
2798 }
2799 
2800 void atomisp_css_set_dvs_6axis(struct atomisp_sub_device *asd,
2801 			       struct ia_css_dvs_6axis_config *dvs_6axis)
2802 {
2803 	asd->params.config.dvs_6axis_config = dvs_6axis;
2804 }
2805 
2806 void atomisp_css_video_set_dis_vector(struct atomisp_sub_device *asd,
2807 				      struct atomisp_dis_vector *vector)
2808 {
2809 	if (!asd->params.config.motion_vector)
2810 		asd->params.config.motion_vector = &asd->params.css_param.motion_vector;
2811 
2812 	memset(asd->params.config.motion_vector,
2813 	       0, sizeof(struct ia_css_vector));
2814 	asd->params.css_param.motion_vector.x = vector->x;
2815 	asd->params.css_param.motion_vector.y = vector->y;
2816 }
2817 
2818 static int atomisp_compare_dvs_grid(struct atomisp_sub_device *asd,
2819 				    struct atomisp_dvs_grid_info *atomgrid)
2820 {
2821 	struct ia_css_dvs_grid_info *cur =
2822 	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
2823 
2824 	if (!cur) {
2825 		dev_err(asd->isp->dev, "dvs grid not available!\n");
2826 		return -EINVAL;
2827 	}
2828 
2829 	if (sizeof(*cur) != sizeof(*atomgrid)) {
2830 		dev_err(asd->isp->dev, "dvs grid mismatch!\n");
2831 		return -EINVAL;
2832 	}
2833 
2834 	if (!cur->enable) {
2835 		dev_err(asd->isp->dev, "dvs not enabled!\n");
2836 		return -EINVAL;
2837 	}
2838 
2839 	return memcmp(atomgrid, cur, sizeof(*cur));
2840 }
2841 
2842 void  atomisp_css_set_dvs2_coefs(struct atomisp_sub_device *asd,
2843 				 struct ia_css_dvs2_coefficients *coefs)
2844 {
2845 	asd->params.config.dvs2_coefs = coefs;
2846 }
2847 
2848 int atomisp_css_set_dis_coefs(struct atomisp_sub_device *asd,
2849 			      struct atomisp_dis_coefficients *coefs)
2850 {
2851 	if (atomisp_compare_dvs_grid(asd, &coefs->grid_info) != 0)
2852 		/* If the grid info in the argument differs from the current
2853 		   grid info, we tell the caller to reset the grid size and
2854 		   try again. */
2855 		return -EAGAIN;
2856 
2857 	if (!coefs->hor_coefs.odd_real ||
2858 	    !coefs->hor_coefs.odd_imag ||
2859 	    !coefs->hor_coefs.even_real ||
2860 	    !coefs->hor_coefs.even_imag ||
2861 	    !coefs->ver_coefs.odd_real ||
2862 	    !coefs->ver_coefs.odd_imag ||
2863 	    !coefs->ver_coefs.even_real ||
2864 	    !coefs->ver_coefs.even_imag ||
2865 	    !asd->params.css_param.dvs2_coeff->hor_coefs.odd_real ||
2866 	    !asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag ||
2867 	    !asd->params.css_param.dvs2_coeff->hor_coefs.even_real ||
2868 	    !asd->params.css_param.dvs2_coeff->hor_coefs.even_imag ||
2869 	    !asd->params.css_param.dvs2_coeff->ver_coefs.odd_real ||
2870 	    !asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag ||
2871 	    !asd->params.css_param.dvs2_coeff->ver_coefs.even_real ||
2872 	    !asd->params.css_param.dvs2_coeff->ver_coefs.even_imag)
2873 		return -EINVAL;
2874 
2875 	if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_real,
2876 			   coefs->hor_coefs.odd_real, asd->params.dvs_hor_coef_bytes))
2877 		return -EFAULT;
2878 	if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.odd_imag,
2879 			   coefs->hor_coefs.odd_imag, asd->params.dvs_hor_coef_bytes))
2880 		return -EFAULT;
2881 	if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_real,
2882 			   coefs->hor_coefs.even_real, asd->params.dvs_hor_coef_bytes))
2883 		return -EFAULT;
2884 	if (copy_from_user(asd->params.css_param.dvs2_coeff->hor_coefs.even_imag,
2885 			   coefs->hor_coefs.even_imag, asd->params.dvs_hor_coef_bytes))
2886 		return -EFAULT;
2887 
2888 	if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_real,
2889 			   coefs->ver_coefs.odd_real, asd->params.dvs_ver_coef_bytes))
2890 		return -EFAULT;
2891 	if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.odd_imag,
2892 			   coefs->ver_coefs.odd_imag, asd->params.dvs_ver_coef_bytes))
2893 		return -EFAULT;
2894 	if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_real,
2895 			   coefs->ver_coefs.even_real, asd->params.dvs_ver_coef_bytes))
2896 		return -EFAULT;
2897 	if (copy_from_user(asd->params.css_param.dvs2_coeff->ver_coefs.even_imag,
2898 			   coefs->ver_coefs.even_imag, asd->params.dvs_ver_coef_bytes))
2899 		return -EFAULT;
2900 
2901 	asd->params.css_param.update_flag.dvs2_coefs =
2902 		(struct atomisp_dis_coefficients *)
2903 		asd->params.css_param.dvs2_coeff;
2904 	/* FIXME! */
2905 	/*	asd->params.dis_proj_data_valid = false; */
2906 	asd->params.css_update_params_needed = true;
2907 
2908 	return 0;
2909 }
2910 
2911 void atomisp_css_set_zoom_factor(struct atomisp_sub_device *asd,
2912 				 unsigned int zoom)
2913 {
2914 	struct atomisp_device *isp = asd->isp;
2915 
2916 	if (zoom == asd->params.css_param.dz_config.dx &&
2917 	    zoom == asd->params.css_param.dz_config.dy) {
2918 		dev_dbg(isp->dev, "same zoom scale. skipped.\n");
2919 		return;
2920 	}
2921 
2922 	memset(&asd->params.css_param.dz_config, 0,
2923 	       sizeof(struct ia_css_dz_config));
2924 	asd->params.css_param.dz_config.dx = zoom;
2925 	asd->params.css_param.dz_config.dy = zoom;
2926 
2927 	asd->params.css_param.update_flag.dz_config =
2928 	    (struct atomisp_dz_config *)&asd->params.css_param.dz_config;
2929 	asd->params.css_update_params_needed = true;
2930 }
2931 
2932 void atomisp_css_set_formats_config(struct atomisp_sub_device *asd,
2933 				    struct ia_css_formats_config *formats_config)
2934 {
2935 	asd->params.config.formats_config = formats_config;
2936 }
2937 
2938 int atomisp_css_get_wb_config(struct atomisp_sub_device *asd,
2939 			      struct atomisp_wb_config *config)
2940 {
2941 	struct ia_css_wb_config wb_config;
2942 	struct ia_css_isp_config isp_config;
2943 	struct atomisp_device *isp = asd->isp;
2944 
2945 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
2946 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
2947 			__func__);
2948 		return -EINVAL;
2949 	}
2950 	memset(&wb_config, 0, sizeof(struct ia_css_wb_config));
2951 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
2952 	isp_config.wb_config = &wb_config;
2953 	ia_css_stream_get_isp_config(
2954 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
2955 	    &isp_config);
2956 	memcpy(config, &wb_config, sizeof(*config));
2957 
2958 	return 0;
2959 }
2960 
2961 int atomisp_css_get_ob_config(struct atomisp_sub_device *asd,
2962 			      struct atomisp_ob_config *config)
2963 {
2964 	struct ia_css_ob_config ob_config;
2965 	struct ia_css_isp_config isp_config;
2966 	struct atomisp_device *isp = asd->isp;
2967 
2968 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
2969 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
2970 			__func__);
2971 		return -EINVAL;
2972 	}
2973 	memset(&ob_config, 0, sizeof(struct ia_css_ob_config));
2974 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
2975 	isp_config.ob_config = &ob_config;
2976 	ia_css_stream_get_isp_config(
2977 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
2978 	    &isp_config);
2979 	memcpy(config, &ob_config, sizeof(*config));
2980 
2981 	return 0;
2982 }
2983 
2984 int atomisp_css_get_dp_config(struct atomisp_sub_device *asd,
2985 			      struct atomisp_dp_config *config)
2986 {
2987 	struct ia_css_dp_config dp_config;
2988 	struct ia_css_isp_config isp_config;
2989 	struct atomisp_device *isp = asd->isp;
2990 
2991 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
2992 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
2993 			__func__);
2994 		return -EINVAL;
2995 	}
2996 	memset(&dp_config, 0, sizeof(struct ia_css_dp_config));
2997 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
2998 	isp_config.dp_config = &dp_config;
2999 	ia_css_stream_get_isp_config(
3000 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3001 	    &isp_config);
3002 	memcpy(config, &dp_config, sizeof(*config));
3003 
3004 	return 0;
3005 }
3006 
3007 int atomisp_css_get_de_config(struct atomisp_sub_device *asd,
3008 			      struct atomisp_de_config *config)
3009 {
3010 	struct ia_css_de_config de_config;
3011 	struct ia_css_isp_config isp_config;
3012 	struct atomisp_device *isp = asd->isp;
3013 
3014 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3015 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3016 			__func__);
3017 		return -EINVAL;
3018 	}
3019 	memset(&de_config, 0, sizeof(struct ia_css_de_config));
3020 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3021 	isp_config.de_config = &de_config;
3022 	ia_css_stream_get_isp_config(
3023 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3024 	    &isp_config);
3025 	memcpy(config, &de_config, sizeof(*config));
3026 
3027 	return 0;
3028 }
3029 
3030 int atomisp_css_get_nr_config(struct atomisp_sub_device *asd,
3031 			      struct atomisp_nr_config *config)
3032 {
3033 	struct ia_css_nr_config nr_config;
3034 	struct ia_css_isp_config isp_config;
3035 	struct atomisp_device *isp = asd->isp;
3036 
3037 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3038 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3039 			__func__);
3040 		return -EINVAL;
3041 	}
3042 	memset(&nr_config, 0, sizeof(struct ia_css_nr_config));
3043 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3044 
3045 	isp_config.nr_config = &nr_config;
3046 	ia_css_stream_get_isp_config(
3047 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3048 	    &isp_config);
3049 	memcpy(config, &nr_config, sizeof(*config));
3050 
3051 	return 0;
3052 }
3053 
3054 int atomisp_css_get_ee_config(struct atomisp_sub_device *asd,
3055 			      struct atomisp_ee_config *config)
3056 {
3057 	struct ia_css_ee_config ee_config;
3058 	struct ia_css_isp_config isp_config;
3059 	struct atomisp_device *isp = asd->isp;
3060 
3061 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3062 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3063 			__func__);
3064 		return -EINVAL;
3065 	}
3066 	memset(&ee_config, 0, sizeof(struct ia_css_ee_config));
3067 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3068 	isp_config.ee_config = &ee_config;
3069 	ia_css_stream_get_isp_config(
3070 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3071 	    &isp_config);
3072 	memcpy(config, &ee_config, sizeof(*config));
3073 
3074 	return 0;
3075 }
3076 
3077 int atomisp_css_get_tnr_config(struct atomisp_sub_device *asd,
3078 			       struct atomisp_tnr_config *config)
3079 {
3080 	struct ia_css_tnr_config tnr_config;
3081 	struct ia_css_isp_config isp_config;
3082 	struct atomisp_device *isp = asd->isp;
3083 
3084 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3085 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3086 			__func__);
3087 		return -EINVAL;
3088 	}
3089 	memset(&tnr_config, 0, sizeof(struct ia_css_tnr_config));
3090 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3091 	isp_config.tnr_config = &tnr_config;
3092 	ia_css_stream_get_isp_config(
3093 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3094 	    &isp_config);
3095 	memcpy(config, &tnr_config, sizeof(*config));
3096 
3097 	return 0;
3098 }
3099 
3100 int atomisp_css_get_ctc_table(struct atomisp_sub_device *asd,
3101 			      struct atomisp_ctc_table *config)
3102 {
3103 	struct ia_css_ctc_table *tab;
3104 	struct ia_css_isp_config isp_config;
3105 	struct atomisp_device *isp = asd->isp;
3106 
3107 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3108 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3109 			__func__);
3110 		return -EINVAL;
3111 	}
3112 
3113 	tab = vzalloc(sizeof(struct ia_css_ctc_table));
3114 	if (!tab)
3115 		return -ENOMEM;
3116 
3117 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3118 	isp_config.ctc_table = tab;
3119 	ia_css_stream_get_isp_config(
3120 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3121 	    &isp_config);
3122 	memcpy(config, tab, sizeof(*tab));
3123 	vfree(tab);
3124 
3125 	return 0;
3126 }
3127 
3128 int atomisp_css_get_gamma_table(struct atomisp_sub_device *asd,
3129 				struct atomisp_gamma_table *config)
3130 {
3131 	struct ia_css_gamma_table *tab;
3132 	struct ia_css_isp_config isp_config;
3133 	struct atomisp_device *isp = asd->isp;
3134 
3135 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3136 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3137 			__func__);
3138 		return -EINVAL;
3139 	}
3140 
3141 	tab = vzalloc(sizeof(struct ia_css_gamma_table));
3142 	if (!tab)
3143 		return -ENOMEM;
3144 
3145 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3146 	isp_config.gamma_table = tab;
3147 	ia_css_stream_get_isp_config(
3148 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3149 	    &isp_config);
3150 	memcpy(config, tab, sizeof(*tab));
3151 	vfree(tab);
3152 
3153 	return 0;
3154 }
3155 
3156 int atomisp_css_get_gc_config(struct atomisp_sub_device *asd,
3157 			      struct atomisp_gc_config *config)
3158 {
3159 	struct ia_css_gc_config gc_config;
3160 	struct ia_css_isp_config isp_config;
3161 	struct atomisp_device *isp = asd->isp;
3162 
3163 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3164 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3165 			__func__);
3166 		return -EINVAL;
3167 	}
3168 	memset(&gc_config, 0, sizeof(struct ia_css_gc_config));
3169 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3170 	isp_config.gc_config = &gc_config;
3171 	ia_css_stream_get_isp_config(
3172 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3173 	    &isp_config);
3174 	/* Get gamma correction params from current setup */
3175 	memcpy(config, &gc_config, sizeof(*config));
3176 
3177 	return 0;
3178 }
3179 
3180 int atomisp_css_get_3a_config(struct atomisp_sub_device *asd,
3181 			      struct atomisp_3a_config *config)
3182 {
3183 	struct ia_css_3a_config s3a_config;
3184 	struct ia_css_isp_config isp_config;
3185 	struct atomisp_device *isp = asd->isp;
3186 
3187 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3188 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3189 			__func__);
3190 		return -EINVAL;
3191 	}
3192 	memset(&s3a_config, 0, sizeof(struct ia_css_3a_config));
3193 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3194 	isp_config.s3a_config = &s3a_config;
3195 	ia_css_stream_get_isp_config(
3196 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3197 	    &isp_config);
3198 	/* Get white balance from current setup */
3199 	memcpy(config, &s3a_config, sizeof(*config));
3200 
3201 	return 0;
3202 }
3203 
3204 int atomisp_css_get_formats_config(struct atomisp_sub_device *asd,
3205 				   struct atomisp_formats_config *config)
3206 {
3207 	struct ia_css_formats_config formats_config;
3208 	struct ia_css_isp_config isp_config;
3209 	struct atomisp_device *isp = asd->isp;
3210 
3211 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3212 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3213 			__func__);
3214 		return -EINVAL;
3215 	}
3216 	memset(&formats_config, 0, sizeof(formats_config));
3217 	memset(&isp_config, 0, sizeof(isp_config));
3218 	isp_config.formats_config = &formats_config;
3219 	ia_css_stream_get_isp_config(
3220 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3221 	    &isp_config);
3222 	/* Get narrow gamma from current setup */
3223 	memcpy(config, &formats_config, sizeof(*config));
3224 
3225 	return 0;
3226 }
3227 
3228 int atomisp_css_get_zoom_factor(struct atomisp_sub_device *asd,
3229 				unsigned int *zoom)
3230 {
3231 	struct ia_css_dz_config dz_config;  /** Digital Zoom */
3232 	struct ia_css_isp_config isp_config;
3233 	struct atomisp_device *isp = asd->isp;
3234 
3235 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3236 		dev_err(isp->dev, "%s called after streamoff, skipping.\n",
3237 			__func__);
3238 		return -EINVAL;
3239 	}
3240 	memset(&dz_config, 0, sizeof(struct ia_css_dz_config));
3241 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3242 	isp_config.dz_config = &dz_config;
3243 	ia_css_stream_get_isp_config(
3244 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3245 	    &isp_config);
3246 	*zoom = dz_config.dx;
3247 
3248 	return 0;
3249 }
3250 
3251 /*
3252  * Function to set/get image stablization statistics
3253  */
3254 int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd,
3255 			     struct atomisp_dis_statistics *stats)
3256 {
3257 	struct atomisp_device *isp = asd->isp;
3258 	struct atomisp_dis_buf *dis_buf;
3259 	unsigned long flags;
3260 
3261 	lockdep_assert_held(&isp->mutex);
3262 
3263 	if (!asd->params.dvs_stat->hor_prod.odd_real ||
3264 	    !asd->params.dvs_stat->hor_prod.odd_imag ||
3265 	    !asd->params.dvs_stat->hor_prod.even_real ||
3266 	    !asd->params.dvs_stat->hor_prod.even_imag ||
3267 	    !asd->params.dvs_stat->ver_prod.odd_real ||
3268 	    !asd->params.dvs_stat->ver_prod.odd_imag ||
3269 	    !asd->params.dvs_stat->ver_prod.even_real ||
3270 	    !asd->params.dvs_stat->ver_prod.even_imag)
3271 		return -EINVAL;
3272 
3273 	/* isp needs to be streaming to get DIS statistics */
3274 	if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
3275 		return -EINVAL;
3276 
3277 	if (atomisp_compare_dvs_grid(asd, &stats->dvs2_stat.grid_info) != 0)
3278 		/* If the grid info in the argument differs from the current
3279 		   grid info, we tell the caller to reset the grid size and
3280 		   try again. */
3281 		return -EAGAIN;
3282 
3283 	spin_lock_irqsave(&asd->dis_stats_lock, flags);
3284 	if (!asd->params.dis_proj_data_valid || list_empty(&asd->dis_stats)) {
3285 		spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3286 		dev_err(isp->dev, "dis statistics is not valid.\n");
3287 		return -EAGAIN;
3288 	}
3289 
3290 	dis_buf = list_entry(asd->dis_stats.next,
3291 			     struct atomisp_dis_buf, list);
3292 	list_del_init(&dis_buf->list);
3293 	spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3294 
3295 	if (dis_buf->dvs_map)
3296 		ia_css_translate_dvs2_statistics(
3297 		    asd->params.dvs_stat, dis_buf->dvs_map);
3298 	else
3299 		ia_css_get_dvs2_statistics(asd->params.dvs_stat,
3300 					   dis_buf->dis_data);
3301 	stats->exp_id = dis_buf->dis_data->exp_id;
3302 
3303 	spin_lock_irqsave(&asd->dis_stats_lock, flags);
3304 	list_add_tail(&dis_buf->list, &asd->dis_stats);
3305 	spin_unlock_irqrestore(&asd->dis_stats_lock, flags);
3306 
3307 	if (copy_to_user(stats->dvs2_stat.ver_prod.odd_real,
3308 			 asd->params.dvs_stat->ver_prod.odd_real,
3309 			 asd->params.dvs_ver_proj_bytes))
3310 		return -EFAULT;
3311 	if (copy_to_user(stats->dvs2_stat.ver_prod.odd_imag,
3312 			 asd->params.dvs_stat->ver_prod.odd_imag,
3313 			 asd->params.dvs_ver_proj_bytes))
3314 		return -EFAULT;
3315 	if (copy_to_user(stats->dvs2_stat.ver_prod.even_real,
3316 			 asd->params.dvs_stat->ver_prod.even_real,
3317 			 asd->params.dvs_ver_proj_bytes))
3318 		return -EFAULT;
3319 	if (copy_to_user(stats->dvs2_stat.ver_prod.even_imag,
3320 			 asd->params.dvs_stat->ver_prod.even_imag,
3321 			 asd->params.dvs_ver_proj_bytes))
3322 		return -EFAULT;
3323 	if (copy_to_user(stats->dvs2_stat.hor_prod.odd_real,
3324 			 asd->params.dvs_stat->hor_prod.odd_real,
3325 			 asd->params.dvs_hor_proj_bytes))
3326 		return -EFAULT;
3327 	if (copy_to_user(stats->dvs2_stat.hor_prod.odd_imag,
3328 			 asd->params.dvs_stat->hor_prod.odd_imag,
3329 			 asd->params.dvs_hor_proj_bytes))
3330 		return -EFAULT;
3331 	if (copy_to_user(stats->dvs2_stat.hor_prod.even_real,
3332 			 asd->params.dvs_stat->hor_prod.even_real,
3333 			 asd->params.dvs_hor_proj_bytes))
3334 		return -EFAULT;
3335 	if (copy_to_user(stats->dvs2_stat.hor_prod.even_imag,
3336 			 asd->params.dvs_stat->hor_prod.even_imag,
3337 			 asd->params.dvs_hor_proj_bytes))
3338 		return -EFAULT;
3339 
3340 	return 0;
3341 }
3342 
3343 struct ia_css_shading_table *atomisp_css_shading_table_alloc(
3344     unsigned int width, unsigned int height)
3345 {
3346 	return ia_css_shading_table_alloc(width, height);
3347 }
3348 
3349 void atomisp_css_set_shading_table(struct atomisp_sub_device *asd,
3350 				   struct ia_css_shading_table *table)
3351 {
3352 	asd->params.config.shading_table = table;
3353 }
3354 
3355 void atomisp_css_shading_table_free(struct ia_css_shading_table *table)
3356 {
3357 	ia_css_shading_table_free(table);
3358 }
3359 
3360 struct ia_css_morph_table *atomisp_css_morph_table_allocate(
3361     unsigned int width, unsigned int height)
3362 {
3363 	return ia_css_morph_table_allocate(width, height);
3364 }
3365 
3366 void atomisp_css_set_morph_table(struct atomisp_sub_device *asd,
3367 				 struct ia_css_morph_table *table)
3368 {
3369 	asd->params.config.morph_table = table;
3370 }
3371 
3372 void atomisp_css_get_morph_table(struct atomisp_sub_device *asd,
3373 				 struct ia_css_morph_table *table)
3374 {
3375 	struct ia_css_isp_config isp_config;
3376 	struct atomisp_device *isp = asd->isp;
3377 
3378 	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3379 		dev_err(isp->dev,
3380 			"%s called after streamoff, skipping.\n", __func__);
3381 		return;
3382 	}
3383 	memset(table, 0, sizeof(struct ia_css_morph_table));
3384 	memset(&isp_config, 0, sizeof(struct ia_css_isp_config));
3385 	isp_config.morph_table = table;
3386 	ia_css_stream_get_isp_config(
3387 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3388 	    &isp_config);
3389 }
3390 
3391 void atomisp_css_morph_table_free(struct ia_css_morph_table *table)
3392 {
3393 	ia_css_morph_table_free(table);
3394 }
3395 
3396 static bool atomisp_css_isr_get_stream_id(struct ia_css_pipe *css_pipe,
3397 					  struct atomisp_device *isp,
3398 					  enum atomisp_input_stream_id *stream_id)
3399 {
3400 	struct atomisp_stream_env *stream_env;
3401 	int i, j;
3402 
3403 	if (isp->asd.streaming == ATOMISP_DEVICE_STREAMING_DISABLED)
3404 		return false;
3405 
3406 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
3407 		stream_env = &isp->asd.stream_env[i];
3408 		for (j = 0; j < IA_CSS_PIPE_ID_NUM; j++) {
3409 			if (stream_env->pipes[j] && stream_env->pipes[j] == css_pipe) {
3410 				*stream_id = i;
3411 				return true;
3412 			}
3413 		}
3414 	}
3415 
3416 	return false;
3417 }
3418 
3419 int atomisp_css_isr_thread(struct atomisp_device *isp)
3420 {
3421 	enum atomisp_input_stream_id stream_id = 0;
3422 	struct atomisp_css_event current_event;
3423 
3424 	lockdep_assert_held(&isp->mutex);
3425 
3426 	while (!ia_css_dequeue_psys_event(&current_event.event)) {
3427 		if (current_event.event.type ==
3428 		    IA_CSS_EVENT_TYPE_FW_ASSERT) {
3429 			/*
3430 			 * Received FW assertion signal,
3431 			 * trigger WDT to recover
3432 			 */
3433 			dev_err(isp->dev,
3434 				"%s: ISP reports FW_ASSERT event! fw_assert_module_id %d fw_assert_line_no %d\n",
3435 				__func__,
3436 				current_event.event.fw_assert_module_id,
3437 				current_event.event.fw_assert_line_no);
3438 
3439 			queue_work(system_long_wq, &isp->assert_recovery_work);
3440 			return -EINVAL;
3441 		} else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) {
3442 			dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n",
3443 				 __func__, current_event.event.fw_warning,
3444 				 current_event.event.exp_id);
3445 			continue;
3446 		}
3447 
3448 		if (!atomisp_css_isr_get_stream_id(current_event.event.pipe, isp, &stream_id)) {
3449 			if (current_event.event.type == IA_CSS_EVENT_TYPE_TIMER)
3450 				dev_dbg(isp->dev,
3451 					"event: Timer event.");
3452 			else
3453 				dev_warn(isp->dev, "%s:no subdev.event:%d",
3454 					 __func__,
3455 					 current_event.event.type);
3456 			continue;
3457 		}
3458 
3459 		atomisp_css_temp_pipe_to_pipe_id(&isp->asd, &current_event);
3460 		switch (current_event.event.type) {
3461 		case IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE:
3462 			dev_dbg(isp->dev, "event: Output frame done");
3463 			atomisp_buf_done(&isp->asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME,
3464 					 current_event.pipe, true, stream_id);
3465 			break;
3466 		case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE:
3467 			dev_dbg(isp->dev, "event: Second output frame done");
3468 			atomisp_buf_done(&isp->asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME,
3469 					 current_event.pipe, true, stream_id);
3470 			break;
3471 		case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE:
3472 			dev_dbg(isp->dev, "event: 3A stats frame done");
3473 			atomisp_buf_done(&isp->asd, 0,
3474 					 IA_CSS_BUFFER_TYPE_3A_STATISTICS,
3475 					 current_event.pipe,
3476 					 false, stream_id);
3477 			break;
3478 		case IA_CSS_EVENT_TYPE_METADATA_DONE:
3479 			dev_dbg(isp->dev, "event: metadata frame done");
3480 			atomisp_buf_done(&isp->asd, 0,
3481 					 IA_CSS_BUFFER_TYPE_METADATA,
3482 					 current_event.pipe,
3483 					 false, stream_id);
3484 			break;
3485 		case IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE:
3486 			dev_dbg(isp->dev, "event: VF output frame done");
3487 			atomisp_buf_done(&isp->asd, 0,
3488 					 IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME,
3489 					 current_event.pipe, true, stream_id);
3490 			break;
3491 		case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE:
3492 			dev_dbg(isp->dev, "event: second VF output frame done");
3493 			atomisp_buf_done(&isp->asd, 0,
3494 					 IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME,
3495 					 current_event.pipe, true, stream_id);
3496 			break;
3497 		case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE:
3498 			dev_dbg(isp->dev, "event: dis stats frame done");
3499 			atomisp_buf_done(&isp->asd, 0,
3500 					 IA_CSS_BUFFER_TYPE_DIS_STATISTICS,
3501 					 current_event.pipe,
3502 					 false, stream_id);
3503 			break;
3504 		case IA_CSS_EVENT_TYPE_PIPELINE_DONE:
3505 			dev_dbg(isp->dev, "event: pipeline done");
3506 			break;
3507 		case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE:
3508 			dev_warn(isp->dev, "unexpected event: acc stage done");
3509 			break;
3510 		default:
3511 			dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n",
3512 				current_event.event.type);
3513 			break;
3514 		}
3515 	}
3516 
3517 	return 0;
3518 }
3519 
3520 bool atomisp_css_valid_sof(struct atomisp_device *isp)
3521 {
3522 	unsigned int i;
3523 
3524 	/* Loop for each css vc stream */
3525 	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
3526 		if (!isp->asd.stream_env[i].stream)
3527 			continue;
3528 
3529 		dev_dbg(isp->dev, "stream #%d: mode: %d\n",
3530 			i, isp->asd.stream_env[i].stream_config.mode);
3531 		if (isp->asd.stream_env[i].stream_config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
3532 			return false;
3533 	}
3534 
3535 	return true;
3536 }
3537 
3538 int atomisp_css_debug_dump_isp_binary(void)
3539 {
3540 	ia_css_debug_dump_isp_binary();
3541 	return 0;
3542 }
3543 
3544 int atomisp_css_dump_sp_raw_copy_linecount(bool reduced)
3545 {
3546 	sh_css_dump_sp_raw_copy_linecount(reduced);
3547 	return 0;
3548 }
3549 
3550 static const char * const fw_type_name[] = {
3551 	[ia_css_sp_firmware]		= "SP",
3552 	[ia_css_isp_firmware]		= "ISP",
3553 	[ia_css_bootloader_firmware]	= "BootLoader",
3554 	[ia_css_acc_firmware]		= "accel",
3555 };
3556 
3557 static const char * const fw_acc_type_name[] = {
3558 	[IA_CSS_ACC_NONE] =		"Normal",
3559 	[IA_CSS_ACC_OUTPUT] =		"Accel stage on output",
3560 	[IA_CSS_ACC_VIEWFINDER] =	"Accel stage on viewfinder",
3561 	[IA_CSS_ACC_STANDALONE] =	"Stand-alone acceleration",
3562 };
3563 
3564 int atomisp_css_dump_blob_infor(struct atomisp_device *isp)
3565 {
3566 	struct ia_css_blob_descr *bd = sh_css_blob_info;
3567 	unsigned int i, nm = sh_css_num_binaries;
3568 
3569 	if (nm == 0)
3570 		return -EPERM;
3571 	if (!bd)
3572 		return -EPERM;
3573 
3574 	/*
3575 	 * The sh_css_load_firmware function discard the initial
3576 	 * "SPS" binaries
3577 	 */
3578 	for (i = 0; i < sh_css_num_binaries - NUM_OF_SPS; i++) {
3579 		switch (bd[i].header.type) {
3580 		case ia_css_isp_firmware:
3581 			dev_dbg(isp->dev, "Num%2d type %s (%s), binary id is %2d, name is %s\n",
3582 				i + NUM_OF_SPS,
3583 				fw_type_name[bd[i].header.type],
3584 				fw_acc_type_name[bd[i].header.info.isp.type],
3585 				bd[i].header.info.isp.sp.id,
3586 				bd[i].name);
3587 			break;
3588 		default:
3589 			dev_dbg(isp->dev, "Num%2d type %s, name is %s\n",
3590 				i + NUM_OF_SPS, fw_type_name[bd[i].header.type],
3591 				bd[i].name);
3592 		}
3593 	}
3594 
3595 	return 0;
3596 }
3597 
3598 void atomisp_css_set_isp_config_id(struct atomisp_sub_device *asd,
3599 				   uint32_t isp_config_id)
3600 {
3601 	asd->params.config.isp_config_id = isp_config_id;
3602 }
3603 
3604 void atomisp_css_set_isp_config_applied_frame(struct atomisp_sub_device *asd,
3605 	struct ia_css_frame *output_frame)
3606 {
3607 	asd->params.config.output_frame = output_frame;
3608 }
3609 
3610 int atomisp_get_css_dbgfunc(void)
3611 {
3612 	return dbg_func;
3613 }
3614 
3615 int atomisp_set_css_dbgfunc(struct atomisp_device *isp, int opt)
3616 {
3617 	int ret;
3618 
3619 	ret = __set_css_print_env(isp, opt);
3620 	if (ret == 0)
3621 		dbg_func = opt;
3622 
3623 	return ret;
3624 }
3625 
3626 void atomisp_en_dz_capt_pipe(struct atomisp_sub_device *asd, bool enable)
3627 {
3628 	ia_css_en_dz_capt_pipe(
3629 	    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3630 	    enable);
3631 }
3632 
3633 struct ia_css_dvs_grid_info *atomisp_css_get_dvs_grid_info(
3634     struct ia_css_grid_info *grid_info)
3635 {
3636 	if (!grid_info)
3637 		return NULL;
3638 
3639 #ifdef IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED
3640 	return &grid_info->dvs_grid.dvs_grid_info;
3641 #else
3642 	return &grid_info->dvs_grid;
3643 #endif
3644 }
3645