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