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