1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Support for Medifield PNW Camera Imaging ISP subsystem.
4   *
5   * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
6   *
7   * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
8   *
9   * This program is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU General Public License version
11   * 2 as published by the Free Software Foundation.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   *
18   *
19   */
20  #include <linux/errno.h>
21  #include <linux/firmware.h>
22  #include <linux/pci.h>
23  #include <linux/interrupt.h>
24  #include <linux/io.h>
25  #include <linux/kernel.h>
26  #include <linux/kfifo.h>
27  #include <linux/pm_runtime.h>
28  #include <linux/timer.h>
29  
30  #include <asm/iosf_mbi.h>
31  
32  #include <media/v4l2-event.h>
33  #include <media/videobuf-vmalloc.h>
34  
35  #define CREATE_TRACE_POINTS
36  #include "atomisp_trace_event.h"
37  
38  #include "atomisp_cmd.h"
39  #include "atomisp_common.h"
40  #include "atomisp_fops.h"
41  #include "atomisp_internal.h"
42  #include "atomisp_ioctl.h"
43  #include "atomisp-regs.h"
44  #include "atomisp_tables.h"
45  #include "atomisp_compat.h"
46  #include "atomisp_subdev.h"
47  #include "atomisp_dfs_tables.h"
48  
49  #include <hmm/hmm.h>
50  
51  #include "sh_css_hrt.h"
52  #include "sh_css_defs.h"
53  #include "system_global.h"
54  #include "sh_css_internal.h"
55  #include "sh_css_sp.h"
56  #include "gp_device.h"
57  #include "device_access.h"
58  #include "irq.h"
59  
60  #include "ia_css_types.h"
61  #include "ia_css_stream.h"
62  #include "ia_css_debug.h"
63  #include "bits.h"
64  
65  /* We should never need to run the flash for more than 2 frames.
66   * At 15fps this means 133ms. We set the timeout a bit longer.
67   * Each flash driver is supposed to set its own timeout, but
68   * just in case someone else changed the timeout, we set it
69   * here to make sure we don't damage the flash hardware. */
70  #define FLASH_TIMEOUT 800 /* ms */
71  
72  union host {
73  	struct {
74  		void *kernel_ptr;
75  		void __user *user_ptr;
76  		int size;
77  	} scalar;
78  	struct {
79  		void *hmm_ptr;
80  	} ptr;
81  };
82  
83  static int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id);
84  
85  /*
86   * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field.
87   * subdev->priv is set in mrst.c
88   */
atomisp_to_sensor_mipi_info(struct v4l2_subdev * sd)89  struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd)
90  {
91  	return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd);
92  }
93  
94  /*
95   * get struct atomisp_video_pipe from v4l2 video_device
96   */
atomisp_to_video_pipe(struct video_device * dev)97  struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev)
98  {
99  	return (struct atomisp_video_pipe *)
100  	       container_of(dev, struct atomisp_video_pipe, vdev);
101  }
102  
atomisp_get_sensor_fps(struct atomisp_sub_device * asd)103  static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
104  {
105  	struct v4l2_subdev_frame_interval fi = { 0 };
106  	struct atomisp_device *isp = asd->isp;
107  
108  	unsigned short fps = 0;
109  	int ret;
110  
111  	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
112  			       video, g_frame_interval, &fi);
113  
114  	if (!ret && fi.interval.numerator)
115  		fps = fi.interval.denominator / fi.interval.numerator;
116  
117  	return fps;
118  }
119  
120  /*
121   * DFS progress is shown as follows:
122   * 1. Target frequency is calculated according to FPS/Resolution/ISP running
123   *    mode.
124   * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1
125   *    with proper rounding.
126   * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40
127   *    to 200MHz in ISPSSPM1.
128   * 4. Wait for FREQVALID to be cleared by P-Unit.
129   * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3.
130   */
write_target_freq_to_hw(struct atomisp_device * isp,unsigned int new_freq)131  static int write_target_freq_to_hw(struct atomisp_device *isp,
132  				   unsigned int new_freq)
133  {
134  	unsigned int ratio, timeout, guar_ratio;
135  	u32 isp_sspm1 = 0;
136  	int i;
137  
138  	if (!isp->hpll_freq) {
139  		dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n");
140  		return -EINVAL;
141  	}
142  
143  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
144  	if (isp_sspm1 & ISP_FREQ_VALID_MASK) {
145  		dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n");
146  		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
147  			       isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET));
148  	}
149  
150  	ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1;
151  	guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1;
152  
153  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
154  	isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET);
155  
156  	for (i = 0; i < ISP_DFS_TRY_TIMES; i++) {
157  		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
158  			       isp_sspm1
159  			       | ratio << ISP_REQ_FREQ_OFFSET
160  			       | 1 << ISP_FREQ_VALID_OFFSET
161  			       | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET);
162  
163  		iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
164  		timeout = 20;
165  		while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) {
166  			iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
167  			dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n");
168  			udelay(100);
169  			timeout--;
170  		}
171  
172  		if (timeout != 0)
173  			break;
174  	}
175  
176  	if (timeout == 0) {
177  		dev_err(isp->dev, "DFS failed due to HW error.\n");
178  		return -EINVAL;
179  	}
180  
181  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
182  	timeout = 10;
183  	while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) {
184  		iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
185  		dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n",
186  			new_freq);
187  		udelay(100);
188  		timeout--;
189  	}
190  	if (timeout == 0) {
191  		dev_err(isp->dev, "DFS target freq is rejected by HW.\n");
192  		return -EINVAL;
193  	}
194  
195  	return 0;
196  }
197  
atomisp_freq_scaling(struct atomisp_device * isp,enum atomisp_dfs_mode mode,bool force)198  int atomisp_freq_scaling(struct atomisp_device *isp,
199  			 enum atomisp_dfs_mode mode,
200  			 bool force)
201  {
202  	struct pci_dev *pdev = to_pci_dev(isp->dev);
203  	/* FIXME! Only use subdev[0] status yet */
204  	struct atomisp_sub_device *asd = &isp->asd[0];
205  	const struct atomisp_dfs_config *dfs;
206  	unsigned int new_freq;
207  	struct atomisp_freq_scaling_rule curr_rules;
208  	int i, ret;
209  	unsigned short fps = 0;
210  
211  	if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP) {
212  		dev_err(isp->dev, "DFS cannot proceed due to no power.\n");
213  		return -EINVAL;
214  	}
215  
216  	if ((pdev->device & ATOMISP_PCI_DEVICE_SOC_MASK) ==
217  	    ATOMISP_PCI_DEVICE_SOC_CHT && ATOMISP_USE_YUVPP(asd))
218  		isp->dfs = &dfs_config_cht_soc;
219  
220  	dfs = isp->dfs;
221  
222  	if (dfs->lowest_freq == 0 || dfs->max_freq_at_vmin == 0 ||
223  	    dfs->highest_freq == 0 || dfs->dfs_table_size == 0 ||
224  	    !dfs->dfs_table) {
225  		dev_err(isp->dev, "DFS configuration is invalid.\n");
226  		return -EINVAL;
227  	}
228  
229  	if (mode == ATOMISP_DFS_MODE_LOW) {
230  		new_freq = dfs->lowest_freq;
231  		goto done;
232  	}
233  
234  	if (mode == ATOMISP_DFS_MODE_MAX) {
235  		new_freq = dfs->highest_freq;
236  		goto done;
237  	}
238  
239  	fps = atomisp_get_sensor_fps(asd);
240  	if (fps == 0) {
241  		dev_info(isp->dev,
242  			 "Sensor didn't report FPS. Using DFS max mode.\n");
243  		new_freq = dfs->highest_freq;
244  		goto done;
245  	}
246  
247  	curr_rules.width = asd->fmt[asd->capture_pad].fmt.width;
248  	curr_rules.height = asd->fmt[asd->capture_pad].fmt.height;
249  	curr_rules.fps = fps;
250  	curr_rules.run_mode = asd->run_mode->val;
251  	/*
252  	 * For continuous mode, we need to make the capture setting applied
253  	 * since preview mode, because there is no chance to do this when
254  	 * starting image capture.
255  	 */
256  	if (asd->continuous_mode->val) {
257  		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
258  			curr_rules.run_mode = ATOMISP_RUN_MODE_SDV;
259  		else
260  			curr_rules.run_mode =
261  			    ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE;
262  	}
263  
264  	/* search for the target frequency by looping freq rules*/
265  	for (i = 0; i < dfs->dfs_table_size; i++) {
266  		if (curr_rules.width != dfs->dfs_table[i].width &&
267  		    dfs->dfs_table[i].width != ISP_FREQ_RULE_ANY)
268  			continue;
269  		if (curr_rules.height != dfs->dfs_table[i].height &&
270  		    dfs->dfs_table[i].height != ISP_FREQ_RULE_ANY)
271  			continue;
272  		if (curr_rules.fps != dfs->dfs_table[i].fps &&
273  		    dfs->dfs_table[i].fps != ISP_FREQ_RULE_ANY)
274  			continue;
275  		if (curr_rules.run_mode != dfs->dfs_table[i].run_mode &&
276  		    dfs->dfs_table[i].run_mode != ISP_FREQ_RULE_ANY)
277  			continue;
278  		break;
279  	}
280  
281  	if (i == dfs->dfs_table_size)
282  		new_freq = dfs->max_freq_at_vmin;
283  	else
284  		new_freq = dfs->dfs_table[i].isp_freq;
285  
286  done:
287  	dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq);
288  
289  	if ((new_freq == isp->sw_contex.running_freq) && !force)
290  		return 0;
291  
292  	dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq);
293  
294  	ret = write_target_freq_to_hw(isp, new_freq);
295  	if (!ret) {
296  		isp->sw_contex.running_freq = new_freq;
297  		trace_ipu_pstate(new_freq, -1);
298  	}
299  	return ret;
300  }
301  
302  /*
303   * reset and restore ISP
304   */
atomisp_reset(struct atomisp_device * isp)305  int atomisp_reset(struct atomisp_device *isp)
306  {
307  	/* Reset ISP by power-cycling it */
308  	int ret = 0;
309  
310  	dev_dbg(isp->dev, "%s\n", __func__);
311  	atomisp_css_suspend(isp);
312  	ret = atomisp_runtime_suspend(isp->dev);
313  	if (ret < 0)
314  		dev_err(isp->dev, "atomisp_runtime_suspend failed, %d\n", ret);
315  	ret = atomisp_mrfld_power_down(isp);
316  	if (ret < 0) {
317  		dev_err(isp->dev, "can not disable ISP power\n");
318  	} else {
319  		ret = atomisp_mrfld_power_up(isp);
320  		if (ret < 0)
321  			dev_err(isp->dev, "can not enable ISP power\n");
322  		ret = atomisp_runtime_resume(isp->dev);
323  		if (ret < 0)
324  			dev_err(isp->dev, "atomisp_runtime_resume failed, %d\n", ret);
325  	}
326  	ret = atomisp_css_resume(isp);
327  	if (ret)
328  		isp->isp_fatal_error = true;
329  
330  	return ret;
331  }
332  
333  /*
334   * interrupt disable functions
335   */
disable_isp_irq(enum hrt_isp_css_irq irq)336  static void disable_isp_irq(enum hrt_isp_css_irq irq)
337  {
338  	irq_disable_channel(IRQ0_ID, irq);
339  
340  	if (irq != hrt_isp_css_irq_sp)
341  		return;
342  
343  	cnd_sp_irq_enable(SP0_ID, false);
344  }
345  
346  /*
347   * interrupt clean function
348   */
clear_isp_irq(enum hrt_isp_css_irq irq)349  static void clear_isp_irq(enum hrt_isp_css_irq irq)
350  {
351  	irq_clear_all(IRQ0_ID);
352  }
353  
atomisp_msi_irq_init(struct atomisp_device * isp)354  void atomisp_msi_irq_init(struct atomisp_device *isp)
355  {
356  	struct pci_dev *pdev = to_pci_dev(isp->dev);
357  	u32 msg32;
358  	u16 msg16;
359  
360  	pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32);
361  	msg32 |= 1 << MSI_ENABLE_BIT;
362  	pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32);
363  
364  	msg32 = (1 << INTR_IER) | (1 << INTR_IIR);
365  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32);
366  
367  	pci_read_config_word(pdev, PCI_COMMAND, &msg16);
368  	msg16 |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
369  		  PCI_COMMAND_INTX_DISABLE);
370  	pci_write_config_word(pdev, PCI_COMMAND, msg16);
371  }
372  
atomisp_msi_irq_uninit(struct atomisp_device * isp)373  void atomisp_msi_irq_uninit(struct atomisp_device *isp)
374  {
375  	struct pci_dev *pdev = to_pci_dev(isp->dev);
376  	u32 msg32;
377  	u16 msg16;
378  
379  	pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32);
380  	msg32 &=  ~(1 << MSI_ENABLE_BIT);
381  	pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32);
382  
383  	msg32 = 0x0;
384  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32);
385  
386  	pci_read_config_word(pdev, PCI_COMMAND, &msg16);
387  	msg16 &= ~(PCI_COMMAND_MASTER);
388  	pci_write_config_word(pdev, PCI_COMMAND, msg16);
389  }
390  
atomisp_sof_event(struct atomisp_sub_device * asd)391  static void atomisp_sof_event(struct atomisp_sub_device *asd)
392  {
393  	struct v4l2_event event = {0};
394  
395  	event.type = V4L2_EVENT_FRAME_SYNC;
396  	event.u.frame_sync.frame_sequence = atomic_read(&asd->sof_count);
397  
398  	v4l2_event_queue(asd->subdev.devnode, &event);
399  }
400  
atomisp_eof_event(struct atomisp_sub_device * asd,uint8_t exp_id)401  void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id)
402  {
403  	struct v4l2_event event = {0};
404  
405  	event.type = V4L2_EVENT_FRAME_END;
406  	event.u.frame_sync.frame_sequence = exp_id;
407  
408  	v4l2_event_queue(asd->subdev.devnode, &event);
409  }
410  
atomisp_3a_stats_ready_event(struct atomisp_sub_device * asd,uint8_t exp_id)411  static void atomisp_3a_stats_ready_event(struct atomisp_sub_device *asd,
412  	uint8_t exp_id)
413  {
414  	struct v4l2_event event = {0};
415  
416  	event.type = V4L2_EVENT_ATOMISP_3A_STATS_READY;
417  	event.u.frame_sync.frame_sequence = exp_id;
418  
419  	v4l2_event_queue(asd->subdev.devnode, &event);
420  }
421  
atomisp_metadata_ready_event(struct atomisp_sub_device * asd,enum atomisp_metadata_type md_type)422  static void atomisp_metadata_ready_event(struct atomisp_sub_device *asd,
423  	enum atomisp_metadata_type md_type)
424  {
425  	struct v4l2_event event = {0};
426  
427  	event.type = V4L2_EVENT_ATOMISP_METADATA_READY;
428  	event.u.data[0] = md_type;
429  
430  	v4l2_event_queue(asd->subdev.devnode, &event);
431  }
432  
atomisp_reset_event(struct atomisp_sub_device * asd)433  static void atomisp_reset_event(struct atomisp_sub_device *asd)
434  {
435  	struct v4l2_event event = {0};
436  
437  	event.type = V4L2_EVENT_ATOMISP_CSS_RESET;
438  
439  	v4l2_event_queue(asd->subdev.devnode, &event);
440  }
441  
print_csi_rx_errors(enum mipi_port_id port,struct atomisp_device * isp)442  static void print_csi_rx_errors(enum mipi_port_id port,
443  				struct atomisp_device *isp)
444  {
445  	u32 infos = 0;
446  
447  	atomisp_css_rx_get_irq_info(port, &infos);
448  
449  	dev_err(isp->dev, "CSI Receiver port %d errors:\n", port);
450  	if (infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN)
451  		dev_err(isp->dev, "  buffer overrun");
452  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT)
453  		dev_err(isp->dev, "  start-of-transmission error");
454  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC)
455  		dev_err(isp->dev, "  start-of-transmission sync error");
456  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL)
457  		dev_err(isp->dev, "  control error");
458  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE)
459  		dev_err(isp->dev, "  2 or more ECC errors");
460  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_CRC)
461  		dev_err(isp->dev, "  CRC mismatch");
462  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID)
463  		dev_err(isp->dev, "  unknown error");
464  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC)
465  		dev_err(isp->dev, "  frame sync error");
466  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA)
467  		dev_err(isp->dev, "  frame data error");
468  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT)
469  		dev_err(isp->dev, "  data timeout");
470  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC)
471  		dev_err(isp->dev, "  unknown escape command entry");
472  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC)
473  		dev_err(isp->dev, "  line sync error");
474  }
475  
476  /* Clear irq reg */
clear_irq_reg(struct atomisp_device * isp)477  static void clear_irq_reg(struct atomisp_device *isp)
478  {
479  	struct pci_dev *pdev = to_pci_dev(isp->dev);
480  	u32 msg_ret;
481  
482  	pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &msg_ret);
483  	msg_ret |= 1 << INTR_IIR;
484  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg_ret);
485  }
486  
487  static struct atomisp_sub_device *
__get_asd_from_port(struct atomisp_device * isp,enum mipi_port_id port)488  __get_asd_from_port(struct atomisp_device *isp, enum mipi_port_id port)
489  {
490  	int i;
491  
492  	/* Check which isp subdev to send eof */
493  	for (i = 0; i < isp->num_of_streams; i++) {
494  		struct atomisp_sub_device *asd = &isp->asd[i];
495  		struct camera_mipi_info *mipi_info;
496  
497  		mipi_info = atomisp_to_sensor_mipi_info(
498  				isp->inputs[asd->input_curr].camera);
499  
500  		if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED &&
501  		    __get_mipi_port(isp, mipi_info->port) == port) {
502  			return asd;
503  		}
504  	}
505  
506  	return NULL;
507  }
508  
509  /* interrupt handling function*/
atomisp_isr(int irq,void * dev)510  irqreturn_t atomisp_isr(int irq, void *dev)
511  {
512  	struct atomisp_device *isp = (struct atomisp_device *)dev;
513  	struct atomisp_sub_device *asd;
514  	struct atomisp_css_event eof_event;
515  	unsigned int irq_infos = 0;
516  	unsigned long flags;
517  	unsigned int i;
518  	int err;
519  
520  	spin_lock_irqsave(&isp->lock, flags);
521  	if (isp->sw_contex.power_state != ATOM_ISP_POWER_UP ||
522  	    !isp->css_initialized) {
523  		spin_unlock_irqrestore(&isp->lock, flags);
524  		return IRQ_HANDLED;
525  	}
526  	err = atomisp_css_irq_translate(isp, &irq_infos);
527  	if (err) {
528  		spin_unlock_irqrestore(&isp->lock, flags);
529  		return IRQ_NONE;
530  	}
531  
532  	clear_irq_reg(isp);
533  
534  	if (!atomisp_streaming_count(isp))
535  		goto out_nowake;
536  
537  	for (i = 0; i < isp->num_of_streams; i++) {
538  		asd = &isp->asd[i];
539  
540  		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
541  			continue;
542  		/*
543  		 * Current SOF only support one stream, so the SOF only valid
544  		 * either solely one stream is running
545  		 */
546  		if (irq_infos & IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF) {
547  			atomic_inc(&asd->sof_count);
548  			atomisp_sof_event(asd);
549  
550  			/* If sequence_temp and sequence are the same
551  			 * there where no frames lost so we can increase
552  			 * sequence_temp.
553  			 * If not then processing of frame is still in progress
554  			 * and driver needs to keep old sequence_temp value.
555  			 * NOTE: There is assumption here that ISP will not
556  			 * start processing next frame from sensor before old
557  			 * one is completely done. */
558  			if (atomic_read(&asd->sequence) == atomic_read(
559  				&asd->sequence_temp))
560  				atomic_set(&asd->sequence_temp,
561  					   atomic_read(&asd->sof_count));
562  		}
563  		if (irq_infos & IA_CSS_IRQ_INFO_EVENTS_READY)
564  			atomic_set(&asd->sequence,
565  				   atomic_read(&asd->sequence_temp));
566  	}
567  
568  	if (irq_infos & IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF) {
569  		dev_dbg_ratelimited(isp->dev,
570  				    "irq:0x%x (SOF)\n",
571  				    irq_infos);
572  		irq_infos &= ~IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF;
573  	}
574  
575  	if ((irq_infos & IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR) ||
576  	    (irq_infos & IA_CSS_IRQ_INFO_IF_ERROR)) {
577  		/* handle mipi receiver error */
578  		u32 rx_infos;
579  		enum mipi_port_id port;
580  
581  		for (port = MIPI_PORT0_ID; port <= MIPI_PORT2_ID;
582  		     port++) {
583  			print_csi_rx_errors(port, isp);
584  			atomisp_css_rx_get_irq_info(port, &rx_infos);
585  			atomisp_css_rx_clear_irq_info(port, rx_infos);
586  		}
587  	}
588  
589  	if (irq_infos & IA_CSS_IRQ_INFO_ISYS_EVENTS_READY) {
590  		while (ia_css_dequeue_isys_event(&eof_event.event) ==
591  		       0) {
592  			/* EOF Event does not have the css_pipe returned */
593  			asd = __get_asd_from_port(isp, eof_event.event.port);
594  			if (!asd) {
595  				dev_err(isp->dev, "%s: ISYS event, but no subdev.event:%d",
596  					__func__, eof_event.event.type);
597  				continue;
598  			}
599  
600  			atomisp_eof_event(asd, eof_event.event.exp_id);
601  			dev_dbg_ratelimited(isp->dev,
602  					    "%s ISYS event: EOF exp_id %d, asd %d\n",
603  					    __func__, eof_event.event.exp_id,
604  					    asd->index);
605  		}
606  
607  		irq_infos &= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY;
608  		if (irq_infos == 0)
609  			goto out_nowake;
610  	}
611  
612  	spin_unlock_irqrestore(&isp->lock, flags);
613  
614  	dev_dbg_ratelimited(isp->dev, "irq:0x%x (unhandled)\n", irq_infos);
615  
616  	return IRQ_WAKE_THREAD;
617  
618  out_nowake:
619  	spin_unlock_irqrestore(&isp->lock, flags);
620  
621  	if (irq_infos)
622  		dev_dbg_ratelimited(isp->dev, "irq:0x%x (ignored, as not streaming anymore)\n",
623  				    irq_infos);
624  
625  	return IRQ_HANDLED;
626  }
627  
atomisp_clear_css_buffer_counters(struct atomisp_sub_device * asd)628  void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd)
629  {
630  	int i;
631  
632  	memset(asd->s3a_bufs_in_css, 0, sizeof(asd->s3a_bufs_in_css));
633  	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++)
634  		memset(asd->metadata_bufs_in_css[i], 0,
635  		       sizeof(asd->metadata_bufs_in_css[i]));
636  	asd->dis_bufs_in_css = 0;
637  	asd->video_out_capture.buffers_in_css = 0;
638  	asd->video_out_vf.buffers_in_css = 0;
639  	asd->video_out_preview.buffers_in_css = 0;
640  	asd->video_out_video_capture.buffers_in_css = 0;
641  }
642  
643  /* ISP2400 */
atomisp_buffers_queued(struct atomisp_sub_device * asd)644  bool atomisp_buffers_queued(struct atomisp_sub_device *asd)
645  {
646  	return asd->video_out_capture.buffers_in_css ||
647  	       asd->video_out_vf.buffers_in_css ||
648  	       asd->video_out_preview.buffers_in_css ||
649  	       asd->video_out_video_capture.buffers_in_css;
650  }
651  
652  /* ISP2401 */
atomisp_buffers_queued_pipe(struct atomisp_video_pipe * pipe)653  bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe)
654  {
655  	return pipe->buffers_in_css ? true : false;
656  }
657  
658  /* 0x100000 is the start of dmem inside SP */
659  #define SP_DMEM_BASE	0x100000
660  
dump_sp_dmem(struct atomisp_device * isp,unsigned int addr,unsigned int size)661  void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
662  		  unsigned int size)
663  {
664  	unsigned int data = 0;
665  	unsigned int size32 = DIV_ROUND_UP(size, sizeof(u32));
666  
667  	dev_dbg(isp->dev, "atomisp mmio base: %p\n", isp->base);
668  	dev_dbg(isp->dev, "%s, addr:0x%x, size: %d, size32: %d\n", __func__,
669  		addr, size, size32);
670  	if (size32 * 4 + addr > 0x4000) {
671  		dev_err(isp->dev, "illegal size (%d) or addr (0x%x)\n",
672  			size32, addr);
673  		return;
674  	}
675  	addr += SP_DMEM_BASE;
676  	addr &= 0x003FFFFF;
677  	do {
678  		data = readl(isp->base + addr);
679  		dev_dbg(isp->dev, "%s, \t [0x%x]:0x%x\n", __func__, addr, data);
680  		addr += sizeof(u32);
681  	} while (--size32);
682  }
683  
atomisp_css_frame_to_vbuf(struct atomisp_video_pipe * pipe,struct ia_css_frame * frame)684  static struct videobuf_buffer *atomisp_css_frame_to_vbuf(
685      struct atomisp_video_pipe *pipe, struct ia_css_frame *frame)
686  {
687  	struct videobuf_vmalloc_memory *vm_mem;
688  	struct ia_css_frame *handle;
689  	int i;
690  
691  	for (i = 0; pipe->capq.bufs[i]; i++) {
692  		vm_mem = pipe->capq.bufs[i]->priv;
693  		handle = vm_mem->vaddr;
694  		if (handle && handle->data == frame->data)
695  			return pipe->capq.bufs[i];
696  	}
697  
698  	return NULL;
699  }
700  
atomisp_flush_video_pipe(struct atomisp_sub_device * asd,struct atomisp_video_pipe * pipe)701  static void atomisp_flush_video_pipe(struct atomisp_sub_device *asd,
702  				     struct atomisp_video_pipe *pipe)
703  {
704  	unsigned long irqflags;
705  	int i;
706  
707  	if (!pipe->users)
708  		return;
709  
710  	for (i = 0; pipe->capq.bufs[i]; i++) {
711  		spin_lock_irqsave(&pipe->irq_lock, irqflags);
712  		if (pipe->capq.bufs[i]->state == VIDEOBUF_ACTIVE ||
713  		    pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED) {
714  			pipe->capq.bufs[i]->ts = ktime_get_ns();
715  			pipe->capq.bufs[i]->field_count =
716  			    atomic_read(&asd->sequence) << 1;
717  			dev_dbg(asd->isp->dev, "release buffers on device %s\n",
718  				pipe->vdev.name);
719  			if (pipe->capq.bufs[i]->state == VIDEOBUF_QUEUED)
720  				list_del_init(&pipe->capq.bufs[i]->queue);
721  			pipe->capq.bufs[i]->state = VIDEOBUF_ERROR;
722  			wake_up(&pipe->capq.bufs[i]->done);
723  		}
724  		spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
725  	}
726  }
727  
728  /* Returns queued buffers back to video-core */
atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device * asd)729  void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd)
730  {
731  	atomisp_flush_video_pipe(asd, &asd->video_out_capture);
732  	atomisp_flush_video_pipe(asd, &asd->video_out_vf);
733  	atomisp_flush_video_pipe(asd, &asd->video_out_preview);
734  	atomisp_flush_video_pipe(asd, &asd->video_out_video_capture);
735  }
736  
737  /* clean out the parameters that did not apply */
atomisp_flush_params_queue(struct atomisp_video_pipe * pipe)738  void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe)
739  {
740  	struct atomisp_css_params_with_list *param;
741  
742  	while (!list_empty(&pipe->per_frame_params)) {
743  		param = list_entry(pipe->per_frame_params.next,
744  				   struct atomisp_css_params_with_list, list);
745  		list_del(&param->list);
746  		atomisp_free_css_parameters(&param->params);
747  		kvfree(param);
748  	}
749  }
750  
751  /* Re-queue per-frame parameters */
atomisp_recover_params_queue(struct atomisp_video_pipe * pipe)752  static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe)
753  {
754  	struct atomisp_css_params_with_list *param;
755  	int i;
756  
757  	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
758  		param = pipe->frame_params[i];
759  		if (param)
760  			list_add_tail(&param->list, &pipe->per_frame_params);
761  		pipe->frame_params[i] = NULL;
762  	}
763  	atomisp_handle_parameter_and_buffer(pipe);
764  }
765  
766  /* find atomisp_video_pipe with css pipe id, buffer type and atomisp run_mode */
__atomisp_get_pipe(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,enum ia_css_pipe_id css_pipe_id,enum ia_css_buffer_type buf_type)767  static struct atomisp_video_pipe *__atomisp_get_pipe(
768      struct atomisp_sub_device *asd,
769      enum atomisp_input_stream_id stream_id,
770      enum ia_css_pipe_id css_pipe_id,
771      enum ia_css_buffer_type buf_type)
772  {
773  	/* video is same in online as in continuouscapture mode */
774  	if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
775  		/*
776  		 * Disable vf_pp and run CSS in still capture mode. In this
777  		 * mode, CSS does not cause extra latency with buffering, but
778  		 * scaling is not available.
779  		 */
780  		return &asd->video_out_capture;
781  	} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
782  		/*
783  		 * Disable vf_pp and run CSS in video mode. This allows using
784  		 * ISP scaling but it has one frame delay due to CSS internal
785  		 * buffering.
786  		 */
787  		return &asd->video_out_video_capture;
788  	} else if (css_pipe_id == IA_CSS_PIPE_ID_YUVPP) {
789  		/*
790  		 * to SOC camera, yuvpp pipe is run for capture/video/SDV/ZSL.
791  		 */
792  		if (asd->continuous_mode->val) {
793  			if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
794  				/* SDV case */
795  				switch (buf_type) {
796  				case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
797  					return &asd->video_out_video_capture;
798  				case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
799  					return &asd->video_out_preview;
800  				case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
801  					return &asd->video_out_capture;
802  				default:
803  					return &asd->video_out_vf;
804  				}
805  			} else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
806  				/* ZSL case */
807  				switch (buf_type) {
808  				case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
809  					return &asd->video_out_preview;
810  				case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
811  					return &asd->video_out_capture;
812  				default:
813  					return &asd->video_out_vf;
814  				}
815  			}
816  		} else if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
817  			switch (asd->run_mode->val) {
818  			case ATOMISP_RUN_MODE_VIDEO:
819  				return &asd->video_out_video_capture;
820  			case ATOMISP_RUN_MODE_PREVIEW:
821  				return &asd->video_out_preview;
822  			default:
823  				return &asd->video_out_capture;
824  			}
825  		} else if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
826  			if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
827  				return &asd->video_out_preview;
828  			else
829  				return &asd->video_out_vf;
830  		}
831  	} else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
832  		/* For online video or SDV video pipe. */
833  		if (css_pipe_id == IA_CSS_PIPE_ID_VIDEO ||
834  		    css_pipe_id == IA_CSS_PIPE_ID_COPY ||
835  		    css_pipe_id == IA_CSS_PIPE_ID_YUVPP) {
836  			if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)
837  				return &asd->video_out_video_capture;
838  			return &asd->video_out_preview;
839  		}
840  	} else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
841  		/* For online preview or ZSL preview pipe. */
842  		if (css_pipe_id == IA_CSS_PIPE_ID_PREVIEW ||
843  		    css_pipe_id == IA_CSS_PIPE_ID_COPY ||
844  		    css_pipe_id == IA_CSS_PIPE_ID_YUVPP)
845  			return &asd->video_out_preview;
846  	}
847  	/* For capture pipe. */
848  	if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)
849  		return &asd->video_out_vf;
850  	return &asd->video_out_capture;
851  }
852  
853  enum atomisp_metadata_type
atomisp_get_metadata_type(struct atomisp_sub_device * asd,enum ia_css_pipe_id pipe_id)854  atomisp_get_metadata_type(struct atomisp_sub_device *asd,
855  			  enum ia_css_pipe_id pipe_id)
856  {
857  	if (!asd->continuous_mode->val)
858  		return ATOMISP_MAIN_METADATA;
859  
860  	if (pipe_id == IA_CSS_PIPE_ID_CAPTURE) /* online capture pipe */
861  		return ATOMISP_SEC_METADATA;
862  	else
863  		return ATOMISP_MAIN_METADATA;
864  }
865  
atomisp_buf_done(struct atomisp_sub_device * asd,int error,enum ia_css_buffer_type buf_type,enum ia_css_pipe_id css_pipe_id,bool q_buffers,enum atomisp_input_stream_id stream_id)866  void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
867  		      enum ia_css_buffer_type buf_type,
868  		      enum ia_css_pipe_id css_pipe_id,
869  		      bool q_buffers, enum atomisp_input_stream_id stream_id)
870  {
871  	struct videobuf_buffer *vb = NULL;
872  	struct atomisp_video_pipe *pipe = NULL;
873  	struct atomisp_css_buffer buffer;
874  	bool requeue = false;
875  	int err;
876  	unsigned long irqflags;
877  	struct ia_css_frame *frame = NULL;
878  	struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter;
879  	struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp, *dis_iter;
880  	struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter;
881  	enum atomisp_metadata_type md_type;
882  	struct atomisp_device *isp = asd->isp;
883  	struct v4l2_control ctrl;
884  
885  	lockdep_assert_held(&isp->mutex);
886  
887  	if (
888  	    buf_type != IA_CSS_BUFFER_TYPE_METADATA &&
889  	    buf_type != IA_CSS_BUFFER_TYPE_3A_STATISTICS &&
890  	    buf_type != IA_CSS_BUFFER_TYPE_DIS_STATISTICS &&
891  	    buf_type != IA_CSS_BUFFER_TYPE_OUTPUT_FRAME &&
892  	    buf_type != IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME &&
893  	    buf_type != IA_CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME &&
894  	    buf_type != IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME &&
895  	    buf_type != IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
896  		dev_err(isp->dev, "%s, unsupported buffer type: %d\n",
897  			__func__, buf_type);
898  		return;
899  	}
900  
901  	memset(&buffer, 0, sizeof(struct atomisp_css_buffer));
902  	buffer.css_buffer.type = buf_type;
903  	err = atomisp_css_dequeue_buffer(asd, stream_id, css_pipe_id,
904  					 buf_type, &buffer);
905  	if (err) {
906  		dev_err(isp->dev,
907  			"atomisp_css_dequeue_buffer failed: 0x%x\n", err);
908  		return;
909  	}
910  
911  	/* need to know the atomisp pipe for frame buffers */
912  	pipe = __atomisp_get_pipe(asd, stream_id, css_pipe_id, buf_type);
913  	if (!pipe) {
914  		dev_err(isp->dev, "error getting atomisp pipe\n");
915  		return;
916  	}
917  
918  	switch (buf_type) {
919  	case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
920  		list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp,
921  					 &asd->s3a_stats_in_css, list) {
922  			if (s3a_iter->s3a_data ==
923  			    buffer.css_buffer.data.stats_3a) {
924  				list_del_init(&s3a_iter->list);
925  				list_add_tail(&s3a_iter->list,
926  					      &asd->s3a_stats_ready);
927  				s3a_buf = s3a_iter;
928  				break;
929  			}
930  		}
931  
932  		asd->s3a_bufs_in_css[css_pipe_id]--;
933  		atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id);
934  		if (s3a_buf)
935  			dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n",
936  				__func__, s3a_buf->s3a_data->exp_id);
937  		else
938  			dev_dbg(isp->dev, "%s: s3a stat is ready with no exp_id found\n",
939  				__func__);
940  		break;
941  	case IA_CSS_BUFFER_TYPE_METADATA:
942  		if (error)
943  			break;
944  
945  		md_type = atomisp_get_metadata_type(asd, css_pipe_id);
946  		list_for_each_entry_safe(md_iter, _md_buf_tmp,
947  					 &asd->metadata_in_css[md_type], list) {
948  			if (md_iter->metadata ==
949  			    buffer.css_buffer.data.metadata) {
950  				list_del_init(&md_iter->list);
951  				list_add_tail(&md_iter->list,
952  					      &asd->metadata_ready[md_type]);
953  				md_buf = md_iter;
954  				break;
955  			}
956  		}
957  		asd->metadata_bufs_in_css[stream_id][css_pipe_id]--;
958  		atomisp_metadata_ready_event(asd, md_type);
959  		if (md_buf)
960  			dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n",
961  				__func__, md_buf->metadata->exp_id);
962  		else
963  			dev_dbg(isp->dev, "%s: metadata is ready with no exp_id found\n",
964  				__func__);
965  		break;
966  	case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
967  		list_for_each_entry_safe(dis_iter, _dis_buf_tmp,
968  					 &asd->dis_stats_in_css, list) {
969  			if (dis_iter->dis_data ==
970  			    buffer.css_buffer.data.stats_dvs) {
971  				spin_lock_irqsave(&asd->dis_stats_lock,
972  						  irqflags);
973  				list_del_init(&dis_iter->list);
974  				list_add(&dis_iter->list, &asd->dis_stats);
975  				asd->params.dis_proj_data_valid = true;
976  				spin_unlock_irqrestore(&asd->dis_stats_lock,
977  						       irqflags);
978  				dis_buf = dis_iter;
979  				break;
980  			}
981  		}
982  		asd->dis_bufs_in_css--;
983  		if (dis_buf)
984  			dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n",
985  				__func__, dis_buf->dis_data->exp_id);
986  		else
987  			dev_dbg(isp->dev, "%s: dis stat is ready with no exp_id found\n",
988  				__func__);
989  		break;
990  	case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
991  	case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
992  		pipe->buffers_in_css--;
993  		frame = buffer.css_buffer.data.frame;
994  		if (!frame) {
995  			WARN_ON(1);
996  			break;
997  		}
998  		if (!frame->valid)
999  			error = true;
1000  
1001  		/* FIXME:
1002  		 * YUVPP doesn't set postview exp_id correctlly in SDV mode.
1003  		 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1004  		 */
1005  		if (IS_BYT && buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME &&
1006  		    asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd))
1007  			frame->exp_id = (asd->postview_exp_id++) %
1008  					(ATOMISP_MAX_EXP_ID + 1);
1009  
1010  		dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n",
1011  			__func__, frame->exp_id);
1012  		if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
1013  			if (frame->flash_state
1014  			    == IA_CSS_FRAME_FLASH_STATE_PARTIAL)
1015  				dev_dbg(isp->dev, "%s thumb partially flashed\n",
1016  					__func__);
1017  			else if (frame->flash_state
1018  				 == IA_CSS_FRAME_FLASH_STATE_FULL)
1019  				dev_dbg(isp->dev, "%s thumb completely flashed\n",
1020  					__func__);
1021  			else
1022  				dev_dbg(isp->dev, "%s thumb no flash in this frame\n",
1023  					__func__);
1024  		}
1025  		vb = atomisp_css_frame_to_vbuf(pipe, frame);
1026  		WARN_ON(!vb);
1027  		if (vb)
1028  			pipe->frame_config_id[vb->i] = frame->isp_config_id;
1029  		if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE &&
1030  		    asd->pending_capture_request > 0) {
1031  			err = atomisp_css_offline_capture_configure(asd,
1032  				asd->params.offline_parm.num_captures,
1033  				asd->params.offline_parm.skip_frames,
1034  				asd->params.offline_parm.offset);
1035  
1036  			asd->pending_capture_request--;
1037  
1038  			dev_dbg(isp->dev, "Trigger capture again for new buffer. err=%d\n",
1039  				err);
1040  		}
1041  		break;
1042  	case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
1043  	case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
1044  		pipe->buffers_in_css--;
1045  		frame = buffer.css_buffer.data.frame;
1046  		if (!frame) {
1047  			WARN_ON(1);
1048  			break;
1049  		}
1050  
1051  		if (!frame->valid)
1052  			error = true;
1053  
1054  		/* FIXME:
1055  		 * YUVPP doesn't set preview exp_id correctlly in ZSL mode.
1056  		 * This is a WORKAROUND to set exp_id. see HSDES-1503911606.
1057  		 */
1058  		if (IS_BYT && buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME &&
1059  		    asd->continuous_mode->val && ATOMISP_USE_YUVPP(asd))
1060  			frame->exp_id = (asd->preview_exp_id++) %
1061  					(ATOMISP_MAX_EXP_ID + 1);
1062  
1063  		dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n",
1064  			__func__, frame->exp_id);
1065  		vb = atomisp_css_frame_to_vbuf(pipe, frame);
1066  		if (!vb) {
1067  			WARN_ON(1);
1068  			break;
1069  		}
1070  
1071  		/* free the parameters */
1072  		if (pipe->frame_params[vb->i]) {
1073  			if (asd->params.dvs_6axis ==
1074  			    pipe->frame_params[vb->i]->params.dvs_6axis)
1075  				asd->params.dvs_6axis = NULL;
1076  			atomisp_free_css_parameters(
1077  			    &pipe->frame_params[vb->i]->params);
1078  			kvfree(pipe->frame_params[vb->i]);
1079  			pipe->frame_params[vb->i] = NULL;
1080  		}
1081  
1082  		pipe->frame_config_id[vb->i] = frame->isp_config_id;
1083  		ctrl.id = V4L2_CID_FLASH_MODE;
1084  		if (asd->params.flash_state == ATOMISP_FLASH_ONGOING) {
1085  			if (frame->flash_state
1086  			    == IA_CSS_FRAME_FLASH_STATE_PARTIAL) {
1087  				asd->frame_status[vb->i] =
1088  				    ATOMISP_FRAME_STATUS_FLASH_PARTIAL;
1089  				dev_dbg(isp->dev, "%s partially flashed\n",
1090  					__func__);
1091  			} else if (frame->flash_state
1092  				   == IA_CSS_FRAME_FLASH_STATE_FULL) {
1093  				asd->frame_status[vb->i] =
1094  				    ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
1095  				asd->params.num_flash_frames--;
1096  				dev_dbg(isp->dev, "%s completely flashed\n",
1097  					__func__);
1098  			} else {
1099  				asd->frame_status[vb->i] =
1100  				    ATOMISP_FRAME_STATUS_OK;
1101  				dev_dbg(isp->dev,
1102  					"%s no flash in this frame\n",
1103  					__func__);
1104  			}
1105  
1106  			/* Check if flashing sequence is done */
1107  			if (asd->frame_status[vb->i] ==
1108  			    ATOMISP_FRAME_STATUS_FLASH_EXPOSED)
1109  				asd->params.flash_state = ATOMISP_FLASH_DONE;
1110  		} else if (isp->flash) {
1111  			if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl) ==
1112  			    0 && ctrl.value == ATOMISP_FLASH_MODE_TORCH) {
1113  				ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY;
1114  				if (v4l2_g_ctrl(isp->flash->ctrl_handler, &ctrl)
1115  				    == 0 && ctrl.value > 0) {
1116  					asd->frame_status[vb->i] =
1117  					    ATOMISP_FRAME_STATUS_FLASH_EXPOSED;
1118  				} else {
1119  					asd->frame_status[vb->i] =
1120  					    ATOMISP_FRAME_STATUS_OK;
1121  				}
1122  			} else {
1123  				asd->frame_status[vb->i] =
1124  				    ATOMISP_FRAME_STATUS_OK;
1125  			}
1126  		} else {
1127  			asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK;
1128  		}
1129  
1130  		asd->params.last_frame_status = asd->frame_status[vb->i];
1131  
1132  		if (asd->continuous_mode->val) {
1133  			if (css_pipe_id == IA_CSS_PIPE_ID_PREVIEW ||
1134  			    css_pipe_id == IA_CSS_PIPE_ID_VIDEO) {
1135  				asd->latest_preview_exp_id = frame->exp_id;
1136  			} else if (css_pipe_id ==
1137  				   IA_CSS_PIPE_ID_CAPTURE) {
1138  				if (asd->run_mode->val ==
1139  				    ATOMISP_RUN_MODE_VIDEO)
1140  					dev_dbg(isp->dev, "SDV capture raw buffer id: %u\n",
1141  						frame->exp_id);
1142  				else
1143  					dev_dbg(isp->dev, "ZSL capture raw buffer id: %u\n",
1144  						frame->exp_id);
1145  			}
1146  		}
1147  		/*
1148  		 * Only after enabled the raw buffer lock
1149  		 * and in continuous mode.
1150  		 * in preview/video pipe, each buffer will
1151  		 * be locked automatically, so record it here.
1152  		 */
1153  		if (((css_pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
1154  		     (css_pipe_id == IA_CSS_PIPE_ID_VIDEO)) &&
1155  		    asd->enable_raw_buffer_lock->val &&
1156  		    asd->continuous_mode->val) {
1157  			atomisp_set_raw_buffer_bitmap(asd, frame->exp_id);
1158  			WARN_ON(frame->exp_id > ATOMISP_MAX_EXP_ID);
1159  		}
1160  
1161  		if (asd->params.css_update_params_needed) {
1162  			atomisp_apply_css_parameters(asd,
1163  						     &asd->params.css_param);
1164  			if (asd->params.css_param.update_flag.dz_config)
1165  				asd->params.config.dz_config = &asd->params.css_param.dz_config;
1166  			/* New global dvs 6axis config should be blocked
1167  			 * here if there's a buffer with per-frame parameters
1168  			 * pending in CSS frame buffer queue.
1169  			 * This is to aviod zooming vibration since global
1170  			 * parameters take effect immediately while
1171  			 * per-frame parameters are taken after previous
1172  			 * buffers in CSS got processed.
1173  			 */
1174  			if (asd->params.dvs_6axis)
1175  				atomisp_css_set_dvs_6axis(asd,
1176  							  asd->params.dvs_6axis);
1177  			else
1178  				asd->params.css_update_params_needed = false;
1179  			/* The update flag should not be cleaned here
1180  			 * since it is still going to be used to make up
1181  			 * following per-frame parameters.
1182  			 * This will introduce more copy work since each
1183  			 * time when updating global parameters, the whole
1184  			 * parameter set are applied.
1185  			 * FIXME: A new set of parameter copy functions can
1186  			 * be added to make up per-frame parameters based on
1187  			 * solid structures stored in asd->params.css_param
1188  			 * instead of using shadow pointers in update flag.
1189  			 */
1190  			atomisp_css_update_isp_params(asd);
1191  		}
1192  		break;
1193  	default:
1194  		break;
1195  	}
1196  	if (vb) {
1197  		vb->ts = ktime_get_ns();
1198  		vb->field_count = atomic_read(&asd->sequence) << 1;
1199  		/*mark videobuffer done for dequeue*/
1200  		spin_lock_irqsave(&pipe->irq_lock, irqflags);
1201  		vb->state = !error ? VIDEOBUF_DONE : VIDEOBUF_ERROR;
1202  		spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
1203  
1204  		/*
1205  		 * Frame capture done, wake up any process block on
1206  		 * current active buffer
1207  		 * possibly hold by videobuf_dqbuf()
1208  		 */
1209  		wake_up(&vb->done);
1210  	}
1211  
1212  	/*
1213  	 * Requeue should only be done for 3a and dis buffers.
1214  	 * Queue/dequeue order will change if driver recycles image buffers.
1215  	 */
1216  	if (requeue) {
1217  		err = atomisp_css_queue_buffer(asd,
1218  					       stream_id, css_pipe_id,
1219  					       buf_type, &buffer);
1220  		if (err)
1221  			dev_err(isp->dev, "%s, q to css fails: %d\n",
1222  				__func__, err);
1223  		return;
1224  	}
1225  	if (!error && q_buffers)
1226  		atomisp_qbuffers_to_css(asd);
1227  }
1228  
atomisp_delayed_init_work(struct work_struct * work)1229  void atomisp_delayed_init_work(struct work_struct *work)
1230  {
1231  	struct atomisp_sub_device *asd = container_of(work,
1232  					 struct atomisp_sub_device,
1233  					 delayed_init_work);
1234  	/*
1235  	 * to SOC camera, use yuvpp pipe and no support continuous mode.
1236  	 */
1237  	if (!ATOMISP_USE_YUVPP(asd)) {
1238  		struct v4l2_event event = {0};
1239  		struct ia_css_stream *stream;
1240  
1241  		stream = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
1242  
1243  
1244  		if (ia_css_alloc_continuous_frame_remain(stream))
1245  			return;
1246  
1247  		ia_css_update_continuous_frames(stream);
1248  
1249  		event.type = V4L2_EVENT_ATOMISP_RAW_BUFFERS_ALLOC_DONE;
1250  		v4l2_event_queue(asd->subdev.devnode, &event);
1251  	}
1252  
1253  	/* signal streamon after delayed init is done */
1254  	asd->delayed_init = ATOMISP_DELAYED_INIT_DONE;
1255  	complete(&asd->init_done);
1256  }
1257  
__atomisp_css_recover(struct atomisp_device * isp,bool isp_timeout)1258  static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout)
1259  {
1260  	struct pci_dev *pdev = to_pci_dev(isp->dev);
1261  	enum ia_css_pipe_id css_pipe_id;
1262  	bool stream_restart[MAX_STREAM_NUM] = {0};
1263  	bool depth_mode = false;
1264  	int i, ret, depth_cnt = 0;
1265  	unsigned long flags;
1266  
1267  	lockdep_assert_held(&isp->mutex);
1268  
1269  	if (!atomisp_streaming_count(isp))
1270  		return;
1271  
1272  	atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false);
1273  
1274  	BUG_ON(isp->num_of_streams > MAX_STREAM_NUM);
1275  
1276  	for (i = 0; i < isp->num_of_streams; i++) {
1277  		struct atomisp_sub_device *asd = &isp->asd[i];
1278  
1279  		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED &&
1280  		    !asd->stream_prepared)
1281  			continue;
1282  
1283  		depth_cnt++;
1284  
1285  		if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED)
1286  			cancel_work_sync(&asd->delayed_init_work);
1287  
1288  		complete(&asd->init_done);
1289  		asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED;
1290  
1291  		stream_restart[asd->index] = true;
1292  
1293  		spin_lock_irqsave(&isp->lock, flags);
1294  		asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING;
1295  		spin_unlock_irqrestore(&isp->lock, flags);
1296  
1297  		/* stream off sensor */
1298  		ret = v4l2_subdev_call(
1299  			  isp->inputs[asd->input_curr].
1300  			  camera, video, s_stream, 0);
1301  		if (ret)
1302  			dev_warn(isp->dev,
1303  				 "can't stop streaming on sensor!\n");
1304  
1305  		atomisp_clear_css_buffer_counters(asd);
1306  
1307  		css_pipe_id = atomisp_get_css_pipe_id(asd);
1308  		atomisp_css_stop(asd, css_pipe_id, true);
1309  
1310  		spin_lock_irqsave(&isp->lock, flags);
1311  		asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
1312  		spin_unlock_irqrestore(&isp->lock, flags);
1313  
1314  		asd->preview_exp_id = 1;
1315  		asd->postview_exp_id = 1;
1316  		/* notify HAL the CSS reset */
1317  		dev_dbg(isp->dev,
1318  			"send reset event to %s\n", asd->subdev.devnode->name);
1319  		atomisp_reset_event(asd);
1320  	}
1321  
1322  	/* clear irq */
1323  	disable_isp_irq(hrt_isp_css_irq_sp);
1324  	clear_isp_irq(hrt_isp_css_irq_sp);
1325  
1326  	/* Set the SRSE to 3 before resetting */
1327  	pci_write_config_dword(pdev, PCI_I_CONTROL,
1328  			       isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK);
1329  
1330  	/* reset ISP and restore its state */
1331  	isp->isp_timeout = true;
1332  	atomisp_reset(isp);
1333  	isp->isp_timeout = false;
1334  
1335  	if (!isp_timeout) {
1336  		for (i = 0; i < isp->num_of_streams; i++) {
1337  			if (isp->asd[i].depth_mode->val)
1338  				return;
1339  		}
1340  	}
1341  
1342  	for (i = 0; i < isp->num_of_streams; i++) {
1343  		struct atomisp_sub_device *asd = &isp->asd[i];
1344  
1345  		if (!stream_restart[i])
1346  			continue;
1347  
1348  		if (isp->inputs[asd->input_curr].type != FILE_INPUT)
1349  			atomisp_css_input_set_mode(asd,
1350  						   IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
1351  
1352  		css_pipe_id = atomisp_get_css_pipe_id(asd);
1353  		if (atomisp_css_start(asd, css_pipe_id, true)) {
1354  			dev_warn(isp->dev,
1355  				 "start SP failed, so do not set streaming to be enable!\n");
1356  		} else {
1357  			spin_lock_irqsave(&isp->lock, flags);
1358  			asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED;
1359  			spin_unlock_irqrestore(&isp->lock, flags);
1360  		}
1361  
1362  		atomisp_csi2_configure(asd);
1363  	}
1364  
1365  	atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF,
1366  			       atomisp_css_valid_sof(isp));
1367  
1368  	if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0)
1369  		dev_dbg(isp->dev, "DFS auto failed while recovering!\n");
1370  
1371  	for (i = 0; i < isp->num_of_streams; i++) {
1372  		struct atomisp_sub_device *asd;
1373  
1374  		asd = &isp->asd[i];
1375  
1376  		if (!stream_restart[i])
1377  			continue;
1378  
1379  		if (asd->continuous_mode->val &&
1380  		    asd->delayed_init == ATOMISP_DELAYED_INIT_NOT_QUEUED) {
1381  			reinit_completion(&asd->init_done);
1382  			asd->delayed_init = ATOMISP_DELAYED_INIT_QUEUED;
1383  			queue_work(asd->delayed_init_workq,
1384  				   &asd->delayed_init_work);
1385  		}
1386  		/*
1387  		 * dequeueing buffers is not needed. CSS will recycle
1388  		 * buffers that it has.
1389  		 */
1390  		atomisp_flush_bufs_and_wakeup(asd);
1391  
1392  		/* Requeue unprocessed per-frame parameters. */
1393  		atomisp_recover_params_queue(&asd->video_out_capture);
1394  		atomisp_recover_params_queue(&asd->video_out_preview);
1395  		atomisp_recover_params_queue(&asd->video_out_video_capture);
1396  
1397  		if ((asd->depth_mode->val) &&
1398  		    (depth_cnt == ATOMISP_DEPTH_SENSOR_STREAMON_COUNT)) {
1399  			depth_mode = true;
1400  			continue;
1401  		}
1402  
1403  		ret = v4l2_subdev_call(
1404  			  isp->inputs[asd->input_curr].camera, video,
1405  			  s_stream, 1);
1406  		if (ret)
1407  			dev_warn(isp->dev,
1408  				 "can't start streaming on sensor!\n");
1409  	}
1410  
1411  	if (depth_mode) {
1412  		if (atomisp_stream_on_master_slave_sensor(isp, true))
1413  			dev_warn(isp->dev,
1414  				 "master slave sensor stream on failed!\n");
1415  	}
1416  }
1417  
atomisp_assert_recovery_work(struct work_struct * work)1418  void atomisp_assert_recovery_work(struct work_struct *work)
1419  {
1420  	struct atomisp_device *isp = container_of(work, struct atomisp_device,
1421  						  assert_recovery_work);
1422  
1423  	mutex_lock(&isp->mutex);
1424  	__atomisp_css_recover(isp, true);
1425  	mutex_unlock(&isp->mutex);
1426  }
1427  
atomisp_css_flush(struct atomisp_device * isp)1428  void atomisp_css_flush(struct atomisp_device *isp)
1429  {
1430  	/* Start recover */
1431  	__atomisp_css_recover(isp, false);
1432  
1433  	dev_dbg(isp->dev, "atomisp css flush done\n");
1434  }
1435  
atomisp_setup_flash(struct atomisp_sub_device * asd)1436  void atomisp_setup_flash(struct atomisp_sub_device *asd)
1437  {
1438  	struct atomisp_device *isp = asd->isp;
1439  	struct v4l2_control ctrl;
1440  
1441  	if (!isp->flash)
1442  		return;
1443  
1444  	if (asd->params.flash_state != ATOMISP_FLASH_REQUESTED &&
1445  	    asd->params.flash_state != ATOMISP_FLASH_DONE)
1446  		return;
1447  
1448  	if (asd->params.num_flash_frames) {
1449  		/* make sure the timeout is set before setting flash mode */
1450  		ctrl.id = V4L2_CID_FLASH_TIMEOUT;
1451  		ctrl.value = FLASH_TIMEOUT;
1452  
1453  		if (v4l2_s_ctrl(NULL, isp->flash->ctrl_handler, &ctrl)) {
1454  			dev_err(isp->dev, "flash timeout configure failed\n");
1455  			return;
1456  		}
1457  
1458  		ia_css_stream_request_flash(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream);
1459  
1460  		asd->params.flash_state = ATOMISP_FLASH_ONGOING;
1461  	} else {
1462  		asd->params.flash_state = ATOMISP_FLASH_IDLE;
1463  	}
1464  }
1465  
atomisp_isr_thread(int irq,void * isp_ptr)1466  irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
1467  {
1468  	struct atomisp_device *isp = isp_ptr;
1469  	unsigned long flags;
1470  	bool frame_done_found[MAX_STREAM_NUM] = {0};
1471  	bool css_pipe_done[MAX_STREAM_NUM] = {0};
1472  	unsigned int i;
1473  	struct atomisp_sub_device *asd;
1474  
1475  	dev_dbg(isp->dev, ">%s\n", __func__);
1476  
1477  	spin_lock_irqsave(&isp->lock, flags);
1478  
1479  	if (!atomisp_streaming_count(isp)) {
1480  		spin_unlock_irqrestore(&isp->lock, flags);
1481  		return IRQ_HANDLED;
1482  	}
1483  
1484  	spin_unlock_irqrestore(&isp->lock, flags);
1485  
1486  	/*
1487  	 * The standard CSS2.0 API tells the following calling sequence of
1488  	 * dequeue ready buffers:
1489  	 * while (ia_css_dequeue_psys_event(...)) {
1490  	 *	switch (event.type) {
1491  	 *	...
1492  	 *	ia_css_pipe_dequeue_buffer()
1493  	 *	}
1494  	 * }
1495  	 * That is, dequeue event and buffer are one after another.
1496  	 *
1497  	 * But the following implementation is to first deuque all the event
1498  	 * to a FIFO, then process the event in the FIFO.
1499  	 * This will not have issue in single stream mode, but it do have some
1500  	 * issue in multiple stream case. The issue is that
1501  	 * ia_css_pipe_dequeue_buffer() will not return the corrent buffer in
1502  	 * a specific pipe.
1503  	 *
1504  	 * This is due to ia_css_pipe_dequeue_buffer() does not take the
1505  	 * ia_css_pipe parameter.
1506  	 *
1507  	 * So:
1508  	 * For CSS2.0: we change the way to not dequeue all the event at one
1509  	 * time, instead, dequue one and process one, then another
1510  	 */
1511  	mutex_lock(&isp->mutex);
1512  	if (atomisp_css_isr_thread(isp, frame_done_found, css_pipe_done))
1513  		goto out;
1514  
1515  	for (i = 0; i < isp->num_of_streams; i++) {
1516  		asd = &isp->asd[i];
1517  		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
1518  			continue;
1519  		atomisp_setup_flash(asd);
1520  	}
1521  out:
1522  	mutex_unlock(&isp->mutex);
1523  	dev_dbg(isp->dev, "<%s\n", __func__);
1524  
1525  	return IRQ_HANDLED;
1526  }
1527  
1528  /*
1529   * Get internal fmt according to V4L2 fmt
1530   */
1531  static enum ia_css_frame_format
v4l2_fmt_to_sh_fmt(u32 fmt)1532  v4l2_fmt_to_sh_fmt(u32 fmt)
1533  {
1534  	switch (fmt) {
1535  	case V4L2_PIX_FMT_YUV420:
1536  				return IA_CSS_FRAME_FORMAT_YUV420;
1537  	case V4L2_PIX_FMT_YVU420:
1538  		return IA_CSS_FRAME_FORMAT_YV12;
1539  	case V4L2_PIX_FMT_YUV422P:
1540  		return IA_CSS_FRAME_FORMAT_YUV422;
1541  	case V4L2_PIX_FMT_YUV444:
1542  		return IA_CSS_FRAME_FORMAT_YUV444;
1543  	case V4L2_PIX_FMT_NV12:
1544  		return IA_CSS_FRAME_FORMAT_NV12;
1545  	case V4L2_PIX_FMT_NV21:
1546  		return IA_CSS_FRAME_FORMAT_NV21;
1547  	case V4L2_PIX_FMT_NV16:
1548  		return IA_CSS_FRAME_FORMAT_NV16;
1549  	case V4L2_PIX_FMT_NV61:
1550  		return IA_CSS_FRAME_FORMAT_NV61;
1551  	case V4L2_PIX_FMT_UYVY:
1552  		return IA_CSS_FRAME_FORMAT_UYVY;
1553  	case V4L2_PIX_FMT_YUYV:
1554  		return IA_CSS_FRAME_FORMAT_YUYV;
1555  	case V4L2_PIX_FMT_RGB24:
1556  		return IA_CSS_FRAME_FORMAT_PLANAR_RGB888;
1557  	case V4L2_PIX_FMT_RGB32:
1558  		return IA_CSS_FRAME_FORMAT_RGBA888;
1559  	case V4L2_PIX_FMT_RGB565:
1560  		return IA_CSS_FRAME_FORMAT_RGB565;
1561  #if 0
1562  	case V4L2_PIX_FMT_JPEG:
1563  	case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
1564  		return IA_CSS_FRAME_FORMAT_BINARY_8;
1565  #endif
1566  	case V4L2_PIX_FMT_SBGGR16:
1567  	case V4L2_PIX_FMT_SBGGR10:
1568  	case V4L2_PIX_FMT_SGBRG10:
1569  	case V4L2_PIX_FMT_SGRBG10:
1570  	case V4L2_PIX_FMT_SRGGB10:
1571  	case V4L2_PIX_FMT_SBGGR12:
1572  	case V4L2_PIX_FMT_SGBRG12:
1573  	case V4L2_PIX_FMT_SGRBG12:
1574  	case V4L2_PIX_FMT_SRGGB12:
1575  	case V4L2_PIX_FMT_SBGGR8:
1576  	case V4L2_PIX_FMT_SGBRG8:
1577  	case V4L2_PIX_FMT_SGRBG8:
1578  	case V4L2_PIX_FMT_SRGGB8:
1579  		return IA_CSS_FRAME_FORMAT_RAW;
1580  	default:
1581  		return -EINVAL;
1582  	}
1583  }
1584  
1585  /*
1586   * raw format match between SH format and V4L2 format
1587   */
raw_output_format_match_input(u32 input,u32 output)1588  static int raw_output_format_match_input(u32 input, u32 output)
1589  {
1590  	if ((input == ATOMISP_INPUT_FORMAT_RAW_12) &&
1591  	    ((output == V4L2_PIX_FMT_SRGGB12) ||
1592  	     (output == V4L2_PIX_FMT_SGRBG12) ||
1593  	     (output == V4L2_PIX_FMT_SBGGR12) ||
1594  	     (output == V4L2_PIX_FMT_SGBRG12)))
1595  		return 0;
1596  
1597  	if ((input == ATOMISP_INPUT_FORMAT_RAW_10) &&
1598  	    ((output == V4L2_PIX_FMT_SRGGB10) ||
1599  	     (output == V4L2_PIX_FMT_SGRBG10) ||
1600  	     (output == V4L2_PIX_FMT_SBGGR10) ||
1601  	     (output == V4L2_PIX_FMT_SGBRG10)))
1602  		return 0;
1603  
1604  	if ((input == ATOMISP_INPUT_FORMAT_RAW_8) &&
1605  	    ((output == V4L2_PIX_FMT_SRGGB8) ||
1606  	     (output == V4L2_PIX_FMT_SGRBG8) ||
1607  	     (output == V4L2_PIX_FMT_SBGGR8) ||
1608  	     (output == V4L2_PIX_FMT_SGBRG8)))
1609  		return 0;
1610  
1611  	if ((input == ATOMISP_INPUT_FORMAT_RAW_16) && (output == V4L2_PIX_FMT_SBGGR16))
1612  		return 0;
1613  
1614  	return -EINVAL;
1615  }
1616  
atomisp_get_pixel_depth(u32 pixelformat)1617  u32 atomisp_get_pixel_depth(u32 pixelformat)
1618  {
1619  	switch (pixelformat) {
1620  	case V4L2_PIX_FMT_YUV420:
1621  	case V4L2_PIX_FMT_NV12:
1622  	case V4L2_PIX_FMT_NV21:
1623  	case V4L2_PIX_FMT_YVU420:
1624  		return 12;
1625  	case V4L2_PIX_FMT_YUV422P:
1626  	case V4L2_PIX_FMT_YUYV:
1627  	case V4L2_PIX_FMT_UYVY:
1628  	case V4L2_PIX_FMT_NV16:
1629  	case V4L2_PIX_FMT_NV61:
1630  	case V4L2_PIX_FMT_RGB565:
1631  	case V4L2_PIX_FMT_SBGGR16:
1632  	case V4L2_PIX_FMT_SBGGR12:
1633  	case V4L2_PIX_FMT_SGBRG12:
1634  	case V4L2_PIX_FMT_SGRBG12:
1635  	case V4L2_PIX_FMT_SRGGB12:
1636  	case V4L2_PIX_FMT_SBGGR10:
1637  	case V4L2_PIX_FMT_SGBRG10:
1638  	case V4L2_PIX_FMT_SGRBG10:
1639  	case V4L2_PIX_FMT_SRGGB10:
1640  		return 16;
1641  	case V4L2_PIX_FMT_RGB24:
1642  	case V4L2_PIX_FMT_YUV444:
1643  		return 24;
1644  	case V4L2_PIX_FMT_RGB32:
1645  		return 32;
1646  	case V4L2_PIX_FMT_JPEG:
1647  	case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
1648  	case V4L2_PIX_FMT_SBGGR8:
1649  	case V4L2_PIX_FMT_SGBRG8:
1650  	case V4L2_PIX_FMT_SGRBG8:
1651  	case V4L2_PIX_FMT_SRGGB8:
1652  		return 8;
1653  	default:
1654  		return 8 * 2;	/* raw type now */
1655  	}
1656  }
1657  
atomisp_is_mbuscode_raw(uint32_t code)1658  bool atomisp_is_mbuscode_raw(uint32_t code)
1659  {
1660  	return code >= 0x3000 && code < 0x4000;
1661  }
1662  
1663  /*
1664   * ISP features control function
1665   */
1666  
1667  /*
1668   * Set ISP capture mode based on current settings
1669   */
atomisp_update_capture_mode(struct atomisp_sub_device * asd)1670  static void atomisp_update_capture_mode(struct atomisp_sub_device *asd)
1671  {
1672  	if (asd->params.gdc_cac_en)
1673  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_ADVANCED);
1674  	else if (asd->params.low_light)
1675  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_LOW_LIGHT);
1676  	else if (asd->video_out_capture.sh_fmt == IA_CSS_FRAME_FORMAT_RAW)
1677  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW);
1678  	else
1679  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_PRIMARY);
1680  }
1681  
1682  /* ISP2401 */
atomisp_set_sensor_runmode(struct atomisp_sub_device * asd,struct atomisp_s_runmode * runmode)1683  int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd,
1684  			       struct atomisp_s_runmode *runmode)
1685  {
1686  	struct atomisp_device *isp = asd->isp;
1687  	struct v4l2_ctrl *c;
1688  	int ret = 0;
1689  
1690  	if (!(runmode && (runmode->mode & RUNMODE_MASK)))
1691  		return -EINVAL;
1692  
1693  	mutex_lock(asd->ctrl_handler.lock);
1694  	c = v4l2_ctrl_find(isp->inputs[asd->input_curr].camera->ctrl_handler,
1695  			   V4L2_CID_RUN_MODE);
1696  
1697  	if (c)
1698  		ret = v4l2_ctrl_s_ctrl(c, runmode->mode);
1699  
1700  	mutex_unlock(asd->ctrl_handler.lock);
1701  	return ret;
1702  }
1703  
1704  /*
1705   * Function to enable/disable lens geometry distortion correction (GDC) and
1706   * chromatic aberration correction (CAC)
1707   */
atomisp_gdc_cac(struct atomisp_sub_device * asd,int flag,__s32 * value)1708  int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
1709  		    __s32 *value)
1710  {
1711  	if (flag == 0) {
1712  		*value = asd->params.gdc_cac_en;
1713  		return 0;
1714  	}
1715  
1716  	asd->params.gdc_cac_en = !!*value;
1717  	if (asd->params.gdc_cac_en) {
1718  		asd->params.config.morph_table = asd->params.css_param.morph_table;
1719  	} else {
1720  		asd->params.config.morph_table = NULL;
1721  	}
1722  	asd->params.css_update_params_needed = true;
1723  	atomisp_update_capture_mode(asd);
1724  	return 0;
1725  }
1726  
1727  /*
1728   * Function to enable/disable low light mode including ANR
1729   */
atomisp_low_light(struct atomisp_sub_device * asd,int flag,__s32 * value)1730  int atomisp_low_light(struct atomisp_sub_device *asd, int flag,
1731  		      __s32 *value)
1732  {
1733  	if (flag == 0) {
1734  		*value = asd->params.low_light;
1735  		return 0;
1736  	}
1737  
1738  	asd->params.low_light = (*value != 0);
1739  	atomisp_update_capture_mode(asd);
1740  	return 0;
1741  }
1742  
1743  /*
1744   * Function to enable/disable extra noise reduction (XNR) in low light
1745   * condition
1746   */
atomisp_xnr(struct atomisp_sub_device * asd,int flag,int * xnr_enable)1747  int atomisp_xnr(struct atomisp_sub_device *asd, int flag,
1748  		int *xnr_enable)
1749  {
1750  	if (flag == 0) {
1751  		*xnr_enable = asd->params.xnr_en;
1752  		return 0;
1753  	}
1754  
1755  	atomisp_css_capture_enable_xnr(asd, !!*xnr_enable);
1756  
1757  	return 0;
1758  }
1759  
1760  /*
1761   * Function to configure bayer noise reduction
1762   */
atomisp_nr(struct atomisp_sub_device * asd,int flag,struct atomisp_nr_config * arg)1763  int atomisp_nr(struct atomisp_sub_device *asd, int flag,
1764  	       struct atomisp_nr_config *arg)
1765  {
1766  	if (flag == 0) {
1767  		/* Get nr config from current setup */
1768  		if (atomisp_css_get_nr_config(asd, arg))
1769  			return -EINVAL;
1770  	} else {
1771  		/* Set nr config to isp parameters */
1772  		memcpy(&asd->params.css_param.nr_config, arg,
1773  		       sizeof(struct ia_css_nr_config));
1774  		asd->params.config.nr_config = &asd->params.css_param.nr_config;
1775  		asd->params.css_update_params_needed = true;
1776  	}
1777  	return 0;
1778  }
1779  
1780  /*
1781   * Function to configure temporal noise reduction (TNR)
1782   */
atomisp_tnr(struct atomisp_sub_device * asd,int flag,struct atomisp_tnr_config * config)1783  int atomisp_tnr(struct atomisp_sub_device *asd, int flag,
1784  		struct atomisp_tnr_config *config)
1785  {
1786  	/* Get tnr config from current setup */
1787  	if (flag == 0) {
1788  		/* Get tnr config from current setup */
1789  		if (atomisp_css_get_tnr_config(asd, config))
1790  			return -EINVAL;
1791  	} else {
1792  		/* Set tnr config to isp parameters */
1793  		memcpy(&asd->params.css_param.tnr_config, config,
1794  		       sizeof(struct ia_css_tnr_config));
1795  		asd->params.config.tnr_config = &asd->params.css_param.tnr_config;
1796  		asd->params.css_update_params_needed = true;
1797  	}
1798  
1799  	return 0;
1800  }
1801  
1802  /*
1803   * Function to configure black level compensation
1804   */
atomisp_black_level(struct atomisp_sub_device * asd,int flag,struct atomisp_ob_config * config)1805  int atomisp_black_level(struct atomisp_sub_device *asd, int flag,
1806  			struct atomisp_ob_config *config)
1807  {
1808  	if (flag == 0) {
1809  		/* Get ob config from current setup */
1810  		if (atomisp_css_get_ob_config(asd, config))
1811  			return -EINVAL;
1812  	} else {
1813  		/* Set ob config to isp parameters */
1814  		memcpy(&asd->params.css_param.ob_config, config,
1815  		       sizeof(struct ia_css_ob_config));
1816  		asd->params.config.ob_config = &asd->params.css_param.ob_config;
1817  		asd->params.css_update_params_needed = true;
1818  	}
1819  
1820  	return 0;
1821  }
1822  
1823  /*
1824   * Function to configure edge enhancement
1825   */
atomisp_ee(struct atomisp_sub_device * asd,int flag,struct atomisp_ee_config * config)1826  int atomisp_ee(struct atomisp_sub_device *asd, int flag,
1827  	       struct atomisp_ee_config *config)
1828  {
1829  	if (flag == 0) {
1830  		/* Get ee config from current setup */
1831  		if (atomisp_css_get_ee_config(asd, config))
1832  			return -EINVAL;
1833  	} else {
1834  		/* Set ee config to isp parameters */
1835  		memcpy(&asd->params.css_param.ee_config, config,
1836  		       sizeof(asd->params.css_param.ee_config));
1837  		asd->params.config.ee_config = &asd->params.css_param.ee_config;
1838  		asd->params.css_update_params_needed = true;
1839  	}
1840  
1841  	return 0;
1842  }
1843  
1844  /*
1845   * Function to update Gamma table for gamma, brightness and contrast config
1846   */
atomisp_gamma(struct atomisp_sub_device * asd,int flag,struct atomisp_gamma_table * config)1847  int atomisp_gamma(struct atomisp_sub_device *asd, int flag,
1848  		  struct atomisp_gamma_table *config)
1849  {
1850  	if (flag == 0) {
1851  		/* Get gamma table from current setup */
1852  		if (atomisp_css_get_gamma_table(asd, config))
1853  			return -EINVAL;
1854  	} else {
1855  		/* Set gamma table to isp parameters */
1856  		memcpy(&asd->params.css_param.gamma_table, config,
1857  		       sizeof(asd->params.css_param.gamma_table));
1858  		asd->params.config.gamma_table = &asd->params.css_param.gamma_table;
1859  	}
1860  
1861  	return 0;
1862  }
1863  
1864  /*
1865   * Function to update Ctc table for Chroma Enhancement
1866   */
atomisp_ctc(struct atomisp_sub_device * asd,int flag,struct atomisp_ctc_table * config)1867  int atomisp_ctc(struct atomisp_sub_device *asd, int flag,
1868  		struct atomisp_ctc_table *config)
1869  {
1870  	if (flag == 0) {
1871  		/* Get ctc table from current setup */
1872  		if (atomisp_css_get_ctc_table(asd, config))
1873  			return -EINVAL;
1874  	} else {
1875  		/* Set ctc table to isp parameters */
1876  		memcpy(&asd->params.css_param.ctc_table, config,
1877  		       sizeof(asd->params.css_param.ctc_table));
1878  		atomisp_css_set_ctc_table(asd, &asd->params.css_param.ctc_table);
1879  	}
1880  
1881  	return 0;
1882  }
1883  
1884  /*
1885   * Function to update gamma correction parameters
1886   */
atomisp_gamma_correction(struct atomisp_sub_device * asd,int flag,struct atomisp_gc_config * config)1887  int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag,
1888  			     struct atomisp_gc_config *config)
1889  {
1890  	if (flag == 0) {
1891  		/* Get gamma correction params from current setup */
1892  		if (atomisp_css_get_gc_config(asd, config))
1893  			return -EINVAL;
1894  	} else {
1895  		/* Set gamma correction params to isp parameters */
1896  		memcpy(&asd->params.css_param.gc_config, config,
1897  		       sizeof(asd->params.css_param.gc_config));
1898  		asd->params.config.gc_config = &asd->params.css_param.gc_config;
1899  		asd->params.css_update_params_needed = true;
1900  	}
1901  
1902  	return 0;
1903  }
1904  
1905  /*
1906   * Function to update narrow gamma flag
1907   */
atomisp_formats(struct atomisp_sub_device * asd,int flag,struct atomisp_formats_config * config)1908  int atomisp_formats(struct atomisp_sub_device *asd, int flag,
1909  		    struct atomisp_formats_config *config)
1910  {
1911  	if (flag == 0) {
1912  		/* Get narrow gamma flag from current setup */
1913  		if (atomisp_css_get_formats_config(asd, config))
1914  			return -EINVAL;
1915  	} else {
1916  		/* Set narrow gamma flag to isp parameters */
1917  		memcpy(&asd->params.css_param.formats_config, config,
1918  		       sizeof(asd->params.css_param.formats_config));
1919  		asd->params.config.formats_config = &asd->params.css_param.formats_config;
1920  	}
1921  
1922  	return 0;
1923  }
1924  
atomisp_free_internal_buffers(struct atomisp_sub_device * asd)1925  void atomisp_free_internal_buffers(struct atomisp_sub_device *asd)
1926  {
1927  	atomisp_free_css_parameters(&asd->params.css_param);
1928  
1929  	if (asd->raw_output_frame) {
1930  		ia_css_frame_free(asd->raw_output_frame);
1931  		asd->raw_output_frame = NULL;
1932  	}
1933  }
1934  
atomisp_update_grid_info(struct atomisp_sub_device * asd,enum ia_css_pipe_id pipe_id,int source_pad)1935  static void atomisp_update_grid_info(struct atomisp_sub_device *asd,
1936  				     enum ia_css_pipe_id pipe_id,
1937  				     int source_pad)
1938  {
1939  	struct atomisp_device *isp = asd->isp;
1940  	int err;
1941  
1942  	if (atomisp_css_get_grid_info(asd, pipe_id, source_pad))
1943  		return;
1944  
1945  	/* We must free all buffers because they no longer match
1946  	   the grid size. */
1947  	atomisp_css_free_stat_buffers(asd);
1948  
1949  	err = atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL);
1950  	if (err) {
1951  		dev_err(isp->dev, "stat_buf allocate error\n");
1952  		goto err;
1953  	}
1954  
1955  	if (atomisp_alloc_3a_output_buf(asd)) {
1956  		/* Failure for 3A buffers does not influence DIS buffers */
1957  		if (asd->params.s3a_output_bytes != 0) {
1958  			/* For SOC sensor happens s3a_output_bytes == 0,
1959  			 * using if condition to exclude false error log */
1960  			dev_err(isp->dev, "Failed to allocate memory for 3A statistics\n");
1961  		}
1962  		goto err;
1963  	}
1964  
1965  	if (atomisp_alloc_dis_coef_buf(asd)) {
1966  		dev_err(isp->dev,
1967  			"Failed to allocate memory for DIS statistics\n");
1968  		goto err;
1969  	}
1970  
1971  	if (atomisp_alloc_metadata_output_buf(asd)) {
1972  		dev_err(isp->dev, "Failed to allocate memory for metadata\n");
1973  		goto err;
1974  	}
1975  
1976  	return;
1977  
1978  err:
1979  	atomisp_css_free_stat_buffers(asd);
1980  	return;
1981  }
1982  
atomisp_curr_user_grid_info(struct atomisp_sub_device * asd,struct atomisp_grid_info * info)1983  static void atomisp_curr_user_grid_info(struct atomisp_sub_device *asd,
1984  					struct atomisp_grid_info *info)
1985  {
1986  	memcpy(info, &asd->params.curr_grid_info.s3a_grid,
1987  	       sizeof(struct ia_css_3a_grid_info));
1988  }
1989  
atomisp_compare_grid(struct atomisp_sub_device * asd,struct atomisp_grid_info * atomgrid)1990  int atomisp_compare_grid(struct atomisp_sub_device *asd,
1991  			 struct atomisp_grid_info *atomgrid)
1992  {
1993  	struct atomisp_grid_info tmp = {0};
1994  
1995  	atomisp_curr_user_grid_info(asd, &tmp);
1996  	return memcmp(atomgrid, &tmp, sizeof(tmp));
1997  }
1998  
1999  /*
2000   * Function to update Gdc table for gdc
2001   */
atomisp_gdc_cac_table(struct atomisp_sub_device * asd,int flag,struct atomisp_morph_table * config)2002  int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag,
2003  			  struct atomisp_morph_table *config)
2004  {
2005  	int ret;
2006  	int i;
2007  	struct atomisp_device *isp = asd->isp;
2008  
2009  	if (flag == 0) {
2010  		/* Get gdc table from current setup */
2011  		struct ia_css_morph_table tab = {0};
2012  
2013  		atomisp_css_get_morph_table(asd, &tab);
2014  
2015  		config->width = tab.width;
2016  		config->height = tab.height;
2017  
2018  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
2019  			ret = copy_to_user(config->coordinates_x[i],
2020  					   tab.coordinates_x[i], tab.height *
2021  					   tab.width * sizeof(*tab.coordinates_x[i]));
2022  			if (ret) {
2023  				dev_err(isp->dev,
2024  					"Failed to copy to User for x\n");
2025  				return -EFAULT;
2026  			}
2027  			ret = copy_to_user(config->coordinates_y[i],
2028  					   tab.coordinates_y[i], tab.height *
2029  					   tab.width * sizeof(*tab.coordinates_y[i]));
2030  			if (ret) {
2031  				dev_err(isp->dev,
2032  					"Failed to copy to User for y\n");
2033  				return -EFAULT;
2034  			}
2035  		}
2036  	} else {
2037  		struct ia_css_morph_table *tab =
2038  			    asd->params.css_param.morph_table;
2039  
2040  		/* free first if we have one */
2041  		if (tab) {
2042  			atomisp_css_morph_table_free(tab);
2043  			asd->params.css_param.morph_table = NULL;
2044  		}
2045  
2046  		/* allocate new one */
2047  		tab = atomisp_css_morph_table_allocate(config->width,
2048  						       config->height);
2049  
2050  		if (!tab) {
2051  			dev_err(isp->dev, "out of memory\n");
2052  			return -EINVAL;
2053  		}
2054  
2055  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
2056  			ret = copy_from_user(tab->coordinates_x[i],
2057  					     config->coordinates_x[i],
2058  					     config->height * config->width *
2059  					     sizeof(*config->coordinates_x[i]));
2060  			if (ret) {
2061  				dev_err(isp->dev,
2062  					"Failed to copy from User for x, ret %d\n",
2063  					ret);
2064  				atomisp_css_morph_table_free(tab);
2065  				return -EFAULT;
2066  			}
2067  			ret = copy_from_user(tab->coordinates_y[i],
2068  					     config->coordinates_y[i],
2069  					     config->height * config->width *
2070  					     sizeof(*config->coordinates_y[i]));
2071  			if (ret) {
2072  				dev_err(isp->dev,
2073  					"Failed to copy from User for y, ret is %d\n",
2074  					ret);
2075  				atomisp_css_morph_table_free(tab);
2076  				return -EFAULT;
2077  			}
2078  		}
2079  		asd->params.css_param.morph_table = tab;
2080  		if (asd->params.gdc_cac_en)
2081  			asd->params.config.morph_table = tab;
2082  	}
2083  
2084  	return 0;
2085  }
2086  
atomisp_macc_table(struct atomisp_sub_device * asd,int flag,struct atomisp_macc_config * config)2087  int atomisp_macc_table(struct atomisp_sub_device *asd, int flag,
2088  		       struct atomisp_macc_config *config)
2089  {
2090  	struct ia_css_macc_table *macc_table;
2091  
2092  	switch (config->color_effect) {
2093  	case V4L2_COLORFX_NONE:
2094  		macc_table = &asd->params.css_param.macc_table;
2095  		break;
2096  	case V4L2_COLORFX_SKY_BLUE:
2097  		macc_table = &blue_macc_table;
2098  		break;
2099  	case V4L2_COLORFX_GRASS_GREEN:
2100  		macc_table = &green_macc_table;
2101  		break;
2102  	case V4L2_COLORFX_SKIN_WHITEN_LOW:
2103  		macc_table = &skin_low_macc_table;
2104  		break;
2105  	case V4L2_COLORFX_SKIN_WHITEN:
2106  		macc_table = &skin_medium_macc_table;
2107  		break;
2108  	case V4L2_COLORFX_SKIN_WHITEN_HIGH:
2109  		macc_table = &skin_high_macc_table;
2110  		break;
2111  	default:
2112  		return -EINVAL;
2113  	}
2114  
2115  	if (flag == 0) {
2116  		/* Get macc table from current setup */
2117  		memcpy(&config->table, macc_table,
2118  		       sizeof(struct ia_css_macc_table));
2119  	} else {
2120  		memcpy(macc_table, &config->table,
2121  		       sizeof(struct ia_css_macc_table));
2122  		if (config->color_effect == asd->params.color_effect)
2123  			asd->params.config.macc_table = macc_table;
2124  	}
2125  
2126  	return 0;
2127  }
2128  
atomisp_set_dis_vector(struct atomisp_sub_device * asd,struct atomisp_dis_vector * vector)2129  int atomisp_set_dis_vector(struct atomisp_sub_device *asd,
2130  			   struct atomisp_dis_vector *vector)
2131  {
2132  	atomisp_css_video_set_dis_vector(asd, vector);
2133  
2134  	asd->params.dis_proj_data_valid = false;
2135  	asd->params.css_update_params_needed = true;
2136  	return 0;
2137  }
2138  
2139  /*
2140   * Function to set/get image stablization statistics
2141   */
atomisp_get_dis_stat(struct atomisp_sub_device * asd,struct atomisp_dis_statistics * stats)2142  int atomisp_get_dis_stat(struct atomisp_sub_device *asd,
2143  			 struct atomisp_dis_statistics *stats)
2144  {
2145  	return atomisp_css_get_dis_stat(asd, stats);
2146  }
2147  
2148  /*
2149   * Function  set camrea_prefiles.xml current sensor pixel array size
2150   */
atomisp_set_array_res(struct atomisp_sub_device * asd,struct atomisp_resolution * config)2151  int atomisp_set_array_res(struct atomisp_sub_device *asd,
2152  			  struct atomisp_resolution  *config)
2153  {
2154  	dev_dbg(asd->isp->dev, ">%s start\n", __func__);
2155  	if (!config) {
2156  		dev_err(asd->isp->dev, "Set sensor array size is not valid\n");
2157  		return -EINVAL;
2158  	}
2159  
2160  	asd->sensor_array_res.width = config->width;
2161  	asd->sensor_array_res.height = config->height;
2162  	return 0;
2163  }
2164  
2165  /*
2166   * Function to get DVS2 BQ resolution settings
2167   */
atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device * asd,struct atomisp_dvs2_bq_resolutions * bq_res)2168  int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd,
2169  				    struct atomisp_dvs2_bq_resolutions *bq_res)
2170  {
2171  	struct ia_css_pipe_config *pipe_cfg = NULL;
2172  	struct ia_css_stream_config *stream_cfg = NULL;
2173  	struct ia_css_stream_input_config *input_config = NULL;
2174  
2175  	struct ia_css_stream *stream =
2176  		    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
2177  	if (!stream) {
2178  		dev_warn(asd->isp->dev, "stream is not created");
2179  		return -EAGAIN;
2180  	}
2181  
2182  	pipe_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2183  		   .pipe_configs[IA_CSS_PIPE_ID_VIDEO];
2184  	stream_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
2185  		     .stream_config;
2186  	input_config = &stream_cfg->input_config;
2187  
2188  	if (!bq_res)
2189  		return -EINVAL;
2190  
2191  	/* the GDC output resolution */
2192  	bq_res->output_bq.width_bq = pipe_cfg->output_info[0].res.width / 2;
2193  	bq_res->output_bq.height_bq = pipe_cfg->output_info[0].res.height / 2;
2194  
2195  	bq_res->envelope_bq.width_bq = 0;
2196  	bq_res->envelope_bq.height_bq = 0;
2197  	/* the GDC input resolution */
2198  	if (!asd->continuous_mode->val) {
2199  		bq_res->source_bq.width_bq = bq_res->output_bq.width_bq +
2200  					     pipe_cfg->dvs_envelope.width / 2;
2201  		bq_res->source_bq.height_bq = bq_res->output_bq.height_bq +
2202  					      pipe_cfg->dvs_envelope.height / 2;
2203  		/*
2204  		 * Bad pixels caused by spatial filter processing
2205  		 * ISP filter resolution should be given by CSS/FW, but for now
2206  		 * there is not such API to query, and it is fixed value, so
2207  		 * hardcoded here.
2208  		 */
2209  		bq_res->ispfilter_bq.width_bq = 12 / 2;
2210  		bq_res->ispfilter_bq.height_bq = 12 / 2;
2211  		/* spatial filter shift, always 4 pixels */
2212  		bq_res->gdc_shift_bq.width_bq = 4 / 2;
2213  		bq_res->gdc_shift_bq.height_bq = 4 / 2;
2214  
2215  		if (asd->params.video_dis_en) {
2216  			bq_res->envelope_bq.width_bq = pipe_cfg->dvs_envelope.width
2217  						       / 2 - bq_res->ispfilter_bq.width_bq;
2218  			bq_res->envelope_bq.height_bq = pipe_cfg->dvs_envelope.height
2219  							/ 2 - bq_res->ispfilter_bq.height_bq;
2220  		}
2221  	} else {
2222  		unsigned int w_padding;
2223  		unsigned int gdc_effective_input = 0;
2224  
2225  		/* For GDC:
2226  		 * gdc_effective_input = effective_input + envelope
2227  		 *
2228  		 * From the comment and formula in BZ1786,
2229  		 * we see the source_bq should be:
2230  		 * effective_input / bayer_ds_ratio
2231  		 */
2232  		bq_res->source_bq.width_bq =
2233  		    (input_config->effective_res.width *
2234  		     pipe_cfg->bayer_ds_out_res.width /
2235  		     input_config->effective_res.width + 1) / 2;
2236  		bq_res->source_bq.height_bq =
2237  		    (input_config->effective_res.height *
2238  		     pipe_cfg->bayer_ds_out_res.height /
2239  		     input_config->effective_res.height + 1) / 2;
2240  
2241  		if (!asd->params.video_dis_en) {
2242  			/*
2243  			 * We adjust the ispfilter_bq to:
2244  			 * ispfilter_bq = 128/BDS
2245  			 * we still need firmware team to provide an offical
2246  			 * formula for SDV.
2247  			 */
2248  			bq_res->ispfilter_bq.width_bq = 128 *
2249  							pipe_cfg->bayer_ds_out_res.width /
2250  							input_config->effective_res.width / 2;
2251  			bq_res->ispfilter_bq.height_bq = 128 *
2252  							 pipe_cfg->bayer_ds_out_res.width /
2253  							 input_config->effective_res.width / 2;
2254  
2255  			if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) {
2256  				/* No additional left padding for ISYS2401 */
2257  				bq_res->gdc_shift_bq.width_bq = 4 / 2;
2258  				bq_res->gdc_shift_bq.height_bq = 4 / 2;
2259  			} else {
2260  				/*
2261  				 * For the w_padding and gdc_shift_bq cacluation
2262  				 * Please see the BZ 1786 and 4358 for more info.
2263  				 * Just test that this formula can work now,
2264  				 * but we still have no offical formula.
2265  				 *
2266  				 * w_padding = ceiling(gdc_effective_input
2267  				 *             /128, 1) * 128 - effective_width
2268  				 * gdc_shift_bq = w_padding/BDS/2 + ispfilter_bq/2
2269  				 */
2270  				gdc_effective_input =
2271  				    input_config->effective_res.width +
2272  				    pipe_cfg->dvs_envelope.width;
2273  				w_padding = roundup(gdc_effective_input, 128) -
2274  					    input_config->effective_res.width;
2275  				w_padding = w_padding *
2276  					    pipe_cfg->bayer_ds_out_res.width /
2277  					    input_config->effective_res.width + 1;
2278  				w_padding = roundup(w_padding / 2, 1);
2279  
2280  				bq_res->gdc_shift_bq.width_bq = bq_res->ispfilter_bq.width_bq / 2
2281  								+ w_padding;
2282  				bq_res->gdc_shift_bq.height_bq = 4 / 2;
2283  			}
2284  		} else {
2285  			unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max;
2286  
2287  			bq_res->ispfilter_bq.width_bq = 8 / 2;
2288  			bq_res->ispfilter_bq.height_bq = 8 / 2;
2289  
2290  			if (IS_HWREVISION(asd->isp, ATOMISP_HW_REVISION_ISP2401)) {
2291  				/* No additional left padding for ISYS2401 */
2292  				bq_res->gdc_shift_bq.width_bq = 4 / 2;
2293  				bq_res->gdc_shift_bq.height_bq = 4 / 2;
2294  			} else {
2295  				w_padding =
2296  				    roundup(input_config->effective_res.width, 128) -
2297  				    input_config->effective_res.width;
2298  				if (w_padding < 12)
2299  					w_padding = 12;
2300  				bq_res->gdc_shift_bq.width_bq = 4 / 2 +
2301  								((w_padding - 12) *
2302  								 pipe_cfg->bayer_ds_out_res.width /
2303  								 input_config->effective_res.width + 1) / 2;
2304  				bq_res->gdc_shift_bq.height_bq = 4 / 2;
2305  			}
2306  
2307  			dvs_w = pipe_cfg->bayer_ds_out_res.width -
2308  				pipe_cfg->output_info[0].res.width;
2309  			dvs_h = pipe_cfg->bayer_ds_out_res.height -
2310  				pipe_cfg->output_info[0].res.height;
2311  			dvs_w_max = rounddown(
2312  					pipe_cfg->output_info[0].res.width / 5,
2313  					ATOM_ISP_STEP_WIDTH);
2314  			dvs_h_max = rounddown(
2315  					pipe_cfg->output_info[0].res.height / 5,
2316  					ATOM_ISP_STEP_HEIGHT);
2317  			bq_res->envelope_bq.width_bq =
2318  			    min((dvs_w / 2), (dvs_w_max / 2)) -
2319  			    bq_res->ispfilter_bq.width_bq;
2320  			bq_res->envelope_bq.height_bq =
2321  			    min((dvs_h / 2), (dvs_h_max / 2)) -
2322  			    bq_res->ispfilter_bq.height_bq;
2323  		}
2324  	}
2325  
2326  	dev_dbg(asd->isp->dev,
2327  		"source_bq.width_bq %d, source_bq.height_bq %d,\nispfilter_bq.width_bq %d, ispfilter_bq.height_bq %d,\ngdc_shift_bq.width_bq %d, gdc_shift_bq.height_bq %d,\nenvelope_bq.width_bq %d, envelope_bq.height_bq %d,\noutput_bq.width_bq %d, output_bq.height_bq %d\n",
2328  		bq_res->source_bq.width_bq, bq_res->source_bq.height_bq,
2329  		bq_res->ispfilter_bq.width_bq, bq_res->ispfilter_bq.height_bq,
2330  		bq_res->gdc_shift_bq.width_bq, bq_res->gdc_shift_bq.height_bq,
2331  		bq_res->envelope_bq.width_bq, bq_res->envelope_bq.height_bq,
2332  		bq_res->output_bq.width_bq, bq_res->output_bq.height_bq);
2333  
2334  	return 0;
2335  }
2336  
atomisp_set_dis_coefs(struct atomisp_sub_device * asd,struct atomisp_dis_coefficients * coefs)2337  int atomisp_set_dis_coefs(struct atomisp_sub_device *asd,
2338  			  struct atomisp_dis_coefficients *coefs)
2339  {
2340  	return atomisp_css_set_dis_coefs(asd, coefs);
2341  }
2342  
2343  /*
2344   * Function to set/get 3A stat from isp
2345   */
atomisp_3a_stat(struct atomisp_sub_device * asd,int flag,struct atomisp_3a_statistics * config)2346  int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag,
2347  		    struct atomisp_3a_statistics *config)
2348  {
2349  	struct atomisp_device *isp = asd->isp;
2350  	struct atomisp_s3a_buf *s3a_buf;
2351  	unsigned long ret;
2352  
2353  	if (flag != 0)
2354  		return -EINVAL;
2355  
2356  	/* sanity check to avoid writing into unallocated memory. */
2357  	if (asd->params.s3a_output_bytes == 0)
2358  		return -EINVAL;
2359  
2360  	if (atomisp_compare_grid(asd, &config->grid_info) != 0) {
2361  		/* If the grid info in the argument differs from the current
2362  		   grid info, we tell the caller to reset the grid size and
2363  		   try again. */
2364  		return -EAGAIN;
2365  	}
2366  
2367  	if (list_empty(&asd->s3a_stats_ready)) {
2368  		dev_err(isp->dev, "3a statistics is not valid.\n");
2369  		return -EAGAIN;
2370  	}
2371  
2372  	s3a_buf = list_entry(asd->s3a_stats_ready.next,
2373  			     struct atomisp_s3a_buf, list);
2374  	if (s3a_buf->s3a_map)
2375  		ia_css_translate_3a_statistics(
2376  		    asd->params.s3a_user_stat, s3a_buf->s3a_map);
2377  	else
2378  		ia_css_get_3a_statistics(asd->params.s3a_user_stat,
2379  					 s3a_buf->s3a_data);
2380  
2381  	config->exp_id = s3a_buf->s3a_data->exp_id;
2382  	config->isp_config_id = s3a_buf->s3a_data->isp_config_id;
2383  
2384  	ret = copy_to_user(config->data, asd->params.s3a_user_stat->data,
2385  			   asd->params.s3a_output_bytes);
2386  	if (ret) {
2387  		dev_err(isp->dev, "copy to user failed: copied %lu bytes\n",
2388  			ret);
2389  		return -EFAULT;
2390  	}
2391  
2392  	/* Move to free buffer list */
2393  	list_del_init(&s3a_buf->list);
2394  	list_add_tail(&s3a_buf->list, &asd->s3a_stats);
2395  	dev_dbg(isp->dev, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n",
2396  		__func__,
2397  		config->exp_id, config->isp_config_id);
2398  	return 0;
2399  }
2400  
atomisp_get_metadata(struct atomisp_sub_device * asd,int flag,struct atomisp_metadata * md)2401  int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag,
2402  			 struct atomisp_metadata *md)
2403  {
2404  	struct atomisp_device *isp = asd->isp;
2405  	struct ia_css_stream_info *stream_info;
2406  	struct camera_mipi_info *mipi_info;
2407  	struct atomisp_metadata_buf *md_buf;
2408  	enum atomisp_metadata_type md_type = ATOMISP_MAIN_METADATA;
2409  	int ret, i;
2410  
2411  	if (flag != 0)
2412  		return -EINVAL;
2413  
2414  	stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2415  		      stream_info;
2416  
2417  	/* We always return the resolution and stride even if there is
2418  	 * no valid metadata. This allows the caller to get the information
2419  	 * needed to allocate user-space buffers. */
2420  	md->width  = stream_info->metadata_info.resolution.width;
2421  	md->height = stream_info->metadata_info.resolution.height;
2422  	md->stride = stream_info->metadata_info.stride;
2423  
2424  	/* sanity check to avoid writing into unallocated memory.
2425  	 * This does not return an error because it is a valid way
2426  	 * for applications to detect that metadata is not enabled. */
2427  	if (md->width == 0 || md->height == 0 || !md->data)
2428  		return 0;
2429  
2430  	/* This is done in the atomisp_buf_done() */
2431  	if (list_empty(&asd->metadata_ready[md_type])) {
2432  		dev_warn(isp->dev, "Metadata queue is empty now!\n");
2433  		return -EAGAIN;
2434  	}
2435  
2436  	mipi_info = atomisp_to_sensor_mipi_info(
2437  			isp->inputs[asd->input_curr].camera);
2438  	if (!mipi_info)
2439  		return -EINVAL;
2440  
2441  	if (mipi_info->metadata_effective_width) {
2442  		for (i = 0; i < md->height; i++)
2443  			md->effective_width[i] =
2444  			    mipi_info->metadata_effective_width[i];
2445  	}
2446  
2447  	md_buf = list_entry(asd->metadata_ready[md_type].next,
2448  			    struct atomisp_metadata_buf, list);
2449  	md->exp_id = md_buf->metadata->exp_id;
2450  	if (md_buf->md_vptr) {
2451  		ret = copy_to_user(md->data,
2452  				   md_buf->md_vptr,
2453  				   stream_info->metadata_info.size);
2454  	} else {
2455  		hmm_load(md_buf->metadata->address,
2456  			 asd->params.metadata_user[md_type],
2457  			 stream_info->metadata_info.size);
2458  
2459  		ret = copy_to_user(md->data,
2460  				   asd->params.metadata_user[md_type],
2461  				   stream_info->metadata_info.size);
2462  	}
2463  	if (ret) {
2464  		dev_err(isp->dev, "copy to user failed: copied %d bytes\n",
2465  			ret);
2466  		return -EFAULT;
2467  	}
2468  
2469  	list_del_init(&md_buf->list);
2470  	list_add_tail(&md_buf->list, &asd->metadata[md_type]);
2471  
2472  	dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2473  		__func__, md_type, md->exp_id);
2474  	return 0;
2475  }
2476  
atomisp_get_metadata_by_type(struct atomisp_sub_device * asd,int flag,struct atomisp_metadata_with_type * md)2477  int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag,
2478  				 struct atomisp_metadata_with_type *md)
2479  {
2480  	struct atomisp_device *isp = asd->isp;
2481  	struct ia_css_stream_info *stream_info;
2482  	struct camera_mipi_info *mipi_info;
2483  	struct atomisp_metadata_buf *md_buf;
2484  	enum atomisp_metadata_type md_type;
2485  	int ret, i;
2486  
2487  	if (flag != 0)
2488  		return -EINVAL;
2489  
2490  	stream_info = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
2491  		      stream_info;
2492  
2493  	/* We always return the resolution and stride even if there is
2494  	 * no valid metadata. This allows the caller to get the information
2495  	 * needed to allocate user-space buffers. */
2496  	md->width  = stream_info->metadata_info.resolution.width;
2497  	md->height = stream_info->metadata_info.resolution.height;
2498  	md->stride = stream_info->metadata_info.stride;
2499  
2500  	/* sanity check to avoid writing into unallocated memory.
2501  	 * This does not return an error because it is a valid way
2502  	 * for applications to detect that metadata is not enabled. */
2503  	if (md->width == 0 || md->height == 0 || !md->data)
2504  		return 0;
2505  
2506  	md_type = md->type;
2507  	if (md_type < 0 || md_type >= ATOMISP_METADATA_TYPE_NUM)
2508  		return -EINVAL;
2509  
2510  	/* This is done in the atomisp_buf_done() */
2511  	if (list_empty(&asd->metadata_ready[md_type])) {
2512  		dev_warn(isp->dev, "Metadata queue is empty now!\n");
2513  		return -EAGAIN;
2514  	}
2515  
2516  	mipi_info = atomisp_to_sensor_mipi_info(
2517  			isp->inputs[asd->input_curr].camera);
2518  	if (!mipi_info)
2519  		return -EINVAL;
2520  
2521  	if (mipi_info->metadata_effective_width) {
2522  		for (i = 0; i < md->height; i++)
2523  			md->effective_width[i] =
2524  			    mipi_info->metadata_effective_width[i];
2525  	}
2526  
2527  	md_buf = list_entry(asd->metadata_ready[md_type].next,
2528  			    struct atomisp_metadata_buf, list);
2529  	md->exp_id = md_buf->metadata->exp_id;
2530  	if (md_buf->md_vptr) {
2531  		ret = copy_to_user(md->data,
2532  				   md_buf->md_vptr,
2533  				   stream_info->metadata_info.size);
2534  	} else {
2535  		hmm_load(md_buf->metadata->address,
2536  			 asd->params.metadata_user[md_type],
2537  			 stream_info->metadata_info.size);
2538  
2539  		ret = copy_to_user(md->data,
2540  				   asd->params.metadata_user[md_type],
2541  				   stream_info->metadata_info.size);
2542  	}
2543  	if (ret) {
2544  		dev_err(isp->dev, "copy to user failed: copied %d bytes\n",
2545  			ret);
2546  		return -EFAULT;
2547  	} else {
2548  		list_del_init(&md_buf->list);
2549  		list_add_tail(&md_buf->list, &asd->metadata[md_type]);
2550  	}
2551  	dev_dbg(isp->dev, "%s: HAL de-queued metadata type %d with exp_id %d\n",
2552  		__func__, md_type, md->exp_id);
2553  	return 0;
2554  }
2555  
2556  /*
2557   * Function to calculate real zoom region for every pipe
2558   */
atomisp_calculate_real_zoom_region(struct atomisp_sub_device * asd,struct ia_css_dz_config * dz_config,enum ia_css_pipe_id css_pipe_id)2559  int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd,
2560  				       struct ia_css_dz_config   *dz_config,
2561  				       enum ia_css_pipe_id css_pipe_id)
2562  
2563  {
2564  	struct atomisp_stream_env *stream_env =
2565  		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
2566  	struct atomisp_resolution  eff_res, out_res;
2567  	int w_offset, h_offset;
2568  
2569  	memset(&eff_res, 0, sizeof(eff_res));
2570  	memset(&out_res, 0, sizeof(out_res));
2571  
2572  	if (dz_config->dx || dz_config->dy)
2573  		return 0;
2574  
2575  	if (css_pipe_id != IA_CSS_PIPE_ID_PREVIEW
2576  	    && css_pipe_id != IA_CSS_PIPE_ID_CAPTURE) {
2577  		dev_err(asd->isp->dev, "%s the set pipe no support crop region"
2578  			, __func__);
2579  		return -EINVAL;
2580  	}
2581  
2582  	eff_res.width =
2583  	    stream_env->stream_config.input_config.effective_res.width;
2584  	eff_res.height =
2585  	    stream_env->stream_config.input_config.effective_res.height;
2586  	if (eff_res.width == 0 || eff_res.height == 0) {
2587  		dev_err(asd->isp->dev, "%s err effective resolution"
2588  			, __func__);
2589  		return -EINVAL;
2590  	}
2591  
2592  	if (dz_config->zoom_region.resolution.width
2593  	    == asd->sensor_array_res.width
2594  	    || dz_config->zoom_region.resolution.height
2595  	    == asd->sensor_array_res.height) {
2596  		/*no need crop region*/
2597  		dz_config->zoom_region.origin.x = 0;
2598  		dz_config->zoom_region.origin.y = 0;
2599  		dz_config->zoom_region.resolution.width = eff_res.width;
2600  		dz_config->zoom_region.resolution.height = eff_res.height;
2601  		return 0;
2602  	}
2603  
2604  	/* FIXME:
2605  	 * This is not the correct implementation with Google's definition, due
2606  	 * to firmware limitation.
2607  	 * map real crop region base on above calculating base max crop region.
2608  	 */
2609  
2610  	if (!IS_ISP2401) {
2611  		dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x
2612  						  * eff_res.width
2613  						  / asd->sensor_array_res.width;
2614  		dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y
2615  						  * eff_res.height
2616  						  / asd->sensor_array_res.height;
2617  		dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width
2618  							  * eff_res.width
2619  							  / asd->sensor_array_res.width;
2620  		dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height
2621  							  * eff_res.height
2622  							  / asd->sensor_array_res.height;
2623  		/*
2624  		 * Set same ratio of crop region resolution and current pipe output
2625  		 * resolution
2626  		 */
2627  		out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
2628  		out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
2629  		if (out_res.width == 0 || out_res.height == 0) {
2630  			dev_err(asd->isp->dev, "%s err current pipe output resolution"
2631  				, __func__);
2632  			return -EINVAL;
2633  		}
2634  	} else {
2635  		out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
2636  		out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
2637  		if (out_res.width == 0 || out_res.height == 0) {
2638  			dev_err(asd->isp->dev, "%s err current pipe output resolution"
2639  				, __func__);
2640  			return -EINVAL;
2641  		}
2642  
2643  		if (asd->sensor_array_res.width * out_res.height
2644  		    < out_res.width * asd->sensor_array_res.height) {
2645  			h_offset = asd->sensor_array_res.height
2646  				   - asd->sensor_array_res.width
2647  				   * out_res.height / out_res.width;
2648  			h_offset = h_offset / 2;
2649  			if (dz_config->zoom_region.origin.y < h_offset)
2650  				dz_config->zoom_region.origin.y = 0;
2651  			else
2652  				dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y - h_offset;
2653  			w_offset = 0;
2654  		} else {
2655  			w_offset = asd->sensor_array_res.width
2656  				   - asd->sensor_array_res.height
2657  				   * out_res.width / out_res.height;
2658  			w_offset = w_offset / 2;
2659  			if (dz_config->zoom_region.origin.x < w_offset)
2660  				dz_config->zoom_region.origin.x = 0;
2661  			else
2662  				dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x - w_offset;
2663  			h_offset = 0;
2664  		}
2665  		dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x
2666  						  * eff_res.width
2667  						  / (asd->sensor_array_res.width - 2 * w_offset);
2668  		dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y
2669  						  * eff_res.height
2670  						  / (asd->sensor_array_res.height - 2 * h_offset);
2671  		dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width
2672  						  * eff_res.width
2673  						  / (asd->sensor_array_res.width - 2 * w_offset);
2674  		dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height
2675  						  * eff_res.height
2676  						  / (asd->sensor_array_res.height - 2 * h_offset);
2677  	}
2678  
2679  	if (out_res.width * dz_config->zoom_region.resolution.height
2680  	    > dz_config->zoom_region.resolution.width * out_res.height) {
2681  		dz_config->zoom_region.resolution.height =
2682  		    dz_config->zoom_region.resolution.width
2683  		    * out_res.height / out_res.width;
2684  	} else {
2685  		dz_config->zoom_region.resolution.width =
2686  		    dz_config->zoom_region.resolution.height
2687  		    * out_res.width / out_res.height;
2688  	}
2689  	dev_dbg(asd->isp->dev,
2690  		"%s crop region:(%d,%d),(%d,%d) eff_res(%d, %d) array_size(%d,%d) out_res(%d, %d)\n",
2691  		__func__, dz_config->zoom_region.origin.x,
2692  		dz_config->zoom_region.origin.y,
2693  		dz_config->zoom_region.resolution.width,
2694  		dz_config->zoom_region.resolution.height,
2695  		eff_res.width, eff_res.height,
2696  		asd->sensor_array_res.width,
2697  		asd->sensor_array_res.height,
2698  		out_res.width, out_res.height);
2699  
2700  	if ((dz_config->zoom_region.origin.x +
2701  	     dz_config->zoom_region.resolution.width
2702  	     > eff_res.width) ||
2703  	    (dz_config->zoom_region.origin.y +
2704  	     dz_config->zoom_region.resolution.height
2705  	     > eff_res.height))
2706  		return -EINVAL;
2707  
2708  	return 0;
2709  }
2710  
2711  /*
2712   * Function to check the zoom region whether is effective
2713   */
atomisp_check_zoom_region(struct atomisp_sub_device * asd,struct ia_css_dz_config * dz_config)2714  static bool atomisp_check_zoom_region(
2715      struct atomisp_sub_device *asd,
2716      struct ia_css_dz_config *dz_config)
2717  {
2718  	struct atomisp_resolution  config;
2719  	bool flag = false;
2720  	unsigned int w, h;
2721  
2722  	memset(&config, 0, sizeof(struct atomisp_resolution));
2723  
2724  	if (dz_config->dx && dz_config->dy)
2725  		return true;
2726  
2727  	config.width = asd->sensor_array_res.width;
2728  	config.height = asd->sensor_array_res.height;
2729  	w = dz_config->zoom_region.origin.x +
2730  	    dz_config->zoom_region.resolution.width;
2731  	h = dz_config->zoom_region.origin.y +
2732  	    dz_config->zoom_region.resolution.height;
2733  
2734  	if ((w <= config.width) && (h <= config.height) && w > 0 && h > 0)
2735  		flag = true;
2736  	else
2737  		/* setting error zoom region */
2738  		dev_err(asd->isp->dev,
2739  			"%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n",
2740  			__func__, dz_config->zoom_region.origin.x,
2741  			dz_config->zoom_region.origin.y,
2742  			dz_config->zoom_region.resolution.width,
2743  			dz_config->zoom_region.resolution.height,
2744  			config.width, config.height);
2745  
2746  	return flag;
2747  }
2748  
atomisp_apply_css_parameters(struct atomisp_sub_device * asd,struct atomisp_css_params * css_param)2749  void atomisp_apply_css_parameters(
2750      struct atomisp_sub_device *asd,
2751      struct atomisp_css_params *css_param)
2752  {
2753  	if (css_param->update_flag.wb_config)
2754  		asd->params.config.wb_config = &css_param->wb_config;
2755  
2756  	if (css_param->update_flag.ob_config)
2757  		asd->params.config.ob_config = &css_param->ob_config;
2758  
2759  	if (css_param->update_flag.dp_config)
2760  		asd->params.config.dp_config = &css_param->dp_config;
2761  
2762  	if (css_param->update_flag.nr_config)
2763  		asd->params.config.nr_config = &css_param->nr_config;
2764  
2765  	if (css_param->update_flag.ee_config)
2766  		asd->params.config.ee_config = &css_param->ee_config;
2767  
2768  	if (css_param->update_flag.tnr_config)
2769  		asd->params.config.tnr_config = &css_param->tnr_config;
2770  
2771  	if (css_param->update_flag.a3a_config)
2772  		asd->params.config.s3a_config = &css_param->s3a_config;
2773  
2774  	if (css_param->update_flag.ctc_config)
2775  		asd->params.config.ctc_config = &css_param->ctc_config;
2776  
2777  	if (css_param->update_flag.cnr_config)
2778  		asd->params.config.cnr_config = &css_param->cnr_config;
2779  
2780  	if (css_param->update_flag.ecd_config)
2781  		asd->params.config.ecd_config = &css_param->ecd_config;
2782  
2783  	if (css_param->update_flag.ynr_config)
2784  		asd->params.config.ynr_config = &css_param->ynr_config;
2785  
2786  	if (css_param->update_flag.fc_config)
2787  		asd->params.config.fc_config = &css_param->fc_config;
2788  
2789  	if (css_param->update_flag.macc_config)
2790  		asd->params.config.macc_config = &css_param->macc_config;
2791  
2792  	if (css_param->update_flag.aa_config)
2793  		asd->params.config.aa_config = &css_param->aa_config;
2794  
2795  	if (css_param->update_flag.anr_config)
2796  		asd->params.config.anr_config = &css_param->anr_config;
2797  
2798  	if (css_param->update_flag.xnr_config)
2799  		asd->params.config.xnr_config = &css_param->xnr_config;
2800  
2801  	if (css_param->update_flag.yuv2rgb_cc_config)
2802  		asd->params.config.yuv2rgb_cc_config = &css_param->yuv2rgb_cc_config;
2803  
2804  	if (css_param->update_flag.rgb2yuv_cc_config)
2805  		asd->params.config.rgb2yuv_cc_config = &css_param->rgb2yuv_cc_config;
2806  
2807  	if (css_param->update_flag.macc_table)
2808  		asd->params.config.macc_table = &css_param->macc_table;
2809  
2810  	if (css_param->update_flag.xnr_table)
2811  		asd->params.config.xnr_table = &css_param->xnr_table;
2812  
2813  	if (css_param->update_flag.r_gamma_table)
2814  		asd->params.config.r_gamma_table = &css_param->r_gamma_table;
2815  
2816  	if (css_param->update_flag.g_gamma_table)
2817  		asd->params.config.g_gamma_table = &css_param->g_gamma_table;
2818  
2819  	if (css_param->update_flag.b_gamma_table)
2820  		asd->params.config.b_gamma_table = &css_param->b_gamma_table;
2821  
2822  	if (css_param->update_flag.anr_thres)
2823  		atomisp_css_set_anr_thres(asd, &css_param->anr_thres);
2824  
2825  	if (css_param->update_flag.shading_table)
2826  		asd->params.config.shading_table = css_param->shading_table;
2827  
2828  	if (css_param->update_flag.morph_table && asd->params.gdc_cac_en)
2829  		asd->params.config.morph_table = css_param->morph_table;
2830  
2831  	if (css_param->update_flag.dvs2_coefs) {
2832  		struct ia_css_dvs_grid_info *dvs_grid_info =
2833  		    atomisp_css_get_dvs_grid_info(
2834  			&asd->params.curr_grid_info);
2835  
2836  		if (dvs_grid_info && dvs_grid_info->enable)
2837  			atomisp_css_set_dvs2_coefs(asd, css_param->dvs2_coeff);
2838  	}
2839  
2840  	if (css_param->update_flag.dvs_6axis_config)
2841  		atomisp_css_set_dvs_6axis(asd, css_param->dvs_6axis);
2842  
2843  	atomisp_css_set_isp_config_id(asd, css_param->isp_config_id);
2844  	/*
2845  	 * These configurations are on used by ISP1.x, not for ISP2.x,
2846  	 * so do not handle them. see comments of ia_css_isp_config.
2847  	 * 1 cc_config
2848  	 * 2 ce_config
2849  	 * 3 de_config
2850  	 * 4 gc_config
2851  	 * 5 gamma_table
2852  	 * 6 ctc_table
2853  	 * 7 dvs_coefs
2854  	 */
2855  }
2856  
copy_from_compatible(void * to,const void * from,unsigned long n,bool from_user)2857  static unsigned int long copy_from_compatible(void *to, const void *from,
2858  	unsigned long n, bool from_user)
2859  {
2860  	if (from_user)
2861  		return copy_from_user(to, (void __user *)from, n);
2862  	else
2863  		memcpy(to, from, n);
2864  	return 0;
2865  }
2866  
atomisp_cp_general_isp_parameters(struct atomisp_sub_device * asd,struct atomisp_parameters * arg,struct atomisp_css_params * css_param,bool from_user)2867  int atomisp_cp_general_isp_parameters(struct atomisp_sub_device *asd,
2868  				      struct atomisp_parameters *arg,
2869  				      struct atomisp_css_params *css_param,
2870  				      bool from_user)
2871  {
2872  	struct atomisp_parameters *cur_config = &css_param->update_flag;
2873  
2874  	if (!arg || !asd || !css_param)
2875  		return -EINVAL;
2876  
2877  	if (arg->wb_config && (from_user || !cur_config->wb_config)) {
2878  		if (copy_from_compatible(&css_param->wb_config, arg->wb_config,
2879  					 sizeof(struct ia_css_wb_config),
2880  					 from_user))
2881  			return -EFAULT;
2882  		css_param->update_flag.wb_config =
2883  		    (struct atomisp_wb_config *)&css_param->wb_config;
2884  	}
2885  
2886  	if (arg->ob_config && (from_user || !cur_config->ob_config)) {
2887  		if (copy_from_compatible(&css_param->ob_config, arg->ob_config,
2888  					 sizeof(struct ia_css_ob_config),
2889  					 from_user))
2890  			return -EFAULT;
2891  		css_param->update_flag.ob_config =
2892  		    (struct atomisp_ob_config *)&css_param->ob_config;
2893  	}
2894  
2895  	if (arg->dp_config && (from_user || !cur_config->dp_config)) {
2896  		if (copy_from_compatible(&css_param->dp_config, arg->dp_config,
2897  					 sizeof(struct ia_css_dp_config),
2898  					 from_user))
2899  			return -EFAULT;
2900  		css_param->update_flag.dp_config =
2901  		    (struct atomisp_dp_config *)&css_param->dp_config;
2902  	}
2903  
2904  	if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
2905  		if (arg->dz_config && (from_user || !cur_config->dz_config)) {
2906  			if (copy_from_compatible(&css_param->dz_config,
2907  						 arg->dz_config,
2908  						 sizeof(struct ia_css_dz_config),
2909  						 from_user))
2910  				return -EFAULT;
2911  			if (!atomisp_check_zoom_region(asd,
2912  						       &css_param->dz_config)) {
2913  				dev_err(asd->isp->dev, "crop region error!");
2914  				return -EINVAL;
2915  			}
2916  			css_param->update_flag.dz_config =
2917  			    (struct atomisp_dz_config *)
2918  			    &css_param->dz_config;
2919  		}
2920  	}
2921  
2922  	if (arg->nr_config && (from_user || !cur_config->nr_config)) {
2923  		if (copy_from_compatible(&css_param->nr_config, arg->nr_config,
2924  					 sizeof(struct ia_css_nr_config),
2925  					 from_user))
2926  			return -EFAULT;
2927  		css_param->update_flag.nr_config =
2928  		    (struct atomisp_nr_config *)&css_param->nr_config;
2929  	}
2930  
2931  	if (arg->ee_config && (from_user || !cur_config->ee_config)) {
2932  		if (copy_from_compatible(&css_param->ee_config, arg->ee_config,
2933  					 sizeof(struct ia_css_ee_config),
2934  					 from_user))
2935  			return -EFAULT;
2936  		css_param->update_flag.ee_config =
2937  		    (struct atomisp_ee_config *)&css_param->ee_config;
2938  	}
2939  
2940  	if (arg->tnr_config && (from_user || !cur_config->tnr_config)) {
2941  		if (copy_from_compatible(&css_param->tnr_config,
2942  					 arg->tnr_config,
2943  					 sizeof(struct ia_css_tnr_config),
2944  					 from_user))
2945  			return -EFAULT;
2946  		css_param->update_flag.tnr_config =
2947  		    (struct atomisp_tnr_config *)
2948  		    &css_param->tnr_config;
2949  	}
2950  
2951  	if (arg->a3a_config && (from_user || !cur_config->a3a_config)) {
2952  		if (copy_from_compatible(&css_param->s3a_config,
2953  					 arg->a3a_config,
2954  					 sizeof(struct ia_css_3a_config),
2955  					 from_user))
2956  			return -EFAULT;
2957  		css_param->update_flag.a3a_config =
2958  		    (struct atomisp_3a_config *)&css_param->s3a_config;
2959  	}
2960  
2961  	if (arg->ctc_config && (from_user || !cur_config->ctc_config)) {
2962  		if (copy_from_compatible(&css_param->ctc_config,
2963  					 arg->ctc_config,
2964  					 sizeof(struct ia_css_ctc_config),
2965  					 from_user))
2966  			return -EFAULT;
2967  		css_param->update_flag.ctc_config =
2968  		    (struct atomisp_ctc_config *)
2969  		    &css_param->ctc_config;
2970  	}
2971  
2972  	if (arg->cnr_config && (from_user || !cur_config->cnr_config)) {
2973  		if (copy_from_compatible(&css_param->cnr_config,
2974  					 arg->cnr_config,
2975  					 sizeof(struct ia_css_cnr_config),
2976  					 from_user))
2977  			return -EFAULT;
2978  		css_param->update_flag.cnr_config =
2979  		    (struct atomisp_cnr_config *)
2980  		    &css_param->cnr_config;
2981  	}
2982  
2983  	if (arg->ecd_config && (from_user || !cur_config->ecd_config)) {
2984  		if (copy_from_compatible(&css_param->ecd_config,
2985  					 arg->ecd_config,
2986  					 sizeof(struct ia_css_ecd_config),
2987  					 from_user))
2988  			return -EFAULT;
2989  		css_param->update_flag.ecd_config =
2990  		    (struct atomisp_ecd_config *)
2991  		    &css_param->ecd_config;
2992  	}
2993  
2994  	if (arg->ynr_config && (from_user || !cur_config->ynr_config)) {
2995  		if (copy_from_compatible(&css_param->ynr_config,
2996  					 arg->ynr_config,
2997  					 sizeof(struct ia_css_ynr_config),
2998  					 from_user))
2999  			return -EFAULT;
3000  		css_param->update_flag.ynr_config =
3001  		    (struct atomisp_ynr_config *)
3002  		    &css_param->ynr_config;
3003  	}
3004  
3005  	if (arg->fc_config && (from_user || !cur_config->fc_config)) {
3006  		if (copy_from_compatible(&css_param->fc_config,
3007  					 arg->fc_config,
3008  					 sizeof(struct ia_css_fc_config),
3009  					 from_user))
3010  			return -EFAULT;
3011  		css_param->update_flag.fc_config =
3012  		    (struct atomisp_fc_config *)&css_param->fc_config;
3013  	}
3014  
3015  	if (arg->macc_config && (from_user || !cur_config->macc_config)) {
3016  		if (copy_from_compatible(&css_param->macc_config,
3017  					 arg->macc_config,
3018  					 sizeof(struct ia_css_macc_config),
3019  					 from_user))
3020  			return -EFAULT;
3021  		css_param->update_flag.macc_config =
3022  		    (struct atomisp_macc_config *)
3023  		    &css_param->macc_config;
3024  	}
3025  
3026  	if (arg->aa_config && (from_user || !cur_config->aa_config)) {
3027  		if (copy_from_compatible(&css_param->aa_config, arg->aa_config,
3028  					 sizeof(struct ia_css_aa_config),
3029  					 from_user))
3030  			return -EFAULT;
3031  		css_param->update_flag.aa_config =
3032  		    (struct atomisp_aa_config *)&css_param->aa_config;
3033  	}
3034  
3035  	if (arg->anr_config && (from_user || !cur_config->anr_config)) {
3036  		if (copy_from_compatible(&css_param->anr_config,
3037  					 arg->anr_config,
3038  					 sizeof(struct ia_css_anr_config),
3039  					 from_user))
3040  			return -EFAULT;
3041  		css_param->update_flag.anr_config =
3042  		    (struct atomisp_anr_config *)
3043  		    &css_param->anr_config;
3044  	}
3045  
3046  	if (arg->xnr_config && (from_user || !cur_config->xnr_config)) {
3047  		if (copy_from_compatible(&css_param->xnr_config,
3048  					 arg->xnr_config,
3049  					 sizeof(struct ia_css_xnr_config),
3050  					 from_user))
3051  			return -EFAULT;
3052  		css_param->update_flag.xnr_config =
3053  		    (struct atomisp_xnr_config *)
3054  		    &css_param->xnr_config;
3055  	}
3056  
3057  	if (arg->yuv2rgb_cc_config &&
3058  	    (from_user || !cur_config->yuv2rgb_cc_config)) {
3059  		if (copy_from_compatible(&css_param->yuv2rgb_cc_config,
3060  					 arg->yuv2rgb_cc_config,
3061  					 sizeof(struct ia_css_cc_config),
3062  					 from_user))
3063  			return -EFAULT;
3064  		css_param->update_flag.yuv2rgb_cc_config =
3065  		    (struct atomisp_cc_config *)
3066  		    &css_param->yuv2rgb_cc_config;
3067  	}
3068  
3069  	if (arg->rgb2yuv_cc_config &&
3070  	    (from_user || !cur_config->rgb2yuv_cc_config)) {
3071  		if (copy_from_compatible(&css_param->rgb2yuv_cc_config,
3072  					 arg->rgb2yuv_cc_config,
3073  					 sizeof(struct ia_css_cc_config),
3074  					 from_user))
3075  			return -EFAULT;
3076  		css_param->update_flag.rgb2yuv_cc_config =
3077  		    (struct atomisp_cc_config *)
3078  		    &css_param->rgb2yuv_cc_config;
3079  	}
3080  
3081  	if (arg->macc_table && (from_user || !cur_config->macc_table)) {
3082  		if (copy_from_compatible(&css_param->macc_table,
3083  					 arg->macc_table,
3084  					 sizeof(struct ia_css_macc_table),
3085  					 from_user))
3086  			return -EFAULT;
3087  		css_param->update_flag.macc_table =
3088  		    (struct atomisp_macc_table *)
3089  		    &css_param->macc_table;
3090  	}
3091  
3092  	if (arg->xnr_table && (from_user || !cur_config->xnr_table)) {
3093  		if (copy_from_compatible(&css_param->xnr_table,
3094  					 arg->xnr_table,
3095  					 sizeof(struct ia_css_xnr_table),
3096  					 from_user))
3097  			return -EFAULT;
3098  		css_param->update_flag.xnr_table =
3099  		    (struct atomisp_xnr_table *)&css_param->xnr_table;
3100  	}
3101  
3102  	if (arg->r_gamma_table && (from_user || !cur_config->r_gamma_table)) {
3103  		if (copy_from_compatible(&css_param->r_gamma_table,
3104  					 arg->r_gamma_table,
3105  					 sizeof(struct ia_css_rgb_gamma_table),
3106  					 from_user))
3107  			return -EFAULT;
3108  		css_param->update_flag.r_gamma_table =
3109  		    (struct atomisp_rgb_gamma_table *)
3110  		    &css_param->r_gamma_table;
3111  	}
3112  
3113  	if (arg->g_gamma_table && (from_user || !cur_config->g_gamma_table)) {
3114  		if (copy_from_compatible(&css_param->g_gamma_table,
3115  					 arg->g_gamma_table,
3116  					 sizeof(struct ia_css_rgb_gamma_table),
3117  					 from_user))
3118  			return -EFAULT;
3119  		css_param->update_flag.g_gamma_table =
3120  		    (struct atomisp_rgb_gamma_table *)
3121  		    &css_param->g_gamma_table;
3122  	}
3123  
3124  	if (arg->b_gamma_table && (from_user || !cur_config->b_gamma_table)) {
3125  		if (copy_from_compatible(&css_param->b_gamma_table,
3126  					 arg->b_gamma_table,
3127  					 sizeof(struct ia_css_rgb_gamma_table),
3128  					 from_user))
3129  			return -EFAULT;
3130  		css_param->update_flag.b_gamma_table =
3131  		    (struct atomisp_rgb_gamma_table *)
3132  		    &css_param->b_gamma_table;
3133  	}
3134  
3135  	if (arg->anr_thres && (from_user || !cur_config->anr_thres)) {
3136  		if (copy_from_compatible(&css_param->anr_thres, arg->anr_thres,
3137  					 sizeof(struct ia_css_anr_thres),
3138  					 from_user))
3139  			return -EFAULT;
3140  		css_param->update_flag.anr_thres =
3141  		    (struct atomisp_anr_thres *)&css_param->anr_thres;
3142  	}
3143  
3144  	if (from_user)
3145  		css_param->isp_config_id = arg->isp_config_id;
3146  	/*
3147  	 * These configurations are on used by ISP1.x, not for ISP2.x,
3148  	 * so do not handle them. see comments of ia_css_isp_config.
3149  	 * 1 cc_config
3150  	 * 2 ce_config
3151  	 * 3 de_config
3152  	 * 4 gc_config
3153  	 * 5 gamma_table
3154  	 * 6 ctc_table
3155  	 * 7 dvs_coefs
3156  	 */
3157  	return 0;
3158  }
3159  
atomisp_cp_lsc_table(struct atomisp_sub_device * asd,struct atomisp_shading_table * source_st,struct atomisp_css_params * css_param,bool from_user)3160  int atomisp_cp_lsc_table(struct atomisp_sub_device *asd,
3161  			 struct atomisp_shading_table *source_st,
3162  			 struct atomisp_css_params *css_param,
3163  			 bool from_user)
3164  {
3165  	unsigned int i;
3166  	unsigned int len_table;
3167  	struct ia_css_shading_table *shading_table;
3168  	struct ia_css_shading_table *old_table;
3169  	struct atomisp_shading_table *st, dest_st;
3170  
3171  	if (!source_st)
3172  		return 0;
3173  
3174  	if (!css_param)
3175  		return -EINVAL;
3176  
3177  	if (!from_user && css_param->update_flag.shading_table)
3178  		return 0;
3179  
3180  	if (IS_ISP2401) {
3181  		if (copy_from_compatible(&dest_st, source_st,
3182  					sizeof(struct atomisp_shading_table),
3183  					from_user)) {
3184  			dev_err(asd->isp->dev, "copy shading table failed!");
3185  			return -EFAULT;
3186  		}
3187  		st = &dest_st;
3188  	} else {
3189  		st = source_st;
3190  	}
3191  
3192  	old_table = css_param->shading_table;
3193  
3194  	/* user config is to disable the shading table. */
3195  	if (!st->enable) {
3196  		/* Generate a minimum table with enable = 0. */
3197  		shading_table = atomisp_css_shading_table_alloc(1, 1);
3198  		if (!shading_table)
3199  			return -ENOMEM;
3200  		shading_table->enable = 0;
3201  		goto set_lsc;
3202  	}
3203  
3204  	/* Setting a new table. Validate first - all tables must be set */
3205  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3206  		if (!st->data[i]) {
3207  			dev_err(asd->isp->dev, "shading table validate failed");
3208  			return -EINVAL;
3209  		}
3210  	}
3211  
3212  	/* Shading table size per color */
3213  	if (st->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
3214  	    st->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) {
3215  		dev_err(asd->isp->dev, "shading table w/h validate failed!");
3216  		return -EINVAL;
3217  	}
3218  
3219  	shading_table = atomisp_css_shading_table_alloc(st->width, st->height);
3220  	if (!shading_table)
3221  		return -ENOMEM;
3222  
3223  	len_table = st->width * st->height * ATOMISP_SC_TYPE_SIZE;
3224  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3225  		if (copy_from_compatible(shading_table->data[i],
3226  					 st->data[i], len_table, from_user)) {
3227  			atomisp_css_shading_table_free(shading_table);
3228  			return -EFAULT;
3229  		}
3230  	}
3231  	shading_table->sensor_width = st->sensor_width;
3232  	shading_table->sensor_height = st->sensor_height;
3233  	shading_table->fraction_bits = st->fraction_bits;
3234  	shading_table->enable = st->enable;
3235  
3236  	/* No need to update shading table if it is the same */
3237  	if (old_table &&
3238  	    old_table->sensor_width == shading_table->sensor_width &&
3239  	    old_table->sensor_height == shading_table->sensor_height &&
3240  	    old_table->width == shading_table->width &&
3241  	    old_table->height == shading_table->height &&
3242  	    old_table->fraction_bits == shading_table->fraction_bits &&
3243  	    old_table->enable == shading_table->enable) {
3244  		bool data_is_same = true;
3245  
3246  		for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
3247  			if (memcmp(shading_table->data[i], old_table->data[i],
3248  				   len_table) != 0) {
3249  				data_is_same = false;
3250  				break;
3251  			}
3252  		}
3253  
3254  		if (data_is_same) {
3255  			atomisp_css_shading_table_free(shading_table);
3256  			return 0;
3257  		}
3258  	}
3259  
3260  set_lsc:
3261  	/* set LSC to CSS */
3262  	css_param->shading_table = shading_table;
3263  	css_param->update_flag.shading_table = (struct atomisp_shading_table *)shading_table;
3264  	asd->params.sc_en = shading_table;
3265  
3266  	if (old_table)
3267  		atomisp_css_shading_table_free(old_table);
3268  
3269  	return 0;
3270  }
3271  
atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device * asd,struct ia_css_dvs2_coefficients * coefs,struct atomisp_css_params * css_param,bool from_user)3272  int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd,
3273  			      struct ia_css_dvs2_coefficients *coefs,
3274  			      struct atomisp_css_params *css_param,
3275  			      bool from_user)
3276  {
3277  	struct ia_css_dvs_grid_info *cur =
3278  	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
3279  	int dvs_hor_coef_bytes, dvs_ver_coef_bytes;
3280  	struct ia_css_dvs2_coefficients dvs2_coefs;
3281  
3282  	if (!coefs || !cur)
3283  		return 0;
3284  
3285  	if (!from_user && css_param->update_flag.dvs2_coefs)
3286  		return 0;
3287  
3288  	if (!IS_ISP2401) {
3289  		if (sizeof(*cur) != sizeof(coefs->grid) ||
3290  		    memcmp(&coefs->grid, cur, sizeof(coefs->grid))) {
3291  			dev_err(asd->isp->dev, "dvs grid mis-match!\n");
3292  			/* If the grid info in the argument differs from the current
3293  			grid info, we tell the caller to reset the grid size and
3294  			try again. */
3295  			return -EAGAIN;
3296  		}
3297  
3298  		if (!coefs->hor_coefs.odd_real ||
3299  		    !coefs->hor_coefs.odd_imag ||
3300  		    !coefs->hor_coefs.even_real ||
3301  		    !coefs->hor_coefs.even_imag ||
3302  		    !coefs->ver_coefs.odd_real ||
3303  		    !coefs->ver_coefs.odd_imag ||
3304  		    !coefs->ver_coefs.even_real ||
3305  		    !coefs->ver_coefs.even_imag)
3306  			return -EINVAL;
3307  
3308  		if (!css_param->dvs2_coeff) {
3309  			/* DIS coefficients. */
3310  			css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur);
3311  			if (!css_param->dvs2_coeff)
3312  				return -ENOMEM;
3313  		}
3314  
3315  		dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes;
3316  		dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes;
3317  		if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real,
3318  					coefs->hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
3319  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag,
3320  					coefs->hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
3321  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real,
3322  					coefs->hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
3323  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag,
3324  					coefs->hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
3325  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real,
3326  					coefs->ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
3327  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag,
3328  					coefs->ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
3329  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real,
3330  					coefs->ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
3331  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag,
3332  					coefs->ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
3333  			ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
3334  			css_param->dvs2_coeff = NULL;
3335  			return -EFAULT;
3336  		}
3337  	} else {
3338  		if (copy_from_compatible(&dvs2_coefs, coefs,
3339  					sizeof(struct ia_css_dvs2_coefficients),
3340  					from_user)) {
3341  			dev_err(asd->isp->dev, "copy dvs2 coef failed");
3342  			return -EFAULT;
3343  		}
3344  
3345  		if (sizeof(*cur) != sizeof(dvs2_coefs.grid) ||
3346  		    memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) {
3347  			dev_err(asd->isp->dev, "dvs grid mis-match!\n");
3348  			/* If the grid info in the argument differs from the current
3349  			grid info, we tell the caller to reset the grid size and
3350  			try again. */
3351  			return -EAGAIN;
3352  		}
3353  
3354  		if (!dvs2_coefs.hor_coefs.odd_real ||
3355  		    !dvs2_coefs.hor_coefs.odd_imag ||
3356  		    !dvs2_coefs.hor_coefs.even_real ||
3357  		    !dvs2_coefs.hor_coefs.even_imag ||
3358  		    !dvs2_coefs.ver_coefs.odd_real ||
3359  		    !dvs2_coefs.ver_coefs.odd_imag ||
3360  		    !dvs2_coefs.ver_coefs.even_real ||
3361  		    !dvs2_coefs.ver_coefs.even_imag)
3362  			return -EINVAL;
3363  
3364  		if (!css_param->dvs2_coeff) {
3365  			/* DIS coefficients. */
3366  			css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur);
3367  			if (!css_param->dvs2_coeff)
3368  				return -ENOMEM;
3369  		}
3370  
3371  		dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes;
3372  		dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes;
3373  		if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real,
3374  					dvs2_coefs.hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
3375  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag,
3376  					dvs2_coefs.hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
3377  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real,
3378  					dvs2_coefs.hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
3379  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag,
3380  					dvs2_coefs.hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
3381  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real,
3382  					dvs2_coefs.ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
3383  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag,
3384  					dvs2_coefs.ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
3385  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real,
3386  					dvs2_coefs.ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
3387  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag,
3388  					dvs2_coefs.ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
3389  			ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
3390  			css_param->dvs2_coeff = NULL;
3391  			return -EFAULT;
3392  		}
3393  	}
3394  
3395  	css_param->update_flag.dvs2_coefs =
3396  	    (struct atomisp_dis_coefficients *)css_param->dvs2_coeff;
3397  	return 0;
3398  }
3399  
atomisp_cp_dvs_6axis_config(struct atomisp_sub_device * asd,struct atomisp_dvs_6axis_config * source_6axis_config,struct atomisp_css_params * css_param,bool from_user)3400  int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd,
3401  				struct atomisp_dvs_6axis_config *source_6axis_config,
3402  				struct atomisp_css_params *css_param,
3403  				bool from_user)
3404  {
3405  	struct ia_css_dvs_6axis_config *dvs_6axis_config;
3406  	struct ia_css_dvs_6axis_config *old_6axis_config;
3407  	struct ia_css_stream *stream =
3408  		    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
3409  	struct ia_css_dvs_grid_info *dvs_grid_info =
3410  	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
3411  	int ret = -EFAULT;
3412  
3413  	if (!stream) {
3414  		dev_err(asd->isp->dev, "%s: internal error!", __func__);
3415  		return -EINVAL;
3416  	}
3417  
3418  	if (!source_6axis_config || !dvs_grid_info)
3419  		return 0;
3420  
3421  	if (!dvs_grid_info->enable)
3422  		return 0;
3423  
3424  	if (!from_user && css_param->update_flag.dvs_6axis_config)
3425  		return 0;
3426  
3427  	/* check whether need to reallocate for 6 axis config */
3428  	old_6axis_config = css_param->dvs_6axis;
3429  	dvs_6axis_config = old_6axis_config;
3430  
3431  	if (IS_ISP2401) {
3432  		struct ia_css_dvs_6axis_config t_6axis_config;
3433  
3434  		if (copy_from_compatible(&t_6axis_config, source_6axis_config,
3435  					sizeof(struct atomisp_dvs_6axis_config),
3436  					from_user)) {
3437  			dev_err(asd->isp->dev, "copy morph table failed!");
3438  			return -EFAULT;
3439  		}
3440  
3441  		if (old_6axis_config &&
3442  		    (old_6axis_config->width_y != t_6axis_config.width_y ||
3443  		    old_6axis_config->height_y != t_6axis_config.height_y ||
3444  		    old_6axis_config->width_uv != t_6axis_config.width_uv ||
3445  		    old_6axis_config->height_uv != t_6axis_config.height_uv)) {
3446  			ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
3447  			css_param->dvs_6axis = NULL;
3448  
3449  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3450  			if (!dvs_6axis_config)
3451  				return -ENOMEM;
3452  		} else if (!dvs_6axis_config) {
3453  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3454  			if (!dvs_6axis_config)
3455  				return -ENOMEM;
3456  		}
3457  
3458  		dvs_6axis_config->exp_id = t_6axis_config.exp_id;
3459  
3460  		if (copy_from_compatible(dvs_6axis_config->xcoords_y,
3461  					t_6axis_config.xcoords_y,
3462  					t_6axis_config.width_y *
3463  					t_6axis_config.height_y *
3464  					sizeof(*dvs_6axis_config->xcoords_y),
3465  					from_user))
3466  			goto error;
3467  		if (copy_from_compatible(dvs_6axis_config->ycoords_y,
3468  					t_6axis_config.ycoords_y,
3469  					t_6axis_config.width_y *
3470  					t_6axis_config.height_y *
3471  					sizeof(*dvs_6axis_config->ycoords_y),
3472  					from_user))
3473  			goto error;
3474  		if (copy_from_compatible(dvs_6axis_config->xcoords_uv,
3475  					t_6axis_config.xcoords_uv,
3476  					t_6axis_config.width_uv *
3477  					t_6axis_config.height_uv *
3478  					sizeof(*dvs_6axis_config->xcoords_uv),
3479  					from_user))
3480  			goto error;
3481  		if (copy_from_compatible(dvs_6axis_config->ycoords_uv,
3482  					t_6axis_config.ycoords_uv,
3483  					t_6axis_config.width_uv *
3484  					t_6axis_config.height_uv *
3485  					sizeof(*dvs_6axis_config->ycoords_uv),
3486  					from_user))
3487  			goto error;
3488  	} else {
3489  		if (old_6axis_config &&
3490  		    (old_6axis_config->width_y != source_6axis_config->width_y ||
3491  		    old_6axis_config->height_y != source_6axis_config->height_y ||
3492  		    old_6axis_config->width_uv != source_6axis_config->width_uv ||
3493  		    old_6axis_config->height_uv != source_6axis_config->height_uv)) {
3494  			ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
3495  			css_param->dvs_6axis = NULL;
3496  
3497  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3498  			if (!dvs_6axis_config)
3499  				return -ENOMEM;
3500  		} else if (!dvs_6axis_config) {
3501  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
3502  			if (!dvs_6axis_config)
3503  				return -ENOMEM;
3504  		}
3505  
3506  		dvs_6axis_config->exp_id = source_6axis_config->exp_id;
3507  
3508  		if (copy_from_compatible(dvs_6axis_config->xcoords_y,
3509  					source_6axis_config->xcoords_y,
3510  					source_6axis_config->width_y *
3511  					source_6axis_config->height_y *
3512  					sizeof(*source_6axis_config->xcoords_y),
3513  					from_user))
3514  			goto error;
3515  		if (copy_from_compatible(dvs_6axis_config->ycoords_y,
3516  					source_6axis_config->ycoords_y,
3517  					source_6axis_config->width_y *
3518  					source_6axis_config->height_y *
3519  					sizeof(*source_6axis_config->ycoords_y),
3520  					from_user))
3521  			goto error;
3522  		if (copy_from_compatible(dvs_6axis_config->xcoords_uv,
3523  					source_6axis_config->xcoords_uv,
3524  					source_6axis_config->width_uv *
3525  					source_6axis_config->height_uv *
3526  					sizeof(*source_6axis_config->xcoords_uv),
3527  					from_user))
3528  			goto error;
3529  		if (copy_from_compatible(dvs_6axis_config->ycoords_uv,
3530  					source_6axis_config->ycoords_uv,
3531  					source_6axis_config->width_uv *
3532  					source_6axis_config->height_uv *
3533  					sizeof(*source_6axis_config->ycoords_uv),
3534  					from_user))
3535  			goto error;
3536  	}
3537  	css_param->dvs_6axis = dvs_6axis_config;
3538  	css_param->update_flag.dvs_6axis_config =
3539  	    (struct atomisp_dvs_6axis_config *)dvs_6axis_config;
3540  	return 0;
3541  
3542  error:
3543  	if (dvs_6axis_config)
3544  		ia_css_dvs2_6axis_config_free(dvs_6axis_config);
3545  	return ret;
3546  }
3547  
atomisp_cp_morph_table(struct atomisp_sub_device * asd,struct atomisp_morph_table * source_morph_table,struct atomisp_css_params * css_param,bool from_user)3548  int atomisp_cp_morph_table(struct atomisp_sub_device *asd,
3549  			   struct atomisp_morph_table *source_morph_table,
3550  			   struct atomisp_css_params *css_param,
3551  			   bool from_user)
3552  {
3553  	int ret = -EFAULT;
3554  	unsigned int i;
3555  	struct ia_css_morph_table *morph_table;
3556  	struct ia_css_morph_table *old_morph_table;
3557  
3558  	if (!source_morph_table)
3559  		return 0;
3560  
3561  	if (!from_user && css_param->update_flag.morph_table)
3562  		return 0;
3563  
3564  	old_morph_table = css_param->morph_table;
3565  
3566  	if (IS_ISP2401) {
3567  		struct ia_css_morph_table mtbl;
3568  
3569  		if (copy_from_compatible(&mtbl, source_morph_table,
3570  				sizeof(struct atomisp_morph_table),
3571  				from_user)) {
3572  			dev_err(asd->isp->dev, "copy morph table failed!");
3573  			return -EFAULT;
3574  		}
3575  
3576  		morph_table = atomisp_css_morph_table_allocate(
3577  				mtbl.width,
3578  				mtbl.height);
3579  		if (!morph_table)
3580  			return -ENOMEM;
3581  
3582  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
3583  			if (copy_from_compatible(morph_table->coordinates_x[i],
3584  						(__force void *)source_morph_table->coordinates_x[i],
3585  						mtbl.height * mtbl.width *
3586  						sizeof(*morph_table->coordinates_x[i]),
3587  						from_user))
3588  				goto error;
3589  
3590  			if (copy_from_compatible(morph_table->coordinates_y[i],
3591  						(__force void *)source_morph_table->coordinates_y[i],
3592  						mtbl.height * mtbl.width *
3593  						sizeof(*morph_table->coordinates_y[i]),
3594  						from_user))
3595  				goto error;
3596  		}
3597  	} else {
3598  		morph_table = atomisp_css_morph_table_allocate(
3599  				source_morph_table->width,
3600  				source_morph_table->height);
3601  		if (!morph_table)
3602  			return -ENOMEM;
3603  
3604  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
3605  			if (copy_from_compatible(morph_table->coordinates_x[i],
3606  						(__force void *)source_morph_table->coordinates_x[i],
3607  						source_morph_table->height * source_morph_table->width *
3608  						sizeof(*source_morph_table->coordinates_x[i]),
3609  						from_user))
3610  				goto error;
3611  
3612  			if (copy_from_compatible(morph_table->coordinates_y[i],
3613  						(__force void *)source_morph_table->coordinates_y[i],
3614  						source_morph_table->height * source_morph_table->width *
3615  						sizeof(*source_morph_table->coordinates_y[i]),
3616  						from_user))
3617  				goto error;
3618  		}
3619  	}
3620  
3621  	css_param->morph_table = morph_table;
3622  	if (old_morph_table)
3623  		atomisp_css_morph_table_free(old_morph_table);
3624  	css_param->update_flag.morph_table =
3625  	    (struct atomisp_morph_table *)morph_table;
3626  	return 0;
3627  
3628  error:
3629  	if (morph_table)
3630  		atomisp_css_morph_table_free(morph_table);
3631  	return ret;
3632  }
3633  
atomisp_makeup_css_parameters(struct atomisp_sub_device * asd,struct atomisp_parameters * arg,struct atomisp_css_params * css_param)3634  int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd,
3635  				  struct atomisp_parameters *arg,
3636  				  struct atomisp_css_params *css_param)
3637  {
3638  	int ret;
3639  
3640  	ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, false);
3641  	if (ret)
3642  		return ret;
3643  	ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, false);
3644  	if (ret)
3645  		return ret;
3646  	ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, false);
3647  	if (ret)
3648  		return ret;
3649  	ret = atomisp_css_cp_dvs2_coefs(asd,
3650  					(struct ia_css_dvs2_coefficients *)arg->dvs2_coefs,
3651  					css_param, false);
3652  	if (ret)
3653  		return ret;
3654  	ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
3655  					  css_param, false);
3656  	return ret;
3657  }
3658  
atomisp_free_css_parameters(struct atomisp_css_params * css_param)3659  void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
3660  {
3661  	if (css_param->dvs_6axis) {
3662  		ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
3663  		css_param->dvs_6axis = NULL;
3664  	}
3665  	if (css_param->dvs2_coeff) {
3666  		ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
3667  		css_param->dvs2_coeff = NULL;
3668  	}
3669  	if (css_param->shading_table) {
3670  		ia_css_shading_table_free(css_param->shading_table);
3671  		css_param->shading_table = NULL;
3672  	}
3673  	if (css_param->morph_table) {
3674  		ia_css_morph_table_free(css_param->morph_table);
3675  		css_param->morph_table = NULL;
3676  	}
3677  }
3678  
3679  /*
3680   * Check parameter queue list and buffer queue list to find out if matched items
3681   * and then set parameter to CSS and enqueue buffer to CSS.
3682   * Of course, if the buffer in buffer waiting list is not bound to a per-frame
3683   * parameter, it will be enqueued into CSS as long as the per-frame setting
3684   * buffers before it get enqueued.
3685   */
atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe * pipe)3686  void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
3687  {
3688  	struct atomisp_sub_device *asd = pipe->asd;
3689  	struct videobuf_buffer *vb = NULL, *vb_tmp;
3690  	struct atomisp_css_params_with_list *param = NULL, *param_tmp;
3691  	struct videobuf_vmalloc_memory *vm_mem = NULL;
3692  	unsigned long irqflags;
3693  	bool need_to_enqueue_buffer = false;
3694  
3695  	lockdep_assert_held(&asd->isp->mutex);
3696  
3697  	if (!asd) {
3698  		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
3699  			__func__, pipe->vdev.name);
3700  		return;
3701  	}
3702  
3703  	if (atomisp_is_vf_pipe(pipe))
3704  		return;
3705  
3706  	/*
3707  	 * CSS/FW requires set parameter and enqueue buffer happen after ISP
3708  	 * is streamon.
3709  	 */
3710  	if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
3711  		return;
3712  
3713  	if (list_empty(&pipe->per_frame_params) ||
3714  	    list_empty(&pipe->buffers_waiting_for_param))
3715  		return;
3716  
3717  	list_for_each_entry_safe(vb, vb_tmp,
3718  				 &pipe->buffers_waiting_for_param, queue) {
3719  		if (pipe->frame_request_config_id[vb->i]) {
3720  			list_for_each_entry_safe(param, param_tmp,
3721  						 &pipe->per_frame_params, list) {
3722  				if (pipe->frame_request_config_id[vb->i] !=
3723  				    param->params.isp_config_id)
3724  					continue;
3725  
3726  				list_del(&param->list);
3727  				list_del(&vb->queue);
3728  				/*
3729  				 * clear the request config id as the buffer
3730  				 * will be handled and enqueued into CSS soon
3731  				 */
3732  				pipe->frame_request_config_id[vb->i] = 0;
3733  				pipe->frame_params[vb->i] = param;
3734  				vm_mem = vb->priv;
3735  				BUG_ON(!vm_mem);
3736  				break;
3737  			}
3738  
3739  			if (vm_mem) {
3740  				spin_lock_irqsave(&pipe->irq_lock, irqflags);
3741  				list_add_tail(&vb->queue, &pipe->activeq);
3742  				spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
3743  				vm_mem = NULL;
3744  				need_to_enqueue_buffer = true;
3745  			} else {
3746  				/* The is the end, stop further loop */
3747  				break;
3748  			}
3749  		} else {
3750  			list_del(&vb->queue);
3751  			pipe->frame_params[vb->i] = NULL;
3752  			spin_lock_irqsave(&pipe->irq_lock, irqflags);
3753  			list_add_tail(&vb->queue, &pipe->activeq);
3754  			spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
3755  			need_to_enqueue_buffer = true;
3756  		}
3757  	}
3758  
3759  	if (!need_to_enqueue_buffer)
3760  		return;
3761  
3762  	atomisp_qbuffers_to_css(asd);
3763  }
3764  
3765  /*
3766  * Function to configure ISP parameters
3767  */
atomisp_set_parameters(struct video_device * vdev,struct atomisp_parameters * arg)3768  int atomisp_set_parameters(struct video_device *vdev,
3769  			   struct atomisp_parameters *arg)
3770  {
3771  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
3772  	struct atomisp_sub_device *asd = pipe->asd;
3773  	struct atomisp_css_params_with_list *param = NULL;
3774  	struct atomisp_css_params *css_param = &asd->params.css_param;
3775  	int ret;
3776  
3777  	lockdep_assert_held(&asd->isp->mutex);
3778  
3779  	if (!asd) {
3780  		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
3781  			__func__, vdev->name);
3782  		return -EINVAL;
3783  	}
3784  
3785  	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
3786  		dev_err(asd->isp->dev, "%s: internal error!\n", __func__);
3787  		return -EINVAL;
3788  	}
3789  
3790  	dev_dbg(asd->isp->dev,
3791  		"%s: set parameter(per_frame_setting %d) for asd%d with isp_config_id %d of %s\n",
3792  		__func__, arg->per_frame_setting, asd->index,
3793  		arg->isp_config_id, vdev->name);
3794  
3795  	if (IS_ISP2401) {
3796  		if (atomisp_is_vf_pipe(pipe) && arg->per_frame_setting) {
3797  			dev_err(asd->isp->dev, "%s: vf pipe not support per_frame_setting",
3798  				__func__);
3799  			return -EINVAL;
3800  		}
3801  	}
3802  
3803  	if (arg->per_frame_setting && !atomisp_is_vf_pipe(pipe)) {
3804  		/*
3805  		 * Per-frame setting enabled, we allocate a new parameter
3806  		 * buffer to cache the parameters and only when frame buffers
3807  		 * are ready, the parameters will be set to CSS.
3808  		 * per-frame setting only works for the main output frame.
3809  		 */
3810  		param = kvzalloc(sizeof(*param), GFP_KERNEL);
3811  		if (!param) {
3812  			dev_err(asd->isp->dev, "%s: failed to alloc params buffer\n",
3813  				__func__);
3814  			return -ENOMEM;
3815  		}
3816  		css_param = &param->params;
3817  	}
3818  
3819  	ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, true);
3820  	if (ret)
3821  		goto apply_parameter_failed;
3822  
3823  	ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, true);
3824  	if (ret)
3825  		goto apply_parameter_failed;
3826  
3827  	ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, true);
3828  	if (ret)
3829  		goto apply_parameter_failed;
3830  
3831  	ret = atomisp_css_cp_dvs2_coefs(asd,
3832  					(struct ia_css_dvs2_coefficients *)arg->dvs2_coefs,
3833  					css_param, true);
3834  	if (ret)
3835  		goto apply_parameter_failed;
3836  
3837  	ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
3838  					  css_param, true);
3839  	if (ret)
3840  		goto apply_parameter_failed;
3841  
3842  	if (!(arg->per_frame_setting && !atomisp_is_vf_pipe(pipe))) {
3843  		/* indicate to CSS that we have parameters to be updated */
3844  		asd->params.css_update_params_needed = true;
3845  	} else {
3846  		list_add_tail(&param->list, &pipe->per_frame_params);
3847  		atomisp_handle_parameter_and_buffer(pipe);
3848  	}
3849  
3850  	return 0;
3851  
3852  apply_parameter_failed:
3853  	if (css_param)
3854  		atomisp_free_css_parameters(css_param);
3855  	kvfree(param);
3856  
3857  	return ret;
3858  }
3859  
3860  /*
3861   * Function to set/get isp parameters to isp
3862   */
atomisp_param(struct atomisp_sub_device * asd,int flag,struct atomisp_parm * config)3863  int atomisp_param(struct atomisp_sub_device *asd, int flag,
3864  		  struct atomisp_parm *config)
3865  {
3866  	struct ia_css_pipe_config *vp_cfg =
3867  		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
3868  		    pipe_configs[IA_CSS_PIPE_ID_VIDEO];
3869  
3870  	/* Read parameter for 3A binary info */
3871  	if (flag == 0) {
3872  		struct ia_css_dvs_grid_info *dvs_grid_info =
3873  		    atomisp_css_get_dvs_grid_info(
3874  			&asd->params.curr_grid_info);
3875  
3876  		atomisp_curr_user_grid_info(asd, &config->info);
3877  
3878  		/* We always return the resolution and stride even if there is
3879  		 * no valid metadata. This allows the caller to get the
3880  		 * information needed to allocate user-space buffers. */
3881  		config->metadata_config.metadata_height = asd->
3882  			stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
3883  			metadata_info.resolution.height;
3884  		config->metadata_config.metadata_stride = asd->
3885  			stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
3886  			metadata_info.stride;
3887  
3888  		/* update dvs grid info */
3889  		if (dvs_grid_info)
3890  			memcpy(&config->dvs_grid,
3891  			       dvs_grid_info,
3892  			       sizeof(struct ia_css_dvs_grid_info));
3893  
3894  		if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
3895  			config->dvs_envelop.width = 0;
3896  			config->dvs_envelop.height = 0;
3897  			return 0;
3898  		}
3899  
3900  		/* update dvs envelop info */
3901  		if (!asd->continuous_mode->val) {
3902  			config->dvs_envelop.width = vp_cfg->dvs_envelope.width;
3903  			config->dvs_envelop.height =
3904  			    vp_cfg->dvs_envelope.height;
3905  		} else {
3906  			unsigned int dvs_w, dvs_h, dvs_w_max, dvs_h_max;
3907  
3908  			dvs_w = vp_cfg->bayer_ds_out_res.width -
3909  				vp_cfg->output_info[0].res.width;
3910  			dvs_h = vp_cfg->bayer_ds_out_res.height -
3911  				vp_cfg->output_info[0].res.height;
3912  			dvs_w_max = rounddown(
3913  					vp_cfg->output_info[0].res.width / 5,
3914  					ATOM_ISP_STEP_WIDTH);
3915  			dvs_h_max = rounddown(
3916  					vp_cfg->output_info[0].res.height / 5,
3917  					ATOM_ISP_STEP_HEIGHT);
3918  
3919  			config->dvs_envelop.width = min(dvs_w, dvs_w_max);
3920  			config->dvs_envelop.height = min(dvs_h, dvs_h_max);
3921  		}
3922  
3923  		return 0;
3924  	}
3925  
3926  	memcpy(&asd->params.css_param.wb_config, &config->wb_config,
3927  	       sizeof(struct ia_css_wb_config));
3928  	memcpy(&asd->params.css_param.ob_config, &config->ob_config,
3929  	       sizeof(struct ia_css_ob_config));
3930  	memcpy(&asd->params.css_param.dp_config, &config->dp_config,
3931  	       sizeof(struct ia_css_dp_config));
3932  	memcpy(&asd->params.css_param.de_config, &config->de_config,
3933  	       sizeof(struct ia_css_de_config));
3934  	memcpy(&asd->params.css_param.dz_config, &config->dz_config,
3935  	       sizeof(struct ia_css_dz_config));
3936  	memcpy(&asd->params.css_param.ce_config, &config->ce_config,
3937  	       sizeof(struct ia_css_ce_config));
3938  	memcpy(&asd->params.css_param.nr_config, &config->nr_config,
3939  	       sizeof(struct ia_css_nr_config));
3940  	memcpy(&asd->params.css_param.ee_config, &config->ee_config,
3941  	       sizeof(struct ia_css_ee_config));
3942  	memcpy(&asd->params.css_param.tnr_config, &config->tnr_config,
3943  	       sizeof(struct ia_css_tnr_config));
3944  
3945  	if (asd->params.color_effect == V4L2_COLORFX_NEGATIVE) {
3946  		asd->params.css_param.cc_config.matrix[3] = -config->cc_config.matrix[3];
3947  		asd->params.css_param.cc_config.matrix[4] = -config->cc_config.matrix[4];
3948  		asd->params.css_param.cc_config.matrix[5] = -config->cc_config.matrix[5];
3949  		asd->params.css_param.cc_config.matrix[6] = -config->cc_config.matrix[6];
3950  		asd->params.css_param.cc_config.matrix[7] = -config->cc_config.matrix[7];
3951  		asd->params.css_param.cc_config.matrix[8] = -config->cc_config.matrix[8];
3952  	}
3953  
3954  	if (asd->params.color_effect != V4L2_COLORFX_SEPIA &&
3955  	    asd->params.color_effect != V4L2_COLORFX_BW) {
3956  		memcpy(&asd->params.css_param.cc_config, &config->cc_config,
3957  		       sizeof(struct ia_css_cc_config));
3958  		asd->params.config.cc_config = &asd->params.css_param.cc_config;
3959  	}
3960  
3961  	asd->params.config.wb_config = &asd->params.css_param.wb_config;
3962  	asd->params.config.ob_config = &asd->params.css_param.ob_config;
3963  	asd->params.config.de_config = &asd->params.css_param.de_config;
3964  	asd->params.config.dz_config = &asd->params.css_param.dz_config;
3965  	asd->params.config.ce_config = &asd->params.css_param.ce_config;
3966  	asd->params.config.dp_config = &asd->params.css_param.dp_config;
3967  	asd->params.config.nr_config = &asd->params.css_param.nr_config;
3968  	asd->params.config.ee_config = &asd->params.css_param.ee_config;
3969  	asd->params.config.tnr_config = &asd->params.css_param.tnr_config;
3970  	asd->params.css_update_params_needed = true;
3971  
3972  	return 0;
3973  }
3974  
3975  /*
3976   * Function to configure color effect of the image
3977   */
atomisp_color_effect(struct atomisp_sub_device * asd,int flag,__s32 * effect)3978  int atomisp_color_effect(struct atomisp_sub_device *asd, int flag,
3979  			 __s32 *effect)
3980  {
3981  	struct ia_css_cc_config *cc_config = NULL;
3982  	struct ia_css_macc_table *macc_table = NULL;
3983  	struct ia_css_ctc_table *ctc_table = NULL;
3984  	int ret = 0;
3985  	struct v4l2_control control;
3986  	struct atomisp_device *isp = asd->isp;
3987  
3988  	if (flag == 0) {
3989  		*effect = asd->params.color_effect;
3990  		return 0;
3991  	}
3992  
3993  	control.id = V4L2_CID_COLORFX;
3994  	control.value = *effect;
3995  	ret =
3996  	    v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].camera->ctrl_handler,
3997  			&control);
3998  	/*
3999  	 * if set color effect to sensor successfully, return
4000  	 * 0 directly.
4001  	 */
4002  	if (!ret) {
4003  		asd->params.color_effect = (u32)*effect;
4004  		return 0;
4005  	}
4006  
4007  	if (*effect == asd->params.color_effect)
4008  		return 0;
4009  
4010  	/*
4011  	 * isp_subdev->params.macc_en should be set to false.
4012  	 */
4013  	asd->params.macc_en = false;
4014  
4015  	switch (*effect) {
4016  	case V4L2_COLORFX_NONE:
4017  		macc_table = &asd->params.css_param.macc_table;
4018  		asd->params.macc_en = true;
4019  		break;
4020  	case V4L2_COLORFX_SEPIA:
4021  		cc_config = &sepia_cc_config;
4022  		break;
4023  	case V4L2_COLORFX_NEGATIVE:
4024  		cc_config = &nega_cc_config;
4025  		break;
4026  	case V4L2_COLORFX_BW:
4027  		cc_config = &mono_cc_config;
4028  		break;
4029  	case V4L2_COLORFX_SKY_BLUE:
4030  		macc_table = &blue_macc_table;
4031  		asd->params.macc_en = true;
4032  		break;
4033  	case V4L2_COLORFX_GRASS_GREEN:
4034  		macc_table = &green_macc_table;
4035  		asd->params.macc_en = true;
4036  		break;
4037  	case V4L2_COLORFX_SKIN_WHITEN_LOW:
4038  		macc_table = &skin_low_macc_table;
4039  		asd->params.macc_en = true;
4040  		break;
4041  	case V4L2_COLORFX_SKIN_WHITEN:
4042  		macc_table = &skin_medium_macc_table;
4043  		asd->params.macc_en = true;
4044  		break;
4045  	case V4L2_COLORFX_SKIN_WHITEN_HIGH:
4046  		macc_table = &skin_high_macc_table;
4047  		asd->params.macc_en = true;
4048  		break;
4049  	case V4L2_COLORFX_VIVID:
4050  		ctc_table = &vivid_ctc_table;
4051  		break;
4052  	default:
4053  		return -EINVAL;
4054  	}
4055  	atomisp_update_capture_mode(asd);
4056  
4057  	if (cc_config)
4058  		asd->params.config.cc_config = cc_config;
4059  	if (macc_table)
4060  		asd->params.config.macc_table = macc_table;
4061  	if (ctc_table)
4062  		atomisp_css_set_ctc_table(asd, ctc_table);
4063  	asd->params.color_effect = (u32)*effect;
4064  	asd->params.css_update_params_needed = true;
4065  	return 0;
4066  }
4067  
4068  /*
4069   * Function to configure bad pixel correction
4070   */
atomisp_bad_pixel(struct atomisp_sub_device * asd,int flag,__s32 * value)4071  int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag,
4072  		      __s32 *value)
4073  {
4074  	if (flag == 0) {
4075  		*value = asd->params.bad_pixel_en;
4076  		return 0;
4077  	}
4078  	asd->params.bad_pixel_en = !!*value;
4079  
4080  	return 0;
4081  }
4082  
4083  /*
4084   * Function to configure bad pixel correction params
4085   */
atomisp_bad_pixel_param(struct atomisp_sub_device * asd,int flag,struct atomisp_dp_config * config)4086  int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag,
4087  			    struct atomisp_dp_config *config)
4088  {
4089  	if (flag == 0) {
4090  		/* Get bad pixel from current setup */
4091  		if (atomisp_css_get_dp_config(asd, config))
4092  			return -EINVAL;
4093  	} else {
4094  		/* Set bad pixel to isp parameters */
4095  		memcpy(&asd->params.css_param.dp_config, config,
4096  		       sizeof(asd->params.css_param.dp_config));
4097  		asd->params.config.dp_config = &asd->params.css_param.dp_config;
4098  		asd->params.css_update_params_needed = true;
4099  	}
4100  
4101  	return 0;
4102  }
4103  
4104  /*
4105   * Function to enable/disable video image stablization
4106   */
atomisp_video_stable(struct atomisp_sub_device * asd,int flag,__s32 * value)4107  int atomisp_video_stable(struct atomisp_sub_device *asd, int flag,
4108  			 __s32 *value)
4109  {
4110  	if (flag == 0)
4111  		*value = asd->params.video_dis_en;
4112  	else
4113  		asd->params.video_dis_en = !!*value;
4114  
4115  	return 0;
4116  }
4117  
4118  /*
4119   * Function to configure fixed pattern noise
4120   */
atomisp_fixed_pattern(struct atomisp_sub_device * asd,int flag,__s32 * value)4121  int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
4122  			  __s32 *value)
4123  {
4124  	if (flag == 0) {
4125  		*value = asd->params.fpn_en;
4126  		return 0;
4127  	}
4128  
4129  	if (*value == 0) {
4130  		asd->params.fpn_en = false;
4131  		return 0;
4132  	}
4133  
4134  	/* Add function to get black from from sensor with shutter off */
4135  	return 0;
4136  }
4137  
4138  static unsigned int
atomisp_bytesperline_to_padded_width(unsigned int bytesperline,enum ia_css_frame_format format)4139  atomisp_bytesperline_to_padded_width(unsigned int bytesperline,
4140  				     enum ia_css_frame_format format)
4141  {
4142  	switch (format) {
4143  	case IA_CSS_FRAME_FORMAT_UYVY:
4144  	case IA_CSS_FRAME_FORMAT_YUYV:
4145  	case IA_CSS_FRAME_FORMAT_RAW:
4146  	case IA_CSS_FRAME_FORMAT_RGB565:
4147  		return bytesperline / 2;
4148  	case IA_CSS_FRAME_FORMAT_RGBA888:
4149  		return bytesperline / 4;
4150  	/* The following cases could be removed, but we leave them
4151  	   in to document the formats that are included. */
4152  	case IA_CSS_FRAME_FORMAT_NV11:
4153  	case IA_CSS_FRAME_FORMAT_NV12:
4154  	case IA_CSS_FRAME_FORMAT_NV16:
4155  	case IA_CSS_FRAME_FORMAT_NV21:
4156  	case IA_CSS_FRAME_FORMAT_NV61:
4157  	case IA_CSS_FRAME_FORMAT_YV12:
4158  	case IA_CSS_FRAME_FORMAT_YV16:
4159  	case IA_CSS_FRAME_FORMAT_YUV420:
4160  	case IA_CSS_FRAME_FORMAT_YUV420_16:
4161  	case IA_CSS_FRAME_FORMAT_YUV422:
4162  	case IA_CSS_FRAME_FORMAT_YUV422_16:
4163  	case IA_CSS_FRAME_FORMAT_YUV444:
4164  	case IA_CSS_FRAME_FORMAT_YUV_LINE:
4165  	case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
4166  	case IA_CSS_FRAME_FORMAT_QPLANE6:
4167  	case IA_CSS_FRAME_FORMAT_BINARY_8:
4168  	default:
4169  		return bytesperline;
4170  	}
4171  }
4172  
4173  static int
atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer * arg,struct ia_css_frame ** result)4174  atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer *arg,
4175  				      struct ia_css_frame **result)
4176  {
4177  	struct ia_css_frame *res = NULL;
4178  	unsigned int padded_width;
4179  	enum ia_css_frame_format sh_format;
4180  	char *tmp_buf = NULL;
4181  	int ret = 0;
4182  
4183  	sh_format = v4l2_fmt_to_sh_fmt(arg->fmt.pixelformat);
4184  	padded_width = atomisp_bytesperline_to_padded_width(
4185  			   arg->fmt.bytesperline, sh_format);
4186  
4187  	/* Note: the padded width on an ia_css_frame is in elements, not in
4188  	   bytes. The RAW frame we use here should always be a 16bit RAW
4189  	   frame. This is why we bytesperline/2 is equal to the padded with */
4190  	if (ia_css_frame_allocate(&res, arg->fmt.width, arg->fmt.height,
4191  				       sh_format, padded_width, 0)) {
4192  		ret = -ENOMEM;
4193  		goto err;
4194  	}
4195  
4196  	tmp_buf = vmalloc(arg->fmt.sizeimage);
4197  	if (!tmp_buf) {
4198  		ret = -ENOMEM;
4199  		goto err;
4200  	}
4201  	if (copy_from_user(tmp_buf, (void __user __force *)arg->base,
4202  			   arg->fmt.sizeimage)) {
4203  		ret = -EFAULT;
4204  		goto err;
4205  	}
4206  
4207  	if (hmm_store(res->data, tmp_buf, arg->fmt.sizeimage)) {
4208  		ret = -EINVAL;
4209  		goto err;
4210  	}
4211  
4212  err:
4213  	if (ret && res)
4214  		ia_css_frame_free(res);
4215  	vfree(tmp_buf);
4216  	if (ret == 0)
4217  		*result = res;
4218  	return ret;
4219  }
4220  
4221  /*
4222   * Function to configure fixed pattern noise table
4223   */
atomisp_fixed_pattern_table(struct atomisp_sub_device * asd,struct v4l2_framebuffer * arg)4224  int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd,
4225  				struct v4l2_framebuffer *arg)
4226  {
4227  	struct ia_css_frame *raw_black_frame = NULL;
4228  	int ret;
4229  
4230  	if (!arg)
4231  		return -EINVAL;
4232  
4233  	ret = atomisp_v4l2_framebuffer_to_css_frame(arg, &raw_black_frame);
4234  	if (ret)
4235  		return ret;
4236  
4237  	if (sh_css_set_black_frame(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
4238  				   raw_black_frame) != 0)
4239  		return -ENOMEM;
4240  
4241  	ia_css_frame_free(raw_black_frame);
4242  	return ret;
4243  }
4244  
4245  /*
4246   * Function to configure false color correction
4247   */
atomisp_false_color(struct atomisp_sub_device * asd,int flag,__s32 * value)4248  int atomisp_false_color(struct atomisp_sub_device *asd, int flag,
4249  			__s32 *value)
4250  {
4251  	/* Get nr config from current setup */
4252  	if (flag == 0) {
4253  		*value = asd->params.false_color;
4254  		return 0;
4255  	}
4256  
4257  	/* Set nr config to isp parameters */
4258  	if (*value) {
4259  		asd->params.config.de_config = NULL;
4260  	} else {
4261  		asd->params.css_param.de_config.pixelnoise = 0;
4262  		asd->params.config.de_config = &asd->params.css_param.de_config;
4263  	}
4264  	asd->params.css_update_params_needed = true;
4265  	asd->params.false_color = *value;
4266  	return 0;
4267  }
4268  
4269  /*
4270   * Function to configure bad pixel correction params
4271   */
atomisp_false_color_param(struct atomisp_sub_device * asd,int flag,struct atomisp_de_config * config)4272  int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag,
4273  			      struct atomisp_de_config *config)
4274  {
4275  	if (flag == 0) {
4276  		/* Get false color from current setup */
4277  		if (atomisp_css_get_de_config(asd, config))
4278  			return -EINVAL;
4279  	} else {
4280  		/* Set false color to isp parameters */
4281  		memcpy(&asd->params.css_param.de_config, config,
4282  		       sizeof(asd->params.css_param.de_config));
4283  		asd->params.config.de_config = &asd->params.css_param.de_config;
4284  		asd->params.css_update_params_needed = true;
4285  	}
4286  
4287  	return 0;
4288  }
4289  
4290  /*
4291   * Function to configure white balance params
4292   */
atomisp_white_balance_param(struct atomisp_sub_device * asd,int flag,struct atomisp_wb_config * config)4293  int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag,
4294  				struct atomisp_wb_config *config)
4295  {
4296  	if (flag == 0) {
4297  		/* Get white balance from current setup */
4298  		if (atomisp_css_get_wb_config(asd, config))
4299  			return -EINVAL;
4300  	} else {
4301  		/* Set white balance to isp parameters */
4302  		memcpy(&asd->params.css_param.wb_config, config,
4303  		       sizeof(asd->params.css_param.wb_config));
4304  		asd->params.config.wb_config = &asd->params.css_param.wb_config;
4305  		asd->params.css_update_params_needed = true;
4306  	}
4307  
4308  	return 0;
4309  }
4310  
atomisp_3a_config_param(struct atomisp_sub_device * asd,int flag,struct atomisp_3a_config * config)4311  int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag,
4312  			    struct atomisp_3a_config *config)
4313  {
4314  	struct atomisp_device *isp = asd->isp;
4315  
4316  	dev_dbg(isp->dev, ">%s %d\n", __func__, flag);
4317  
4318  	if (flag == 0) {
4319  		/* Get white balance from current setup */
4320  		if (atomisp_css_get_3a_config(asd, config))
4321  			return -EINVAL;
4322  	} else {
4323  		/* Set white balance to isp parameters */
4324  		memcpy(&asd->params.css_param.s3a_config, config,
4325  		       sizeof(asd->params.css_param.s3a_config));
4326  		asd->params.config.s3a_config = &asd->params.css_param.s3a_config;
4327  		asd->params.css_update_params_needed = true;
4328  	}
4329  
4330  	dev_dbg(isp->dev, "<%s %d\n", __func__, flag);
4331  	return 0;
4332  }
4333  
4334  /*
4335   * Function to setup digital zoom
4336   */
atomisp_digital_zoom(struct atomisp_sub_device * asd,int flag,__s32 * value)4337  int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
4338  			 __s32 *value)
4339  {
4340  	u32 zoom;
4341  	struct atomisp_device *isp = asd->isp;
4342  
4343  	unsigned int max_zoom = MRFLD_MAX_ZOOM_FACTOR;
4344  
4345  	if (flag == 0) {
4346  		atomisp_css_get_zoom_factor(asd, &zoom);
4347  		*value = max_zoom - zoom;
4348  	} else {
4349  		if (*value < 0)
4350  			return -EINVAL;
4351  
4352  		zoom = max_zoom - min_t(u32, max_zoom - 1, *value);
4353  		atomisp_css_set_zoom_factor(asd, zoom);
4354  
4355  		dev_dbg(isp->dev, "%s, zoom: %d\n", __func__, zoom);
4356  		asd->params.css_update_params_needed = true;
4357  	}
4358  
4359  	return 0;
4360  }
4361  
4362  /*
4363   * Function to get sensor specific info for current resolution,
4364   * which will be used for auto exposure conversion.
4365   */
atomisp_get_sensor_mode_data(struct atomisp_sub_device * asd,struct atomisp_sensor_mode_data * config)4366  int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd,
4367  				 struct atomisp_sensor_mode_data *config)
4368  {
4369  	struct camera_mipi_info *mipi_info;
4370  	struct atomisp_device *isp = asd->isp;
4371  
4372  	mipi_info = atomisp_to_sensor_mipi_info(
4373  			isp->inputs[asd->input_curr].camera);
4374  	if (!mipi_info)
4375  		return -EINVAL;
4376  
4377  	memcpy(config, &mipi_info->data, sizeof(*config));
4378  	return 0;
4379  }
4380  
__atomisp_update_stream_env(struct atomisp_sub_device * asd,u16 stream_index,struct atomisp_input_stream_info * stream_info)4381  static void __atomisp_update_stream_env(struct atomisp_sub_device *asd,
4382  					u16 stream_index, struct atomisp_input_stream_info *stream_info)
4383  {
4384  	int i;
4385  
4386  	/* assign virtual channel id return from sensor driver query */
4387  	asd->stream_env[stream_index].ch_id = stream_info->ch_id;
4388  	asd->stream_env[stream_index].isys_configs = stream_info->isys_configs;
4389  	for (i = 0; i < stream_info->isys_configs; i++) {
4390  		asd->stream_env[stream_index].isys_info[i].input_format =
4391  		    stream_info->isys_info[i].input_format;
4392  		asd->stream_env[stream_index].isys_info[i].width =
4393  		    stream_info->isys_info[i].width;
4394  		asd->stream_env[stream_index].isys_info[i].height =
4395  		    stream_info->isys_info[i].height;
4396  	}
4397  }
4398  
__atomisp_init_stream_info(u16 stream_index,struct atomisp_input_stream_info * stream_info)4399  static void __atomisp_init_stream_info(u16 stream_index,
4400  				       struct atomisp_input_stream_info *stream_info)
4401  {
4402  	int i;
4403  
4404  	stream_info->enable = 1;
4405  	stream_info->stream = stream_index;
4406  	stream_info->ch_id = 0;
4407  	stream_info->isys_configs = 0;
4408  	for (i = 0; i < MAX_STREAMS_PER_CHANNEL; i++) {
4409  		stream_info->isys_info[i].input_format = 0;
4410  		stream_info->isys_info[i].width = 0;
4411  		stream_info->isys_info[i].height = 0;
4412  	}
4413  }
4414  
4415  /* This function looks up the closest available resolution. */
atomisp_try_fmt(struct video_device * vdev,struct v4l2_pix_format * f,bool * res_overflow)4416  int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f,
4417  		    bool *res_overflow)
4418  {
4419  	struct atomisp_device *isp = video_get_drvdata(vdev);
4420  	struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
4421  	struct v4l2_subdev_pad_config pad_cfg;
4422  	struct v4l2_subdev_state pad_state = {
4423  		.pads = &pad_cfg
4424  		};
4425  	struct v4l2_subdev_format format = {
4426  		.which = V4L2_SUBDEV_FORMAT_TRY,
4427  	};
4428  
4429  	struct v4l2_mbus_framefmt *snr_mbus_fmt = &format.format;
4430  	const struct atomisp_format_bridge *fmt;
4431  	struct atomisp_input_stream_info *stream_info =
4432  	    (struct atomisp_input_stream_info *)snr_mbus_fmt->reserved;
4433  	int ret;
4434  
4435  	if (!asd) {
4436  		dev_err(isp->dev, "%s(): asd is NULL, device is %s\n",
4437  			__func__, vdev->name);
4438  		return -EINVAL;
4439  	}
4440  
4441  	if (!isp->inputs[asd->input_curr].camera)
4442  		return -EINVAL;
4443  
4444  	fmt = atomisp_get_format_bridge(f->pixelformat);
4445  	if (!fmt) {
4446  		dev_err(isp->dev, "unsupported pixelformat!\n");
4447  		fmt = atomisp_output_fmts;
4448  	}
4449  
4450  	if (f->width <= 0 || f->height <= 0)
4451  		return -EINVAL;
4452  
4453  	snr_mbus_fmt->code = fmt->mbus_code;
4454  	snr_mbus_fmt->width = f->width;
4455  	snr_mbus_fmt->height = f->height;
4456  
4457  	__atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info);
4458  
4459  	dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n",
4460  		snr_mbus_fmt->width, snr_mbus_fmt->height);
4461  
4462  	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
4463  			       pad, set_fmt, &pad_state, &format);
4464  	if (ret)
4465  		return ret;
4466  
4467  	dev_dbg(isp->dev, "try_mbus_fmt: got %ux%u\n",
4468  		snr_mbus_fmt->width, snr_mbus_fmt->height);
4469  
4470  	fmt = atomisp_get_format_bridge_from_mbus(snr_mbus_fmt->code);
4471  	if (!fmt) {
4472  		dev_err(isp->dev, "unknown sensor format 0x%8.8x\n",
4473  			snr_mbus_fmt->code);
4474  		return -EINVAL;
4475  	}
4476  
4477  	f->pixelformat = fmt->pixelformat;
4478  
4479  	/*
4480  	 * If the format is jpeg or custom RAW, then the width and height will
4481  	 * not satisfy the normal atomisp requirements and no need to check
4482  	 * the below conditions. So just assign to what is being returned from
4483  	 * the sensor driver.
4484  	 */
4485  	if (f->pixelformat == V4L2_PIX_FMT_JPEG ||
4486  	    f->pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) {
4487  		f->width = snr_mbus_fmt->width;
4488  		f->height = snr_mbus_fmt->height;
4489  		return 0;
4490  	}
4491  
4492  	if (!res_overflow || (snr_mbus_fmt->width < f->width &&
4493  			      snr_mbus_fmt->height < f->height)) {
4494  		f->width = snr_mbus_fmt->width;
4495  		f->height = snr_mbus_fmt->height;
4496  		/* Set the flag when resolution requested is
4497  		 * beyond the max value supported by sensor
4498  		 */
4499  		if (res_overflow)
4500  			*res_overflow = true;
4501  	}
4502  
4503  	/* app vs isp */
4504  	f->width = rounddown(clamp_t(u32, f->width, ATOM_ISP_MIN_WIDTH,
4505  				     ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH);
4506  	f->height = rounddown(clamp_t(u32, f->height, ATOM_ISP_MIN_HEIGHT,
4507  				      ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT);
4508  
4509  	return 0;
4510  }
4511  
__get_mipi_port(struct atomisp_device * isp,enum atomisp_camera_port port)4512  enum mipi_port_id __get_mipi_port(struct atomisp_device *isp,
4513  				  enum atomisp_camera_port port)
4514  {
4515  	switch (port) {
4516  	case ATOMISP_CAMERA_PORT_PRIMARY:
4517  		return MIPI_PORT0_ID;
4518  	case ATOMISP_CAMERA_PORT_SECONDARY:
4519  		return MIPI_PORT1_ID;
4520  	case ATOMISP_CAMERA_PORT_TERTIARY:
4521  		if (MIPI_PORT1_ID + 1 != N_MIPI_PORT_ID)
4522  			return MIPI_PORT1_ID + 1;
4523  		fallthrough;
4524  	default:
4525  		dev_err(isp->dev, "unsupported port: %d\n", port);
4526  		return MIPI_PORT0_ID;
4527  	}
4528  }
4529  
atomisp_set_sensor_mipi_to_isp(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,struct camera_mipi_info * mipi_info)4530  static inline int atomisp_set_sensor_mipi_to_isp(
4531      struct atomisp_sub_device *asd,
4532      enum atomisp_input_stream_id stream_id,
4533      struct camera_mipi_info *mipi_info)
4534  {
4535  	struct v4l2_control ctrl;
4536  	struct atomisp_device *isp = asd->isp;
4537  	const struct atomisp_in_fmt_conv *fc;
4538  	int mipi_freq = 0;
4539  	unsigned int input_format, bayer_order;
4540  
4541  	ctrl.id = V4L2_CID_LINK_FREQ;
4542  	if (v4l2_g_ctrl
4543  	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl) == 0)
4544  		mipi_freq = ctrl.value;
4545  
4546  	if (asd->stream_env[stream_id].isys_configs == 1) {
4547  		input_format =
4548  		    asd->stream_env[stream_id].isys_info[0].input_format;
4549  		atomisp_css_isys_set_format(asd, stream_id,
4550  					    input_format, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
4551  	} else if (asd->stream_env[stream_id].isys_configs == 2) {
4552  		atomisp_css_isys_two_stream_cfg_update_stream1(
4553  		    asd, stream_id,
4554  		    asd->stream_env[stream_id].isys_info[0].input_format,
4555  		    asd->stream_env[stream_id].isys_info[0].width,
4556  		    asd->stream_env[stream_id].isys_info[0].height);
4557  
4558  		atomisp_css_isys_two_stream_cfg_update_stream2(
4559  		    asd, stream_id,
4560  		    asd->stream_env[stream_id].isys_info[1].input_format,
4561  		    asd->stream_env[stream_id].isys_info[1].width,
4562  		    asd->stream_env[stream_id].isys_info[1].height);
4563  	}
4564  
4565  	/* Compatibility for sensors which provide no media bus code
4566  	 * in s_mbus_framefmt() nor support pad formats. */
4567  	if (mipi_info->input_format != -1) {
4568  		bayer_order = mipi_info->raw_bayer_order;
4569  
4570  		/* Input stream config is still needs configured */
4571  		/* TODO: Check if this is necessary */
4572  		fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
4573  			 mipi_info->input_format);
4574  		if (!fc)
4575  			return -EINVAL;
4576  		input_format = fc->atomisp_in_fmt;
4577  	} else {
4578  		struct v4l2_mbus_framefmt *sink;
4579  
4580  		sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
4581  					       V4L2_SUBDEV_FORMAT_ACTIVE,
4582  					       ATOMISP_SUBDEV_PAD_SINK);
4583  		fc = atomisp_find_in_fmt_conv(sink->code);
4584  		if (!fc)
4585  			return -EINVAL;
4586  		input_format = fc->atomisp_in_fmt;
4587  		bayer_order = fc->bayer_order;
4588  	}
4589  
4590  	atomisp_css_input_set_format(asd, stream_id, input_format);
4591  	atomisp_css_input_set_bayer_order(asd, stream_id, bayer_order);
4592  
4593  	fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
4594  		 mipi_info->metadata_format);
4595  	if (!fc)
4596  		return -EINVAL;
4597  	input_format = fc->atomisp_in_fmt;
4598  	atomisp_css_input_configure_port(asd,
4599  					 __get_mipi_port(asd->isp, mipi_info->port),
4600  					 mipi_info->num_lanes,
4601  					 0xffff4, mipi_freq,
4602  					 input_format,
4603  					 mipi_info->metadata_width,
4604  					 mipi_info->metadata_height);
4605  	return 0;
4606  }
4607  
__enable_continuous_mode(struct atomisp_sub_device * asd,bool enable)4608  static int __enable_continuous_mode(struct atomisp_sub_device *asd,
4609  				    bool enable)
4610  {
4611  	struct atomisp_device *isp = asd->isp;
4612  
4613  	dev_dbg(isp->dev,
4614  		"continuous mode %d, raw buffers %d, stop preview %d\n",
4615  		enable, asd->continuous_raw_buffer_size->val,
4616  		!asd->continuous_viewfinder->val);
4617  
4618  	if (!IS_ISP2401)
4619  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_PRIMARY);
4620  	else
4621  		atomisp_update_capture_mode(asd);
4622  
4623  	/* in case of ANR, force capture pipe to offline mode */
4624  	atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
4625  					  asd->params.low_light ? false : !enable);
4626  	atomisp_css_preview_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
4627  					  !enable);
4628  	atomisp_css_enable_continuous(asd, enable);
4629  	atomisp_css_enable_cvf(asd, asd->continuous_viewfinder->val);
4630  
4631  	atomisp_css_continuous_set_num_raw_frames(asd,
4632  		asd->continuous_raw_buffer_size->val);
4633  
4634  	if (!enable) {
4635  		atomisp_css_enable_raw_binning(asd, false);
4636  		atomisp_css_input_set_two_pixels_per_clock(asd, false);
4637  	}
4638  
4639  	if (isp->inputs[asd->input_curr].type != FILE_INPUT)
4640  		atomisp_css_input_set_mode(asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
4641  
4642  	return atomisp_update_run_mode(asd);
4643  }
4644  
configure_pp_input_nop(struct atomisp_sub_device * asd,unsigned int width,unsigned int height)4645  static int configure_pp_input_nop(struct atomisp_sub_device *asd,
4646  				  unsigned int width, unsigned int height)
4647  {
4648  	return 0;
4649  }
4650  
configure_output_nop(struct atomisp_sub_device * asd,unsigned int width,unsigned int height,unsigned int min_width,enum ia_css_frame_format sh_fmt)4651  static int configure_output_nop(struct atomisp_sub_device *asd,
4652  				unsigned int width, unsigned int height,
4653  				unsigned int min_width,
4654  				enum ia_css_frame_format sh_fmt)
4655  {
4656  	return 0;
4657  }
4658  
get_frame_info_nop(struct atomisp_sub_device * asd,struct ia_css_frame_info * finfo)4659  static int get_frame_info_nop(struct atomisp_sub_device *asd,
4660  			      struct ia_css_frame_info *finfo)
4661  {
4662  	return 0;
4663  }
4664  
4665  /*
4666   * Resets CSS parameters that depend on input resolution.
4667   *
4668   * Update params like CSS RAW binning, 2ppc mode and pp_input
4669   * which depend on input size, but are not automatically
4670   * handled in CSS when the input resolution is changed.
4671   */
css_input_resolution_changed(struct atomisp_sub_device * asd,struct v4l2_mbus_framefmt * ffmt)4672  static int css_input_resolution_changed(struct atomisp_sub_device *asd,
4673  					struct v4l2_mbus_framefmt *ffmt)
4674  {
4675  	struct atomisp_metadata_buf *md_buf = NULL, *_md_buf;
4676  	unsigned int i;
4677  
4678  	dev_dbg(asd->isp->dev, "css_input_resolution_changed to %ux%u\n",
4679  		ffmt->width, ffmt->height);
4680  
4681  	if (IS_ISP2401)
4682  		atomisp_css_input_set_two_pixels_per_clock(asd, false);
4683  	else
4684  		atomisp_css_input_set_two_pixels_per_clock(asd, true);
4685  
4686  	if (asd->continuous_mode->val) {
4687  		/* Note for all checks: ffmt includes pad_w+pad_h */
4688  		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO ||
4689  		    (ffmt->width >= 2048 || ffmt->height >= 1536)) {
4690  			/*
4691  			 * For preview pipe, enable only if resolution
4692  			 * is >= 3M for ISP2400.
4693  			 */
4694  			atomisp_css_enable_raw_binning(asd, true);
4695  		}
4696  	}
4697  	/*
4698  	 * If sensor input changed, which means metadata resolution changed
4699  	 * together. Release all metadata buffers here to let it re-allocated
4700  	 * next time in reqbufs.
4701  	 */
4702  	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
4703  		list_for_each_entry_safe(md_buf, _md_buf, &asd->metadata[i],
4704  					 list) {
4705  			atomisp_css_free_metadata_buffer(md_buf);
4706  			list_del(&md_buf->list);
4707  			kfree(md_buf);
4708  		}
4709  	}
4710  	return 0;
4711  
4712  	/*
4713  	 * TODO: atomisp_css_preview_configure_pp_input() not
4714  	 *       reset due to CSS bug tracked as PSI BZ 115124
4715  	 */
4716  }
4717  
atomisp_set_fmt_to_isp(struct video_device * vdev,struct ia_css_frame_info * output_info,struct ia_css_frame_info * raw_output_info,struct v4l2_pix_format * pix,unsigned int source_pad)4718  static int atomisp_set_fmt_to_isp(struct video_device *vdev,
4719  				  struct ia_css_frame_info *output_info,
4720  				  struct ia_css_frame_info *raw_output_info,
4721  				  struct v4l2_pix_format *pix,
4722  				  unsigned int source_pad)
4723  {
4724  	struct camera_mipi_info *mipi_info;
4725  	struct atomisp_device *isp = video_get_drvdata(vdev);
4726  	struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
4727  	const struct atomisp_format_bridge *format;
4728  	struct v4l2_rect *isp_sink_crop;
4729  	enum ia_css_pipe_id pipe_id;
4730  	struct v4l2_subdev_fh fh;
4731  	int (*configure_output)(struct atomisp_sub_device *asd,
4732  				unsigned int width, unsigned int height,
4733  				unsigned int min_width,
4734  				enum ia_css_frame_format sh_fmt) =
4735  				    configure_output_nop;
4736  	int (*get_frame_info)(struct atomisp_sub_device *asd,
4737  			      struct ia_css_frame_info *finfo) =
4738  				  get_frame_info_nop;
4739  	int (*configure_pp_input)(struct atomisp_sub_device *asd,
4740  				  unsigned int width, unsigned int height) =
4741  				      configure_pp_input_nop;
4742  	const struct atomisp_in_fmt_conv *fc;
4743  	int ret, i;
4744  
4745  	if (!asd) {
4746  		dev_err(isp->dev, "%s(): asd is NULL, device is %s\n",
4747  			__func__, vdev->name);
4748  		return -EINVAL;
4749  	}
4750  
4751  	v4l2_fh_init(&fh.vfh, vdev);
4752  
4753  	isp_sink_crop = atomisp_subdev_get_rect(
4754  			    &asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
4755  			    ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP);
4756  
4757  	format = atomisp_get_format_bridge(pix->pixelformat);
4758  	if (!format)
4759  		return -EINVAL;
4760  
4761  	if (isp->inputs[asd->input_curr].type != TEST_PATTERN &&
4762  	    isp->inputs[asd->input_curr].type != FILE_INPUT) {
4763  		mipi_info = atomisp_to_sensor_mipi_info(
4764  				isp->inputs[asd->input_curr].camera);
4765  		if (!mipi_info) {
4766  			dev_err(isp->dev, "mipi_info is NULL\n");
4767  			return -EINVAL;
4768  		}
4769  		if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL,
4770  						   mipi_info))
4771  			return -EINVAL;
4772  		fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
4773  			 mipi_info->input_format);
4774  		if (!fc)
4775  			fc = atomisp_find_in_fmt_conv(
4776  				 atomisp_subdev_get_ffmt(&asd->subdev,
4777  							 NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
4778  							 ATOMISP_SUBDEV_PAD_SINK)->code);
4779  		if (!fc)
4780  			return -EINVAL;
4781  		if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
4782  		    raw_output_format_match_input(fc->atomisp_in_fmt,
4783  						  pix->pixelformat))
4784  			return -EINVAL;
4785  	}
4786  
4787  	/*
4788  	 * Configure viewfinder also when vfpp is disabled: the
4789  	 * CSS still requires viewfinder configuration.
4790  	 */
4791  	if (asd->fmt_auto->val ||
4792  	    asd->vfpp->val != ATOMISP_VFPP_ENABLE) {
4793  		struct v4l2_rect vf_size = {0};
4794  		struct v4l2_mbus_framefmt vf_ffmt = {0};
4795  
4796  		if (pix->width < 640 || pix->height < 480) {
4797  			vf_size.width = pix->width;
4798  			vf_size.height = pix->height;
4799  		} else {
4800  			vf_size.width = 640;
4801  			vf_size.height = 480;
4802  		}
4803  
4804  		/* FIXME: proper format name for this one. See
4805  		   atomisp_output_fmts[] in atomisp_v4l2.c */
4806  		vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420;
4807  
4808  		atomisp_subdev_set_selection(&asd->subdev, fh.state,
4809  					     V4L2_SUBDEV_FORMAT_ACTIVE,
4810  					     ATOMISP_SUBDEV_PAD_SOURCE_VF,
4811  					     V4L2_SEL_TGT_COMPOSE, 0, &vf_size);
4812  		atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
4813  					V4L2_SUBDEV_FORMAT_ACTIVE,
4814  					ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt);
4815  		asd->video_out_vf.sh_fmt = IA_CSS_FRAME_FORMAT_NV12;
4816  
4817  		if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
4818  			atomisp_css_video_configure_viewfinder(asd,
4819  							       vf_size.width, vf_size.height, 0,
4820  							       asd->video_out_vf.sh_fmt);
4821  		} else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
4822  			if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
4823  			    source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO)
4824  				atomisp_css_video_configure_viewfinder(asd,
4825  								       vf_size.width, vf_size.height, 0,
4826  								       asd->video_out_vf.sh_fmt);
4827  			else
4828  				atomisp_css_capture_configure_viewfinder(asd,
4829  					vf_size.width, vf_size.height, 0,
4830  					asd->video_out_vf.sh_fmt);
4831  		} else if (source_pad != ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
4832  			   asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
4833  			atomisp_css_capture_configure_viewfinder(asd,
4834  				vf_size.width, vf_size.height, 0,
4835  				asd->video_out_vf.sh_fmt);
4836  		}
4837  	}
4838  
4839  	if (asd->continuous_mode->val) {
4840  		ret = __enable_continuous_mode(asd, true);
4841  		if (ret)
4842  			return -EINVAL;
4843  	}
4844  
4845  	atomisp_css_input_set_mode(asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
4846  
4847  	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
4848  		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipe_extra_configs[i].disable_vf_pp = asd->vfpp->val != ATOMISP_VFPP_ENABLE;
4849  
4850  	/* ISP2401 new input system need to use copy pipe */
4851  	if (asd->copy_mode) {
4852  		pipe_id = IA_CSS_PIPE_ID_COPY;
4853  		atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, false);
4854  	} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
4855  		/* video same in continuouscapture and online modes */
4856  		configure_output = atomisp_css_video_configure_output;
4857  		get_frame_info = atomisp_css_video_get_output_frame_info;
4858  		pipe_id = IA_CSS_PIPE_ID_VIDEO;
4859  	} else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
4860  		if (!asd->continuous_mode->val) {
4861  			configure_output = atomisp_css_video_configure_output;
4862  			get_frame_info =
4863  			    atomisp_css_video_get_output_frame_info;
4864  			pipe_id = IA_CSS_PIPE_ID_VIDEO;
4865  		} else {
4866  			if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW ||
4867  			    source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
4868  				configure_output =
4869  				    atomisp_css_video_configure_output;
4870  				get_frame_info =
4871  				    atomisp_css_video_get_output_frame_info;
4872  				configure_pp_input =
4873  				    atomisp_css_video_configure_pp_input;
4874  				pipe_id = IA_CSS_PIPE_ID_VIDEO;
4875  			} else {
4876  				configure_output =
4877  				    atomisp_css_capture_configure_output;
4878  				get_frame_info =
4879  				    atomisp_css_capture_get_output_frame_info;
4880  				configure_pp_input =
4881  				    atomisp_css_capture_configure_pp_input;
4882  				pipe_id = IA_CSS_PIPE_ID_CAPTURE;
4883  
4884  				atomisp_update_capture_mode(asd);
4885  				atomisp_css_capture_enable_online(asd,
4886  								  ATOMISP_INPUT_STREAM_GENERAL,
4887  								  false);
4888  			}
4889  		}
4890  	} else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) {
4891  		configure_output = atomisp_css_preview_configure_output;
4892  		get_frame_info = atomisp_css_preview_get_output_frame_info;
4893  		configure_pp_input = atomisp_css_preview_configure_pp_input;
4894  		pipe_id = IA_CSS_PIPE_ID_PREVIEW;
4895  	} else {
4896  		/* CSS doesn't support low light mode on SOC cameras, so disable
4897  		 * it. FIXME: if this is done elsewhere, it gives corrupted
4898  		 * colors into thumbnail image.
4899  		 */
4900  		if (isp->inputs[asd->input_curr].type == SOC_CAMERA)
4901  			asd->params.low_light = false;
4902  
4903  		if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
4904  			atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW);
4905  			atomisp_css_enable_dz(asd, false);
4906  		} else {
4907  			atomisp_update_capture_mode(asd);
4908  		}
4909  
4910  		if (!asd->continuous_mode->val)
4911  			/* in case of ANR, force capture pipe to offline mode */
4912  			atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
4913  							  asd->params.low_light ?
4914  							  false : asd->params.online_process);
4915  
4916  		configure_output = atomisp_css_capture_configure_output;
4917  		get_frame_info = atomisp_css_capture_get_output_frame_info;
4918  		configure_pp_input = atomisp_css_capture_configure_pp_input;
4919  		pipe_id = IA_CSS_PIPE_ID_CAPTURE;
4920  
4921  		if (!asd->params.online_process &&
4922  		    !asd->continuous_mode->val) {
4923  			ret = atomisp_css_capture_get_output_raw_frame_info(asd,
4924  				raw_output_info);
4925  			if (ret)
4926  				return ret;
4927  		}
4928  		if (!asd->continuous_mode->val && asd->run_mode->val
4929  		    != ATOMISP_RUN_MODE_STILL_CAPTURE) {
4930  			dev_err(isp->dev,
4931  				"Need to set the running mode first\n");
4932  			asd->run_mode->val = ATOMISP_RUN_MODE_STILL_CAPTURE;
4933  		}
4934  	}
4935  
4936  	/*
4937  	 * to SOC camera, use yuvpp pipe.
4938  	 */
4939  	if (ATOMISP_USE_YUVPP(asd))
4940  		pipe_id = IA_CSS_PIPE_ID_YUVPP;
4941  
4942  	if (asd->copy_mode)
4943  		ret = atomisp_css_copy_configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL,
4944  							pix->width, pix->height,
4945  							format->planar ? pix->bytesperline :
4946  							pix->bytesperline * 8 / format->depth,
4947  							format->sh_fmt);
4948  	else
4949  		ret = configure_output(asd, pix->width, pix->height,
4950  				       format->planar ? pix->bytesperline :
4951  				       pix->bytesperline * 8 / format->depth,
4952  				       format->sh_fmt);
4953  	if (ret) {
4954  		dev_err(isp->dev, "configure_output %ux%u, format %8.8x\n",
4955  			pix->width, pix->height, format->sh_fmt);
4956  		return -EINVAL;
4957  	}
4958  
4959  	ret = configure_pp_input(asd, isp_sink_crop->width, isp_sink_crop->height);
4960  	if (ret) {
4961  		dev_err(isp->dev, "configure_pp_input %ux%u\n",
4962  			isp_sink_crop->width,
4963  			isp_sink_crop->height);
4964  		return -EINVAL;
4965  	}
4966  	if (asd->copy_mode)
4967  		ret = atomisp_css_copy_get_output_frame_info(asd,
4968  							     ATOMISP_INPUT_STREAM_GENERAL,
4969  							     output_info);
4970  	else
4971  		ret = get_frame_info(asd, output_info);
4972  	if (ret) {
4973  		dev_err(isp->dev, "__get_frame_info %ux%u (padded to %u) returned %d\n",
4974  			pix->width, pix->height, pix->bytesperline, ret);
4975  		return ret;
4976  	}
4977  
4978  	atomisp_update_grid_info(asd, pipe_id, source_pad);
4979  
4980  	/* Free the raw_dump buffer first */
4981  	ia_css_frame_free(asd->raw_output_frame);
4982  	asd->raw_output_frame = NULL;
4983  
4984  	if (!asd->continuous_mode->val && !asd->params.online_process &&
4985  	    ia_css_frame_allocate_from_info(&asd->raw_output_frame,
4986  		    raw_output_info))
4987  		return -ENOMEM;
4988  
4989  	return 0;
4990  }
4991  
atomisp_get_dis_envelop(struct atomisp_sub_device * asd,unsigned int width,unsigned int height,unsigned int * dvs_env_w,unsigned int * dvs_env_h)4992  static void atomisp_get_dis_envelop(struct atomisp_sub_device *asd,
4993  				    unsigned int width, unsigned int height,
4994  				    unsigned int *dvs_env_w, unsigned int *dvs_env_h)
4995  {
4996  	struct atomisp_device *isp = asd->isp;
4997  
4998  	/* if subdev type is SOC camera,we do not need to set DVS */
4999  	if (isp->inputs[asd->input_curr].type == SOC_CAMERA)
5000  		asd->params.video_dis_en = false;
5001  
5002  	if (asd->params.video_dis_en &&
5003  	    asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
5004  		/* envelope is 20% of the output resolution */
5005  		/*
5006  		 * dvs envelope cannot be round up.
5007  		 * it would cause ISP timeout and color switch issue
5008  		 */
5009  		*dvs_env_w = rounddown(width / 5, ATOM_ISP_STEP_WIDTH);
5010  		*dvs_env_h = rounddown(height / 5, ATOM_ISP_STEP_HEIGHT);
5011  	}
5012  
5013  	asd->params.dis_proj_data_valid = false;
5014  	asd->params.css_update_params_needed = true;
5015  }
5016  
atomisp_check_copy_mode(struct atomisp_sub_device * asd,int source_pad,struct v4l2_pix_format * f)5017  static void atomisp_check_copy_mode(struct atomisp_sub_device *asd,
5018  				    int source_pad, struct v4l2_pix_format *f)
5019  {
5020  	struct v4l2_mbus_framefmt *sink, *src;
5021  
5022  	if (!IS_ISP2401) {
5023  		/* Only used for the new input system */
5024  		asd->copy_mode = false;
5025  		return;
5026  	}
5027  
5028  	sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5029  				       V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK);
5030  	src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5031  				      V4L2_SUBDEV_FORMAT_ACTIVE, source_pad);
5032  
5033  	if (sink->code == src->code && sink->width == f->width && sink->height == f->height)
5034  		asd->copy_mode = true;
5035  	else
5036  		asd->copy_mode = false;
5037  
5038  	dev_dbg(asd->isp->dev, "copy_mode: %d\n", asd->copy_mode);
5039  }
5040  
atomisp_set_fmt_to_snr(struct video_device * vdev,struct v4l2_pix_format * f,unsigned int pixelformat,unsigned int padding_w,unsigned int padding_h,unsigned int dvs_env_w,unsigned int dvs_env_h)5041  static int atomisp_set_fmt_to_snr(struct video_device *vdev,
5042  				  struct v4l2_pix_format *f, unsigned int pixelformat,
5043  				  unsigned int padding_w, unsigned int padding_h,
5044  				  unsigned int dvs_env_w, unsigned int dvs_env_h)
5045  {
5046  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
5047  	struct atomisp_sub_device *asd = pipe->asd;
5048  	const struct atomisp_format_bridge *format;
5049  	struct v4l2_subdev_pad_config pad_cfg;
5050  	struct v4l2_subdev_state pad_state = {
5051  		.pads = &pad_cfg
5052  		};
5053  	struct v4l2_subdev_format vformat = {
5054  		.which = V4L2_SUBDEV_FORMAT_TRY,
5055  	};
5056  	struct v4l2_mbus_framefmt *ffmt = &vformat.format;
5057  	struct v4l2_mbus_framefmt *req_ffmt;
5058  	struct atomisp_device *isp;
5059  	struct atomisp_input_stream_info *stream_info =
5060  	    (struct atomisp_input_stream_info *)ffmt->reserved;
5061  	int source_pad = atomisp_subdev_source_pad(vdev);
5062  	struct v4l2_subdev_fh fh;
5063  	int ret;
5064  
5065  	if (!asd) {
5066  		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
5067  			__func__, vdev->name);
5068  		return -EINVAL;
5069  	}
5070  
5071  	isp = asd->isp;
5072  
5073  	v4l2_fh_init(&fh.vfh, vdev);
5074  
5075  	format = atomisp_get_format_bridge(pixelformat);
5076  	if (!format)
5077  		return -EINVAL;
5078  
5079  	v4l2_fill_mbus_format(ffmt, f, format->mbus_code);
5080  	ffmt->height += padding_h + dvs_env_h;
5081  	ffmt->width += padding_w + dvs_env_w;
5082  
5083  	dev_dbg(isp->dev, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n",
5084  		ffmt->width, ffmt->height, padding_w, padding_h,
5085  		dvs_env_w, dvs_env_h);
5086  
5087  	__atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info);
5088  
5089  	req_ffmt = ffmt;
5090  
5091  	/* Disable dvs if resolution can't be supported by sensor */
5092  	if (asd->params.video_dis_en &&
5093  	    source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) {
5094  		vformat.which = V4L2_SUBDEV_FORMAT_TRY;
5095  		ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
5096  				       pad, set_fmt, &pad_state, &vformat);
5097  		if (ret)
5098  			return ret;
5099  
5100  		dev_dbg(isp->dev, "video dis: sensor width: %d, height: %d\n",
5101  			ffmt->width, ffmt->height);
5102  
5103  		if (ffmt->width < req_ffmt->width ||
5104  		    ffmt->height < req_ffmt->height) {
5105  			req_ffmt->height -= dvs_env_h;
5106  			req_ffmt->width -= dvs_env_w;
5107  			ffmt = req_ffmt;
5108  			dev_warn(isp->dev,
5109  				 "can not enable video dis due to sensor limitation.");
5110  			asd->params.video_dis_en = false;
5111  		}
5112  	}
5113  	vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
5114  	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad,
5115  			       set_fmt, NULL, &vformat);
5116  	if (ret)
5117  		return ret;
5118  
5119  	__atomisp_update_stream_env(asd, ATOMISP_INPUT_STREAM_GENERAL, stream_info);
5120  
5121  	dev_dbg(isp->dev, "sensor width: %d, height: %d\n",
5122  		ffmt->width, ffmt->height);
5123  
5124  	if (ffmt->width < ATOM_ISP_STEP_WIDTH ||
5125  	    ffmt->height < ATOM_ISP_STEP_HEIGHT)
5126  		return -EINVAL;
5127  
5128  	if (asd->params.video_dis_en &&
5129  	    source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO &&
5130  	    (ffmt->width < req_ffmt->width || ffmt->height < req_ffmt->height)) {
5131  		dev_warn(isp->dev,
5132  			 "can not enable video dis due to sensor limitation.");
5133  		asd->params.video_dis_en = false;
5134  	}
5135  
5136  	atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
5137  				V4L2_SUBDEV_FORMAT_ACTIVE,
5138  				ATOMISP_SUBDEV_PAD_SINK, ffmt);
5139  
5140  	return css_input_resolution_changed(asd, ffmt);
5141  }
5142  
atomisp_set_fmt(struct file * file,void * unused,struct v4l2_format * f)5143  int atomisp_set_fmt(struct file *file, void *unused, struct v4l2_format *f)
5144  {
5145  	struct video_device *vdev = video_devdata(file);
5146  	struct atomisp_device *isp = video_get_drvdata(vdev);
5147  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
5148  	struct atomisp_sub_device *asd = pipe->asd;
5149  	const struct atomisp_format_bridge *format_bridge;
5150  	const struct atomisp_format_bridge *snr_format_bridge;
5151  	struct ia_css_frame_info output_info, raw_output_info;
5152  	struct v4l2_pix_format snr_fmt;
5153  	struct v4l2_pix_format backup_fmt, s_fmt;
5154  	unsigned int dvs_env_w = 0, dvs_env_h = 0;
5155  	unsigned int padding_w = pad_w, padding_h = pad_h;
5156  	bool res_overflow = false, crop_needs_override = false;
5157  	struct v4l2_mbus_framefmt *isp_sink_fmt;
5158  	struct v4l2_mbus_framefmt isp_source_fmt = {0};
5159  	struct v4l2_subdev_format vformat = {
5160  		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
5161  	};
5162  	struct v4l2_mbus_framefmt *ffmt = &vformat.format;
5163  	struct v4l2_rect isp_sink_crop;
5164  	u16 source_pad = atomisp_subdev_source_pad(vdev);
5165  	struct v4l2_subdev_fh fh;
5166  	int ret;
5167  
5168  	ret = atomisp_pipe_check(pipe, true);
5169  	if (ret)
5170  		return ret;
5171  
5172  	if (source_pad >= ATOMISP_SUBDEV_PADS_NUM)
5173  		return -EINVAL;
5174  
5175  	dev_dbg(isp->dev,
5176  		"setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n",
5177  		f->fmt.pix.width, f->fmt.pix.height, source_pad,
5178  		asd->index, f->fmt.pix.bytesperline);
5179  
5180  	v4l2_fh_init(&fh.vfh, vdev);
5181  
5182  	format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
5183  	if (!format_bridge)
5184  		return -EINVAL;
5185  
5186  	/* Currently, raw formats are broken!!! */
5187  
5188  	if (format_bridge->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
5189  		f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
5190  
5191  		format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat);
5192  		if (!format_bridge)
5193  			return -EINVAL;
5194  	}
5195  	pipe->sh_fmt = format_bridge->sh_fmt;
5196  	pipe->pix.pixelformat = f->fmt.pix.pixelformat;
5197  
5198  	/* Ensure that the resolution is equal or below the maximum supported */
5199  
5200  	vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE;
5201  	v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code);
5202  	ffmt->height += padding_h;
5203  	ffmt->width += padding_w;
5204  
5205  	ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad,
5206  			       set_fmt, NULL, &vformat);
5207  	if (ret)
5208  		return ret;
5209  
5210  	f->fmt.pix.width = ffmt->width - padding_w;
5211  	f->fmt.pix.height = ffmt->height - padding_h;
5212  
5213  	snr_fmt = f->fmt.pix;
5214  	backup_fmt = snr_fmt;
5215  
5216  	/**********************************************************************/
5217  
5218  	if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VF ||
5219  	    (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5220  	     && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)) {
5221  		if (asd->fmt_auto->val) {
5222  			struct v4l2_rect *capture_comp;
5223  			struct v4l2_rect r = {0};
5224  
5225  			r.width = f->fmt.pix.width;
5226  			r.height = f->fmt.pix.height;
5227  
5228  			if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW)
5229  				capture_comp = atomisp_subdev_get_rect(
5230  						   &asd->subdev, NULL,
5231  						   V4L2_SUBDEV_FORMAT_ACTIVE,
5232  						   ATOMISP_SUBDEV_PAD_SOURCE_VIDEO,
5233  						   V4L2_SEL_TGT_COMPOSE);
5234  			else
5235  				capture_comp = atomisp_subdev_get_rect(
5236  						   &asd->subdev, NULL,
5237  						   V4L2_SUBDEV_FORMAT_ACTIVE,
5238  						   ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
5239  						   V4L2_SEL_TGT_COMPOSE);
5240  
5241  			if (capture_comp->width < r.width
5242  			    || capture_comp->height < r.height) {
5243  				r.width = capture_comp->width;
5244  				r.height = capture_comp->height;
5245  			}
5246  
5247  			atomisp_subdev_set_selection(
5248  			    &asd->subdev, fh.state,
5249  			    V4L2_SUBDEV_FORMAT_ACTIVE, source_pad,
5250  			    V4L2_SEL_TGT_COMPOSE, 0, &r);
5251  
5252  			f->fmt.pix.width = r.width;
5253  			f->fmt.pix.height = r.height;
5254  		}
5255  
5256  		if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) {
5257  			atomisp_css_video_configure_viewfinder(asd,
5258  							       f->fmt.pix.width, f->fmt.pix.height,
5259  							       format_bridge->planar ? f->fmt.pix.bytesperline
5260  							       : f->fmt.pix.bytesperline * 8
5261  							       / format_bridge->depth,	format_bridge->sh_fmt);
5262  			atomisp_css_video_get_viewfinder_frame_info(asd,
5263  				&output_info);
5264  			asd->copy_mode = false;
5265  		} else {
5266  			atomisp_css_capture_configure_viewfinder(asd,
5267  				f->fmt.pix.width, f->fmt.pix.height,
5268  				format_bridge->planar ? f->fmt.pix.bytesperline
5269  				: f->fmt.pix.bytesperline * 8
5270  				/ format_bridge->depth,	format_bridge->sh_fmt);
5271  			atomisp_css_capture_get_viewfinder_frame_info(asd,
5272  				&output_info);
5273  			asd->copy_mode = false;
5274  		}
5275  
5276  		goto done;
5277  	}
5278  	/*
5279  	 * Check whether main resolution configured smaller
5280  	 * than snapshot resolution. If so, force main resolution
5281  	 * to be the same as snapshot resolution
5282  	 */
5283  	if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) {
5284  		struct v4l2_rect *r;
5285  
5286  		r = atomisp_subdev_get_rect(
5287  			&asd->subdev, NULL,
5288  			V4L2_SUBDEV_FORMAT_ACTIVE,
5289  			ATOMISP_SUBDEV_PAD_SOURCE_VF, V4L2_SEL_TGT_COMPOSE);
5290  
5291  		if (r->width && r->height
5292  		    && (r->width > f->fmt.pix.width
5293  			|| r->height > f->fmt.pix.height))
5294  			dev_warn(isp->dev,
5295  				 "Main Resolution config smaller then Vf Resolution. Force to be equal with Vf Resolution.");
5296  	}
5297  
5298  	/* Pipeline configuration done through subdevs. Bail out now. */
5299  	if (!asd->fmt_auto->val)
5300  		goto set_fmt_to_isp;
5301  
5302  	/* get sensor resolution and format */
5303  	ret = atomisp_try_fmt(vdev, &snr_fmt, &res_overflow);
5304  	if (ret) {
5305  		dev_warn(isp->dev, "Try format failed with error %d\n", ret);
5306  		return ret;
5307  	}
5308  	f->fmt.pix.width = snr_fmt.width;
5309  	f->fmt.pix.height = snr_fmt.height;
5310  
5311  	snr_format_bridge = atomisp_get_format_bridge(snr_fmt.pixelformat);
5312  	if (!snr_format_bridge) {
5313  		dev_warn(isp->dev, "Can't find bridge format\n");
5314  		return -EINVAL;
5315  	}
5316  
5317  	atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5318  				V4L2_SUBDEV_FORMAT_ACTIVE,
5319  				ATOMISP_SUBDEV_PAD_SINK)->code =
5320  				    snr_format_bridge->mbus_code;
5321  
5322  	isp_sink_fmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
5323  						V4L2_SUBDEV_FORMAT_ACTIVE,
5324  						ATOMISP_SUBDEV_PAD_SINK);
5325  
5326  	isp_source_fmt.code = format_bridge->mbus_code;
5327  	atomisp_subdev_set_ffmt(&asd->subdev, fh.state,
5328  				V4L2_SUBDEV_FORMAT_ACTIVE,
5329  				source_pad, &isp_source_fmt);
5330  
5331  	if (!atomisp_subdev_format_conversion(asd, source_pad)) {
5332  		padding_w = 0;
5333  		padding_h = 0;
5334  	} else if (IS_BYT) {
5335  		padding_w = 12;
5336  		padding_h = 12;
5337  	}
5338  
5339  	/* construct resolution supported by isp */
5340  	if (res_overflow && !asd->continuous_mode->val) {
5341  		f->fmt.pix.width = rounddown(
5342  				       clamp_t(u32, f->fmt.pix.width - padding_w,
5343  					       ATOM_ISP_MIN_WIDTH,
5344  					       ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH);
5345  		f->fmt.pix.height = rounddown(
5346  					clamp_t(u32, f->fmt.pix.height - padding_h,
5347  						ATOM_ISP_MIN_HEIGHT,
5348  						ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT);
5349  	}
5350  
5351  	atomisp_get_dis_envelop(asd, f->fmt.pix.width, f->fmt.pix.height,
5352  				&dvs_env_w, &dvs_env_h);
5353  
5354  	if (asd->continuous_mode->val) {
5355  		struct v4l2_rect *r;
5356  
5357  		r = atomisp_subdev_get_rect(
5358  			&asd->subdev, NULL,
5359  			V4L2_SUBDEV_FORMAT_ACTIVE,
5360  			ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE,
5361  			V4L2_SEL_TGT_COMPOSE);
5362  		/*
5363  		 * The ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE should get resolutions
5364  		 * properly set otherwise, it should not be the capture_pad.
5365  		 */
5366  		if (r->width && r->height)
5367  			asd->capture_pad = ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE;
5368  		else
5369  			asd->capture_pad = source_pad;
5370  	} else {
5371  		asd->capture_pad = source_pad;
5372  	}
5373  	/*
5374  	 * set format info to sensor
5375  	 * In continuous mode, resolution is set only if it is higher than
5376  	 * existing value. This because preview pipe will be configured after
5377  	 * capture pipe and usually has lower resolution than capture pipe.
5378  	 */
5379  	if (!asd->continuous_mode->val ||
5380  	    isp_sink_fmt->width < (f->fmt.pix.width + padding_w + dvs_env_w) ||
5381  	    isp_sink_fmt->height < (f->fmt.pix.height + padding_h +
5382  				    dvs_env_h)) {
5383  		/*
5384  		 * For jpeg or custom raw format the sensor will return constant
5385  		 * width and height. Because we already had quried try_mbus_fmt,
5386  		 * f->fmt.pix.width and f->fmt.pix.height has been changed to
5387  		 * this fixed width and height. So we cannot select the correct
5388  		 * resolution with that information. So use the original width
5389  		 * and height while set_mbus_fmt() so actual resolutions are
5390  		 * being used in while set media bus format.
5391  		 */
5392  		s_fmt = f->fmt.pix;
5393  		if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG ||
5394  		    f->fmt.pix.pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW) {
5395  			s_fmt.width = backup_fmt.width;
5396  			s_fmt.height = backup_fmt.height;
5397  		}
5398  		ret = atomisp_set_fmt_to_snr(vdev, &s_fmt,
5399  					     f->fmt.pix.pixelformat, padding_w,
5400  					     padding_h, dvs_env_w, dvs_env_h);
5401  		if (ret) {
5402  			dev_warn(isp->dev,
5403  				 "Set format to sensor failed with %d\n", ret);
5404  			return -EINVAL;
5405  		}
5406  
5407  		atomisp_csi_lane_config(isp);
5408  		crop_needs_override = true;
5409  	}
5410  
5411  	atomisp_check_copy_mode(asd, source_pad, &backup_fmt);
5412  	asd->yuvpp_mode = false;			/* Reset variable */
5413  
5414  	isp_sink_crop = *atomisp_subdev_get_rect(&asd->subdev, NULL,
5415  			V4L2_SUBDEV_FORMAT_ACTIVE,
5416  			ATOMISP_SUBDEV_PAD_SINK,
5417  			V4L2_SEL_TGT_CROP);
5418  
5419  	/* Try to enable YUV downscaling if ISP input is 10 % (either
5420  	 * width or height) bigger than the desired result. */
5421  	if (isp_sink_crop.width * 9 / 10 < f->fmt.pix.width ||
5422  	    isp_sink_crop.height * 9 / 10 < f->fmt.pix.height ||
5423  	    (atomisp_subdev_format_conversion(asd, source_pad) &&
5424  	     ((asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
5425  	       !asd->continuous_mode->val) ||
5426  	      asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER))) {
5427  		/* for continuous mode, preview size might be smaller than
5428  		 * still capture size. if preview size still needs crop,
5429  		 * pick the larger one between crop size of preview and
5430  		 * still capture.
5431  		 */
5432  		if (asd->continuous_mode->val
5433  		    && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW
5434  		    && !crop_needs_override) {
5435  			isp_sink_crop.width =
5436  			    max_t(unsigned int, f->fmt.pix.width,
5437  				  isp_sink_crop.width);
5438  			isp_sink_crop.height =
5439  			    max_t(unsigned int, f->fmt.pix.height,
5440  				  isp_sink_crop.height);
5441  		} else {
5442  			isp_sink_crop.width = f->fmt.pix.width;
5443  			isp_sink_crop.height = f->fmt.pix.height;
5444  		}
5445  
5446  		atomisp_subdev_set_selection(&asd->subdev, fh.state,
5447  					     V4L2_SUBDEV_FORMAT_ACTIVE,
5448  					     ATOMISP_SUBDEV_PAD_SINK,
5449  					     V4L2_SEL_TGT_CROP,
5450  					     V4L2_SEL_FLAG_KEEP_CONFIG,
5451  					     &isp_sink_crop);
5452  		atomisp_subdev_set_selection(&asd->subdev, fh.state,
5453  					     V4L2_SUBDEV_FORMAT_ACTIVE,
5454  					     source_pad, V4L2_SEL_TGT_COMPOSE,
5455  					     0, &isp_sink_crop);
5456  	} else if (IS_MOFD) {
5457  		struct v4l2_rect main_compose = {0};
5458  
5459  		main_compose.width = isp_sink_crop.width;
5460  		main_compose.height =
5461  		    DIV_ROUND_UP(main_compose.width * f->fmt.pix.height,
5462  				 f->fmt.pix.width);
5463  		if (main_compose.height > isp_sink_crop.height) {
5464  			main_compose.height = isp_sink_crop.height;
5465  			main_compose.width =
5466  			    DIV_ROUND_UP(main_compose.height *
5467  					 f->fmt.pix.width,
5468  					 f->fmt.pix.height);
5469  		}
5470  
5471  		atomisp_subdev_set_selection(&asd->subdev, fh.state,
5472  					     V4L2_SUBDEV_FORMAT_ACTIVE,
5473  					     source_pad,
5474  					     V4L2_SEL_TGT_COMPOSE, 0,
5475  					     &main_compose);
5476  	} else {
5477  		struct v4l2_rect sink_crop = {0};
5478  		struct v4l2_rect main_compose = {0};
5479  
5480  		main_compose.width = f->fmt.pix.width;
5481  		main_compose.height = f->fmt.pix.height;
5482  
5483  		/* WORKAROUND: this override is universally enabled in
5484  		 * GMIN to work around a CTS failures (GMINL-539)
5485  		 * which appears to be related by a hardware
5486  		 * performance limitation.  It's unclear why this
5487  		 * particular code triggers the issue. */
5488  		if (crop_needs_override) {
5489  			if (isp_sink_crop.width * main_compose.height >
5490  			    isp_sink_crop.height * main_compose.width) {
5491  				sink_crop.height = isp_sink_crop.height;
5492  				sink_crop.width = DIV_NEAREST_STEP(
5493  						      sink_crop.height *
5494  						      f->fmt.pix.width,
5495  						      f->fmt.pix.height,
5496  						      ATOM_ISP_STEP_WIDTH);
5497  			} else {
5498  				sink_crop.width = isp_sink_crop.width;
5499  				sink_crop.height = DIV_NEAREST_STEP(
5500  						       sink_crop.width *
5501  						       f->fmt.pix.height,
5502  						       f->fmt.pix.width,
5503  						       ATOM_ISP_STEP_HEIGHT);
5504  			}
5505  			atomisp_subdev_set_selection(&asd->subdev, fh.state,
5506  						     V4L2_SUBDEV_FORMAT_ACTIVE,
5507  						     ATOMISP_SUBDEV_PAD_SINK,
5508  						     V4L2_SEL_TGT_CROP,
5509  						     V4L2_SEL_FLAG_KEEP_CONFIG,
5510  						     &sink_crop);
5511  		}
5512  		atomisp_subdev_set_selection(&asd->subdev, fh.state,
5513  					     V4L2_SUBDEV_FORMAT_ACTIVE,
5514  					     source_pad,
5515  					     V4L2_SEL_TGT_COMPOSE, 0,
5516  					     &main_compose);
5517  	}
5518  
5519  set_fmt_to_isp:
5520  	ret = atomisp_set_fmt_to_isp(vdev, &output_info, &raw_output_info,
5521  				     &f->fmt.pix, source_pad);
5522  	if (ret) {
5523  		dev_warn(isp->dev, "Can't set format on ISP. Error %d\n", ret);
5524  		return -EINVAL;
5525  	}
5526  done:
5527  	pipe->pix.width = f->fmt.pix.width;
5528  	pipe->pix.height = f->fmt.pix.height;
5529  	pipe->pix.pixelformat = f->fmt.pix.pixelformat;
5530  	/*
5531  	 * FIXME: do we need to setup this differently, depending on the
5532  	 * sensor or the pipeline?
5533  	 */
5534  	pipe->pix.colorspace = V4L2_COLORSPACE_REC709;
5535  	pipe->pix.ycbcr_enc = V4L2_YCBCR_ENC_709;
5536  	pipe->pix.xfer_func = V4L2_XFER_FUNC_709;
5537  
5538  	if (format_bridge->planar) {
5539  		pipe->pix.bytesperline = output_info.padded_width;
5540  		pipe->pix.sizeimage = PAGE_ALIGN(f->fmt.pix.height *
5541  						 DIV_ROUND_UP(format_bridge->depth *
5542  							 output_info.padded_width, 8));
5543  	} else {
5544  		pipe->pix.bytesperline =
5545  		    DIV_ROUND_UP(format_bridge->depth *
5546  				 output_info.padded_width, 8);
5547  		pipe->pix.sizeimage =
5548  		    PAGE_ALIGN(f->fmt.pix.height * pipe->pix.bytesperline);
5549  	}
5550  	dev_dbg(isp->dev, "%s: image size: %d, %d bytes per line\n",
5551  		__func__, pipe->pix.sizeimage, pipe->pix.bytesperline);
5552  
5553  	if (f->fmt.pix.field == V4L2_FIELD_ANY)
5554  		f->fmt.pix.field = V4L2_FIELD_NONE;
5555  	pipe->pix.field = f->fmt.pix.field;
5556  
5557  	f->fmt.pix = pipe->pix;
5558  	f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width *
5559  				     pipe->pix.height * 2);
5560  
5561  	pipe->capq.field = f->fmt.pix.field;
5562  
5563  	/*
5564  	 * If in video 480P case, no GFX throttle
5565  	 */
5566  	if (asd->run_mode->val == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO &&
5567  	    f->fmt.pix.width == 720 && f->fmt.pix.height == 480)
5568  		isp->need_gfx_throttle = false;
5569  	else
5570  		isp->need_gfx_throttle = true;
5571  
5572  	/* Report the needed sizes */
5573  	f->fmt.pix.sizeimage = pipe->pix.sizeimage;
5574  	f->fmt.pix.bytesperline = pipe->pix.bytesperline;
5575  
5576  	dev_dbg(isp->dev, "%s: %dx%d, image size: %d, %d bytes per line\n",
5577  		__func__,
5578  		f->fmt.pix.width, f->fmt.pix.height,
5579  		f->fmt.pix.sizeimage, f->fmt.pix.bytesperline);
5580  
5581  	return 0;
5582  }
5583  
atomisp_set_shading_table(struct atomisp_sub_device * asd,struct atomisp_shading_table * user_shading_table)5584  int atomisp_set_shading_table(struct atomisp_sub_device *asd,
5585  			      struct atomisp_shading_table *user_shading_table)
5586  {
5587  	struct ia_css_shading_table *shading_table;
5588  	struct ia_css_shading_table *free_table;
5589  	unsigned int len_table;
5590  	int i;
5591  	int ret = 0;
5592  
5593  	if (!user_shading_table)
5594  		return -EINVAL;
5595  
5596  	if (!user_shading_table->enable) {
5597  		asd->params.config.shading_table = NULL;
5598  		asd->params.sc_en = false;
5599  		return 0;
5600  	}
5601  
5602  	/* If enabling, all tables must be set */
5603  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
5604  		if (!user_shading_table->data[i])
5605  			return -EINVAL;
5606  	}
5607  
5608  	/* Shading table size per color */
5609  	if (user_shading_table->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
5610  	    user_shading_table->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR)
5611  		return -EINVAL;
5612  
5613  	shading_table = atomisp_css_shading_table_alloc(
5614  			    user_shading_table->width, user_shading_table->height);
5615  	if (!shading_table)
5616  		return -ENOMEM;
5617  
5618  	len_table = user_shading_table->width * user_shading_table->height *
5619  		    ATOMISP_SC_TYPE_SIZE;
5620  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
5621  		ret = copy_from_user(shading_table->data[i],
5622  				     (void __user *)user_shading_table->data[i],
5623  				     len_table);
5624  		if (ret) {
5625  			free_table = shading_table;
5626  			ret = -EFAULT;
5627  			goto out;
5628  		}
5629  	}
5630  	shading_table->sensor_width = user_shading_table->sensor_width;
5631  	shading_table->sensor_height = user_shading_table->sensor_height;
5632  	shading_table->fraction_bits = user_shading_table->fraction_bits;
5633  
5634  	free_table = asd->params.css_param.shading_table;
5635  	asd->params.css_param.shading_table = shading_table;
5636  	asd->params.config.shading_table = shading_table;
5637  	asd->params.sc_en = true;
5638  
5639  out:
5640  	if (free_table)
5641  		atomisp_css_shading_table_free(free_table);
5642  
5643  	return ret;
5644  }
5645  
5646  /*Turn off ISP dphy */
atomisp_ospm_dphy_down(struct atomisp_device * isp)5647  int atomisp_ospm_dphy_down(struct atomisp_device *isp)
5648  {
5649  	struct pci_dev *pdev = to_pci_dev(isp->dev);
5650  	unsigned long flags;
5651  	u32 reg;
5652  
5653  	dev_dbg(isp->dev, "%s\n", __func__);
5654  
5655  	/* if ISP timeout, we can force powerdown */
5656  	if (isp->isp_timeout)
5657  		goto done;
5658  
5659  	if (!atomisp_dev_users(isp))
5660  		goto done;
5661  
5662  	spin_lock_irqsave(&isp->lock, flags);
5663  	isp->sw_contex.power_state = ATOM_ISP_POWER_DOWN;
5664  	spin_unlock_irqrestore(&isp->lock, flags);
5665  done:
5666  	/*
5667  	 * MRFLD IUNIT DPHY is located in an always-power-on island
5668  	 * MRFLD HW design need all CSI ports are disabled before
5669  	 * powering down the IUNIT.
5670  	 */
5671  	pci_read_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, &reg);
5672  	reg |= MRFLD_ALL_CSI_PORTS_OFF_MASK;
5673  	pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg);
5674  	return 0;
5675  }
5676  
5677  /*Turn on ISP dphy */
atomisp_ospm_dphy_up(struct atomisp_device * isp)5678  int atomisp_ospm_dphy_up(struct atomisp_device *isp)
5679  {
5680  	unsigned long flags;
5681  
5682  	dev_dbg(isp->dev, "%s\n", __func__);
5683  
5684  	spin_lock_irqsave(&isp->lock, flags);
5685  	isp->sw_contex.power_state = ATOM_ISP_POWER_UP;
5686  	spin_unlock_irqrestore(&isp->lock, flags);
5687  
5688  	return 0;
5689  }
5690  
atomisp_exif_makernote(struct atomisp_sub_device * asd,struct atomisp_makernote_info * config)5691  int atomisp_exif_makernote(struct atomisp_sub_device *asd,
5692  			   struct atomisp_makernote_info *config)
5693  {
5694  	struct v4l2_control ctrl;
5695  	struct atomisp_device *isp = asd->isp;
5696  
5697  	ctrl.id = V4L2_CID_FOCAL_ABSOLUTE;
5698  	if (v4l2_g_ctrl
5699  	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
5700  		dev_warn(isp->dev, "failed to g_ctrl for focal length\n");
5701  		return -EINVAL;
5702  	} else {
5703  		config->focal_length = ctrl.value;
5704  	}
5705  
5706  	ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE;
5707  	if (v4l2_g_ctrl
5708  	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
5709  		dev_warn(isp->dev, "failed to g_ctrl for f-number\n");
5710  		return -EINVAL;
5711  	} else {
5712  		config->f_number_curr = ctrl.value;
5713  	}
5714  
5715  	ctrl.id = V4L2_CID_FNUMBER_RANGE;
5716  	if (v4l2_g_ctrl
5717  	    (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) {
5718  		dev_warn(isp->dev, "failed to g_ctrl for f number range\n");
5719  		return -EINVAL;
5720  	} else {
5721  		config->f_number_range = ctrl.value;
5722  	}
5723  
5724  	return 0;
5725  }
5726  
atomisp_offline_capture_configure(struct atomisp_sub_device * asd,struct atomisp_cont_capture_conf * cvf_config)5727  int atomisp_offline_capture_configure(struct atomisp_sub_device *asd,
5728  				      struct atomisp_cont_capture_conf *cvf_config)
5729  {
5730  	struct v4l2_ctrl *c;
5731  
5732  	lockdep_assert_held(&asd->isp->mutex);
5733  
5734  	/*
5735  	* In case of M10MO ZSL capture case, we need to issue a separate
5736  	* capture request to M10MO which will output captured jpeg image
5737  	*/
5738  	c = v4l2_ctrl_find(
5739  		asd->isp->inputs[asd->input_curr].camera->ctrl_handler,
5740  		V4L2_CID_START_ZSL_CAPTURE);
5741  	if (c) {
5742  		int ret;
5743  
5744  		dev_dbg(asd->isp->dev, "%s trigger ZSL capture request\n",
5745  			__func__);
5746  		/* TODO: use the cvf_config */
5747  		ret = v4l2_ctrl_s_ctrl(c, 1);
5748  		if (ret)
5749  			return ret;
5750  
5751  		return v4l2_ctrl_s_ctrl(c, 0);
5752  	}
5753  
5754  	asd->params.offline_parm = *cvf_config;
5755  
5756  	if (asd->params.offline_parm.num_captures) {
5757  		if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED) {
5758  			unsigned int init_raw_num;
5759  
5760  			if (asd->enable_raw_buffer_lock->val) {
5761  				init_raw_num =
5762  				    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES_LOCK_EN;
5763  				if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
5764  				    asd->params.video_dis_en)
5765  					init_raw_num +=
5766  					    ATOMISP_CSS2_NUM_DVS_FRAME_DELAY;
5767  			} else {
5768  				init_raw_num =
5769  				    ATOMISP_CSS2_NUM_OFFLINE_INIT_CONTINUOUS_FRAMES;
5770  			}
5771  
5772  			/* TODO: this can be removed once user-space
5773  			 *       has been updated to use control API */
5774  			asd->continuous_raw_buffer_size->val =
5775  			    max_t(int,
5776  				  asd->continuous_raw_buffer_size->val,
5777  				  asd->params.offline_parm.
5778  				  num_captures + init_raw_num);
5779  			asd->continuous_raw_buffer_size->val =
5780  			    min_t(int, ATOMISP_CONT_RAW_FRAMES,
5781  				  asd->continuous_raw_buffer_size->val);
5782  		}
5783  		asd->continuous_mode->val = true;
5784  	} else {
5785  		asd->continuous_mode->val = false;
5786  		__enable_continuous_mode(asd, false);
5787  	}
5788  
5789  	return 0;
5790  }
5791  
5792  /*
5793   * set auto exposure metering window to camera sensor
5794   */
atomisp_s_ae_window(struct atomisp_sub_device * asd,struct atomisp_ae_window * arg)5795  int atomisp_s_ae_window(struct atomisp_sub_device *asd,
5796  			struct atomisp_ae_window *arg)
5797  {
5798  	struct atomisp_device *isp = asd->isp;
5799  	/* Coverity CID 298071 - initialzize struct */
5800  	struct v4l2_subdev_selection sel = { 0 };
5801  
5802  	sel.r.left = arg->x_left;
5803  	sel.r.top = arg->y_top;
5804  	sel.r.width = arg->x_right - arg->x_left + 1;
5805  	sel.r.height = arg->y_bottom - arg->y_top + 1;
5806  
5807  	if (v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
5808  			     pad, set_selection, NULL, &sel)) {
5809  		dev_err(isp->dev, "failed to call sensor set_selection.\n");
5810  		return -EINVAL;
5811  	}
5812  
5813  	return 0;
5814  }
5815  
atomisp_flash_enable(struct atomisp_sub_device * asd,int num_frames)5816  int atomisp_flash_enable(struct atomisp_sub_device *asd, int num_frames)
5817  {
5818  	struct atomisp_device *isp = asd->isp;
5819  
5820  	if (num_frames < 0) {
5821  		dev_dbg(isp->dev, "%s ERROR: num_frames: %d\n", __func__,
5822  			num_frames);
5823  		return -EINVAL;
5824  	}
5825  	/* a requested flash is still in progress. */
5826  	if (num_frames && asd->params.flash_state != ATOMISP_FLASH_IDLE) {
5827  		dev_dbg(isp->dev, "%s flash busy: %d frames left: %d\n",
5828  			__func__, asd->params.flash_state,
5829  			asd->params.num_flash_frames);
5830  		return -EBUSY;
5831  	}
5832  
5833  	asd->params.num_flash_frames = num_frames;
5834  	asd->params.flash_state = ATOMISP_FLASH_REQUESTED;
5835  	return 0;
5836  }
5837  
atomisp_is_vf_pipe(struct atomisp_video_pipe * pipe)5838  bool atomisp_is_vf_pipe(struct atomisp_video_pipe *pipe)
5839  {
5840  	struct atomisp_sub_device *asd = pipe->asd;
5841  
5842  	if (!asd) {
5843  		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
5844  			__func__, pipe->vdev.name);
5845  		return false;
5846  	}
5847  
5848  	if (pipe == &asd->video_out_vf)
5849  		return true;
5850  
5851  	if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
5852  	    pipe == &asd->video_out_preview)
5853  		return true;
5854  
5855  	return false;
5856  }
5857  
__checking_exp_id(struct atomisp_sub_device * asd,int exp_id)5858  static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id)
5859  {
5860  	struct atomisp_device *isp = asd->isp;
5861  
5862  	if (!asd->enable_raw_buffer_lock->val) {
5863  		dev_warn(isp->dev, "%s Raw Buffer Lock is disable.\n", __func__);
5864  		return -EINVAL;
5865  	}
5866  	if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) {
5867  		dev_err(isp->dev, "%s streaming %d invalid exp_id %d.\n",
5868  			__func__, exp_id, asd->streaming);
5869  		return -EINVAL;
5870  	}
5871  	if ((exp_id > ATOMISP_MAX_EXP_ID) || (exp_id <= 0)) {
5872  		dev_err(isp->dev, "%s exp_id %d invalid.\n", __func__, exp_id);
5873  		return -EINVAL;
5874  	}
5875  	return 0;
5876  }
5877  
atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device * asd)5878  void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd)
5879  {
5880  	unsigned long flags;
5881  
5882  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
5883  	memset(asd->raw_buffer_bitmap, 0, sizeof(asd->raw_buffer_bitmap));
5884  	asd->raw_buffer_locked_count = 0;
5885  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
5886  }
5887  
atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device * asd,int exp_id)5888  static int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
5889  {
5890  	int *bitmap, bit;
5891  	unsigned long flags;
5892  
5893  	if (__checking_exp_id(asd, exp_id))
5894  		return -EINVAL;
5895  
5896  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
5897  	bit = exp_id % 32;
5898  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
5899  	(*bitmap) |= (1 << bit);
5900  	asd->raw_buffer_locked_count++;
5901  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
5902  
5903  	dev_dbg(asd->isp->dev, "%s: exp_id %d,  raw_buffer_locked_count %d\n",
5904  		__func__, exp_id, asd->raw_buffer_locked_count);
5905  
5906  	/* Check if the raw buffer after next is still locked!!! */
5907  	exp_id += 2;
5908  	if (exp_id > ATOMISP_MAX_EXP_ID)
5909  		exp_id -= ATOMISP_MAX_EXP_ID;
5910  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
5911  	bit = exp_id % 32;
5912  	if ((*bitmap) & (1 << bit)) {
5913  		int ret;
5914  
5915  		/* WORKAROUND unlock the raw buffer compulsively */
5916  		ret = atomisp_css_exp_id_unlock(asd, exp_id);
5917  		if (ret) {
5918  			dev_err(asd->isp->dev,
5919  				"%s exp_id is wrapping back to %d but force unlock failed, err %d.\n",
5920  				__func__, exp_id, ret);
5921  			return ret;
5922  		}
5923  
5924  		spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
5925  		(*bitmap) &= ~(1 << bit);
5926  		asd->raw_buffer_locked_count--;
5927  		spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
5928  		dev_warn(asd->isp->dev,
5929  			 "%s exp_id is wrapping back to %d but it is still locked so force unlock it, raw_buffer_locked_count %d\n",
5930  			 __func__, exp_id, asd->raw_buffer_locked_count);
5931  	}
5932  	return 0;
5933  }
5934  
__is_raw_buffer_locked(struct atomisp_sub_device * asd,int exp_id)5935  static int __is_raw_buffer_locked(struct atomisp_sub_device *asd, int exp_id)
5936  {
5937  	int *bitmap, bit;
5938  	unsigned long flags;
5939  	int ret;
5940  
5941  	if (__checking_exp_id(asd, exp_id))
5942  		return -EINVAL;
5943  
5944  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
5945  	bit = exp_id % 32;
5946  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
5947  	ret = ((*bitmap) & (1 << bit));
5948  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
5949  	return !ret;
5950  }
5951  
__clear_raw_buffer_bitmap(struct atomisp_sub_device * asd,int exp_id)5952  static int __clear_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
5953  {
5954  	int *bitmap, bit;
5955  	unsigned long flags;
5956  
5957  	if (__is_raw_buffer_locked(asd, exp_id))
5958  		return -EINVAL;
5959  
5960  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
5961  	bit = exp_id % 32;
5962  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
5963  	(*bitmap) &= ~(1 << bit);
5964  	asd->raw_buffer_locked_count--;
5965  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
5966  
5967  	dev_dbg(asd->isp->dev, "%s: exp_id %d,  raw_buffer_locked_count %d\n",
5968  		__func__, exp_id, asd->raw_buffer_locked_count);
5969  	return 0;
5970  }
5971  
atomisp_exp_id_capture(struct atomisp_sub_device * asd,int * exp_id)5972  int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id)
5973  {
5974  	struct atomisp_device *isp = asd->isp;
5975  	int value = *exp_id;
5976  	int ret;
5977  
5978  	lockdep_assert_held(&isp->mutex);
5979  
5980  	ret = __is_raw_buffer_locked(asd, value);
5981  	if (ret) {
5982  		dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
5983  		return -EINVAL;
5984  	}
5985  
5986  	dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
5987  	ret = atomisp_css_exp_id_capture(asd, value);
5988  	if (ret) {
5989  		dev_err(isp->dev, "%s exp_id %d failed.\n", __func__, value);
5990  		return -EIO;
5991  	}
5992  	return 0;
5993  }
5994  
atomisp_exp_id_unlock(struct atomisp_sub_device * asd,int * exp_id)5995  int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id)
5996  {
5997  	struct atomisp_device *isp = asd->isp;
5998  	int value = *exp_id;
5999  	int ret;
6000  
6001  	lockdep_assert_held(&isp->mutex);
6002  
6003  	ret = __clear_raw_buffer_bitmap(asd, value);
6004  	if (ret) {
6005  		dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
6006  		return -EINVAL;
6007  	}
6008  
6009  	dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
6010  	ret = atomisp_css_exp_id_unlock(asd, value);
6011  	if (ret)
6012  		dev_err(isp->dev, "%s exp_id %d failed, err %d.\n",
6013  			__func__, value, ret);
6014  
6015  	return ret;
6016  }
6017  
atomisp_enable_dz_capt_pipe(struct atomisp_sub_device * asd,unsigned int * enable)6018  int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd,
6019  				unsigned int *enable)
6020  {
6021  	bool value;
6022  
6023  	if (!enable)
6024  		return -EINVAL;
6025  
6026  	value = *enable > 0;
6027  
6028  	atomisp_en_dz_capt_pipe(asd, value);
6029  
6030  	return 0;
6031  }
6032  
atomisp_inject_a_fake_event(struct atomisp_sub_device * asd,int * event)6033  int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event)
6034  {
6035  	if (!event || asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
6036  		return -EINVAL;
6037  
6038  	lockdep_assert_held(&asd->isp->mutex);
6039  
6040  	dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n",
6041  		__func__, *event);
6042  
6043  	switch (*event) {
6044  	case V4L2_EVENT_FRAME_SYNC:
6045  		atomisp_sof_event(asd);
6046  		break;
6047  	case V4L2_EVENT_FRAME_END:
6048  		atomisp_eof_event(asd, 0);
6049  		break;
6050  	case V4L2_EVENT_ATOMISP_3A_STATS_READY:
6051  		atomisp_3a_stats_ready_event(asd, 0);
6052  		break;
6053  	case V4L2_EVENT_ATOMISP_METADATA_READY:
6054  		atomisp_metadata_ready_event(asd, 0);
6055  		break;
6056  	default:
6057  		return -EINVAL;
6058  	}
6059  
6060  	return 0;
6061  }
6062  
atomisp_get_pipe_id(struct atomisp_video_pipe * pipe)6063  static int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe)
6064  {
6065  	struct atomisp_sub_device *asd = pipe->asd;
6066  
6067  	if (!asd) {
6068  		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
6069  			__func__, pipe->vdev.name);
6070  		return -EINVAL;
6071  	}
6072  
6073  	if (ATOMISP_USE_YUVPP(asd)) {
6074  		return IA_CSS_PIPE_ID_YUVPP;
6075  	} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
6076  		return IA_CSS_PIPE_ID_VIDEO;
6077  	} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
6078  		return IA_CSS_PIPE_ID_CAPTURE;
6079  	} else if (pipe == &asd->video_out_video_capture) {
6080  		return IA_CSS_PIPE_ID_VIDEO;
6081  	} else if (pipe == &asd->video_out_vf) {
6082  		return IA_CSS_PIPE_ID_CAPTURE;
6083  	} else if (pipe == &asd->video_out_preview) {
6084  		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO)
6085  			return IA_CSS_PIPE_ID_VIDEO;
6086  		else
6087  			return IA_CSS_PIPE_ID_PREVIEW;
6088  	} else if (pipe == &asd->video_out_capture) {
6089  		if (asd->copy_mode)
6090  			return IA_CSS_PIPE_ID_COPY;
6091  		else
6092  			return IA_CSS_PIPE_ID_CAPTURE;
6093  	}
6094  
6095  	/* fail through */
6096  	dev_warn(asd->isp->dev, "%s failed to find proper pipe\n",
6097  		 __func__);
6098  	return IA_CSS_PIPE_ID_CAPTURE;
6099  }
6100  
atomisp_get_invalid_frame_num(struct video_device * vdev,int * invalid_frame_num)6101  int atomisp_get_invalid_frame_num(struct video_device *vdev,
6102  				  int *invalid_frame_num)
6103  {
6104  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
6105  	struct atomisp_sub_device *asd = pipe->asd;
6106  	enum ia_css_pipe_id pipe_id;
6107  	struct ia_css_pipe_info p_info;
6108  	int ret;
6109  
6110  	pipe_id = atomisp_get_pipe_id(pipe);
6111  	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id]) {
6112  		dev_warn(asd->isp->dev,
6113  			 "%s pipe %d has not been created yet, do SET_FMT first!\n",
6114  			 __func__, pipe_id);
6115  		return -EINVAL;
6116  	}
6117  
6118  	ret = ia_css_pipe_get_info(
6119  		  asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
6120  		  .pipes[pipe_id], &p_info);
6121  	if (!ret) {
6122  		*invalid_frame_num = p_info.num_invalid_frames;
6123  		return 0;
6124  	} else {
6125  		dev_warn(asd->isp->dev, "%s get pipe infor failed %d\n",
6126  			 __func__, ret);
6127  		return -EINVAL;
6128  	}
6129  }
6130