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  
34  #define CREATE_TRACE_POINTS
35  #include "atomisp_trace_event.h"
36  
37  #include "atomisp_cmd.h"
38  #include "atomisp_common.h"
39  #include "atomisp_fops.h"
40  #include "atomisp_internal.h"
41  #include "atomisp_ioctl.h"
42  #include "atomisp-regs.h"
43  #include "atomisp_tables.h"
44  #include "atomisp_compat.h"
45  #include "atomisp_subdev.h"
46  #include "atomisp_dfs_tables.h"
47  
48  #include <hmm/hmm.h>
49  
50  #include "sh_css_hrt.h"
51  #include "sh_css_defs.h"
52  #include "system_global.h"
53  #include "sh_css_internal.h"
54  #include "sh_css_sp.h"
55  #include "gp_device.h"
56  #include "device_access.h"
57  #include "irq.h"
58  
59  #include "ia_css_types.h"
60  #include "ia_css_stream.h"
61  #include "ia_css_debug.h"
62  #include "bits.h"
63  
64  union host {
65  	struct {
66  		void *kernel_ptr;
67  		void __user *user_ptr;
68  		int size;
69  	} scalar;
70  	struct {
71  		void *hmm_ptr;
72  	} ptr;
73  };
74  
75  /*
76   * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field.
77   * subdev->priv is set in mrst.c
78   */
atomisp_to_sensor_mipi_info(struct v4l2_subdev * sd)79  struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd)
80  {
81  	return (struct camera_mipi_info *)v4l2_get_subdev_hostdata(sd);
82  }
83  
84  /*
85   * get struct atomisp_video_pipe from v4l2 video_device
86   */
atomisp_to_video_pipe(struct video_device * dev)87  struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev)
88  {
89  	return (struct atomisp_video_pipe *)
90  	       container_of(dev, struct atomisp_video_pipe, vdev);
91  }
92  
atomisp_get_sensor_fps(struct atomisp_sub_device * asd)93  static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
94  {
95  	struct v4l2_subdev_frame_interval fi = { 0 };
96  	struct atomisp_device *isp = asd->isp;
97  
98  	unsigned short fps = 0;
99  	int ret;
100  
101  	ret = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
102  					    pad, get_frame_interval, &fi);
103  
104  	if (!ret && fi.interval.numerator)
105  		fps = fi.interval.denominator / fi.interval.numerator;
106  
107  	return fps;
108  }
109  
110  /*
111   * DFS progress is shown as follows:
112   * 1. Target frequency is calculated according to FPS/Resolution/ISP running
113   *    mode.
114   * 2. Ratio is calculated using formula: 2 * HPLL / target frequency - 1
115   *    with proper rounding.
116   * 3. Set ratio to ISPFREQ40, 1 to FREQVALID and ISPFREQGUAR40
117   *    to 200MHz in ISPSSPM1.
118   * 4. Wait for FREQVALID to be cleared by P-Unit.
119   * 5. Wait for field ISPFREQSTAT40 in ISPSSPM1 turn to ratio set in 3.
120   */
write_target_freq_to_hw(struct atomisp_device * isp,unsigned int new_freq)121  static int write_target_freq_to_hw(struct atomisp_device *isp,
122  				   unsigned int new_freq)
123  {
124  	unsigned int ratio, timeout, guar_ratio;
125  	u32 isp_sspm1 = 0;
126  	int i;
127  
128  	if (!isp->hpll_freq) {
129  		dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n");
130  		return -EINVAL;
131  	}
132  
133  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
134  	if (isp_sspm1 & ISP_FREQ_VALID_MASK) {
135  		dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n");
136  		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
137  			       isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET));
138  	}
139  
140  	ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1;
141  	guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1;
142  
143  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
144  	isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET);
145  
146  	for (i = 0; i < ISP_DFS_TRY_TIMES; i++) {
147  		iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1,
148  			       isp_sspm1
149  			       | ratio << ISP_REQ_FREQ_OFFSET
150  			       | 1 << ISP_FREQ_VALID_OFFSET
151  			       | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET);
152  
153  		iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
154  		timeout = 20;
155  		while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) {
156  			iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
157  			dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n");
158  			udelay(100);
159  			timeout--;
160  		}
161  
162  		if (timeout != 0)
163  			break;
164  	}
165  
166  	if (timeout == 0) {
167  		dev_err(isp->dev, "DFS failed due to HW error.\n");
168  		return -EINVAL;
169  	}
170  
171  	iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
172  	timeout = 10;
173  	while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) {
174  		iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1);
175  		dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n",
176  			new_freq);
177  		udelay(100);
178  		timeout--;
179  	}
180  	if (timeout == 0) {
181  		dev_err(isp->dev, "DFS target freq is rejected by HW.\n");
182  		return -EINVAL;
183  	}
184  
185  	return 0;
186  }
187  
atomisp_freq_scaling(struct atomisp_device * isp,enum atomisp_dfs_mode mode,bool force)188  int atomisp_freq_scaling(struct atomisp_device *isp,
189  			 enum atomisp_dfs_mode mode,
190  			 bool force)
191  {
192  	const struct atomisp_dfs_config *dfs;
193  	unsigned int new_freq;
194  	struct atomisp_freq_scaling_rule curr_rules;
195  	int i, ret;
196  	unsigned short fps = 0;
197  
198  	dfs = isp->dfs;
199  
200  	if (dfs->lowest_freq == 0 || dfs->max_freq_at_vmin == 0 ||
201  	    dfs->highest_freq == 0 || dfs->dfs_table_size == 0 ||
202  	    !dfs->dfs_table) {
203  		dev_err(isp->dev, "DFS configuration is invalid.\n");
204  		return -EINVAL;
205  	}
206  
207  	if (mode == ATOMISP_DFS_MODE_LOW) {
208  		new_freq = dfs->lowest_freq;
209  		goto done;
210  	}
211  
212  	if (mode == ATOMISP_DFS_MODE_MAX) {
213  		new_freq = dfs->highest_freq;
214  		goto done;
215  	}
216  
217  	fps = atomisp_get_sensor_fps(&isp->asd);
218  	if (fps == 0) {
219  		dev_info(isp->dev,
220  			 "Sensor didn't report FPS. Using DFS max mode.\n");
221  		new_freq = dfs->highest_freq;
222  		goto done;
223  	}
224  
225  	curr_rules.width = isp->asd.fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.width;
226  	curr_rules.height = isp->asd.fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.height;
227  	curr_rules.fps = fps;
228  	curr_rules.run_mode = isp->asd.run_mode->val;
229  
230  	/* search for the target frequency by looping freq rules*/
231  	for (i = 0; i < dfs->dfs_table_size; i++) {
232  		if (curr_rules.width != dfs->dfs_table[i].width &&
233  		    dfs->dfs_table[i].width != ISP_FREQ_RULE_ANY)
234  			continue;
235  		if (curr_rules.height != dfs->dfs_table[i].height &&
236  		    dfs->dfs_table[i].height != ISP_FREQ_RULE_ANY)
237  			continue;
238  		if (curr_rules.fps != dfs->dfs_table[i].fps &&
239  		    dfs->dfs_table[i].fps != ISP_FREQ_RULE_ANY)
240  			continue;
241  		if (curr_rules.run_mode != dfs->dfs_table[i].run_mode &&
242  		    dfs->dfs_table[i].run_mode != ISP_FREQ_RULE_ANY)
243  			continue;
244  		break;
245  	}
246  
247  	if (i == dfs->dfs_table_size)
248  		new_freq = dfs->max_freq_at_vmin;
249  	else
250  		new_freq = dfs->dfs_table[i].isp_freq;
251  
252  done:
253  	dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq);
254  
255  	if ((new_freq == isp->running_freq) && !force)
256  		return 0;
257  
258  	dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq);
259  
260  	ret = write_target_freq_to_hw(isp, new_freq);
261  	if (!ret) {
262  		isp->running_freq = new_freq;
263  		trace_ipu_pstate(new_freq, -1);
264  	}
265  	return ret;
266  }
267  
268  /*
269   * reset and restore ISP
270   */
atomisp_reset(struct atomisp_device * isp)271  int atomisp_reset(struct atomisp_device *isp)
272  {
273  	/* Reset ISP by power-cycling it */
274  	int ret = 0;
275  
276  	dev_dbg(isp->dev, "%s\n", __func__);
277  
278  	ret = atomisp_power_off(isp->dev);
279  	if (ret < 0)
280  		dev_err(isp->dev, "atomisp_power_off failed, %d\n", ret);
281  
282  	ret = atomisp_power_on(isp->dev);
283  	if (ret < 0) {
284  		dev_err(isp->dev, "atomisp_power_on failed, %d\n", ret);
285  		isp->isp_fatal_error = true;
286  	}
287  
288  	return ret;
289  }
290  
291  /*
292   * interrupt disable functions
293   */
disable_isp_irq(enum hrt_isp_css_irq irq)294  static void disable_isp_irq(enum hrt_isp_css_irq irq)
295  {
296  	irq_disable_channel(IRQ0_ID, irq);
297  
298  	if (irq != hrt_isp_css_irq_sp)
299  		return;
300  
301  	cnd_sp_irq_enable(SP0_ID, false);
302  }
303  
304  /*
305   * interrupt clean function
306   */
clear_isp_irq(enum hrt_isp_css_irq irq)307  static void clear_isp_irq(enum hrt_isp_css_irq irq)
308  {
309  	irq_clear_all(IRQ0_ID);
310  }
311  
atomisp_msi_irq_init(struct atomisp_device * isp)312  void atomisp_msi_irq_init(struct atomisp_device *isp)
313  {
314  	struct pci_dev *pdev = to_pci_dev(isp->dev);
315  	u32 msg32;
316  	u16 msg16;
317  
318  	pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32);
319  	msg32 |= 1 << MSI_ENABLE_BIT;
320  	pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32);
321  
322  	msg32 = (1 << INTR_IER) | (1 << INTR_IIR);
323  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32);
324  
325  	pci_read_config_word(pdev, PCI_COMMAND, &msg16);
326  	msg16 |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
327  		  PCI_COMMAND_INTX_DISABLE);
328  	pci_write_config_word(pdev, PCI_COMMAND, msg16);
329  }
330  
atomisp_msi_irq_uninit(struct atomisp_device * isp)331  void atomisp_msi_irq_uninit(struct atomisp_device *isp)
332  {
333  	struct pci_dev *pdev = to_pci_dev(isp->dev);
334  	u32 msg32;
335  	u16 msg16;
336  
337  	pci_read_config_dword(pdev, PCI_MSI_CAPID, &msg32);
338  	msg32 &=  ~(1 << MSI_ENABLE_BIT);
339  	pci_write_config_dword(pdev, PCI_MSI_CAPID, msg32);
340  
341  	msg32 = 0x0;
342  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg32);
343  
344  	pci_read_config_word(pdev, PCI_COMMAND, &msg16);
345  	msg16 &= ~(PCI_COMMAND_MASTER);
346  	pci_write_config_word(pdev, PCI_COMMAND, msg16);
347  }
348  
atomisp_sof_event(struct atomisp_sub_device * asd)349  static void atomisp_sof_event(struct atomisp_sub_device *asd)
350  {
351  	struct v4l2_event event = {0};
352  
353  	event.type = V4L2_EVENT_FRAME_SYNC;
354  	event.u.frame_sync.frame_sequence = atomic_read(&asd->sof_count);
355  
356  	v4l2_event_queue(asd->subdev.devnode, &event);
357  }
358  
atomisp_eof_event(struct atomisp_sub_device * asd,uint8_t exp_id)359  void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id)
360  {
361  	struct v4l2_event event = {0};
362  
363  	event.type = V4L2_EVENT_FRAME_END;
364  	event.u.frame_sync.frame_sequence = exp_id;
365  
366  	v4l2_event_queue(asd->subdev.devnode, &event);
367  }
368  
atomisp_3a_stats_ready_event(struct atomisp_sub_device * asd,uint8_t exp_id)369  static void atomisp_3a_stats_ready_event(struct atomisp_sub_device *asd,
370  	uint8_t exp_id)
371  {
372  	struct v4l2_event event = {0};
373  
374  	event.type = V4L2_EVENT_ATOMISP_3A_STATS_READY;
375  	event.u.frame_sync.frame_sequence = exp_id;
376  
377  	v4l2_event_queue(asd->subdev.devnode, &event);
378  }
379  
atomisp_metadata_ready_event(struct atomisp_sub_device * asd,enum atomisp_metadata_type md_type)380  static void atomisp_metadata_ready_event(struct atomisp_sub_device *asd,
381  	enum atomisp_metadata_type md_type)
382  {
383  	struct v4l2_event event = {0};
384  
385  	event.type = V4L2_EVENT_ATOMISP_METADATA_READY;
386  	event.u.data[0] = md_type;
387  
388  	v4l2_event_queue(asd->subdev.devnode, &event);
389  }
390  
atomisp_reset_event(struct atomisp_sub_device * asd)391  static void atomisp_reset_event(struct atomisp_sub_device *asd)
392  {
393  	struct v4l2_event event = {0};
394  
395  	event.type = V4L2_EVENT_ATOMISP_CSS_RESET;
396  
397  	v4l2_event_queue(asd->subdev.devnode, &event);
398  }
399  
print_csi_rx_errors(enum mipi_port_id port,struct atomisp_device * isp)400  static void print_csi_rx_errors(enum mipi_port_id port,
401  				struct atomisp_device *isp)
402  {
403  	u32 infos = 0;
404  
405  	atomisp_css_rx_get_irq_info(port, &infos);
406  
407  	dev_err(isp->dev, "CSI Receiver port %d errors:\n", port);
408  	if (infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN)
409  		dev_err(isp->dev, "  buffer overrun");
410  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT)
411  		dev_err(isp->dev, "  start-of-transmission error");
412  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC)
413  		dev_err(isp->dev, "  start-of-transmission sync error");
414  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL)
415  		dev_err(isp->dev, "  control error");
416  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE)
417  		dev_err(isp->dev, "  2 or more ECC errors");
418  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_CRC)
419  		dev_err(isp->dev, "  CRC mismatch");
420  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID)
421  		dev_err(isp->dev, "  unknown error");
422  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC)
423  		dev_err(isp->dev, "  frame sync error");
424  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA)
425  		dev_err(isp->dev, "  frame data error");
426  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT)
427  		dev_err(isp->dev, "  data timeout");
428  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC)
429  		dev_err(isp->dev, "  unknown escape command entry");
430  	if (infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC)
431  		dev_err(isp->dev, "  line sync error");
432  }
433  
434  /* Clear irq reg */
clear_irq_reg(struct atomisp_device * isp)435  static void clear_irq_reg(struct atomisp_device *isp)
436  {
437  	struct pci_dev *pdev = to_pci_dev(isp->dev);
438  	u32 msg_ret;
439  
440  	pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &msg_ret);
441  	msg_ret |= 1 << INTR_IIR;
442  	pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, msg_ret);
443  }
444  
445  /* interrupt handling function*/
atomisp_isr(int irq,void * dev)446  irqreturn_t atomisp_isr(int irq, void *dev)
447  {
448  	struct atomisp_device *isp = (struct atomisp_device *)dev;
449  	struct atomisp_css_event eof_event;
450  	unsigned int irq_infos = 0;
451  	unsigned long flags;
452  	int err;
453  
454  	spin_lock_irqsave(&isp->lock, flags);
455  
456  	if (!isp->css_initialized) {
457  		spin_unlock_irqrestore(&isp->lock, flags);
458  		return IRQ_HANDLED;
459  	}
460  	err = atomisp_css_irq_translate(isp, &irq_infos);
461  	if (err) {
462  		spin_unlock_irqrestore(&isp->lock, flags);
463  		return IRQ_NONE;
464  	}
465  
466  	clear_irq_reg(isp);
467  
468  	if (!isp->asd.streaming)
469  		goto out_nowake;
470  
471  	if (irq_infos & IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF) {
472  		atomic_inc(&isp->asd.sof_count);
473  		atomisp_sof_event(&isp->asd);
474  
475  		/*
476  		 * If sequence_temp and sequence are the same there where no frames
477  		 * lost so we can increase sequence_temp.
478  		 * If not then processing of frame is still in progress and driver
479  		 * needs to keep old sequence_temp value.
480  		 * NOTE: There is assumption here that ISP will not start processing
481  		 * next frame from sensor before old one is completely done.
482  		 */
483  		if (atomic_read(&isp->asd.sequence) == atomic_read(&isp->asd.sequence_temp))
484  			atomic_set(&isp->asd.sequence_temp, atomic_read(&isp->asd.sof_count));
485  
486  		dev_dbg_ratelimited(isp->dev, "irq:0x%x (SOF)\n", irq_infos);
487  		irq_infos &= ~IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF;
488  	}
489  
490  	if (irq_infos & IA_CSS_IRQ_INFO_EVENTS_READY)
491  		atomic_set(&isp->asd.sequence, atomic_read(&isp->asd.sequence_temp));
492  
493  	if ((irq_infos & IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR) ||
494  	    (irq_infos & IA_CSS_IRQ_INFO_IF_ERROR)) {
495  		/* handle mipi receiver error */
496  		u32 rx_infos;
497  		enum mipi_port_id port;
498  
499  		for (port = MIPI_PORT0_ID; port <= MIPI_PORT2_ID;
500  		     port++) {
501  			print_csi_rx_errors(port, isp);
502  			atomisp_css_rx_get_irq_info(port, &rx_infos);
503  			atomisp_css_rx_clear_irq_info(port, rx_infos);
504  		}
505  	}
506  
507  	if (irq_infos & IA_CSS_IRQ_INFO_ISYS_EVENTS_READY) {
508  		while (ia_css_dequeue_isys_event(&eof_event.event) == 0) {
509  			atomisp_eof_event(&isp->asd, eof_event.event.exp_id);
510  			dev_dbg_ratelimited(isp->dev, "ISYS event: EOF exp_id %d\n",
511  					    eof_event.event.exp_id);
512  		}
513  
514  		irq_infos &= ~IA_CSS_IRQ_INFO_ISYS_EVENTS_READY;
515  		if (irq_infos == 0)
516  			goto out_nowake;
517  	}
518  
519  	spin_unlock_irqrestore(&isp->lock, flags);
520  
521  	dev_dbg_ratelimited(isp->dev, "irq:0x%x (unhandled)\n", irq_infos);
522  
523  	return IRQ_WAKE_THREAD;
524  
525  out_nowake:
526  	spin_unlock_irqrestore(&isp->lock, flags);
527  
528  	if (irq_infos)
529  		dev_dbg_ratelimited(isp->dev, "irq:0x%x (ignored, as not streaming anymore)\n",
530  				    irq_infos);
531  
532  	return IRQ_HANDLED;
533  }
534  
atomisp_clear_css_buffer_counters(struct atomisp_sub_device * asd)535  void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd)
536  {
537  	int i;
538  
539  	memset(asd->s3a_bufs_in_css, 0, sizeof(asd->s3a_bufs_in_css));
540  	for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++)
541  		memset(asd->metadata_bufs_in_css[i], 0,
542  		       sizeof(asd->metadata_bufs_in_css[i]));
543  	asd->dis_bufs_in_css = 0;
544  }
545  
546  /* 0x100000 is the start of dmem inside SP */
547  #define SP_DMEM_BASE	0x100000
548  
dump_sp_dmem(struct atomisp_device * isp,unsigned int addr,unsigned int size)549  void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
550  		  unsigned int size)
551  {
552  	unsigned int data = 0;
553  	unsigned int size32 = DIV_ROUND_UP(size, sizeof(u32));
554  
555  	dev_dbg(isp->dev, "atomisp mmio base: %p\n", isp->base);
556  	dev_dbg(isp->dev, "%s, addr:0x%x, size: %d, size32: %d\n", __func__,
557  		addr, size, size32);
558  	if (size32 * 4 + addr > 0x4000) {
559  		dev_err(isp->dev, "illegal size (%d) or addr (0x%x)\n",
560  			size32, addr);
561  		return;
562  	}
563  	addr += SP_DMEM_BASE;
564  	addr &= 0x003FFFFF;
565  	do {
566  		data = readl(isp->base + addr);
567  		dev_dbg(isp->dev, "%s, \t [0x%x]:0x%x\n", __func__, addr, data);
568  		addr += sizeof(u32);
569  	} while (--size32);
570  }
571  
atomisp_buffers_in_css(struct atomisp_video_pipe * pipe)572  int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe)
573  {
574  	unsigned long irqflags;
575  	struct list_head *pos;
576  	int buffers_in_css = 0;
577  
578  	spin_lock_irqsave(&pipe->irq_lock, irqflags);
579  
580  	list_for_each(pos, &pipe->buffers_in_css)
581  		buffers_in_css++;
582  
583  	spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
584  
585  	return buffers_in_css;
586  }
587  
atomisp_buffer_done(struct ia_css_frame * frame,enum vb2_buffer_state state)588  void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state)
589  {
590  	struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
591  
592  	lockdep_assert_held(&pipe->irq_lock);
593  
594  	frame->vb.vb2_buf.timestamp = ktime_get_ns();
595  	frame->vb.field = pipe->pix.field;
596  	frame->vb.sequence = atomic_read(&pipe->asd->sequence);
597  	list_del(&frame->queue);
598  	if (state == VB2_BUF_STATE_DONE)
599  		vb2_set_plane_payload(&frame->vb.vb2_buf, 0, pipe->pix.sizeimage);
600  	vb2_buffer_done(&frame->vb.vb2_buf, state);
601  }
602  
atomisp_flush_video_pipe(struct atomisp_video_pipe * pipe,enum vb2_buffer_state state,bool warn_on_css_frames)603  void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state,
604  			      bool warn_on_css_frames)
605  {
606  	struct ia_css_frame *frame, *_frame;
607  	unsigned long irqflags;
608  
609  	spin_lock_irqsave(&pipe->irq_lock, irqflags);
610  
611  	list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) {
612  		if (warn_on_css_frames)
613  			dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n");
614  		atomisp_buffer_done(frame, state);
615  	}
616  
617  	list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue)
618  		atomisp_buffer_done(frame, state);
619  
620  	list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) {
621  		pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0;
622  		atomisp_buffer_done(frame, state);
623  	}
624  
625  	spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
626  }
627  
628  /* clean out the parameters that did not apply */
atomisp_flush_params_queue(struct atomisp_video_pipe * pipe)629  void atomisp_flush_params_queue(struct atomisp_video_pipe *pipe)
630  {
631  	struct atomisp_css_params_with_list *param;
632  
633  	while (!list_empty(&pipe->per_frame_params)) {
634  		param = list_entry(pipe->per_frame_params.next,
635  				   struct atomisp_css_params_with_list, list);
636  		list_del(&param->list);
637  		atomisp_free_css_parameters(&param->params);
638  		kvfree(param);
639  	}
640  }
641  
642  /* Re-queue per-frame parameters */
atomisp_recover_params_queue(struct atomisp_video_pipe * pipe)643  static void atomisp_recover_params_queue(struct atomisp_video_pipe *pipe)
644  {
645  	struct atomisp_css_params_with_list *param;
646  	int i;
647  
648  	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
649  		param = pipe->frame_params[i];
650  		if (param)
651  			list_add_tail(&param->list, &pipe->per_frame_params);
652  		pipe->frame_params[i] = NULL;
653  	}
654  	atomisp_handle_parameter_and_buffer(pipe);
655  }
656  
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)657  void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
658  		      enum ia_css_buffer_type buf_type,
659  		      enum ia_css_pipe_id css_pipe_id,
660  		      bool q_buffers, enum atomisp_input_stream_id stream_id)
661  {
662  	struct atomisp_video_pipe *pipe = NULL;
663  	struct atomisp_css_buffer buffer;
664  	bool requeue = false;
665  	unsigned long irqflags;
666  	struct ia_css_frame *frame = NULL;
667  	struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter;
668  	struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp, *dis_iter;
669  	struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter;
670  	enum atomisp_metadata_type md_type;
671  	struct atomisp_device *isp = asd->isp;
672  	int i, err;
673  
674  	lockdep_assert_held(&isp->mutex);
675  
676  	if (
677  	    buf_type != IA_CSS_BUFFER_TYPE_METADATA &&
678  	    buf_type != IA_CSS_BUFFER_TYPE_3A_STATISTICS &&
679  	    buf_type != IA_CSS_BUFFER_TYPE_DIS_STATISTICS &&
680  	    buf_type != IA_CSS_BUFFER_TYPE_OUTPUT_FRAME &&
681  	    buf_type != IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME &&
682  	    buf_type != IA_CSS_BUFFER_TYPE_RAW_OUTPUT_FRAME &&
683  	    buf_type != IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME &&
684  	    buf_type != IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
685  		dev_err(isp->dev, "%s, unsupported buffer type: %d\n",
686  			__func__, buf_type);
687  		return;
688  	}
689  
690  	memset(&buffer, 0, sizeof(struct atomisp_css_buffer));
691  	buffer.css_buffer.type = buf_type;
692  	err = atomisp_css_dequeue_buffer(asd, stream_id, css_pipe_id,
693  					 buf_type, &buffer);
694  	if (err) {
695  		dev_err(isp->dev,
696  			"atomisp_css_dequeue_buffer failed: 0x%x\n", err);
697  		return;
698  	}
699  
700  	switch (buf_type) {
701  	case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
702  		list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp,
703  					 &asd->s3a_stats_in_css, list) {
704  			if (s3a_iter->s3a_data ==
705  			    buffer.css_buffer.data.stats_3a) {
706  				list_del_init(&s3a_iter->list);
707  				list_add_tail(&s3a_iter->list,
708  					      &asd->s3a_stats_ready);
709  				s3a_buf = s3a_iter;
710  				break;
711  			}
712  		}
713  
714  		asd->s3a_bufs_in_css[css_pipe_id]--;
715  		atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id);
716  		if (s3a_buf)
717  			dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n",
718  				__func__, s3a_buf->s3a_data->exp_id);
719  		else
720  			dev_dbg(isp->dev, "%s: s3a stat is ready with no exp_id found\n",
721  				__func__);
722  		break;
723  	case IA_CSS_BUFFER_TYPE_METADATA:
724  		if (error)
725  			break;
726  
727  		md_type = ATOMISP_MAIN_METADATA;
728  		list_for_each_entry_safe(md_iter, _md_buf_tmp,
729  					 &asd->metadata_in_css[md_type], list) {
730  			if (md_iter->metadata ==
731  			    buffer.css_buffer.data.metadata) {
732  				list_del_init(&md_iter->list);
733  				list_add_tail(&md_iter->list,
734  					      &asd->metadata_ready[md_type]);
735  				md_buf = md_iter;
736  				break;
737  			}
738  		}
739  		asd->metadata_bufs_in_css[stream_id][css_pipe_id]--;
740  		atomisp_metadata_ready_event(asd, md_type);
741  		if (md_buf)
742  			dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n",
743  				__func__, md_buf->metadata->exp_id);
744  		else
745  			dev_dbg(isp->dev, "%s: metadata is ready with no exp_id found\n",
746  				__func__);
747  		break;
748  	case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
749  		list_for_each_entry_safe(dis_iter, _dis_buf_tmp,
750  					 &asd->dis_stats_in_css, list) {
751  			if (dis_iter->dis_data ==
752  			    buffer.css_buffer.data.stats_dvs) {
753  				spin_lock_irqsave(&asd->dis_stats_lock,
754  						  irqflags);
755  				list_del_init(&dis_iter->list);
756  				list_add(&dis_iter->list, &asd->dis_stats);
757  				asd->params.dis_proj_data_valid = true;
758  				spin_unlock_irqrestore(&asd->dis_stats_lock,
759  						       irqflags);
760  				dis_buf = dis_iter;
761  				break;
762  			}
763  		}
764  		asd->dis_bufs_in_css--;
765  		if (dis_buf)
766  			dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n",
767  				__func__, dis_buf->dis_data->exp_id);
768  		else
769  			dev_dbg(isp->dev, "%s: dis stat is ready with no exp_id found\n",
770  				__func__);
771  		break;
772  	case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
773  	case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
774  		frame = buffer.css_buffer.data.frame;
775  		if (!frame) {
776  			WARN_ON(1);
777  			break;
778  		}
779  		if (!frame->valid)
780  			error = true;
781  
782  		pipe = vb_to_pipe(&frame->vb.vb2_buf);
783  
784  		dev_dbg(isp->dev, "%s: vf frame with exp_id %d is ready\n",
785  			__func__, frame->exp_id);
786  		pipe->frame_config_id[frame->vb.vb2_buf.index] = frame->isp_config_id;
787  		break;
788  	case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
789  	case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
790  		frame = buffer.css_buffer.data.frame;
791  		if (!frame) {
792  			WARN_ON(1);
793  			break;
794  		}
795  
796  		if (!frame->valid)
797  			error = true;
798  
799  		pipe = vb_to_pipe(&frame->vb.vb2_buf);
800  
801  		dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n",
802  			__func__, frame->exp_id);
803  
804  		i = frame->vb.vb2_buf.index;
805  
806  		/* free the parameters */
807  		if (pipe->frame_params[i]) {
808  			if (asd->params.dvs_6axis == pipe->frame_params[i]->params.dvs_6axis)
809  				asd->params.dvs_6axis = NULL;
810  			atomisp_free_css_parameters(&pipe->frame_params[i]->params);
811  			kvfree(pipe->frame_params[i]);
812  			pipe->frame_params[i] = NULL;
813  		}
814  
815  		pipe->frame_config_id[i] = frame->isp_config_id;
816  
817  		if (asd->params.css_update_params_needed) {
818  			atomisp_apply_css_parameters(asd,
819  						     &asd->params.css_param);
820  			if (asd->params.css_param.update_flag.dz_config)
821  				asd->params.config.dz_config = &asd->params.css_param.dz_config;
822  			/* New global dvs 6axis config should be blocked
823  			 * here if there's a buffer with per-frame parameters
824  			 * pending in CSS frame buffer queue.
825  			 * This is to aviod zooming vibration since global
826  			 * parameters take effect immediately while
827  			 * per-frame parameters are taken after previous
828  			 * buffers in CSS got processed.
829  			 */
830  			if (asd->params.dvs_6axis)
831  				atomisp_css_set_dvs_6axis(asd,
832  							  asd->params.dvs_6axis);
833  			else
834  				asd->params.css_update_params_needed = false;
835  			/* The update flag should not be cleaned here
836  			 * since it is still going to be used to make up
837  			 * following per-frame parameters.
838  			 * This will introduce more copy work since each
839  			 * time when updating global parameters, the whole
840  			 * parameter set are applied.
841  			 * FIXME: A new set of parameter copy functions can
842  			 * be added to make up per-frame parameters based on
843  			 * solid structures stored in asd->params.css_param
844  			 * instead of using shadow pointers in update flag.
845  			 */
846  			atomisp_css_update_isp_params(asd);
847  		}
848  		break;
849  	default:
850  		break;
851  	}
852  	if (frame) {
853  		spin_lock_irqsave(&pipe->irq_lock, irqflags);
854  		atomisp_buffer_done(frame, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
855  		spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
856  	}
857  
858  	/*
859  	 * Requeue should only be done for 3a and dis buffers.
860  	 * Queue/dequeue order will change if driver recycles image buffers.
861  	 */
862  	if (requeue) {
863  		err = atomisp_css_queue_buffer(asd,
864  					       stream_id, css_pipe_id,
865  					       buf_type, &buffer);
866  		if (err)
867  			dev_err(isp->dev, "%s, q to css fails: %d\n",
868  				__func__, err);
869  		return;
870  	}
871  	if (!error && q_buffers)
872  		atomisp_qbuffers_to_css(asd);
873  }
874  
atomisp_assert_recovery_work(struct work_struct * work)875  void atomisp_assert_recovery_work(struct work_struct *work)
876  {
877  	struct atomisp_device *isp = container_of(work, struct atomisp_device,
878  						  assert_recovery_work);
879  	struct pci_dev *pdev = to_pci_dev(isp->dev);
880  	unsigned long flags;
881  	int ret;
882  
883  	mutex_lock(&isp->mutex);
884  
885  	if (!isp->asd.streaming)
886  		goto out_unlock;
887  
888  	atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false);
889  
890  	spin_lock_irqsave(&isp->lock, flags);
891  	isp->asd.streaming = false;
892  	spin_unlock_irqrestore(&isp->lock, flags);
893  
894  	/* stream off sensor */
895  	ret = v4l2_subdev_call(isp->inputs[isp->asd.input_curr].camera, video, s_stream, 0);
896  	if (ret)
897  		dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret);
898  
899  	atomisp_clear_css_buffer_counters(&isp->asd);
900  
901  	atomisp_css_stop(&isp->asd, true);
902  
903  	isp->asd.preview_exp_id = 1;
904  	isp->asd.postview_exp_id = 1;
905  	/* notify HAL the CSS reset */
906  	dev_dbg(isp->dev, "send reset event to %s\n", isp->asd.subdev.devnode->name);
907  	atomisp_reset_event(&isp->asd);
908  
909  	/* clear irq */
910  	disable_isp_irq(hrt_isp_css_irq_sp);
911  	clear_isp_irq(hrt_isp_css_irq_sp);
912  
913  	/* Set the SRSE to 3 before resetting */
914  	pci_write_config_dword(pdev, PCI_I_CONTROL,
915  			       isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK);
916  
917  	/* reset ISP and restore its state */
918  	atomisp_reset(isp);
919  
920  	atomisp_css_input_set_mode(&isp->asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
921  
922  	/* Recreate streams destroyed by atomisp_css_stop() */
923  	atomisp_create_pipes_stream(&isp->asd);
924  
925  	/* Invalidate caches. FIXME: should flush only necessary buffers */
926  	wbinvd();
927  
928  	if (atomisp_css_start(&isp->asd)) {
929  		dev_warn(isp->dev, "start SP failed, so do not set streaming to be enable!\n");
930  	} else {
931  		spin_lock_irqsave(&isp->lock, flags);
932  		isp->asd.streaming = true;
933  		spin_unlock_irqrestore(&isp->lock, flags);
934  	}
935  
936  	atomisp_csi2_configure(&isp->asd);
937  
938  	atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF,
939  			       atomisp_css_valid_sof(isp));
940  
941  	if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0)
942  		dev_dbg(isp->dev, "DFS auto failed while recovering!\n");
943  
944  	/* Dequeueing buffers is not needed, CSS will recycle buffers that it has */
945  	atomisp_flush_video_pipe(&isp->asd.video_out, VB2_BUF_STATE_ERROR, false);
946  
947  	/* Requeue unprocessed per-frame parameters. */
948  	atomisp_recover_params_queue(&isp->asd.video_out);
949  
950  	ret = v4l2_subdev_call(isp->inputs[isp->asd.input_curr].camera, video, s_stream, 1);
951  	if (ret)
952  		dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret);
953  
954  out_unlock:
955  	mutex_unlock(&isp->mutex);
956  }
957  
atomisp_isr_thread(int irq,void * isp_ptr)958  irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
959  {
960  	struct atomisp_device *isp = isp_ptr;
961  	unsigned long flags;
962  	bool streaming;
963  
964  	spin_lock_irqsave(&isp->lock, flags);
965  	streaming = isp->asd.streaming;
966  	spin_unlock_irqrestore(&isp->lock, flags);
967  
968  	if (!streaming)
969  		return IRQ_HANDLED;
970  
971  	/*
972  	 * The standard CSS2.0 API tells the following calling sequence of
973  	 * dequeue ready buffers:
974  	 * while (ia_css_dequeue_psys_event(...)) {
975  	 *	switch (event.type) {
976  	 *	...
977  	 *	ia_css_pipe_dequeue_buffer()
978  	 *	}
979  	 * }
980  	 * That is, dequeue event and buffer are one after another.
981  	 *
982  	 * But the following implementation is to first deuque all the event
983  	 * to a FIFO, then process the event in the FIFO.
984  	 * This will not have issue in single stream mode, but it do have some
985  	 * issue in multiple stream case. The issue is that
986  	 * ia_css_pipe_dequeue_buffer() will not return the corrent buffer in
987  	 * a specific pipe.
988  	 *
989  	 * This is due to ia_css_pipe_dequeue_buffer() does not take the
990  	 * ia_css_pipe parameter.
991  	 *
992  	 * So:
993  	 * For CSS2.0: we change the way to not dequeue all the event at one
994  	 * time, instead, dequue one and process one, then another
995  	 */
996  	mutex_lock(&isp->mutex);
997  	atomisp_css_isr_thread(isp);
998  	mutex_unlock(&isp->mutex);
999  
1000  	return IRQ_HANDLED;
1001  }
1002  
1003  /*
1004   * Get internal fmt according to V4L2 fmt
1005   */
1006  static enum ia_css_frame_format
v4l2_fmt_to_sh_fmt(u32 fmt)1007  v4l2_fmt_to_sh_fmt(u32 fmt)
1008  {
1009  	switch (fmt) {
1010  	case V4L2_PIX_FMT_YUV420:
1011  				return IA_CSS_FRAME_FORMAT_YUV420;
1012  	case V4L2_PIX_FMT_YVU420:
1013  		return IA_CSS_FRAME_FORMAT_YV12;
1014  	case V4L2_PIX_FMT_YUV422P:
1015  		return IA_CSS_FRAME_FORMAT_YUV422;
1016  	case V4L2_PIX_FMT_YUV444:
1017  		return IA_CSS_FRAME_FORMAT_YUV444;
1018  	case V4L2_PIX_FMT_NV12:
1019  		return IA_CSS_FRAME_FORMAT_NV12;
1020  	case V4L2_PIX_FMT_NV21:
1021  		return IA_CSS_FRAME_FORMAT_NV21;
1022  	case V4L2_PIX_FMT_NV16:
1023  		return IA_CSS_FRAME_FORMAT_NV16;
1024  	case V4L2_PIX_FMT_NV61:
1025  		return IA_CSS_FRAME_FORMAT_NV61;
1026  	case V4L2_PIX_FMT_UYVY:
1027  		return IA_CSS_FRAME_FORMAT_UYVY;
1028  	case V4L2_PIX_FMT_YUYV:
1029  		return IA_CSS_FRAME_FORMAT_YUYV;
1030  	case V4L2_PIX_FMT_RGB24:
1031  		return IA_CSS_FRAME_FORMAT_PLANAR_RGB888;
1032  	case V4L2_PIX_FMT_RGBX32:
1033  		return IA_CSS_FRAME_FORMAT_RGBA888;
1034  	case V4L2_PIX_FMT_RGB565:
1035  		return IA_CSS_FRAME_FORMAT_RGB565;
1036  #if 0
1037  	case V4L2_PIX_FMT_JPEG:
1038  	case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
1039  		return IA_CSS_FRAME_FORMAT_BINARY_8;
1040  #endif
1041  	case V4L2_PIX_FMT_SBGGR16:
1042  	case V4L2_PIX_FMT_SBGGR10:
1043  	case V4L2_PIX_FMT_SGBRG10:
1044  	case V4L2_PIX_FMT_SGRBG10:
1045  	case V4L2_PIX_FMT_SRGGB10:
1046  	case V4L2_PIX_FMT_SBGGR12:
1047  	case V4L2_PIX_FMT_SGBRG12:
1048  	case V4L2_PIX_FMT_SGRBG12:
1049  	case V4L2_PIX_FMT_SRGGB12:
1050  	case V4L2_PIX_FMT_SBGGR8:
1051  	case V4L2_PIX_FMT_SGBRG8:
1052  	case V4L2_PIX_FMT_SGRBG8:
1053  	case V4L2_PIX_FMT_SRGGB8:
1054  		return IA_CSS_FRAME_FORMAT_RAW;
1055  	default:
1056  		return -EINVAL;
1057  	}
1058  }
1059  
1060  /*
1061   * raw format match between SH format and V4L2 format
1062   */
raw_output_format_match_input(u32 input,u32 output)1063  static int raw_output_format_match_input(u32 input, u32 output)
1064  {
1065  	if ((input == ATOMISP_INPUT_FORMAT_RAW_12) &&
1066  	    ((output == V4L2_PIX_FMT_SRGGB12) ||
1067  	     (output == V4L2_PIX_FMT_SGRBG12) ||
1068  	     (output == V4L2_PIX_FMT_SBGGR12) ||
1069  	     (output == V4L2_PIX_FMT_SGBRG12)))
1070  		return 0;
1071  
1072  	if ((input == ATOMISP_INPUT_FORMAT_RAW_10) &&
1073  	    ((output == V4L2_PIX_FMT_SRGGB10) ||
1074  	     (output == V4L2_PIX_FMT_SGRBG10) ||
1075  	     (output == V4L2_PIX_FMT_SBGGR10) ||
1076  	     (output == V4L2_PIX_FMT_SGBRG10)))
1077  		return 0;
1078  
1079  	if ((input == ATOMISP_INPUT_FORMAT_RAW_8) &&
1080  	    ((output == V4L2_PIX_FMT_SRGGB8) ||
1081  	     (output == V4L2_PIX_FMT_SGRBG8) ||
1082  	     (output == V4L2_PIX_FMT_SBGGR8) ||
1083  	     (output == V4L2_PIX_FMT_SGBRG8)))
1084  		return 0;
1085  
1086  	if ((input == ATOMISP_INPUT_FORMAT_RAW_16) && (output == V4L2_PIX_FMT_SBGGR16))
1087  		return 0;
1088  
1089  	return -EINVAL;
1090  }
1091  
atomisp_get_pixel_depth(u32 pixelformat)1092  u32 atomisp_get_pixel_depth(u32 pixelformat)
1093  {
1094  	switch (pixelformat) {
1095  	case V4L2_PIX_FMT_YUV420:
1096  	case V4L2_PIX_FMT_NV12:
1097  	case V4L2_PIX_FMT_NV21:
1098  	case V4L2_PIX_FMT_YVU420:
1099  		return 12;
1100  	case V4L2_PIX_FMT_YUV422P:
1101  	case V4L2_PIX_FMT_YUYV:
1102  	case V4L2_PIX_FMT_UYVY:
1103  	case V4L2_PIX_FMT_NV16:
1104  	case V4L2_PIX_FMT_NV61:
1105  	case V4L2_PIX_FMT_RGB565:
1106  	case V4L2_PIX_FMT_SBGGR16:
1107  	case V4L2_PIX_FMT_SBGGR12:
1108  	case V4L2_PIX_FMT_SGBRG12:
1109  	case V4L2_PIX_FMT_SGRBG12:
1110  	case V4L2_PIX_FMT_SRGGB12:
1111  	case V4L2_PIX_FMT_SBGGR10:
1112  	case V4L2_PIX_FMT_SGBRG10:
1113  	case V4L2_PIX_FMT_SGRBG10:
1114  	case V4L2_PIX_FMT_SRGGB10:
1115  		return 16;
1116  	case V4L2_PIX_FMT_RGB24:
1117  	case V4L2_PIX_FMT_YUV444:
1118  		return 24;
1119  	case V4L2_PIX_FMT_RGBX32:
1120  		return 32;
1121  	case V4L2_PIX_FMT_JPEG:
1122  	case V4L2_PIX_FMT_CUSTOM_M10MO_RAW:
1123  	case V4L2_PIX_FMT_SBGGR8:
1124  	case V4L2_PIX_FMT_SGBRG8:
1125  	case V4L2_PIX_FMT_SGRBG8:
1126  	case V4L2_PIX_FMT_SRGGB8:
1127  		return 8;
1128  	default:
1129  		return 8 * 2;	/* raw type now */
1130  	}
1131  }
1132  
atomisp_is_mbuscode_raw(uint32_t code)1133  bool atomisp_is_mbuscode_raw(uint32_t code)
1134  {
1135  	return code >= 0x3000 && code < 0x4000;
1136  }
1137  
1138  /*
1139   * ISP features control function
1140   */
1141  
1142  /*
1143   * Set ISP capture mode based on current settings
1144   */
atomisp_update_capture_mode(struct atomisp_sub_device * asd)1145  static void atomisp_update_capture_mode(struct atomisp_sub_device *asd)
1146  {
1147  	if (asd->params.gdc_cac_en)
1148  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_ADVANCED);
1149  	else if (asd->params.low_light)
1150  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_LOW_LIGHT);
1151  	else if (asd->video_out.sh_fmt == IA_CSS_FRAME_FORMAT_RAW)
1152  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW);
1153  	else
1154  		atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_PRIMARY);
1155  }
1156  
1157  /*
1158   * Function to enable/disable lens geometry distortion correction (GDC) and
1159   * chromatic aberration correction (CAC)
1160   */
atomisp_gdc_cac(struct atomisp_sub_device * asd,int flag,__s32 * value)1161  int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag,
1162  		    __s32 *value)
1163  {
1164  	if (flag == 0) {
1165  		*value = asd->params.gdc_cac_en;
1166  		return 0;
1167  	}
1168  
1169  	asd->params.gdc_cac_en = !!*value;
1170  	if (asd->params.gdc_cac_en)
1171  		asd->params.config.morph_table = asd->params.css_param.morph_table;
1172  	else
1173  		asd->params.config.morph_table = NULL;
1174  
1175  	asd->params.css_update_params_needed = true;
1176  	atomisp_update_capture_mode(asd);
1177  	return 0;
1178  }
1179  
1180  /*
1181   * Function to enable/disable low light mode including ANR
1182   */
atomisp_low_light(struct atomisp_sub_device * asd,int flag,__s32 * value)1183  int atomisp_low_light(struct atomisp_sub_device *asd, int flag,
1184  		      __s32 *value)
1185  {
1186  	if (flag == 0) {
1187  		*value = asd->params.low_light;
1188  		return 0;
1189  	}
1190  
1191  	asd->params.low_light = (*value != 0);
1192  	atomisp_update_capture_mode(asd);
1193  	return 0;
1194  }
1195  
1196  /*
1197   * Function to enable/disable extra noise reduction (XNR) in low light
1198   * condition
1199   */
atomisp_xnr(struct atomisp_sub_device * asd,int flag,int * xnr_enable)1200  int atomisp_xnr(struct atomisp_sub_device *asd, int flag,
1201  		int *xnr_enable)
1202  {
1203  	if (flag == 0) {
1204  		*xnr_enable = asd->params.xnr_en;
1205  		return 0;
1206  	}
1207  
1208  	atomisp_css_capture_enable_xnr(asd, !!*xnr_enable);
1209  
1210  	return 0;
1211  }
1212  
1213  /*
1214   * Function to configure bayer noise reduction
1215   */
atomisp_nr(struct atomisp_sub_device * asd,int flag,struct atomisp_nr_config * arg)1216  int atomisp_nr(struct atomisp_sub_device *asd, int flag,
1217  	       struct atomisp_nr_config *arg)
1218  {
1219  	if (flag == 0) {
1220  		/* Get nr config from current setup */
1221  		if (atomisp_css_get_nr_config(asd, arg))
1222  			return -EINVAL;
1223  	} else {
1224  		/* Set nr config to isp parameters */
1225  		memcpy(&asd->params.css_param.nr_config, arg,
1226  		       sizeof(struct ia_css_nr_config));
1227  		asd->params.config.nr_config = &asd->params.css_param.nr_config;
1228  		asd->params.css_update_params_needed = true;
1229  	}
1230  	return 0;
1231  }
1232  
1233  /*
1234   * Function to configure temporal noise reduction (TNR)
1235   */
atomisp_tnr(struct atomisp_sub_device * asd,int flag,struct atomisp_tnr_config * config)1236  int atomisp_tnr(struct atomisp_sub_device *asd, int flag,
1237  		struct atomisp_tnr_config *config)
1238  {
1239  	/* Get tnr config from current setup */
1240  	if (flag == 0) {
1241  		/* Get tnr config from current setup */
1242  		if (atomisp_css_get_tnr_config(asd, config))
1243  			return -EINVAL;
1244  	} else {
1245  		/* Set tnr config to isp parameters */
1246  		memcpy(&asd->params.css_param.tnr_config, config,
1247  		       sizeof(struct ia_css_tnr_config));
1248  		asd->params.config.tnr_config = &asd->params.css_param.tnr_config;
1249  		asd->params.css_update_params_needed = true;
1250  	}
1251  
1252  	return 0;
1253  }
1254  
1255  /*
1256   * Function to configure black level compensation
1257   */
atomisp_black_level(struct atomisp_sub_device * asd,int flag,struct atomisp_ob_config * config)1258  int atomisp_black_level(struct atomisp_sub_device *asd, int flag,
1259  			struct atomisp_ob_config *config)
1260  {
1261  	if (flag == 0) {
1262  		/* Get ob config from current setup */
1263  		if (atomisp_css_get_ob_config(asd, config))
1264  			return -EINVAL;
1265  	} else {
1266  		/* Set ob config to isp parameters */
1267  		memcpy(&asd->params.css_param.ob_config, config,
1268  		       sizeof(struct ia_css_ob_config));
1269  		asd->params.config.ob_config = &asd->params.css_param.ob_config;
1270  		asd->params.css_update_params_needed = true;
1271  	}
1272  
1273  	return 0;
1274  }
1275  
1276  /*
1277   * Function to configure edge enhancement
1278   */
atomisp_ee(struct atomisp_sub_device * asd,int flag,struct atomisp_ee_config * config)1279  int atomisp_ee(struct atomisp_sub_device *asd, int flag,
1280  	       struct atomisp_ee_config *config)
1281  {
1282  	if (flag == 0) {
1283  		/* Get ee config from current setup */
1284  		if (atomisp_css_get_ee_config(asd, config))
1285  			return -EINVAL;
1286  	} else {
1287  		/* Set ee config to isp parameters */
1288  		memcpy(&asd->params.css_param.ee_config, config,
1289  		       sizeof(asd->params.css_param.ee_config));
1290  		asd->params.config.ee_config = &asd->params.css_param.ee_config;
1291  		asd->params.css_update_params_needed = true;
1292  	}
1293  
1294  	return 0;
1295  }
1296  
1297  /*
1298   * Function to update Gamma table for gamma, brightness and contrast config
1299   */
atomisp_gamma(struct atomisp_sub_device * asd,int flag,struct atomisp_gamma_table * config)1300  int atomisp_gamma(struct atomisp_sub_device *asd, int flag,
1301  		  struct atomisp_gamma_table *config)
1302  {
1303  	if (flag == 0) {
1304  		/* Get gamma table from current setup */
1305  		if (atomisp_css_get_gamma_table(asd, config))
1306  			return -EINVAL;
1307  	} else {
1308  		/* Set gamma table to isp parameters */
1309  		memcpy(&asd->params.css_param.gamma_table, config,
1310  		       sizeof(asd->params.css_param.gamma_table));
1311  		asd->params.config.gamma_table = &asd->params.css_param.gamma_table;
1312  	}
1313  
1314  	return 0;
1315  }
1316  
1317  /*
1318   * Function to update Ctc table for Chroma Enhancement
1319   */
atomisp_ctc(struct atomisp_sub_device * asd,int flag,struct atomisp_ctc_table * config)1320  int atomisp_ctc(struct atomisp_sub_device *asd, int flag,
1321  		struct atomisp_ctc_table *config)
1322  {
1323  	if (flag == 0) {
1324  		/* Get ctc table from current setup */
1325  		if (atomisp_css_get_ctc_table(asd, config))
1326  			return -EINVAL;
1327  	} else {
1328  		/* Set ctc table to isp parameters */
1329  		memcpy(&asd->params.css_param.ctc_table, config,
1330  		       sizeof(asd->params.css_param.ctc_table));
1331  		atomisp_css_set_ctc_table(asd, &asd->params.css_param.ctc_table);
1332  	}
1333  
1334  	return 0;
1335  }
1336  
1337  /*
1338   * Function to update gamma correction parameters
1339   */
atomisp_gamma_correction(struct atomisp_sub_device * asd,int flag,struct atomisp_gc_config * config)1340  int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag,
1341  			     struct atomisp_gc_config *config)
1342  {
1343  	if (flag == 0) {
1344  		/* Get gamma correction params from current setup */
1345  		if (atomisp_css_get_gc_config(asd, config))
1346  			return -EINVAL;
1347  	} else {
1348  		/* Set gamma correction params to isp parameters */
1349  		memcpy(&asd->params.css_param.gc_config, config,
1350  		       sizeof(asd->params.css_param.gc_config));
1351  		asd->params.config.gc_config = &asd->params.css_param.gc_config;
1352  		asd->params.css_update_params_needed = true;
1353  	}
1354  
1355  	return 0;
1356  }
1357  
1358  /*
1359   * Function to update narrow gamma flag
1360   */
atomisp_formats(struct atomisp_sub_device * asd,int flag,struct atomisp_formats_config * config)1361  int atomisp_formats(struct atomisp_sub_device *asd, int flag,
1362  		    struct atomisp_formats_config *config)
1363  {
1364  	if (flag == 0) {
1365  		/* Get narrow gamma flag from current setup */
1366  		if (atomisp_css_get_formats_config(asd, config))
1367  			return -EINVAL;
1368  	} else {
1369  		/* Set narrow gamma flag to isp parameters */
1370  		memcpy(&asd->params.css_param.formats_config, config,
1371  		       sizeof(asd->params.css_param.formats_config));
1372  		asd->params.config.formats_config = &asd->params.css_param.formats_config;
1373  	}
1374  
1375  	return 0;
1376  }
1377  
atomisp_free_internal_buffers(struct atomisp_sub_device * asd)1378  void atomisp_free_internal_buffers(struct atomisp_sub_device *asd)
1379  {
1380  	atomisp_free_css_parameters(&asd->params.css_param);
1381  }
1382  
atomisp_update_grid_info(struct atomisp_sub_device * asd,enum ia_css_pipe_id pipe_id)1383  static void atomisp_update_grid_info(struct atomisp_sub_device *asd,
1384  				     enum ia_css_pipe_id pipe_id)
1385  {
1386  	struct atomisp_device *isp = asd->isp;
1387  	int err;
1388  
1389  	if (atomisp_css_get_grid_info(asd, pipe_id))
1390  		return;
1391  
1392  	/* We must free all buffers because they no longer match
1393  	   the grid size. */
1394  	atomisp_css_free_stat_buffers(asd);
1395  
1396  	err = atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL);
1397  	if (err) {
1398  		dev_err(isp->dev, "stat_buf allocate error\n");
1399  		goto err;
1400  	}
1401  
1402  	if (atomisp_alloc_3a_output_buf(asd)) {
1403  		/* Failure for 3A buffers does not influence DIS buffers */
1404  		if (asd->params.s3a_output_bytes != 0) {
1405  			/* For SOC sensor happens s3a_output_bytes == 0,
1406  			 * using if condition to exclude false error log */
1407  			dev_err(isp->dev, "Failed to allocate memory for 3A statistics\n");
1408  		}
1409  		goto err;
1410  	}
1411  
1412  	if (atomisp_alloc_dis_coef_buf(asd)) {
1413  		dev_err(isp->dev,
1414  			"Failed to allocate memory for DIS statistics\n");
1415  		goto err;
1416  	}
1417  
1418  	if (atomisp_alloc_metadata_output_buf(asd)) {
1419  		dev_err(isp->dev, "Failed to allocate memory for metadata\n");
1420  		goto err;
1421  	}
1422  
1423  	return;
1424  
1425  err:
1426  	atomisp_css_free_stat_buffers(asd);
1427  	return;
1428  }
1429  
atomisp_curr_user_grid_info(struct atomisp_sub_device * asd,struct atomisp_grid_info * info)1430  static void atomisp_curr_user_grid_info(struct atomisp_sub_device *asd,
1431  					struct atomisp_grid_info *info)
1432  {
1433  	memcpy(info, &asd->params.curr_grid_info.s3a_grid,
1434  	       sizeof(struct ia_css_3a_grid_info));
1435  }
1436  
atomisp_compare_grid(struct atomisp_sub_device * asd,struct atomisp_grid_info * atomgrid)1437  int atomisp_compare_grid(struct atomisp_sub_device *asd,
1438  			 struct atomisp_grid_info *atomgrid)
1439  {
1440  	struct atomisp_grid_info tmp = {0};
1441  
1442  	atomisp_curr_user_grid_info(asd, &tmp);
1443  	return memcmp(atomgrid, &tmp, sizeof(tmp));
1444  }
1445  
1446  /*
1447   * Function to update Gdc table for gdc
1448   */
atomisp_gdc_cac_table(struct atomisp_sub_device * asd,int flag,struct atomisp_morph_table * config)1449  int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag,
1450  			  struct atomisp_morph_table *config)
1451  {
1452  	int ret;
1453  	int i;
1454  	struct atomisp_device *isp = asd->isp;
1455  
1456  	if (flag == 0) {
1457  		/* Get gdc table from current setup */
1458  		struct ia_css_morph_table tab = {0};
1459  
1460  		atomisp_css_get_morph_table(asd, &tab);
1461  
1462  		config->width = tab.width;
1463  		config->height = tab.height;
1464  
1465  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
1466  			ret = copy_to_user(config->coordinates_x[i],
1467  					   tab.coordinates_x[i], tab.height *
1468  					   tab.width * sizeof(*tab.coordinates_x[i]));
1469  			if (ret) {
1470  				dev_err(isp->dev,
1471  					"Failed to copy to User for x\n");
1472  				return -EFAULT;
1473  			}
1474  			ret = copy_to_user(config->coordinates_y[i],
1475  					   tab.coordinates_y[i], tab.height *
1476  					   tab.width * sizeof(*tab.coordinates_y[i]));
1477  			if (ret) {
1478  				dev_err(isp->dev,
1479  					"Failed to copy to User for y\n");
1480  				return -EFAULT;
1481  			}
1482  		}
1483  	} else {
1484  		struct ia_css_morph_table *tab =
1485  			    asd->params.css_param.morph_table;
1486  
1487  		/* free first if we have one */
1488  		if (tab) {
1489  			atomisp_css_morph_table_free(tab);
1490  			asd->params.css_param.morph_table = NULL;
1491  		}
1492  
1493  		/* allocate new one */
1494  		tab = atomisp_css_morph_table_allocate(config->width,
1495  						       config->height);
1496  
1497  		if (!tab) {
1498  			dev_err(isp->dev, "out of memory\n");
1499  			return -EINVAL;
1500  		}
1501  
1502  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
1503  			ret = copy_from_user(tab->coordinates_x[i],
1504  					     config->coordinates_x[i],
1505  					     config->height * config->width *
1506  					     sizeof(*config->coordinates_x[i]));
1507  			if (ret) {
1508  				dev_err(isp->dev,
1509  					"Failed to copy from User for x, ret %d\n",
1510  					ret);
1511  				atomisp_css_morph_table_free(tab);
1512  				return -EFAULT;
1513  			}
1514  			ret = copy_from_user(tab->coordinates_y[i],
1515  					     config->coordinates_y[i],
1516  					     config->height * config->width *
1517  					     sizeof(*config->coordinates_y[i]));
1518  			if (ret) {
1519  				dev_err(isp->dev,
1520  					"Failed to copy from User for y, ret is %d\n",
1521  					ret);
1522  				atomisp_css_morph_table_free(tab);
1523  				return -EFAULT;
1524  			}
1525  		}
1526  		asd->params.css_param.morph_table = tab;
1527  		if (asd->params.gdc_cac_en)
1528  			asd->params.config.morph_table = tab;
1529  	}
1530  
1531  	return 0;
1532  }
1533  
atomisp_macc_table(struct atomisp_sub_device * asd,int flag,struct atomisp_macc_config * config)1534  int atomisp_macc_table(struct atomisp_sub_device *asd, int flag,
1535  		       struct atomisp_macc_config *config)
1536  {
1537  	struct ia_css_macc_table *macc_table;
1538  
1539  	switch (config->color_effect) {
1540  	case V4L2_COLORFX_NONE:
1541  		macc_table = &asd->params.css_param.macc_table;
1542  		break;
1543  	case V4L2_COLORFX_SKY_BLUE:
1544  		macc_table = &blue_macc_table;
1545  		break;
1546  	case V4L2_COLORFX_GRASS_GREEN:
1547  		macc_table = &green_macc_table;
1548  		break;
1549  	case V4L2_COLORFX_SKIN_WHITEN_LOW:
1550  		macc_table = &skin_low_macc_table;
1551  		break;
1552  	case V4L2_COLORFX_SKIN_WHITEN:
1553  		macc_table = &skin_medium_macc_table;
1554  		break;
1555  	case V4L2_COLORFX_SKIN_WHITEN_HIGH:
1556  		macc_table = &skin_high_macc_table;
1557  		break;
1558  	default:
1559  		return -EINVAL;
1560  	}
1561  
1562  	if (flag == 0) {
1563  		/* Get macc table from current setup */
1564  		memcpy(&config->table, macc_table,
1565  		       sizeof(struct ia_css_macc_table));
1566  	} else {
1567  		memcpy(macc_table, &config->table,
1568  		       sizeof(struct ia_css_macc_table));
1569  		if (config->color_effect == asd->params.color_effect)
1570  			asd->params.config.macc_table = macc_table;
1571  	}
1572  
1573  	return 0;
1574  }
1575  
atomisp_set_dis_vector(struct atomisp_sub_device * asd,struct atomisp_dis_vector * vector)1576  int atomisp_set_dis_vector(struct atomisp_sub_device *asd,
1577  			   struct atomisp_dis_vector *vector)
1578  {
1579  	atomisp_css_video_set_dis_vector(asd, vector);
1580  
1581  	asd->params.dis_proj_data_valid = false;
1582  	asd->params.css_update_params_needed = true;
1583  	return 0;
1584  }
1585  
1586  /*
1587   * Function to set/get image stablization statistics
1588   */
atomisp_get_dis_stat(struct atomisp_sub_device * asd,struct atomisp_dis_statistics * stats)1589  int atomisp_get_dis_stat(struct atomisp_sub_device *asd,
1590  			 struct atomisp_dis_statistics *stats)
1591  {
1592  	return atomisp_css_get_dis_stat(asd, stats);
1593  }
1594  
1595  /*
1596   * Function  set camrea_prefiles.xml current sensor pixel array size
1597   */
atomisp_set_array_res(struct atomisp_sub_device * asd,struct atomisp_resolution * config)1598  int atomisp_set_array_res(struct atomisp_sub_device *asd,
1599  			  struct atomisp_resolution  *config)
1600  {
1601  	dev_dbg(asd->isp->dev, ">%s start\n", __func__);
1602  	if (!config) {
1603  		dev_err(asd->isp->dev, "Set sensor array size is not valid\n");
1604  		return -EINVAL;
1605  	}
1606  
1607  	asd->sensor_array_res.width = config->width;
1608  	asd->sensor_array_res.height = config->height;
1609  	return 0;
1610  }
1611  
1612  /*
1613   * Function to get DVS2 BQ resolution settings
1614   */
atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device * asd,struct atomisp_dvs2_bq_resolutions * bq_res)1615  int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd,
1616  				    struct atomisp_dvs2_bq_resolutions *bq_res)
1617  {
1618  	struct ia_css_pipe_config *pipe_cfg = NULL;
1619  
1620  	struct ia_css_stream *stream =
1621  		    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
1622  	if (!stream) {
1623  		dev_warn(asd->isp->dev, "stream is not created");
1624  		return -EAGAIN;
1625  	}
1626  
1627  	pipe_cfg = &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
1628  		   .pipe_configs[IA_CSS_PIPE_ID_VIDEO];
1629  
1630  	if (!bq_res)
1631  		return -EINVAL;
1632  
1633  	/* the GDC output resolution */
1634  	bq_res->output_bq.width_bq = pipe_cfg->output_info[0].res.width / 2;
1635  	bq_res->output_bq.height_bq = pipe_cfg->output_info[0].res.height / 2;
1636  
1637  	bq_res->envelope_bq.width_bq = 0;
1638  	bq_res->envelope_bq.height_bq = 0;
1639  	/* the GDC input resolution */
1640  	bq_res->source_bq.width_bq = bq_res->output_bq.width_bq +
1641  				     pipe_cfg->dvs_envelope.width / 2;
1642  	bq_res->source_bq.height_bq = bq_res->output_bq.height_bq +
1643  				      pipe_cfg->dvs_envelope.height / 2;
1644  	/*
1645  	 * Bad pixels caused by spatial filter processing
1646  	 * ISP filter resolution should be given by CSS/FW, but for now
1647  	 * there is not such API to query, and it is fixed value, so
1648  	 * hardcoded here.
1649  	 */
1650  	bq_res->ispfilter_bq.width_bq = 12 / 2;
1651  	bq_res->ispfilter_bq.height_bq = 12 / 2;
1652  	/* spatial filter shift, always 4 pixels */
1653  	bq_res->gdc_shift_bq.width_bq = 4 / 2;
1654  	bq_res->gdc_shift_bq.height_bq = 4 / 2;
1655  
1656  	if (asd->params.video_dis_en) {
1657  		bq_res->envelope_bq.width_bq = pipe_cfg->dvs_envelope.width / 2 -
1658  					       bq_res->ispfilter_bq.width_bq;
1659  		bq_res->envelope_bq.height_bq = pipe_cfg->dvs_envelope.height / 2 -
1660  						bq_res->ispfilter_bq.height_bq;
1661  	}
1662  
1663  	dev_dbg(asd->isp->dev,
1664  		"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",
1665  		bq_res->source_bq.width_bq, bq_res->source_bq.height_bq,
1666  		bq_res->ispfilter_bq.width_bq, bq_res->ispfilter_bq.height_bq,
1667  		bq_res->gdc_shift_bq.width_bq, bq_res->gdc_shift_bq.height_bq,
1668  		bq_res->envelope_bq.width_bq, bq_res->envelope_bq.height_bq,
1669  		bq_res->output_bq.width_bq, bq_res->output_bq.height_bq);
1670  
1671  	return 0;
1672  }
1673  
atomisp_set_dis_coefs(struct atomisp_sub_device * asd,struct atomisp_dis_coefficients * coefs)1674  int atomisp_set_dis_coefs(struct atomisp_sub_device *asd,
1675  			  struct atomisp_dis_coefficients *coefs)
1676  {
1677  	return atomisp_css_set_dis_coefs(asd, coefs);
1678  }
1679  
1680  /*
1681   * Function to set/get 3A stat from isp
1682   */
atomisp_3a_stat(struct atomisp_sub_device * asd,int flag,struct atomisp_3a_statistics * config)1683  int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag,
1684  		    struct atomisp_3a_statistics *config)
1685  {
1686  	struct atomisp_device *isp = asd->isp;
1687  	struct atomisp_s3a_buf *s3a_buf;
1688  	unsigned long ret;
1689  
1690  	if (flag != 0)
1691  		return -EINVAL;
1692  
1693  	/* sanity check to avoid writing into unallocated memory. */
1694  	if (asd->params.s3a_output_bytes == 0)
1695  		return -EINVAL;
1696  
1697  	if (atomisp_compare_grid(asd, &config->grid_info) != 0) {
1698  		/* If the grid info in the argument differs from the current
1699  		   grid info, we tell the caller to reset the grid size and
1700  		   try again. */
1701  		return -EAGAIN;
1702  	}
1703  
1704  	if (list_empty(&asd->s3a_stats_ready)) {
1705  		dev_err(isp->dev, "3a statistics is not valid.\n");
1706  		return -EAGAIN;
1707  	}
1708  
1709  	s3a_buf = list_entry(asd->s3a_stats_ready.next,
1710  			     struct atomisp_s3a_buf, list);
1711  	if (s3a_buf->s3a_map)
1712  		ia_css_translate_3a_statistics(
1713  		    asd->params.s3a_user_stat, s3a_buf->s3a_map);
1714  	else
1715  		ia_css_get_3a_statistics(asd->params.s3a_user_stat,
1716  					 s3a_buf->s3a_data);
1717  
1718  	config->exp_id = s3a_buf->s3a_data->exp_id;
1719  	config->isp_config_id = s3a_buf->s3a_data->isp_config_id;
1720  
1721  	ret = copy_to_user(config->data, asd->params.s3a_user_stat->data,
1722  			   asd->params.s3a_output_bytes);
1723  	if (ret) {
1724  		dev_err(isp->dev, "copy to user failed: copied %lu bytes\n",
1725  			ret);
1726  		return -EFAULT;
1727  	}
1728  
1729  	/* Move to free buffer list */
1730  	list_del_init(&s3a_buf->list);
1731  	list_add_tail(&s3a_buf->list, &asd->s3a_stats);
1732  	dev_dbg(isp->dev, "%s: finish getting exp_id %d 3a stat, isp_config_id %d\n",
1733  		__func__,
1734  		config->exp_id, config->isp_config_id);
1735  	return 0;
1736  }
1737  
1738  /*
1739   * Function to calculate real zoom region for every pipe
1740   */
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)1741  int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd,
1742  				       struct ia_css_dz_config   *dz_config,
1743  				       enum ia_css_pipe_id css_pipe_id)
1744  
1745  {
1746  	struct atomisp_stream_env *stream_env =
1747  		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
1748  	struct atomisp_resolution  eff_res, out_res;
1749  	int w_offset, h_offset;
1750  
1751  	memset(&eff_res, 0, sizeof(eff_res));
1752  	memset(&out_res, 0, sizeof(out_res));
1753  
1754  	if (dz_config->dx || dz_config->dy)
1755  		return 0;
1756  
1757  	if (css_pipe_id != IA_CSS_PIPE_ID_PREVIEW
1758  	    && css_pipe_id != IA_CSS_PIPE_ID_CAPTURE) {
1759  		dev_err(asd->isp->dev, "%s the set pipe no support crop region"
1760  			, __func__);
1761  		return -EINVAL;
1762  	}
1763  
1764  	eff_res.width =
1765  	    stream_env->stream_config.input_config.effective_res.width;
1766  	eff_res.height =
1767  	    stream_env->stream_config.input_config.effective_res.height;
1768  	if (eff_res.width == 0 || eff_res.height == 0) {
1769  		dev_err(asd->isp->dev, "%s err effective resolution"
1770  			, __func__);
1771  		return -EINVAL;
1772  	}
1773  
1774  	if (dz_config->zoom_region.resolution.width
1775  	    == asd->sensor_array_res.width
1776  	    || dz_config->zoom_region.resolution.height
1777  	    == asd->sensor_array_res.height) {
1778  		/*no need crop region*/
1779  		dz_config->zoom_region.origin.x = 0;
1780  		dz_config->zoom_region.origin.y = 0;
1781  		dz_config->zoom_region.resolution.width = eff_res.width;
1782  		dz_config->zoom_region.resolution.height = eff_res.height;
1783  		return 0;
1784  	}
1785  
1786  	/* FIXME:
1787  	 * This is not the correct implementation with Google's definition, due
1788  	 * to firmware limitation.
1789  	 * map real crop region base on above calculating base max crop region.
1790  	 */
1791  
1792  	if (!IS_ISP2401) {
1793  		dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x
1794  						  * eff_res.width
1795  						  / asd->sensor_array_res.width;
1796  		dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y
1797  						  * eff_res.height
1798  						  / asd->sensor_array_res.height;
1799  		dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width
1800  							  * eff_res.width
1801  							  / asd->sensor_array_res.width;
1802  		dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height
1803  							  * eff_res.height
1804  							  / asd->sensor_array_res.height;
1805  		/*
1806  		 * Set same ratio of crop region resolution and current pipe output
1807  		 * resolution
1808  		 */
1809  		out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
1810  		out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
1811  		if (out_res.width == 0 || out_res.height == 0) {
1812  			dev_err(asd->isp->dev, "%s err current pipe output resolution"
1813  				, __func__);
1814  			return -EINVAL;
1815  		}
1816  	} else {
1817  		out_res.width = stream_env->pipe_configs[css_pipe_id].output_info[0].res.width;
1818  		out_res.height = stream_env->pipe_configs[css_pipe_id].output_info[0].res.height;
1819  		if (out_res.width == 0 || out_res.height == 0) {
1820  			dev_err(asd->isp->dev, "%s err current pipe output resolution"
1821  				, __func__);
1822  			return -EINVAL;
1823  		}
1824  
1825  		if (asd->sensor_array_res.width * out_res.height
1826  		    < out_res.width * asd->sensor_array_res.height) {
1827  			h_offset = asd->sensor_array_res.height
1828  				   - asd->sensor_array_res.width
1829  				   * out_res.height / out_res.width;
1830  			h_offset = h_offset / 2;
1831  			if (dz_config->zoom_region.origin.y < h_offset)
1832  				dz_config->zoom_region.origin.y = 0;
1833  			else
1834  				dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y - h_offset;
1835  			w_offset = 0;
1836  		} else {
1837  			w_offset = asd->sensor_array_res.width
1838  				   - asd->sensor_array_res.height
1839  				   * out_res.width / out_res.height;
1840  			w_offset = w_offset / 2;
1841  			if (dz_config->zoom_region.origin.x < w_offset)
1842  				dz_config->zoom_region.origin.x = 0;
1843  			else
1844  				dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x - w_offset;
1845  			h_offset = 0;
1846  		}
1847  		dz_config->zoom_region.origin.x = dz_config->zoom_region.origin.x
1848  						  * eff_res.width
1849  						  / (asd->sensor_array_res.width - 2 * w_offset);
1850  		dz_config->zoom_region.origin.y = dz_config->zoom_region.origin.y
1851  						  * eff_res.height
1852  						  / (asd->sensor_array_res.height - 2 * h_offset);
1853  		dz_config->zoom_region.resolution.width = dz_config->zoom_region.resolution.width
1854  						  * eff_res.width
1855  						  / (asd->sensor_array_res.width - 2 * w_offset);
1856  		dz_config->zoom_region.resolution.height = dz_config->zoom_region.resolution.height
1857  						  * eff_res.height
1858  						  / (asd->sensor_array_res.height - 2 * h_offset);
1859  	}
1860  
1861  	if (out_res.width * dz_config->zoom_region.resolution.height
1862  	    > dz_config->zoom_region.resolution.width * out_res.height) {
1863  		dz_config->zoom_region.resolution.height =
1864  		    dz_config->zoom_region.resolution.width
1865  		    * out_res.height / out_res.width;
1866  	} else {
1867  		dz_config->zoom_region.resolution.width =
1868  		    dz_config->zoom_region.resolution.height
1869  		    * out_res.width / out_res.height;
1870  	}
1871  	dev_dbg(asd->isp->dev,
1872  		"%s crop region:(%d,%d),(%d,%d) eff_res(%d, %d) array_size(%d,%d) out_res(%d, %d)\n",
1873  		__func__, dz_config->zoom_region.origin.x,
1874  		dz_config->zoom_region.origin.y,
1875  		dz_config->zoom_region.resolution.width,
1876  		dz_config->zoom_region.resolution.height,
1877  		eff_res.width, eff_res.height,
1878  		asd->sensor_array_res.width,
1879  		asd->sensor_array_res.height,
1880  		out_res.width, out_res.height);
1881  
1882  	if ((dz_config->zoom_region.origin.x +
1883  	     dz_config->zoom_region.resolution.width
1884  	     > eff_res.width) ||
1885  	    (dz_config->zoom_region.origin.y +
1886  	     dz_config->zoom_region.resolution.height
1887  	     > eff_res.height))
1888  		return -EINVAL;
1889  
1890  	return 0;
1891  }
1892  
1893  /*
1894   * Function to check the zoom region whether is effective
1895   */
atomisp_check_zoom_region(struct atomisp_sub_device * asd,struct ia_css_dz_config * dz_config)1896  static bool atomisp_check_zoom_region(
1897      struct atomisp_sub_device *asd,
1898      struct ia_css_dz_config *dz_config)
1899  {
1900  	struct atomisp_resolution  config;
1901  	bool flag = false;
1902  	unsigned int w, h;
1903  
1904  	memset(&config, 0, sizeof(struct atomisp_resolution));
1905  
1906  	if (dz_config->dx && dz_config->dy)
1907  		return true;
1908  
1909  	config.width = asd->sensor_array_res.width;
1910  	config.height = asd->sensor_array_res.height;
1911  	w = dz_config->zoom_region.origin.x +
1912  	    dz_config->zoom_region.resolution.width;
1913  	h = dz_config->zoom_region.origin.y +
1914  	    dz_config->zoom_region.resolution.height;
1915  
1916  	if ((w <= config.width) && (h <= config.height) && w > 0 && h > 0)
1917  		flag = true;
1918  	else
1919  		/* setting error zoom region */
1920  		dev_err(asd->isp->dev,
1921  			"%s zoom region ERROR:dz_config:(%d,%d),(%d,%d)array_res(%d, %d)\n",
1922  			__func__, dz_config->zoom_region.origin.x,
1923  			dz_config->zoom_region.origin.y,
1924  			dz_config->zoom_region.resolution.width,
1925  			dz_config->zoom_region.resolution.height,
1926  			config.width, config.height);
1927  
1928  	return flag;
1929  }
1930  
atomisp_apply_css_parameters(struct atomisp_sub_device * asd,struct atomisp_css_params * css_param)1931  void atomisp_apply_css_parameters(
1932      struct atomisp_sub_device *asd,
1933      struct atomisp_css_params *css_param)
1934  {
1935  	if (css_param->update_flag.wb_config)
1936  		asd->params.config.wb_config = &css_param->wb_config;
1937  
1938  	if (css_param->update_flag.ob_config)
1939  		asd->params.config.ob_config = &css_param->ob_config;
1940  
1941  	if (css_param->update_flag.dp_config)
1942  		asd->params.config.dp_config = &css_param->dp_config;
1943  
1944  	if (css_param->update_flag.nr_config)
1945  		asd->params.config.nr_config = &css_param->nr_config;
1946  
1947  	if (css_param->update_flag.ee_config)
1948  		asd->params.config.ee_config = &css_param->ee_config;
1949  
1950  	if (css_param->update_flag.tnr_config)
1951  		asd->params.config.tnr_config = &css_param->tnr_config;
1952  
1953  	if (css_param->update_flag.a3a_config)
1954  		asd->params.config.s3a_config = &css_param->s3a_config;
1955  
1956  	if (css_param->update_flag.ctc_config)
1957  		asd->params.config.ctc_config = &css_param->ctc_config;
1958  
1959  	if (css_param->update_flag.cnr_config)
1960  		asd->params.config.cnr_config = &css_param->cnr_config;
1961  
1962  	if (css_param->update_flag.ecd_config)
1963  		asd->params.config.ecd_config = &css_param->ecd_config;
1964  
1965  	if (css_param->update_flag.ynr_config)
1966  		asd->params.config.ynr_config = &css_param->ynr_config;
1967  
1968  	if (css_param->update_flag.fc_config)
1969  		asd->params.config.fc_config = &css_param->fc_config;
1970  
1971  	if (css_param->update_flag.macc_config)
1972  		asd->params.config.macc_config = &css_param->macc_config;
1973  
1974  	if (css_param->update_flag.aa_config)
1975  		asd->params.config.aa_config = &css_param->aa_config;
1976  
1977  	if (css_param->update_flag.anr_config)
1978  		asd->params.config.anr_config = &css_param->anr_config;
1979  
1980  	if (css_param->update_flag.xnr_config)
1981  		asd->params.config.xnr_config = &css_param->xnr_config;
1982  
1983  	if (css_param->update_flag.yuv2rgb_cc_config)
1984  		asd->params.config.yuv2rgb_cc_config = &css_param->yuv2rgb_cc_config;
1985  
1986  	if (css_param->update_flag.rgb2yuv_cc_config)
1987  		asd->params.config.rgb2yuv_cc_config = &css_param->rgb2yuv_cc_config;
1988  
1989  	if (css_param->update_flag.macc_table)
1990  		asd->params.config.macc_table = &css_param->macc_table;
1991  
1992  	if (css_param->update_flag.xnr_table)
1993  		asd->params.config.xnr_table = &css_param->xnr_table;
1994  
1995  	if (css_param->update_flag.r_gamma_table)
1996  		asd->params.config.r_gamma_table = &css_param->r_gamma_table;
1997  
1998  	if (css_param->update_flag.g_gamma_table)
1999  		asd->params.config.g_gamma_table = &css_param->g_gamma_table;
2000  
2001  	if (css_param->update_flag.b_gamma_table)
2002  		asd->params.config.b_gamma_table = &css_param->b_gamma_table;
2003  
2004  	if (css_param->update_flag.anr_thres)
2005  		atomisp_css_set_anr_thres(asd, &css_param->anr_thres);
2006  
2007  	if (css_param->update_flag.shading_table)
2008  		asd->params.config.shading_table = css_param->shading_table;
2009  
2010  	if (css_param->update_flag.morph_table && asd->params.gdc_cac_en)
2011  		asd->params.config.morph_table = css_param->morph_table;
2012  
2013  	if (css_param->update_flag.dvs2_coefs) {
2014  		struct ia_css_dvs_grid_info *dvs_grid_info =
2015  		    atomisp_css_get_dvs_grid_info(
2016  			&asd->params.curr_grid_info);
2017  
2018  		if (dvs_grid_info && dvs_grid_info->enable)
2019  			atomisp_css_set_dvs2_coefs(asd, css_param->dvs2_coeff);
2020  	}
2021  
2022  	if (css_param->update_flag.dvs_6axis_config)
2023  		atomisp_css_set_dvs_6axis(asd, css_param->dvs_6axis);
2024  
2025  	atomisp_css_set_isp_config_id(asd, css_param->isp_config_id);
2026  	/*
2027  	 * These configurations are on used by ISP1.x, not for ISP2.x,
2028  	 * so do not handle them. see comments of ia_css_isp_config.
2029  	 * 1 cc_config
2030  	 * 2 ce_config
2031  	 * 3 de_config
2032  	 * 4 gc_config
2033  	 * 5 gamma_table
2034  	 * 6 ctc_table
2035  	 * 7 dvs_coefs
2036  	 */
2037  }
2038  
copy_from_compatible(void * to,const void * from,unsigned long n,bool from_user)2039  static unsigned int long copy_from_compatible(void *to, const void *from,
2040  	unsigned long n, bool from_user)
2041  {
2042  	if (from_user)
2043  		return copy_from_user(to, (void __user *)from, n);
2044  	else
2045  		memcpy(to, from, n);
2046  	return 0;
2047  }
2048  
atomisp_cp_general_isp_parameters(struct atomisp_sub_device * asd,struct atomisp_parameters * arg,struct atomisp_css_params * css_param,bool from_user)2049  int atomisp_cp_general_isp_parameters(struct atomisp_sub_device *asd,
2050  				      struct atomisp_parameters *arg,
2051  				      struct atomisp_css_params *css_param,
2052  				      bool from_user)
2053  {
2054  	struct atomisp_parameters *cur_config = &css_param->update_flag;
2055  
2056  	if (!arg || !asd || !css_param)
2057  		return -EINVAL;
2058  
2059  	if (arg->wb_config && (from_user || !cur_config->wb_config)) {
2060  		if (copy_from_compatible(&css_param->wb_config, arg->wb_config,
2061  					 sizeof(struct ia_css_wb_config),
2062  					 from_user))
2063  			return -EFAULT;
2064  		css_param->update_flag.wb_config =
2065  		    (struct atomisp_wb_config *)&css_param->wb_config;
2066  	}
2067  
2068  	if (arg->ob_config && (from_user || !cur_config->ob_config)) {
2069  		if (copy_from_compatible(&css_param->ob_config, arg->ob_config,
2070  					 sizeof(struct ia_css_ob_config),
2071  					 from_user))
2072  			return -EFAULT;
2073  		css_param->update_flag.ob_config =
2074  		    (struct atomisp_ob_config *)&css_param->ob_config;
2075  	}
2076  
2077  	if (arg->dp_config && (from_user || !cur_config->dp_config)) {
2078  		if (copy_from_compatible(&css_param->dp_config, arg->dp_config,
2079  					 sizeof(struct ia_css_dp_config),
2080  					 from_user))
2081  			return -EFAULT;
2082  		css_param->update_flag.dp_config =
2083  		    (struct atomisp_dp_config *)&css_param->dp_config;
2084  	}
2085  
2086  	if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
2087  		if (arg->dz_config && (from_user || !cur_config->dz_config)) {
2088  			if (copy_from_compatible(&css_param->dz_config,
2089  						 arg->dz_config,
2090  						 sizeof(struct ia_css_dz_config),
2091  						 from_user))
2092  				return -EFAULT;
2093  			if (!atomisp_check_zoom_region(asd,
2094  						       &css_param->dz_config)) {
2095  				dev_err(asd->isp->dev, "crop region error!");
2096  				return -EINVAL;
2097  			}
2098  			css_param->update_flag.dz_config =
2099  			    (struct atomisp_dz_config *)
2100  			    &css_param->dz_config;
2101  		}
2102  	}
2103  
2104  	if (arg->nr_config && (from_user || !cur_config->nr_config)) {
2105  		if (copy_from_compatible(&css_param->nr_config, arg->nr_config,
2106  					 sizeof(struct ia_css_nr_config),
2107  					 from_user))
2108  			return -EFAULT;
2109  		css_param->update_flag.nr_config =
2110  		    (struct atomisp_nr_config *)&css_param->nr_config;
2111  	}
2112  
2113  	if (arg->ee_config && (from_user || !cur_config->ee_config)) {
2114  		if (copy_from_compatible(&css_param->ee_config, arg->ee_config,
2115  					 sizeof(struct ia_css_ee_config),
2116  					 from_user))
2117  			return -EFAULT;
2118  		css_param->update_flag.ee_config =
2119  		    (struct atomisp_ee_config *)&css_param->ee_config;
2120  	}
2121  
2122  	if (arg->tnr_config && (from_user || !cur_config->tnr_config)) {
2123  		if (copy_from_compatible(&css_param->tnr_config,
2124  					 arg->tnr_config,
2125  					 sizeof(struct ia_css_tnr_config),
2126  					 from_user))
2127  			return -EFAULT;
2128  		css_param->update_flag.tnr_config =
2129  		    (struct atomisp_tnr_config *)
2130  		    &css_param->tnr_config;
2131  	}
2132  
2133  	if (arg->a3a_config && (from_user || !cur_config->a3a_config)) {
2134  		if (copy_from_compatible(&css_param->s3a_config,
2135  					 arg->a3a_config,
2136  					 sizeof(struct ia_css_3a_config),
2137  					 from_user))
2138  			return -EFAULT;
2139  		css_param->update_flag.a3a_config =
2140  		    (struct atomisp_3a_config *)&css_param->s3a_config;
2141  	}
2142  
2143  	if (arg->ctc_config && (from_user || !cur_config->ctc_config)) {
2144  		if (copy_from_compatible(&css_param->ctc_config,
2145  					 arg->ctc_config,
2146  					 sizeof(struct ia_css_ctc_config),
2147  					 from_user))
2148  			return -EFAULT;
2149  		css_param->update_flag.ctc_config =
2150  		    (struct atomisp_ctc_config *)
2151  		    &css_param->ctc_config;
2152  	}
2153  
2154  	if (arg->cnr_config && (from_user || !cur_config->cnr_config)) {
2155  		if (copy_from_compatible(&css_param->cnr_config,
2156  					 arg->cnr_config,
2157  					 sizeof(struct ia_css_cnr_config),
2158  					 from_user))
2159  			return -EFAULT;
2160  		css_param->update_flag.cnr_config =
2161  		    (struct atomisp_cnr_config *)
2162  		    &css_param->cnr_config;
2163  	}
2164  
2165  	if (arg->ecd_config && (from_user || !cur_config->ecd_config)) {
2166  		if (copy_from_compatible(&css_param->ecd_config,
2167  					 arg->ecd_config,
2168  					 sizeof(struct ia_css_ecd_config),
2169  					 from_user))
2170  			return -EFAULT;
2171  		css_param->update_flag.ecd_config =
2172  		    (struct atomisp_ecd_config *)
2173  		    &css_param->ecd_config;
2174  	}
2175  
2176  	if (arg->ynr_config && (from_user || !cur_config->ynr_config)) {
2177  		if (copy_from_compatible(&css_param->ynr_config,
2178  					 arg->ynr_config,
2179  					 sizeof(struct ia_css_ynr_config),
2180  					 from_user))
2181  			return -EFAULT;
2182  		css_param->update_flag.ynr_config =
2183  		    (struct atomisp_ynr_config *)
2184  		    &css_param->ynr_config;
2185  	}
2186  
2187  	if (arg->fc_config && (from_user || !cur_config->fc_config)) {
2188  		if (copy_from_compatible(&css_param->fc_config,
2189  					 arg->fc_config,
2190  					 sizeof(struct ia_css_fc_config),
2191  					 from_user))
2192  			return -EFAULT;
2193  		css_param->update_flag.fc_config =
2194  		    (struct atomisp_fc_config *)&css_param->fc_config;
2195  	}
2196  
2197  	if (arg->macc_config && (from_user || !cur_config->macc_config)) {
2198  		if (copy_from_compatible(&css_param->macc_config,
2199  					 arg->macc_config,
2200  					 sizeof(struct ia_css_macc_config),
2201  					 from_user))
2202  			return -EFAULT;
2203  		css_param->update_flag.macc_config =
2204  		    (struct atomisp_macc_config *)
2205  		    &css_param->macc_config;
2206  	}
2207  
2208  	if (arg->aa_config && (from_user || !cur_config->aa_config)) {
2209  		if (copy_from_compatible(&css_param->aa_config, arg->aa_config,
2210  					 sizeof(struct ia_css_aa_config),
2211  					 from_user))
2212  			return -EFAULT;
2213  		css_param->update_flag.aa_config =
2214  		    (struct atomisp_aa_config *)&css_param->aa_config;
2215  	}
2216  
2217  	if (arg->anr_config && (from_user || !cur_config->anr_config)) {
2218  		if (copy_from_compatible(&css_param->anr_config,
2219  					 arg->anr_config,
2220  					 sizeof(struct ia_css_anr_config),
2221  					 from_user))
2222  			return -EFAULT;
2223  		css_param->update_flag.anr_config =
2224  		    (struct atomisp_anr_config *)
2225  		    &css_param->anr_config;
2226  	}
2227  
2228  	if (arg->xnr_config && (from_user || !cur_config->xnr_config)) {
2229  		if (copy_from_compatible(&css_param->xnr_config,
2230  					 arg->xnr_config,
2231  					 sizeof(struct ia_css_xnr_config),
2232  					 from_user))
2233  			return -EFAULT;
2234  		css_param->update_flag.xnr_config =
2235  		    (struct atomisp_xnr_config *)
2236  		    &css_param->xnr_config;
2237  	}
2238  
2239  	if (arg->yuv2rgb_cc_config &&
2240  	    (from_user || !cur_config->yuv2rgb_cc_config)) {
2241  		if (copy_from_compatible(&css_param->yuv2rgb_cc_config,
2242  					 arg->yuv2rgb_cc_config,
2243  					 sizeof(struct ia_css_cc_config),
2244  					 from_user))
2245  			return -EFAULT;
2246  		css_param->update_flag.yuv2rgb_cc_config =
2247  		    (struct atomisp_cc_config *)
2248  		    &css_param->yuv2rgb_cc_config;
2249  	}
2250  
2251  	if (arg->rgb2yuv_cc_config &&
2252  	    (from_user || !cur_config->rgb2yuv_cc_config)) {
2253  		if (copy_from_compatible(&css_param->rgb2yuv_cc_config,
2254  					 arg->rgb2yuv_cc_config,
2255  					 sizeof(struct ia_css_cc_config),
2256  					 from_user))
2257  			return -EFAULT;
2258  		css_param->update_flag.rgb2yuv_cc_config =
2259  		    (struct atomisp_cc_config *)
2260  		    &css_param->rgb2yuv_cc_config;
2261  	}
2262  
2263  	if (arg->macc_table && (from_user || !cur_config->macc_table)) {
2264  		if (copy_from_compatible(&css_param->macc_table,
2265  					 arg->macc_table,
2266  					 sizeof(struct ia_css_macc_table),
2267  					 from_user))
2268  			return -EFAULT;
2269  		css_param->update_flag.macc_table =
2270  		    (struct atomisp_macc_table *)
2271  		    &css_param->macc_table;
2272  	}
2273  
2274  	if (arg->xnr_table && (from_user || !cur_config->xnr_table)) {
2275  		if (copy_from_compatible(&css_param->xnr_table,
2276  					 arg->xnr_table,
2277  					 sizeof(struct ia_css_xnr_table),
2278  					 from_user))
2279  			return -EFAULT;
2280  		css_param->update_flag.xnr_table =
2281  		    (struct atomisp_xnr_table *)&css_param->xnr_table;
2282  	}
2283  
2284  	if (arg->r_gamma_table && (from_user || !cur_config->r_gamma_table)) {
2285  		if (copy_from_compatible(&css_param->r_gamma_table,
2286  					 arg->r_gamma_table,
2287  					 sizeof(struct ia_css_rgb_gamma_table),
2288  					 from_user))
2289  			return -EFAULT;
2290  		css_param->update_flag.r_gamma_table =
2291  		    (struct atomisp_rgb_gamma_table *)
2292  		    &css_param->r_gamma_table;
2293  	}
2294  
2295  	if (arg->g_gamma_table && (from_user || !cur_config->g_gamma_table)) {
2296  		if (copy_from_compatible(&css_param->g_gamma_table,
2297  					 arg->g_gamma_table,
2298  					 sizeof(struct ia_css_rgb_gamma_table),
2299  					 from_user))
2300  			return -EFAULT;
2301  		css_param->update_flag.g_gamma_table =
2302  		    (struct atomisp_rgb_gamma_table *)
2303  		    &css_param->g_gamma_table;
2304  	}
2305  
2306  	if (arg->b_gamma_table && (from_user || !cur_config->b_gamma_table)) {
2307  		if (copy_from_compatible(&css_param->b_gamma_table,
2308  					 arg->b_gamma_table,
2309  					 sizeof(struct ia_css_rgb_gamma_table),
2310  					 from_user))
2311  			return -EFAULT;
2312  		css_param->update_flag.b_gamma_table =
2313  		    (struct atomisp_rgb_gamma_table *)
2314  		    &css_param->b_gamma_table;
2315  	}
2316  
2317  	if (arg->anr_thres && (from_user || !cur_config->anr_thres)) {
2318  		if (copy_from_compatible(&css_param->anr_thres, arg->anr_thres,
2319  					 sizeof(struct ia_css_anr_thres),
2320  					 from_user))
2321  			return -EFAULT;
2322  		css_param->update_flag.anr_thres =
2323  		    (struct atomisp_anr_thres *)&css_param->anr_thres;
2324  	}
2325  
2326  	if (from_user)
2327  		css_param->isp_config_id = arg->isp_config_id;
2328  	/*
2329  	 * These configurations are on used by ISP1.x, not for ISP2.x,
2330  	 * so do not handle them. see comments of ia_css_isp_config.
2331  	 * 1 cc_config
2332  	 * 2 ce_config
2333  	 * 3 de_config
2334  	 * 4 gc_config
2335  	 * 5 gamma_table
2336  	 * 6 ctc_table
2337  	 * 7 dvs_coefs
2338  	 */
2339  	return 0;
2340  }
2341  
atomisp_cp_lsc_table(struct atomisp_sub_device * asd,struct atomisp_shading_table * source_st,struct atomisp_css_params * css_param,bool from_user)2342  int atomisp_cp_lsc_table(struct atomisp_sub_device *asd,
2343  			 struct atomisp_shading_table *source_st,
2344  			 struct atomisp_css_params *css_param,
2345  			 bool from_user)
2346  {
2347  	unsigned int i;
2348  	unsigned int len_table;
2349  	struct ia_css_shading_table *shading_table;
2350  	struct ia_css_shading_table *old_table;
2351  	struct atomisp_shading_table *st, dest_st;
2352  
2353  	if (!source_st)
2354  		return 0;
2355  
2356  	if (!css_param)
2357  		return -EINVAL;
2358  
2359  	if (!from_user && css_param->update_flag.shading_table)
2360  		return 0;
2361  
2362  	if (IS_ISP2401) {
2363  		if (copy_from_compatible(&dest_st, source_st,
2364  					sizeof(struct atomisp_shading_table),
2365  					from_user)) {
2366  			dev_err(asd->isp->dev, "copy shading table failed!");
2367  			return -EFAULT;
2368  		}
2369  		st = &dest_st;
2370  	} else {
2371  		st = source_st;
2372  	}
2373  
2374  	old_table = css_param->shading_table;
2375  
2376  	/* user config is to disable the shading table. */
2377  	if (!st->enable) {
2378  		/* Generate a minimum table with enable = 0. */
2379  		shading_table = atomisp_css_shading_table_alloc(1, 1);
2380  		if (!shading_table)
2381  			return -ENOMEM;
2382  		shading_table->enable = 0;
2383  		goto set_lsc;
2384  	}
2385  
2386  	/* Setting a new table. Validate first - all tables must be set */
2387  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
2388  		if (!st->data[i]) {
2389  			dev_err(asd->isp->dev, "shading table validate failed");
2390  			return -EINVAL;
2391  		}
2392  	}
2393  
2394  	/* Shading table size per color */
2395  	if (st->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
2396  	    st->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR) {
2397  		dev_err(asd->isp->dev, "shading table w/h validate failed!");
2398  		return -EINVAL;
2399  	}
2400  
2401  	shading_table = atomisp_css_shading_table_alloc(st->width, st->height);
2402  	if (!shading_table)
2403  		return -ENOMEM;
2404  
2405  	len_table = st->width * st->height * ATOMISP_SC_TYPE_SIZE;
2406  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
2407  		if (copy_from_compatible(shading_table->data[i],
2408  					 st->data[i], len_table, from_user)) {
2409  			atomisp_css_shading_table_free(shading_table);
2410  			return -EFAULT;
2411  		}
2412  	}
2413  	shading_table->sensor_width = st->sensor_width;
2414  	shading_table->sensor_height = st->sensor_height;
2415  	shading_table->fraction_bits = st->fraction_bits;
2416  	shading_table->enable = st->enable;
2417  
2418  	/* No need to update shading table if it is the same */
2419  	if (old_table &&
2420  	    old_table->sensor_width == shading_table->sensor_width &&
2421  	    old_table->sensor_height == shading_table->sensor_height &&
2422  	    old_table->width == shading_table->width &&
2423  	    old_table->height == shading_table->height &&
2424  	    old_table->fraction_bits == shading_table->fraction_bits &&
2425  	    old_table->enable == shading_table->enable) {
2426  		bool data_is_same = true;
2427  
2428  		for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
2429  			if (memcmp(shading_table->data[i], old_table->data[i],
2430  				   len_table) != 0) {
2431  				data_is_same = false;
2432  				break;
2433  			}
2434  		}
2435  
2436  		if (data_is_same) {
2437  			atomisp_css_shading_table_free(shading_table);
2438  			return 0;
2439  		}
2440  	}
2441  
2442  set_lsc:
2443  	/* set LSC to CSS */
2444  	css_param->shading_table = shading_table;
2445  	css_param->update_flag.shading_table = (struct atomisp_shading_table *)shading_table;
2446  	asd->params.sc_en = shading_table;
2447  
2448  	if (old_table)
2449  		atomisp_css_shading_table_free(old_table);
2450  
2451  	return 0;
2452  }
2453  
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)2454  int atomisp_css_cp_dvs2_coefs(struct atomisp_sub_device *asd,
2455  			      struct ia_css_dvs2_coefficients *coefs,
2456  			      struct atomisp_css_params *css_param,
2457  			      bool from_user)
2458  {
2459  	struct ia_css_dvs_grid_info *cur =
2460  	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
2461  	int dvs_hor_coef_bytes, dvs_ver_coef_bytes;
2462  	struct ia_css_dvs2_coefficients dvs2_coefs;
2463  
2464  	if (!coefs || !cur)
2465  		return 0;
2466  
2467  	if (!from_user && css_param->update_flag.dvs2_coefs)
2468  		return 0;
2469  
2470  	if (!IS_ISP2401) {
2471  		if (sizeof(*cur) != sizeof(coefs->grid) ||
2472  		    memcmp(&coefs->grid, cur, sizeof(coefs->grid))) {
2473  			dev_err(asd->isp->dev, "dvs grid mismatch!\n");
2474  			/* If the grid info in the argument differs from the current
2475  			grid info, we tell the caller to reset the grid size and
2476  			try again. */
2477  			return -EAGAIN;
2478  		}
2479  
2480  		if (!coefs->hor_coefs.odd_real ||
2481  		    !coefs->hor_coefs.odd_imag ||
2482  		    !coefs->hor_coefs.even_real ||
2483  		    !coefs->hor_coefs.even_imag ||
2484  		    !coefs->ver_coefs.odd_real ||
2485  		    !coefs->ver_coefs.odd_imag ||
2486  		    !coefs->ver_coefs.even_real ||
2487  		    !coefs->ver_coefs.even_imag)
2488  			return -EINVAL;
2489  
2490  		if (!css_param->dvs2_coeff) {
2491  			/* DIS coefficients. */
2492  			css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur);
2493  			if (!css_param->dvs2_coeff)
2494  				return -ENOMEM;
2495  		}
2496  
2497  		dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes;
2498  		dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes;
2499  		if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real,
2500  					coefs->hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
2501  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag,
2502  					coefs->hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
2503  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real,
2504  					coefs->hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
2505  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag,
2506  					coefs->hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
2507  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real,
2508  					coefs->ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
2509  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag,
2510  					coefs->ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
2511  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real,
2512  					coefs->ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
2513  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag,
2514  					coefs->ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
2515  			ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
2516  			css_param->dvs2_coeff = NULL;
2517  			return -EFAULT;
2518  		}
2519  	} else {
2520  		if (copy_from_compatible(&dvs2_coefs, coefs,
2521  					sizeof(struct ia_css_dvs2_coefficients),
2522  					from_user)) {
2523  			dev_err(asd->isp->dev, "copy dvs2 coef failed");
2524  			return -EFAULT;
2525  		}
2526  
2527  		if (sizeof(*cur) != sizeof(dvs2_coefs.grid) ||
2528  		    memcmp(&dvs2_coefs.grid, cur, sizeof(dvs2_coefs.grid))) {
2529  			dev_err(asd->isp->dev, "dvs grid mismatch!\n");
2530  			/* If the grid info in the argument differs from the current
2531  			grid info, we tell the caller to reset the grid size and
2532  			try again. */
2533  			return -EAGAIN;
2534  		}
2535  
2536  		if (!dvs2_coefs.hor_coefs.odd_real ||
2537  		    !dvs2_coefs.hor_coefs.odd_imag ||
2538  		    !dvs2_coefs.hor_coefs.even_real ||
2539  		    !dvs2_coefs.hor_coefs.even_imag ||
2540  		    !dvs2_coefs.ver_coefs.odd_real ||
2541  		    !dvs2_coefs.ver_coefs.odd_imag ||
2542  		    !dvs2_coefs.ver_coefs.even_real ||
2543  		    !dvs2_coefs.ver_coefs.even_imag)
2544  			return -EINVAL;
2545  
2546  		if (!css_param->dvs2_coeff) {
2547  			/* DIS coefficients. */
2548  			css_param->dvs2_coeff = ia_css_dvs2_coefficients_allocate(cur);
2549  			if (!css_param->dvs2_coeff)
2550  				return -ENOMEM;
2551  		}
2552  
2553  		dvs_hor_coef_bytes = asd->params.dvs_hor_coef_bytes;
2554  		dvs_ver_coef_bytes = asd->params.dvs_ver_coef_bytes;
2555  		if (copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_real,
2556  					dvs2_coefs.hor_coefs.odd_real, dvs_hor_coef_bytes, from_user) ||
2557  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.odd_imag,
2558  					dvs2_coefs.hor_coefs.odd_imag, dvs_hor_coef_bytes, from_user) ||
2559  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_real,
2560  					dvs2_coefs.hor_coefs.even_real, dvs_hor_coef_bytes, from_user) ||
2561  		    copy_from_compatible(css_param->dvs2_coeff->hor_coefs.even_imag,
2562  					dvs2_coefs.hor_coefs.even_imag, dvs_hor_coef_bytes, from_user) ||
2563  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_real,
2564  					dvs2_coefs.ver_coefs.odd_real, dvs_ver_coef_bytes, from_user) ||
2565  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.odd_imag,
2566  					dvs2_coefs.ver_coefs.odd_imag, dvs_ver_coef_bytes, from_user) ||
2567  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_real,
2568  					dvs2_coefs.ver_coefs.even_real, dvs_ver_coef_bytes, from_user) ||
2569  		    copy_from_compatible(css_param->dvs2_coeff->ver_coefs.even_imag,
2570  					dvs2_coefs.ver_coefs.even_imag, dvs_ver_coef_bytes, from_user)) {
2571  			ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
2572  			css_param->dvs2_coeff = NULL;
2573  			return -EFAULT;
2574  		}
2575  	}
2576  
2577  	css_param->update_flag.dvs2_coefs =
2578  	    (struct atomisp_dis_coefficients *)css_param->dvs2_coeff;
2579  	return 0;
2580  }
2581  
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)2582  int atomisp_cp_dvs_6axis_config(struct atomisp_sub_device *asd,
2583  				struct atomisp_dvs_6axis_config *source_6axis_config,
2584  				struct atomisp_css_params *css_param,
2585  				bool from_user)
2586  {
2587  	struct ia_css_dvs_6axis_config *dvs_6axis_config;
2588  	struct ia_css_dvs_6axis_config *old_6axis_config;
2589  	struct ia_css_stream *stream =
2590  		    asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream;
2591  	struct ia_css_dvs_grid_info *dvs_grid_info =
2592  	    atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
2593  	int ret = -EFAULT;
2594  
2595  	if (!stream) {
2596  		dev_err(asd->isp->dev, "%s: internal error!", __func__);
2597  		return -EINVAL;
2598  	}
2599  
2600  	if (!source_6axis_config || !dvs_grid_info)
2601  		return 0;
2602  
2603  	if (!dvs_grid_info->enable)
2604  		return 0;
2605  
2606  	if (!from_user && css_param->update_flag.dvs_6axis_config)
2607  		return 0;
2608  
2609  	/* check whether need to reallocate for 6 axis config */
2610  	old_6axis_config = css_param->dvs_6axis;
2611  	dvs_6axis_config = old_6axis_config;
2612  
2613  	if (IS_ISP2401) {
2614  		struct ia_css_dvs_6axis_config t_6axis_config;
2615  
2616  		if (copy_from_compatible(&t_6axis_config, source_6axis_config,
2617  					sizeof(struct atomisp_dvs_6axis_config),
2618  					from_user)) {
2619  			dev_err(asd->isp->dev, "copy morph table failed!");
2620  			return -EFAULT;
2621  		}
2622  
2623  		if (old_6axis_config &&
2624  		    (old_6axis_config->width_y != t_6axis_config.width_y ||
2625  		    old_6axis_config->height_y != t_6axis_config.height_y ||
2626  		    old_6axis_config->width_uv != t_6axis_config.width_uv ||
2627  		    old_6axis_config->height_uv != t_6axis_config.height_uv)) {
2628  			ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
2629  			css_param->dvs_6axis = NULL;
2630  
2631  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
2632  			if (!dvs_6axis_config)
2633  				return -ENOMEM;
2634  		} else if (!dvs_6axis_config) {
2635  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
2636  			if (!dvs_6axis_config)
2637  				return -ENOMEM;
2638  		}
2639  
2640  		dvs_6axis_config->exp_id = t_6axis_config.exp_id;
2641  
2642  		if (copy_from_compatible(dvs_6axis_config->xcoords_y,
2643  					t_6axis_config.xcoords_y,
2644  					t_6axis_config.width_y *
2645  					t_6axis_config.height_y *
2646  					sizeof(*dvs_6axis_config->xcoords_y),
2647  					from_user))
2648  			goto error;
2649  		if (copy_from_compatible(dvs_6axis_config->ycoords_y,
2650  					t_6axis_config.ycoords_y,
2651  					t_6axis_config.width_y *
2652  					t_6axis_config.height_y *
2653  					sizeof(*dvs_6axis_config->ycoords_y),
2654  					from_user))
2655  			goto error;
2656  		if (copy_from_compatible(dvs_6axis_config->xcoords_uv,
2657  					t_6axis_config.xcoords_uv,
2658  					t_6axis_config.width_uv *
2659  					t_6axis_config.height_uv *
2660  					sizeof(*dvs_6axis_config->xcoords_uv),
2661  					from_user))
2662  			goto error;
2663  		if (copy_from_compatible(dvs_6axis_config->ycoords_uv,
2664  					t_6axis_config.ycoords_uv,
2665  					t_6axis_config.width_uv *
2666  					t_6axis_config.height_uv *
2667  					sizeof(*dvs_6axis_config->ycoords_uv),
2668  					from_user))
2669  			goto error;
2670  	} else {
2671  		if (old_6axis_config &&
2672  		    (old_6axis_config->width_y != source_6axis_config->width_y ||
2673  		    old_6axis_config->height_y != source_6axis_config->height_y ||
2674  		    old_6axis_config->width_uv != source_6axis_config->width_uv ||
2675  		    old_6axis_config->height_uv != source_6axis_config->height_uv)) {
2676  			ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
2677  			css_param->dvs_6axis = NULL;
2678  
2679  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
2680  			if (!dvs_6axis_config) {
2681  				ret = -ENOMEM;
2682  				goto error;
2683  			}
2684  		} else if (!dvs_6axis_config) {
2685  			dvs_6axis_config = ia_css_dvs2_6axis_config_allocate(stream);
2686  			if (!dvs_6axis_config) {
2687  				ret = -ENOMEM;
2688  				goto error;
2689  			}
2690  		}
2691  
2692  		dvs_6axis_config->exp_id = source_6axis_config->exp_id;
2693  
2694  		if (copy_from_compatible(dvs_6axis_config->xcoords_y,
2695  					source_6axis_config->xcoords_y,
2696  					source_6axis_config->width_y *
2697  					source_6axis_config->height_y *
2698  					sizeof(*source_6axis_config->xcoords_y),
2699  					from_user))
2700  			goto error;
2701  		if (copy_from_compatible(dvs_6axis_config->ycoords_y,
2702  					source_6axis_config->ycoords_y,
2703  					source_6axis_config->width_y *
2704  					source_6axis_config->height_y *
2705  					sizeof(*source_6axis_config->ycoords_y),
2706  					from_user))
2707  			goto error;
2708  		if (copy_from_compatible(dvs_6axis_config->xcoords_uv,
2709  					source_6axis_config->xcoords_uv,
2710  					source_6axis_config->width_uv *
2711  					source_6axis_config->height_uv *
2712  					sizeof(*source_6axis_config->xcoords_uv),
2713  					from_user))
2714  			goto error;
2715  		if (copy_from_compatible(dvs_6axis_config->ycoords_uv,
2716  					source_6axis_config->ycoords_uv,
2717  					source_6axis_config->width_uv *
2718  					source_6axis_config->height_uv *
2719  					sizeof(*source_6axis_config->ycoords_uv),
2720  					from_user))
2721  			goto error;
2722  	}
2723  	css_param->dvs_6axis = dvs_6axis_config;
2724  	css_param->update_flag.dvs_6axis_config =
2725  	    (struct atomisp_dvs_6axis_config *)dvs_6axis_config;
2726  	return 0;
2727  
2728  error:
2729  	if (dvs_6axis_config)
2730  		ia_css_dvs2_6axis_config_free(dvs_6axis_config);
2731  	return ret;
2732  }
2733  
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)2734  int atomisp_cp_morph_table(struct atomisp_sub_device *asd,
2735  			   struct atomisp_morph_table *source_morph_table,
2736  			   struct atomisp_css_params *css_param,
2737  			   bool from_user)
2738  {
2739  	int ret = -EFAULT;
2740  	unsigned int i;
2741  	struct ia_css_morph_table *morph_table;
2742  	struct ia_css_morph_table *old_morph_table;
2743  
2744  	if (!source_morph_table)
2745  		return 0;
2746  
2747  	if (!from_user && css_param->update_flag.morph_table)
2748  		return 0;
2749  
2750  	old_morph_table = css_param->morph_table;
2751  
2752  	if (IS_ISP2401) {
2753  		struct ia_css_morph_table mtbl;
2754  
2755  		if (copy_from_compatible(&mtbl, source_morph_table,
2756  				sizeof(struct atomisp_morph_table),
2757  				from_user)) {
2758  			dev_err(asd->isp->dev, "copy morph table failed!");
2759  			return -EFAULT;
2760  		}
2761  
2762  		morph_table = atomisp_css_morph_table_allocate(
2763  				mtbl.width,
2764  				mtbl.height);
2765  		if (!morph_table)
2766  			return -ENOMEM;
2767  
2768  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
2769  			if (copy_from_compatible(morph_table->coordinates_x[i],
2770  						(__force void *)source_morph_table->coordinates_x[i],
2771  						mtbl.height * mtbl.width *
2772  						sizeof(*morph_table->coordinates_x[i]),
2773  						from_user))
2774  				goto error;
2775  
2776  			if (copy_from_compatible(morph_table->coordinates_y[i],
2777  						(__force void *)source_morph_table->coordinates_y[i],
2778  						mtbl.height * mtbl.width *
2779  						sizeof(*morph_table->coordinates_y[i]),
2780  						from_user))
2781  				goto error;
2782  		}
2783  	} else {
2784  		morph_table = atomisp_css_morph_table_allocate(
2785  				source_morph_table->width,
2786  				source_morph_table->height);
2787  		if (!morph_table) {
2788  			ret = -ENOMEM;
2789  			goto error;
2790  		}
2791  
2792  		for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) {
2793  			if (copy_from_compatible(morph_table->coordinates_x[i],
2794  						(__force void *)source_morph_table->coordinates_x[i],
2795  						source_morph_table->height * source_morph_table->width *
2796  						sizeof(*source_morph_table->coordinates_x[i]),
2797  						from_user))
2798  				goto error;
2799  
2800  			if (copy_from_compatible(morph_table->coordinates_y[i],
2801  						(__force void *)source_morph_table->coordinates_y[i],
2802  						source_morph_table->height * source_morph_table->width *
2803  						sizeof(*source_morph_table->coordinates_y[i]),
2804  						from_user))
2805  				goto error;
2806  		}
2807  	}
2808  
2809  	css_param->morph_table = morph_table;
2810  	if (old_morph_table)
2811  		atomisp_css_morph_table_free(old_morph_table);
2812  	css_param->update_flag.morph_table =
2813  	    (struct atomisp_morph_table *)morph_table;
2814  	return 0;
2815  
2816  error:
2817  	if (morph_table)
2818  		atomisp_css_morph_table_free(morph_table);
2819  	return ret;
2820  }
2821  
atomisp_makeup_css_parameters(struct atomisp_sub_device * asd,struct atomisp_parameters * arg,struct atomisp_css_params * css_param)2822  int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd,
2823  				  struct atomisp_parameters *arg,
2824  				  struct atomisp_css_params *css_param)
2825  {
2826  	int ret;
2827  
2828  	ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, false);
2829  	if (ret)
2830  		return ret;
2831  	ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, false);
2832  	if (ret)
2833  		return ret;
2834  	ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, false);
2835  	if (ret)
2836  		return ret;
2837  	ret = atomisp_css_cp_dvs2_coefs(asd,
2838  					(struct ia_css_dvs2_coefficients *)arg->dvs2_coefs,
2839  					css_param, false);
2840  	if (ret)
2841  		return ret;
2842  	ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
2843  					  css_param, false);
2844  	return ret;
2845  }
2846  
atomisp_free_css_parameters(struct atomisp_css_params * css_param)2847  void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
2848  {
2849  	if (css_param->dvs_6axis) {
2850  		ia_css_dvs2_6axis_config_free(css_param->dvs_6axis);
2851  		css_param->dvs_6axis = NULL;
2852  	}
2853  	if (css_param->dvs2_coeff) {
2854  		ia_css_dvs2_coefficients_free(css_param->dvs2_coeff);
2855  		css_param->dvs2_coeff = NULL;
2856  	}
2857  	if (css_param->shading_table) {
2858  		ia_css_shading_table_free(css_param->shading_table);
2859  		css_param->shading_table = NULL;
2860  	}
2861  	if (css_param->morph_table) {
2862  		ia_css_morph_table_free(css_param->morph_table);
2863  		css_param->morph_table = NULL;
2864  	}
2865  }
2866  
atomisp_move_frame_to_activeq(struct ia_css_frame * frame,struct atomisp_css_params_with_list * param)2867  static void atomisp_move_frame_to_activeq(struct ia_css_frame *frame,
2868  					  struct atomisp_css_params_with_list *param)
2869  {
2870  	struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
2871  	unsigned long irqflags;
2872  
2873  	pipe->frame_params[frame->vb.vb2_buf.index] = param;
2874  	spin_lock_irqsave(&pipe->irq_lock, irqflags);
2875  	list_move_tail(&frame->queue, &pipe->activeq);
2876  	spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
2877  }
2878  
2879  /*
2880   * Check parameter queue list and buffer queue list to find out if matched items
2881   * and then set parameter to CSS and enqueue buffer to CSS.
2882   * Of course, if the buffer in buffer waiting list is not bound to a per-frame
2883   * parameter, it will be enqueued into CSS as long as the per-frame setting
2884   * buffers before it get enqueued.
2885   */
atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe * pipe)2886  void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
2887  {
2888  	struct atomisp_sub_device *asd = pipe->asd;
2889  	struct ia_css_frame *frame = NULL, *frame_tmp;
2890  	struct atomisp_css_params_with_list *param = NULL, *param_tmp;
2891  	bool need_to_enqueue_buffer = false;
2892  	int i;
2893  
2894  	lockdep_assert_held(&asd->isp->mutex);
2895  
2896  	/*
2897  	 * CSS/FW requires set parameter and enqueue buffer happen after ISP
2898  	 * is streamon.
2899  	 */
2900  	if (!asd->streaming)
2901  		return;
2902  
2903  	if (list_empty(&pipe->per_frame_params) ||
2904  	    list_empty(&pipe->buffers_waiting_for_param))
2905  		return;
2906  
2907  	list_for_each_entry_safe(frame, frame_tmp,
2908  				 &pipe->buffers_waiting_for_param, queue) {
2909  		i = frame->vb.vb2_buf.index;
2910  		if (pipe->frame_request_config_id[i]) {
2911  			list_for_each_entry_safe(param, param_tmp,
2912  						 &pipe->per_frame_params, list) {
2913  				if (pipe->frame_request_config_id[i] != param->params.isp_config_id)
2914  					continue;
2915  
2916  				list_del(&param->list);
2917  
2918  				/*
2919  				 * clear the request config id as the buffer
2920  				 * will be handled and enqueued into CSS soon
2921  				 */
2922  				pipe->frame_request_config_id[i] = 0;
2923  				atomisp_move_frame_to_activeq(frame, param);
2924  				need_to_enqueue_buffer = true;
2925  				break;
2926  			}
2927  
2928  			/* If this is the end, stop further loop */
2929  			if (list_entry_is_head(param, &pipe->per_frame_params, list))
2930  				break;
2931  		} else {
2932  			atomisp_move_frame_to_activeq(frame, NULL);
2933  			need_to_enqueue_buffer = true;
2934  		}
2935  	}
2936  
2937  	if (!need_to_enqueue_buffer)
2938  		return;
2939  
2940  	atomisp_qbuffers_to_css(asd);
2941  }
2942  
2943  /*
2944   * Function to configure ISP parameters
2945   */
atomisp_set_parameters(struct video_device * vdev,struct atomisp_parameters * arg)2946  int atomisp_set_parameters(struct video_device *vdev,
2947  			   struct atomisp_parameters *arg)
2948  {
2949  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
2950  	struct atomisp_sub_device *asd = pipe->asd;
2951  	struct atomisp_css_params_with_list *param = NULL;
2952  	struct atomisp_css_params *css_param = &asd->params.css_param;
2953  	int ret;
2954  
2955  	lockdep_assert_held(&asd->isp->mutex);
2956  
2957  	if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream) {
2958  		dev_err(asd->isp->dev, "%s: internal error!\n", __func__);
2959  		return -EINVAL;
2960  	}
2961  
2962  	dev_dbg(asd->isp->dev, "set parameter(per_frame_setting %d) isp_config_id %d of %s\n",
2963  		arg->per_frame_setting, arg->isp_config_id, vdev->name);
2964  
2965  	if (arg->per_frame_setting) {
2966  		/*
2967  		 * Per-frame setting enabled, we allocate a new parameter
2968  		 * buffer to cache the parameters and only when frame buffers
2969  		 * are ready, the parameters will be set to CSS.
2970  		 * per-frame setting only works for the main output frame.
2971  		 */
2972  		param = kvzalloc(sizeof(*param), GFP_KERNEL);
2973  		if (!param) {
2974  			dev_err(asd->isp->dev, "%s: failed to alloc params buffer\n",
2975  				__func__);
2976  			return -ENOMEM;
2977  		}
2978  		css_param = &param->params;
2979  	}
2980  
2981  	ret = atomisp_cp_general_isp_parameters(asd, arg, css_param, true);
2982  	if (ret)
2983  		goto apply_parameter_failed;
2984  
2985  	ret = atomisp_cp_lsc_table(asd, arg->shading_table, css_param, true);
2986  	if (ret)
2987  		goto apply_parameter_failed;
2988  
2989  	ret = atomisp_cp_morph_table(asd, arg->morph_table, css_param, true);
2990  	if (ret)
2991  		goto apply_parameter_failed;
2992  
2993  	ret = atomisp_css_cp_dvs2_coefs(asd,
2994  					(struct ia_css_dvs2_coefficients *)arg->dvs2_coefs,
2995  					css_param, true);
2996  	if (ret)
2997  		goto apply_parameter_failed;
2998  
2999  	ret = atomisp_cp_dvs_6axis_config(asd, arg->dvs_6axis_config,
3000  					  css_param, true);
3001  	if (ret)
3002  		goto apply_parameter_failed;
3003  
3004  	if (!arg->per_frame_setting) {
3005  		/* indicate to CSS that we have parameters to be updated */
3006  		asd->params.css_update_params_needed = true;
3007  	} else {
3008  		list_add_tail(&param->list, &pipe->per_frame_params);
3009  		atomisp_handle_parameter_and_buffer(pipe);
3010  	}
3011  
3012  	return 0;
3013  
3014  apply_parameter_failed:
3015  	if (css_param)
3016  		atomisp_free_css_parameters(css_param);
3017  	kvfree(param);
3018  
3019  	return ret;
3020  }
3021  
3022  /*
3023   * Function to set/get isp parameters to isp
3024   */
atomisp_param(struct atomisp_sub_device * asd,int flag,struct atomisp_parm * config)3025  int atomisp_param(struct atomisp_sub_device *asd, int flag,
3026  		  struct atomisp_parm *config)
3027  {
3028  	struct ia_css_pipe_config *vp_cfg =
3029  		    &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
3030  		    pipe_configs[IA_CSS_PIPE_ID_VIDEO];
3031  
3032  	/* Read parameter for 3A binary info */
3033  	if (flag == 0) {
3034  		struct ia_css_dvs_grid_info *dvs_grid_info =
3035  		    atomisp_css_get_dvs_grid_info(
3036  			&asd->params.curr_grid_info);
3037  
3038  		atomisp_curr_user_grid_info(asd, &config->info);
3039  
3040  		/* We always return the resolution and stride even if there is
3041  		 * no valid metadata. This allows the caller to get the
3042  		 * information needed to allocate user-space buffers. */
3043  		config->metadata_config.metadata_height = asd->
3044  			stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
3045  			metadata_info.resolution.height;
3046  		config->metadata_config.metadata_stride = asd->
3047  			stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info.
3048  			metadata_info.stride;
3049  
3050  		/* update dvs grid info */
3051  		if (dvs_grid_info)
3052  			memcpy(&config->dvs_grid,
3053  			       dvs_grid_info,
3054  			       sizeof(struct ia_css_dvs_grid_info));
3055  
3056  		if (asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) {
3057  			config->dvs_envelop.width = 0;
3058  			config->dvs_envelop.height = 0;
3059  			return 0;
3060  		}
3061  
3062  		/* update dvs envelop info */
3063  		config->dvs_envelop.width = vp_cfg->dvs_envelope.width;
3064  		config->dvs_envelop.height = vp_cfg->dvs_envelope.height;
3065  		return 0;
3066  	}
3067  
3068  	memcpy(&asd->params.css_param.wb_config, &config->wb_config,
3069  	       sizeof(struct ia_css_wb_config));
3070  	memcpy(&asd->params.css_param.ob_config, &config->ob_config,
3071  	       sizeof(struct ia_css_ob_config));
3072  	memcpy(&asd->params.css_param.dp_config, &config->dp_config,
3073  	       sizeof(struct ia_css_dp_config));
3074  	memcpy(&asd->params.css_param.de_config, &config->de_config,
3075  	       sizeof(struct ia_css_de_config));
3076  	memcpy(&asd->params.css_param.dz_config, &config->dz_config,
3077  	       sizeof(struct ia_css_dz_config));
3078  	memcpy(&asd->params.css_param.ce_config, &config->ce_config,
3079  	       sizeof(struct ia_css_ce_config));
3080  	memcpy(&asd->params.css_param.nr_config, &config->nr_config,
3081  	       sizeof(struct ia_css_nr_config));
3082  	memcpy(&asd->params.css_param.ee_config, &config->ee_config,
3083  	       sizeof(struct ia_css_ee_config));
3084  	memcpy(&asd->params.css_param.tnr_config, &config->tnr_config,
3085  	       sizeof(struct ia_css_tnr_config));
3086  
3087  	if (asd->params.color_effect == V4L2_COLORFX_NEGATIVE) {
3088  		asd->params.css_param.cc_config.matrix[3] = -config->cc_config.matrix[3];
3089  		asd->params.css_param.cc_config.matrix[4] = -config->cc_config.matrix[4];
3090  		asd->params.css_param.cc_config.matrix[5] = -config->cc_config.matrix[5];
3091  		asd->params.css_param.cc_config.matrix[6] = -config->cc_config.matrix[6];
3092  		asd->params.css_param.cc_config.matrix[7] = -config->cc_config.matrix[7];
3093  		asd->params.css_param.cc_config.matrix[8] = -config->cc_config.matrix[8];
3094  	}
3095  
3096  	if (asd->params.color_effect != V4L2_COLORFX_SEPIA &&
3097  	    asd->params.color_effect != V4L2_COLORFX_BW) {
3098  		memcpy(&asd->params.css_param.cc_config, &config->cc_config,
3099  		       sizeof(struct ia_css_cc_config));
3100  		asd->params.config.cc_config = &asd->params.css_param.cc_config;
3101  	}
3102  
3103  	asd->params.config.wb_config = &asd->params.css_param.wb_config;
3104  	asd->params.config.ob_config = &asd->params.css_param.ob_config;
3105  	asd->params.config.de_config = &asd->params.css_param.de_config;
3106  	asd->params.config.dz_config = &asd->params.css_param.dz_config;
3107  	asd->params.config.ce_config = &asd->params.css_param.ce_config;
3108  	asd->params.config.dp_config = &asd->params.css_param.dp_config;
3109  	asd->params.config.nr_config = &asd->params.css_param.nr_config;
3110  	asd->params.config.ee_config = &asd->params.css_param.ee_config;
3111  	asd->params.config.tnr_config = &asd->params.css_param.tnr_config;
3112  	asd->params.css_update_params_needed = true;
3113  
3114  	return 0;
3115  }
3116  
3117  /*
3118   * Function to configure color effect of the image
3119   */
atomisp_color_effect(struct atomisp_sub_device * asd,int flag,__s32 * effect)3120  int atomisp_color_effect(struct atomisp_sub_device *asd, int flag,
3121  			 __s32 *effect)
3122  {
3123  	struct ia_css_cc_config *cc_config = NULL;
3124  	struct ia_css_macc_table *macc_table = NULL;
3125  	struct ia_css_ctc_table *ctc_table = NULL;
3126  	int ret = 0;
3127  	struct v4l2_control control;
3128  	struct atomisp_device *isp = asd->isp;
3129  
3130  	if (flag == 0) {
3131  		*effect = asd->params.color_effect;
3132  		return 0;
3133  	}
3134  
3135  	control.id = V4L2_CID_COLORFX;
3136  	control.value = *effect;
3137  	ret =
3138  	    v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].camera->ctrl_handler,
3139  			&control);
3140  	/*
3141  	 * if set color effect to sensor successfully, return
3142  	 * 0 directly.
3143  	 */
3144  	if (!ret) {
3145  		asd->params.color_effect = (u32)*effect;
3146  		return 0;
3147  	}
3148  
3149  	if (*effect == asd->params.color_effect)
3150  		return 0;
3151  
3152  	/*
3153  	 * isp_subdev->params.macc_en should be set to false.
3154  	 */
3155  	asd->params.macc_en = false;
3156  
3157  	switch (*effect) {
3158  	case V4L2_COLORFX_NONE:
3159  		macc_table = &asd->params.css_param.macc_table;
3160  		asd->params.macc_en = true;
3161  		break;
3162  	case V4L2_COLORFX_SEPIA:
3163  		cc_config = &sepia_cc_config;
3164  		break;
3165  	case V4L2_COLORFX_NEGATIVE:
3166  		cc_config = &nega_cc_config;
3167  		break;
3168  	case V4L2_COLORFX_BW:
3169  		cc_config = &mono_cc_config;
3170  		break;
3171  	case V4L2_COLORFX_SKY_BLUE:
3172  		macc_table = &blue_macc_table;
3173  		asd->params.macc_en = true;
3174  		break;
3175  	case V4L2_COLORFX_GRASS_GREEN:
3176  		macc_table = &green_macc_table;
3177  		asd->params.macc_en = true;
3178  		break;
3179  	case V4L2_COLORFX_SKIN_WHITEN_LOW:
3180  		macc_table = &skin_low_macc_table;
3181  		asd->params.macc_en = true;
3182  		break;
3183  	case V4L2_COLORFX_SKIN_WHITEN:
3184  		macc_table = &skin_medium_macc_table;
3185  		asd->params.macc_en = true;
3186  		break;
3187  	case V4L2_COLORFX_SKIN_WHITEN_HIGH:
3188  		macc_table = &skin_high_macc_table;
3189  		asd->params.macc_en = true;
3190  		break;
3191  	case V4L2_COLORFX_VIVID:
3192  		ctc_table = &vivid_ctc_table;
3193  		break;
3194  	default:
3195  		return -EINVAL;
3196  	}
3197  	atomisp_update_capture_mode(asd);
3198  
3199  	if (cc_config)
3200  		asd->params.config.cc_config = cc_config;
3201  	if (macc_table)
3202  		asd->params.config.macc_table = macc_table;
3203  	if (ctc_table)
3204  		atomisp_css_set_ctc_table(asd, ctc_table);
3205  	asd->params.color_effect = (u32)*effect;
3206  	asd->params.css_update_params_needed = true;
3207  	return 0;
3208  }
3209  
3210  /*
3211   * Function to configure bad pixel correction
3212   */
atomisp_bad_pixel(struct atomisp_sub_device * asd,int flag,__s32 * value)3213  int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag,
3214  		      __s32 *value)
3215  {
3216  	if (flag == 0) {
3217  		*value = asd->params.bad_pixel_en;
3218  		return 0;
3219  	}
3220  	asd->params.bad_pixel_en = !!*value;
3221  
3222  	return 0;
3223  }
3224  
3225  /*
3226   * Function to configure bad pixel correction params
3227   */
atomisp_bad_pixel_param(struct atomisp_sub_device * asd,int flag,struct atomisp_dp_config * config)3228  int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag,
3229  			    struct atomisp_dp_config *config)
3230  {
3231  	if (flag == 0) {
3232  		/* Get bad pixel from current setup */
3233  		if (atomisp_css_get_dp_config(asd, config))
3234  			return -EINVAL;
3235  	} else {
3236  		/* Set bad pixel to isp parameters */
3237  		memcpy(&asd->params.css_param.dp_config, config,
3238  		       sizeof(asd->params.css_param.dp_config));
3239  		asd->params.config.dp_config = &asd->params.css_param.dp_config;
3240  		asd->params.css_update_params_needed = true;
3241  	}
3242  
3243  	return 0;
3244  }
3245  
3246  /*
3247   * Function to enable/disable video image stablization
3248   */
atomisp_video_stable(struct atomisp_sub_device * asd,int flag,__s32 * value)3249  int atomisp_video_stable(struct atomisp_sub_device *asd, int flag,
3250  			 __s32 *value)
3251  {
3252  	if (flag == 0)
3253  		*value = asd->params.video_dis_en;
3254  	else
3255  		asd->params.video_dis_en = !!*value;
3256  
3257  	return 0;
3258  }
3259  
3260  /*
3261   * Function to configure fixed pattern noise
3262   */
atomisp_fixed_pattern(struct atomisp_sub_device * asd,int flag,__s32 * value)3263  int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag,
3264  			  __s32 *value)
3265  {
3266  	if (flag == 0) {
3267  		*value = asd->params.fpn_en;
3268  		return 0;
3269  	}
3270  
3271  	if (*value == 0) {
3272  		asd->params.fpn_en = false;
3273  		return 0;
3274  	}
3275  
3276  	/* Add function to get black from sensor with shutter off */
3277  	return 0;
3278  }
3279  
3280  static unsigned int
atomisp_bytesperline_to_padded_width(unsigned int bytesperline,enum ia_css_frame_format format)3281  atomisp_bytesperline_to_padded_width(unsigned int bytesperline,
3282  				     enum ia_css_frame_format format)
3283  {
3284  	switch (format) {
3285  	case IA_CSS_FRAME_FORMAT_UYVY:
3286  	case IA_CSS_FRAME_FORMAT_YUYV:
3287  	case IA_CSS_FRAME_FORMAT_RAW:
3288  	case IA_CSS_FRAME_FORMAT_RGB565:
3289  		return bytesperline / 2;
3290  	case IA_CSS_FRAME_FORMAT_RGBA888:
3291  		return bytesperline / 4;
3292  	/* The following cases could be removed, but we leave them
3293  	   in to document the formats that are included. */
3294  	case IA_CSS_FRAME_FORMAT_NV11:
3295  	case IA_CSS_FRAME_FORMAT_NV12:
3296  	case IA_CSS_FRAME_FORMAT_NV16:
3297  	case IA_CSS_FRAME_FORMAT_NV21:
3298  	case IA_CSS_FRAME_FORMAT_NV61:
3299  	case IA_CSS_FRAME_FORMAT_YV12:
3300  	case IA_CSS_FRAME_FORMAT_YV16:
3301  	case IA_CSS_FRAME_FORMAT_YUV420:
3302  	case IA_CSS_FRAME_FORMAT_YUV420_16:
3303  	case IA_CSS_FRAME_FORMAT_YUV422:
3304  	case IA_CSS_FRAME_FORMAT_YUV422_16:
3305  	case IA_CSS_FRAME_FORMAT_YUV444:
3306  	case IA_CSS_FRAME_FORMAT_YUV_LINE:
3307  	case IA_CSS_FRAME_FORMAT_PLANAR_RGB888:
3308  	case IA_CSS_FRAME_FORMAT_QPLANE6:
3309  	case IA_CSS_FRAME_FORMAT_BINARY_8:
3310  	default:
3311  		return bytesperline;
3312  	}
3313  }
3314  
3315  static int
atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer * arg,struct ia_css_frame ** result)3316  atomisp_v4l2_framebuffer_to_css_frame(const struct v4l2_framebuffer *arg,
3317  				      struct ia_css_frame **result)
3318  {
3319  	struct ia_css_frame *res = NULL;
3320  	unsigned int padded_width;
3321  	enum ia_css_frame_format sh_format;
3322  	char *tmp_buf = NULL;
3323  	int ret = 0;
3324  
3325  	sh_format = v4l2_fmt_to_sh_fmt(arg->fmt.pixelformat);
3326  	padded_width = atomisp_bytesperline_to_padded_width(
3327  			   arg->fmt.bytesperline, sh_format);
3328  
3329  	/* Note: the padded width on an ia_css_frame is in elements, not in
3330  	   bytes. The RAW frame we use here should always be a 16bit RAW
3331  	   frame. This is why we bytesperline/2 is equal to the padded with */
3332  	if (ia_css_frame_allocate(&res, arg->fmt.width, arg->fmt.height,
3333  				       sh_format, padded_width, 0)) {
3334  		ret = -ENOMEM;
3335  		goto err;
3336  	}
3337  
3338  	tmp_buf = vmalloc(arg->fmt.sizeimage);
3339  	if (!tmp_buf) {
3340  		ret = -ENOMEM;
3341  		goto err;
3342  	}
3343  	if (copy_from_user(tmp_buf, (void __user __force *)arg->base,
3344  			   arg->fmt.sizeimage)) {
3345  		ret = -EFAULT;
3346  		goto err;
3347  	}
3348  
3349  	if (hmm_store(res->data, tmp_buf, arg->fmt.sizeimage)) {
3350  		ret = -EINVAL;
3351  		goto err;
3352  	}
3353  
3354  err:
3355  	if (ret && res)
3356  		ia_css_frame_free(res);
3357  	vfree(tmp_buf);
3358  	if (ret == 0)
3359  		*result = res;
3360  	return ret;
3361  }
3362  
3363  /*
3364   * Function to configure fixed pattern noise table
3365   */
atomisp_fixed_pattern_table(struct atomisp_sub_device * asd,struct v4l2_framebuffer * arg)3366  int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd,
3367  				struct v4l2_framebuffer *arg)
3368  {
3369  	struct ia_css_frame *raw_black_frame = NULL;
3370  	int ret;
3371  
3372  	if (!arg)
3373  		return -EINVAL;
3374  
3375  	ret = atomisp_v4l2_framebuffer_to_css_frame(arg, &raw_black_frame);
3376  	if (ret)
3377  		return ret;
3378  
3379  	if (sh_css_set_black_frame(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream,
3380  				   raw_black_frame) != 0)
3381  		return -ENOMEM;
3382  
3383  	ia_css_frame_free(raw_black_frame);
3384  	return ret;
3385  }
3386  
3387  /*
3388   * Function to configure false color correction
3389   */
atomisp_false_color(struct atomisp_sub_device * asd,int flag,__s32 * value)3390  int atomisp_false_color(struct atomisp_sub_device *asd, int flag,
3391  			__s32 *value)
3392  {
3393  	/* Get nr config from current setup */
3394  	if (flag == 0) {
3395  		*value = asd->params.false_color;
3396  		return 0;
3397  	}
3398  
3399  	/* Set nr config to isp parameters */
3400  	if (*value) {
3401  		asd->params.config.de_config = NULL;
3402  	} else {
3403  		asd->params.css_param.de_config.pixelnoise = 0;
3404  		asd->params.config.de_config = &asd->params.css_param.de_config;
3405  	}
3406  	asd->params.css_update_params_needed = true;
3407  	asd->params.false_color = *value;
3408  	return 0;
3409  }
3410  
3411  /*
3412   * Function to configure bad pixel correction params
3413   */
atomisp_false_color_param(struct atomisp_sub_device * asd,int flag,struct atomisp_de_config * config)3414  int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag,
3415  			      struct atomisp_de_config *config)
3416  {
3417  	if (flag == 0) {
3418  		/* Get false color from current setup */
3419  		if (atomisp_css_get_de_config(asd, config))
3420  			return -EINVAL;
3421  	} else {
3422  		/* Set false color to isp parameters */
3423  		memcpy(&asd->params.css_param.de_config, config,
3424  		       sizeof(asd->params.css_param.de_config));
3425  		asd->params.config.de_config = &asd->params.css_param.de_config;
3426  		asd->params.css_update_params_needed = true;
3427  	}
3428  
3429  	return 0;
3430  }
3431  
3432  /*
3433   * Function to configure white balance params
3434   */
atomisp_white_balance_param(struct atomisp_sub_device * asd,int flag,struct atomisp_wb_config * config)3435  int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag,
3436  				struct atomisp_wb_config *config)
3437  {
3438  	if (flag == 0) {
3439  		/* Get white balance from current setup */
3440  		if (atomisp_css_get_wb_config(asd, config))
3441  			return -EINVAL;
3442  	} else {
3443  		/* Set white balance to isp parameters */
3444  		memcpy(&asd->params.css_param.wb_config, config,
3445  		       sizeof(asd->params.css_param.wb_config));
3446  		asd->params.config.wb_config = &asd->params.css_param.wb_config;
3447  		asd->params.css_update_params_needed = true;
3448  	}
3449  
3450  	return 0;
3451  }
3452  
atomisp_3a_config_param(struct atomisp_sub_device * asd,int flag,struct atomisp_3a_config * config)3453  int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag,
3454  			    struct atomisp_3a_config *config)
3455  {
3456  	struct atomisp_device *isp = asd->isp;
3457  
3458  	dev_dbg(isp->dev, ">%s %d\n", __func__, flag);
3459  
3460  	if (flag == 0) {
3461  		/* Get white balance from current setup */
3462  		if (atomisp_css_get_3a_config(asd, config))
3463  			return -EINVAL;
3464  	} else {
3465  		/* Set white balance to isp parameters */
3466  		memcpy(&asd->params.css_param.s3a_config, config,
3467  		       sizeof(asd->params.css_param.s3a_config));
3468  		asd->params.config.s3a_config = &asd->params.css_param.s3a_config;
3469  		asd->params.css_update_params_needed = true;
3470  	}
3471  
3472  	dev_dbg(isp->dev, "<%s %d\n", __func__, flag);
3473  	return 0;
3474  }
3475  
3476  /*
3477   * Function to setup digital zoom
3478   */
atomisp_digital_zoom(struct atomisp_sub_device * asd,int flag,__s32 * value)3479  int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag,
3480  			 __s32 *value)
3481  {
3482  	u32 zoom;
3483  	struct atomisp_device *isp = asd->isp;
3484  
3485  	unsigned int max_zoom = MRFLD_MAX_ZOOM_FACTOR;
3486  
3487  	if (flag == 0) {
3488  		atomisp_css_get_zoom_factor(asd, &zoom);
3489  		*value = max_zoom - zoom;
3490  	} else {
3491  		if (*value < 0)
3492  			return -EINVAL;
3493  
3494  		zoom = max_zoom - min_t(u32, max_zoom - 1, *value);
3495  		atomisp_css_set_zoom_factor(asd, zoom);
3496  
3497  		dev_dbg(isp->dev, "%s, zoom: %d\n", __func__, zoom);
3498  		asd->params.css_update_params_needed = true;
3499  	}
3500  
3501  	return 0;
3502  }
3503  
__atomisp_update_stream_env(struct atomisp_sub_device * asd,u16 stream_index,struct atomisp_input_stream_info * stream_info)3504  static void __atomisp_update_stream_env(struct atomisp_sub_device *asd,
3505  					u16 stream_index, struct atomisp_input_stream_info *stream_info)
3506  {
3507  	int i;
3508  
3509  	/* assign virtual channel id return from sensor driver query */
3510  	asd->stream_env[stream_index].ch_id = stream_info->ch_id;
3511  	asd->stream_env[stream_index].isys_configs = stream_info->isys_configs;
3512  	for (i = 0; i < stream_info->isys_configs; i++) {
3513  		asd->stream_env[stream_index].isys_info[i].input_format =
3514  		    stream_info->isys_info[i].input_format;
3515  		asd->stream_env[stream_index].isys_info[i].width =
3516  		    stream_info->isys_info[i].width;
3517  		asd->stream_env[stream_index].isys_info[i].height =
3518  		    stream_info->isys_info[i].height;
3519  	}
3520  }
3521  
__atomisp_init_stream_info(u16 stream_index,struct atomisp_input_stream_info * stream_info)3522  static void __atomisp_init_stream_info(u16 stream_index,
3523  				       struct atomisp_input_stream_info *stream_info)
3524  {
3525  	int i;
3526  
3527  	stream_info->enable = 1;
3528  	stream_info->stream = stream_index;
3529  	stream_info->ch_id = 0;
3530  	stream_info->isys_configs = 0;
3531  	for (i = 0; i < MAX_STREAMS_PER_CHANNEL; i++) {
3532  		stream_info->isys_info[i].input_format = 0;
3533  		stream_info->isys_info[i].width = 0;
3534  		stream_info->isys_info[i].height = 0;
3535  	}
3536  }
3537  
atomisp_fill_pix_format(struct v4l2_pix_format * f,u32 width,u32 height,const struct atomisp_format_bridge * br_fmt)3538  static void atomisp_fill_pix_format(struct v4l2_pix_format *f,
3539  				    u32 width, u32 height,
3540  				    const struct atomisp_format_bridge *br_fmt)
3541  {
3542  	u32 bytes;
3543  
3544  	f->width = width;
3545  	f->height = height;
3546  	f->pixelformat = br_fmt->pixelformat;
3547  
3548  	/* Adding padding to width for bytesperline calculation */
3549  	width = ia_css_frame_pad_width(width, br_fmt->sh_fmt);
3550  	bytes = BITS_TO_BYTES(br_fmt->depth * width);
3551  
3552  	if (br_fmt->planar)
3553  		f->bytesperline = width;
3554  	else
3555  		f->bytesperline = bytes;
3556  
3557  	f->sizeimage = PAGE_ALIGN(height * bytes);
3558  
3559  	if (f->field == V4L2_FIELD_ANY)
3560  		f->field = V4L2_FIELD_NONE;
3561  
3562  	/*
3563  	 * FIXME: do we need to set this up differently, depending on the
3564  	 * sensor or the pipeline?
3565  	 */
3566  	f->colorspace = V4L2_COLORSPACE_REC709;
3567  	f->ycbcr_enc = V4L2_YCBCR_ENC_709;
3568  	f->xfer_func = V4L2_XFER_FUNC_709;
3569  }
3570  
3571  /* Get sensor padding values for the non padded width x height resolution */
atomisp_get_padding(struct atomisp_device * isp,u32 width,u32 height,u32 * padding_w,u32 * padding_h)3572  void atomisp_get_padding(struct atomisp_device *isp, u32 width, u32 height,
3573  			 u32 *padding_w, u32 *padding_h)
3574  {
3575  	struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr];
3576  	struct v4l2_rect native_rect = input->native_rect;
3577  	const struct atomisp_in_fmt_conv *fc = NULL;
3578  	u32 min_pad_w = ISP2400_MIN_PAD_W;
3579  	u32 min_pad_h = ISP2400_MIN_PAD_H;
3580  	struct v4l2_mbus_framefmt *sink;
3581  
3582  	if (!input->crop_support) {
3583  		*padding_w = pad_w;
3584  		*padding_h = pad_h;
3585  		return;
3586  	}
3587  
3588  	width = min(width, input->active_rect.width);
3589  	height = min(height, input->active_rect.height);
3590  
3591  	if (input->binning_support && width <= (input->active_rect.width / 2) &&
3592  				      height <= (input->active_rect.height / 2)) {
3593  		native_rect.width /= 2;
3594  		native_rect.height /= 2;
3595  	}
3596  
3597  	*padding_w = min_t(u32, (native_rect.width - width) & ~1, pad_w);
3598  	*padding_h = min_t(u32, (native_rect.height - height) & ~1, pad_h);
3599  
3600  	/* The below minimum padding requirements are for BYT / ISP2400 only */
3601  	if (IS_ISP2401)
3602  		return;
3603  
3604  	sink = atomisp_subdev_get_ffmt(&isp->asd.subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
3605  				       ATOMISP_SUBDEV_PAD_SINK);
3606  	if (sink)
3607  		fc = atomisp_find_in_fmt_conv(sink->code);
3608  	if (!fc) {
3609  		dev_warn(isp->dev, "%s: Could not get sensor format\n", __func__);
3610  		goto apply_min_padding;
3611  	}
3612  
3613  	/*
3614  	 * The ISP only supports GRBG for other bayer-orders additional padding
3615  	 * is used so that the raw sensor data can be cropped to fix the order.
3616  	 */
3617  	if (fc->bayer_order == IA_CSS_BAYER_ORDER_RGGB ||
3618  	    fc->bayer_order == IA_CSS_BAYER_ORDER_GBRG)
3619  		min_pad_w += 2;
3620  
3621  	if (fc->bayer_order == IA_CSS_BAYER_ORDER_BGGR ||
3622  	    fc->bayer_order == IA_CSS_BAYER_ORDER_GBRG)
3623  		min_pad_h += 2;
3624  
3625  apply_min_padding:
3626  	*padding_w = max_t(u32, *padding_w, min_pad_w);
3627  	*padding_h = max_t(u32, *padding_h, min_pad_h);
3628  }
3629  
atomisp_s_sensor_power(struct atomisp_device * isp,unsigned int input,bool on)3630  int atomisp_s_sensor_power(struct atomisp_device *isp, unsigned int input, bool on)
3631  {
3632  	int ret;
3633  
3634  	if (isp->inputs[input].camera_on == on)
3635  		return 0;
3636  
3637  	ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, on);
3638  	if (ret && ret != -ENOIOCTLCMD) {
3639  		dev_err(isp->dev, "Error setting sensor power %d: %d\n", on, ret);
3640  		return ret;
3641  	}
3642  
3643  	isp->inputs[input].camera_on = on;
3644  	return 0;
3645  }
3646  
atomisp_select_input(struct atomisp_device * isp,unsigned int input)3647  int atomisp_select_input(struct atomisp_device *isp, unsigned int input)
3648  {
3649  	unsigned int input_orig = isp->asd.input_curr;
3650  	int ret;
3651  
3652  	/* Power on new sensor */
3653  	ret = atomisp_s_sensor_power(isp, input, 1);
3654  	if (ret)
3655  		return ret;
3656  
3657  	isp->asd.input_curr = input;
3658  
3659  	/* Power off previous sensor */
3660  	if (input != input_orig)
3661  		atomisp_s_sensor_power(isp, input_orig, 0);
3662  
3663  	atomisp_setup_input_links(isp);
3664  	return 0;
3665  }
3666  
3667  /*
3668   * Ensure the CSI-receiver -> ISP link for input_curr is marked as enabled and
3669   * the other CSI-receiver -> ISP links are disabled.
3670   */
atomisp_setup_input_links(struct atomisp_device * isp)3671  void atomisp_setup_input_links(struct atomisp_device *isp)
3672  {
3673  	struct media_link *link;
3674  
3675  	lockdep_assert_held(&isp->media_dev.graph_mutex);
3676  
3677  	for (int i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
3678  		link = media_entity_find_link(
3679  				&isp->csi2_port[i].subdev.entity.pads[CSI2_PAD_SOURCE],
3680  				&isp->asd.subdev.entity.pads[ATOMISP_SUBDEV_PAD_SINK]);
3681  		if (!link) {
3682  			dev_err(isp->dev, "Error cannot find CSI2-port[%d] -> ISP link\n", i);
3683  			continue; /* Should never happen */
3684  		}
3685  
3686  		/*
3687  		 * Modify the flags directly, calling media_entity_setup_link()
3688  		 * will end up calling atomisp_link_setup() which calls this
3689  		 * function again leading to endless recursion.
3690  		 */
3691  		if (isp->sensor_subdevs[i] == isp->inputs[isp->asd.input_curr].camera)
3692  			link->flags |= MEDIA_LNK_FL_ENABLED;
3693  		else
3694  			link->flags &= ~MEDIA_LNK_FL_ENABLED;
3695  
3696  		link->reverse->flags = link->flags;
3697  	}
3698  }
3699  
atomisp_set_sensor_crop_and_fmt(struct atomisp_device * isp,struct v4l2_mbus_framefmt * ffmt,int which)3700  static int atomisp_set_sensor_crop_and_fmt(struct atomisp_device *isp,
3701  					   struct v4l2_mbus_framefmt *ffmt,
3702  					   int which)
3703  {
3704  	struct atomisp_input_subdev *input = &isp->inputs[isp->asd.input_curr];
3705  	struct v4l2_subdev_selection sel = {
3706  		.which = which,
3707  		.target = V4L2_SEL_TGT_CROP,
3708  		.r.width = ffmt->width,
3709  		.r.height = ffmt->height,
3710  	};
3711  	struct v4l2_subdev_format format = {
3712  		.which = which,
3713  		.format = *ffmt,
3714  	};
3715  	struct v4l2_subdev_state *sd_state;
3716  	int ret = 0;
3717  
3718  	if (!input->camera)
3719  		return -EINVAL;
3720  
3721  	/*
3722  	 * Some old sensor drivers already write the registers on set_fmt
3723  	 * instead of on stream on, power on the sensor now (on newer
3724  	 * sensor drivers the s_power op is a no-op).
3725  	 */
3726  	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
3727  		ret = atomisp_s_sensor_power(isp, isp->asd.input_curr, 1);
3728  		if (ret)
3729  			return ret;
3730  	}
3731  
3732  	sd_state = (which == V4L2_SUBDEV_FORMAT_TRY) ? input->try_sd_state :
3733  						       input->camera->active_state;
3734  	if (sd_state)
3735  		v4l2_subdev_lock_state(sd_state);
3736  
3737  	if (!input->crop_support)
3738  		goto set_fmt;
3739  
3740  	/* Cropping is done before binning, when binning double the crop rect */
3741  	if (input->binning_support && sel.r.width <= (input->native_rect.width / 2) &&
3742  				      sel.r.height <= (input->native_rect.height / 2)) {
3743  		sel.r.width *= 2;
3744  		sel.r.height *= 2;
3745  	}
3746  
3747  	/* Clamp to avoid top/left calculations overflowing */
3748  	sel.r.width = min(sel.r.width, input->native_rect.width);
3749  	sel.r.height = min(sel.r.height, input->native_rect.height);
3750  
3751  	sel.r.left = ((input->native_rect.width - sel.r.width) / 2) & ~1;
3752  	sel.r.top = ((input->native_rect.height - sel.r.height) / 2) & ~1;
3753  
3754  	ret = v4l2_subdev_call(input->camera, pad, set_selection, sd_state, &sel);
3755  	if (ret)
3756  		dev_err(isp->dev, "Error setting crop to %ux%u @%ux%u: %d\n",
3757  			sel.r.width, sel.r.height, sel.r.left, sel.r.top, ret);
3758  
3759  set_fmt:
3760  	if (ret == 0)
3761  		ret = v4l2_subdev_call(input->camera, pad, set_fmt, sd_state, &format);
3762  
3763  	if (sd_state)
3764  		v4l2_subdev_unlock_state(sd_state);
3765  
3766  	/* Propagate new fmt to CSI port */
3767  	if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
3768  		ret = v4l2_subdev_call(input->csi_port, pad, set_fmt, NULL, &format);
3769  		if (ret)
3770  			return ret;
3771  	}
3772  
3773  	*ffmt = format.format;
3774  	return ret;
3775  }
3776  
3777  /* This function looks up the closest available resolution. */
atomisp_try_fmt(struct atomisp_device * isp,struct v4l2_pix_format * f,const struct atomisp_format_bridge ** fmt_ret,const struct atomisp_format_bridge ** snr_fmt_ret)3778  int atomisp_try_fmt(struct atomisp_device *isp, struct v4l2_pix_format *f,
3779  		    const struct atomisp_format_bridge **fmt_ret,
3780  		    const struct atomisp_format_bridge **snr_fmt_ret)
3781  {
3782  	const struct atomisp_format_bridge *fmt, *snr_fmt;
3783  	struct atomisp_sub_device *asd = &isp->asd;
3784  	struct v4l2_mbus_framefmt ffmt = { };
3785  	u32 padding_w, padding_h;
3786  	int ret;
3787  
3788  	fmt = atomisp_get_format_bridge(f->pixelformat);
3789  	/* Currently, raw formats are broken!!! */
3790  	if (!fmt || fmt->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
3791  		f->pixelformat = V4L2_PIX_FMT_YUV420;
3792  
3793  		fmt = atomisp_get_format_bridge(f->pixelformat);
3794  		if (!fmt)
3795  			return -EINVAL;
3796  	}
3797  
3798  	/* The preview pipeline does not support width > 1920 */
3799  	if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW)
3800  		f->width = min_t(u32, f->width, 1920);
3801  
3802  	/*
3803  	 * atomisp_set_fmt() will set the sensor resolution to the requested
3804  	 * resolution + padding. Add padding here and remove it again after
3805  	 * the set_fmt call, like atomisp_set_fmt_to_snr() does.
3806  	 */
3807  	atomisp_get_padding(isp, f->width, f->height, &padding_w, &padding_h);
3808  	v4l2_fill_mbus_format(&ffmt, f, fmt->mbus_code);
3809  	ffmt.width += padding_w;
3810  	ffmt.height += padding_h;
3811  
3812  	dev_dbg(isp->dev, "try_mbus_fmt: try %ux%u\n", ffmt.width, ffmt.height);
3813  
3814  	ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
3815  	if (ret)
3816  		return ret;
3817  
3818  	dev_dbg(isp->dev, "try_mbus_fmt: got %ux%u\n", ffmt.width, ffmt.height);
3819  
3820  	snr_fmt = atomisp_get_format_bridge_from_mbus(ffmt.code);
3821  	if (!snr_fmt) {
3822  		dev_err(isp->dev, "unknown sensor format 0x%8.8x\n",
3823  			ffmt.code);
3824  		return -EINVAL;
3825  	}
3826  
3827  	f->width = ffmt.width - padding_w;
3828  	f->height = ffmt.height - padding_h;
3829  
3830  	/*
3831  	 * If the format is jpeg or custom RAW, then the width and height will
3832  	 * not satisfy the normal atomisp requirements and no need to check
3833  	 * the below conditions. So just assign to what is being returned from
3834  	 * the sensor driver.
3835  	 */
3836  	if (f->pixelformat == V4L2_PIX_FMT_JPEG ||
3837  	    f->pixelformat == V4L2_PIX_FMT_CUSTOM_M10MO_RAW)
3838  		goto out_fill_pix_format;
3839  
3840  	/* app vs isp */
3841  	f->width = rounddown(clamp_t(u32, f->width, ATOM_ISP_MIN_WIDTH,
3842  				     ATOM_ISP_MAX_WIDTH), ATOM_ISP_STEP_WIDTH);
3843  	f->height = rounddown(clamp_t(u32, f->height, ATOM_ISP_MIN_HEIGHT,
3844  				      ATOM_ISP_MAX_HEIGHT), ATOM_ISP_STEP_HEIGHT);
3845  
3846  out_fill_pix_format:
3847  	atomisp_fill_pix_format(f, f->width, f->height, fmt);
3848  
3849  	if (fmt_ret)
3850  		*fmt_ret = fmt;
3851  
3852  	if (snr_fmt_ret)
3853  		*snr_fmt_ret = snr_fmt;
3854  
3855  	return 0;
3856  }
3857  
atomisp_port_to_mipi_port(struct atomisp_device * isp,enum atomisp_camera_port port)3858  enum mipi_port_id atomisp_port_to_mipi_port(struct atomisp_device *isp,
3859  					    enum atomisp_camera_port port)
3860  {
3861  	switch (port) {
3862  	case ATOMISP_CAMERA_PORT_PRIMARY:
3863  		return MIPI_PORT0_ID;
3864  	case ATOMISP_CAMERA_PORT_SECONDARY:
3865  		return MIPI_PORT1_ID;
3866  	case ATOMISP_CAMERA_PORT_TERTIARY:
3867  		return MIPI_PORT2_ID;
3868  	default:
3869  		dev_err(isp->dev, "unsupported port: %d\n", port);
3870  		return MIPI_PORT0_ID;
3871  	}
3872  }
3873  
atomisp_set_sensor_mipi_to_isp(struct atomisp_sub_device * asd,enum atomisp_input_stream_id stream_id,struct camera_mipi_info * mipi_info)3874  static inline int atomisp_set_sensor_mipi_to_isp(
3875      struct atomisp_sub_device *asd,
3876      enum atomisp_input_stream_id stream_id,
3877      struct camera_mipi_info *mipi_info)
3878  {
3879  	struct v4l2_control ctrl;
3880  	struct atomisp_device *isp = asd->isp;
3881  	struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
3882  	const struct atomisp_in_fmt_conv *fc;
3883  	int mipi_freq = 0;
3884  	unsigned int input_format, bayer_order;
3885  	enum atomisp_input_format metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED;
3886  	u32 mipi_port, metadata_width = 0, metadata_height = 0;
3887  
3888  	ctrl.id = V4L2_CID_LINK_FREQ;
3889  	if (v4l2_g_ctrl(input->camera->ctrl_handler, &ctrl) == 0)
3890  		mipi_freq = ctrl.value;
3891  
3892  	if (asd->stream_env[stream_id].isys_configs == 1) {
3893  		input_format =
3894  		    asd->stream_env[stream_id].isys_info[0].input_format;
3895  		atomisp_css_isys_set_format(asd, stream_id,
3896  					    input_format, IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX);
3897  	} else if (asd->stream_env[stream_id].isys_configs == 2) {
3898  		atomisp_css_isys_two_stream_cfg_update_stream1(
3899  		    asd, stream_id,
3900  		    asd->stream_env[stream_id].isys_info[0].input_format,
3901  		    asd->stream_env[stream_id].isys_info[0].width,
3902  		    asd->stream_env[stream_id].isys_info[0].height);
3903  
3904  		atomisp_css_isys_two_stream_cfg_update_stream2(
3905  		    asd, stream_id,
3906  		    asd->stream_env[stream_id].isys_info[1].input_format,
3907  		    asd->stream_env[stream_id].isys_info[1].width,
3908  		    asd->stream_env[stream_id].isys_info[1].height);
3909  	}
3910  
3911  	/* Compatibility for sensors which provide no media bus code
3912  	 * in s_mbus_framefmt() nor support pad formats. */
3913  	if (mipi_info && mipi_info->input_format != -1) {
3914  		bayer_order = mipi_info->raw_bayer_order;
3915  
3916  		/* Input stream config is still needs configured */
3917  		/* TODO: Check if this is necessary */
3918  		fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(
3919  			 mipi_info->input_format);
3920  		if (!fc)
3921  			return -EINVAL;
3922  		input_format = fc->atomisp_in_fmt;
3923  		metadata_format = mipi_info->metadata_format;
3924  		metadata_width = mipi_info->metadata_width;
3925  		metadata_height = mipi_info->metadata_height;
3926  	} else {
3927  		struct v4l2_mbus_framefmt *sink;
3928  
3929  		sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
3930  					       V4L2_SUBDEV_FORMAT_ACTIVE,
3931  					       ATOMISP_SUBDEV_PAD_SINK);
3932  		fc = atomisp_find_in_fmt_conv(sink->code);
3933  		if (!fc)
3934  			return -EINVAL;
3935  		input_format = fc->atomisp_in_fmt;
3936  		bayer_order = fc->bayer_order;
3937  	}
3938  
3939  	atomisp_css_input_set_format(asd, stream_id, input_format);
3940  	atomisp_css_input_set_bayer_order(asd, stream_id, bayer_order);
3941  
3942  	fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(metadata_format);
3943  	if (!fc)
3944  		return -EINVAL;
3945  
3946  	input_format = fc->atomisp_in_fmt;
3947  	mipi_port = atomisp_port_to_mipi_port(isp, input->port);
3948  	atomisp_css_input_configure_port(asd, mipi_port,
3949  					 isp->sensor_lanes[mipi_port],
3950  					 0xffff4, mipi_freq,
3951  					 input_format,
3952  					 metadata_width, metadata_height);
3953  	return 0;
3954  }
3955  
configure_pp_input_nop(struct atomisp_sub_device * asd,unsigned int width,unsigned int height)3956  static int configure_pp_input_nop(struct atomisp_sub_device *asd,
3957  				  unsigned int width, unsigned int height)
3958  {
3959  	return 0;
3960  }
3961  
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)3962  static int configure_output_nop(struct atomisp_sub_device *asd,
3963  				unsigned int width, unsigned int height,
3964  				unsigned int min_width,
3965  				enum ia_css_frame_format sh_fmt)
3966  {
3967  	return 0;
3968  }
3969  
get_frame_info_nop(struct atomisp_sub_device * asd,struct ia_css_frame_info * finfo)3970  static int get_frame_info_nop(struct atomisp_sub_device *asd,
3971  			      struct ia_css_frame_info *finfo)
3972  {
3973  	return 0;
3974  }
3975  
3976  /*
3977   * Resets CSS parameters that depend on input resolution.
3978   *
3979   * Update params like CSS RAW binning, 2ppc mode and pp_input
3980   * which depend on input size, but are not automatically
3981   * handled in CSS when the input resolution is changed.
3982   */
css_input_resolution_changed(struct atomisp_sub_device * asd,struct v4l2_mbus_framefmt * ffmt)3983  static int css_input_resolution_changed(struct atomisp_sub_device *asd,
3984  					struct v4l2_mbus_framefmt *ffmt)
3985  {
3986  	struct atomisp_metadata_buf *md_buf = NULL, *_md_buf;
3987  	unsigned int i;
3988  
3989  	dev_dbg(asd->isp->dev, "css_input_resolution_changed to %ux%u\n",
3990  		ffmt->width, ffmt->height);
3991  
3992  	if (IS_ISP2401)
3993  		atomisp_css_input_set_two_pixels_per_clock(asd, false);
3994  	else
3995  		atomisp_css_input_set_two_pixels_per_clock(asd, true);
3996  
3997  	/*
3998  	 * If sensor input changed, which means metadata resolution changed
3999  	 * together. Release all metadata buffers here to let it re-allocated
4000  	 * next time in reqbufs.
4001  	 */
4002  	for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) {
4003  		list_for_each_entry_safe(md_buf, _md_buf, &asd->metadata[i],
4004  					 list) {
4005  			atomisp_css_free_metadata_buffer(md_buf);
4006  			list_del(&md_buf->list);
4007  			kfree(md_buf);
4008  		}
4009  	}
4010  	return 0;
4011  
4012  	/*
4013  	 * TODO: atomisp_css_preview_configure_pp_input() not
4014  	 *       reset due to CSS bug tracked as PSI BZ 115124
4015  	 */
4016  }
4017  
atomisp_set_fmt_to_isp(struct video_device * vdev,struct ia_css_frame_info * output_info,const struct v4l2_pix_format * pix)4018  static int atomisp_set_fmt_to_isp(struct video_device *vdev,
4019  				  struct ia_css_frame_info *output_info,
4020  				  const struct v4l2_pix_format *pix)
4021  {
4022  	struct camera_mipi_info *mipi_info;
4023  	struct atomisp_device *isp = video_get_drvdata(vdev);
4024  	struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd;
4025  	struct atomisp_input_subdev *input = &isp->inputs[asd->input_curr];
4026  	const struct atomisp_format_bridge *format;
4027  	struct v4l2_rect *isp_sink_crop;
4028  	enum ia_css_pipe_id pipe_id;
4029  	int (*configure_output)(struct atomisp_sub_device *asd,
4030  				unsigned int width, unsigned int height,
4031  				unsigned int min_width,
4032  				enum ia_css_frame_format sh_fmt) =
4033  				    configure_output_nop;
4034  	int (*get_frame_info)(struct atomisp_sub_device *asd,
4035  			      struct ia_css_frame_info *finfo) =
4036  				  get_frame_info_nop;
4037  	int (*configure_pp_input)(struct atomisp_sub_device *asd,
4038  				  unsigned int width, unsigned int height) =
4039  				      configure_pp_input_nop;
4040  	const struct atomisp_in_fmt_conv *fc = NULL;
4041  	struct v4l2_mbus_framefmt *ffmt;
4042  	int ret, i;
4043  
4044  	isp_sink_crop = atomisp_subdev_get_rect(
4045  			    &asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE,
4046  			    ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP);
4047  
4048  	format = atomisp_get_format_bridge(pix->pixelformat);
4049  	if (!format)
4050  		return -EINVAL;
4051  
4052  	mipi_info = atomisp_to_sensor_mipi_info(input->camera);
4053  
4054  	if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL,
4055  					   mipi_info))
4056  		return -EINVAL;
4057  
4058  	if (mipi_info)
4059  		fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt(mipi_info->input_format);
4060  	if (!fc) {
4061  		ffmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
4062  					       V4L2_SUBDEV_FORMAT_ACTIVE,
4063  					       ATOMISP_SUBDEV_PAD_SINK);
4064  		fc = atomisp_find_in_fmt_conv(ffmt->code);
4065  	}
4066  	if (!fc)
4067  		return -EINVAL;
4068  
4069  	if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW &&
4070  	    raw_output_format_match_input(fc->atomisp_in_fmt, pix->pixelformat))
4071  		return -EINVAL;
4072  
4073  	/*
4074  	 * Configure viewfinder also when vfpp is disabled: the
4075  	 * CSS still requires viewfinder configuration.
4076  	 */
4077  	{
4078  		u32 width, height;
4079  
4080  		if (pix->width < 640 || pix->height < 480) {
4081  			width = pix->width;
4082  			height = pix->height;
4083  		} else {
4084  			width = 640;
4085  			height = 480;
4086  		}
4087  
4088  		if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO ||
4089  		    asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
4090  			atomisp_css_video_configure_viewfinder(asd, width, height, 0,
4091  							       IA_CSS_FRAME_FORMAT_NV12);
4092  		} else if (asd->run_mode->val == ATOMISP_RUN_MODE_STILL_CAPTURE ||
4093  			   asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) {
4094  			atomisp_css_capture_configure_viewfinder(asd, width, height, 0,
4095  								 IA_CSS_FRAME_FORMAT_NV12);
4096  		}
4097  	}
4098  
4099  	atomisp_css_input_set_mode(asd, IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
4100  
4101  	for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
4102  		asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipe_extra_configs[i].disable_vf_pp = asd->vfpp->val != ATOMISP_VFPP_ENABLE;
4103  
4104  	/* ISP2401 new input system need to use copy pipe */
4105  	if (asd->copy_mode) {
4106  		pipe_id = IA_CSS_PIPE_ID_COPY;
4107  		atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, false);
4108  	} else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) {
4109  		/* video same in continuouscapture and online modes */
4110  		configure_output = atomisp_css_video_configure_output;
4111  		get_frame_info = atomisp_css_video_get_output_frame_info;
4112  		pipe_id = IA_CSS_PIPE_ID_VIDEO;
4113  	} else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
4114  		configure_output = atomisp_css_video_configure_output;
4115  		get_frame_info = atomisp_css_video_get_output_frame_info;
4116  		pipe_id = IA_CSS_PIPE_ID_VIDEO;
4117  	} else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) {
4118  		configure_output = atomisp_css_preview_configure_output;
4119  		get_frame_info = atomisp_css_preview_get_output_frame_info;
4120  		configure_pp_input = atomisp_css_preview_configure_pp_input;
4121  		pipe_id = IA_CSS_PIPE_ID_PREVIEW;
4122  	} else {
4123  		if (format->sh_fmt == IA_CSS_FRAME_FORMAT_RAW) {
4124  			atomisp_css_capture_set_mode(asd, IA_CSS_CAPTURE_MODE_RAW);
4125  			atomisp_css_enable_dz(asd, false);
4126  		} else {
4127  			atomisp_update_capture_mode(asd);
4128  		}
4129  
4130  		/* in case of ANR, force capture pipe to offline mode */
4131  		atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL,
4132  						  !asd->params.low_light);
4133  
4134  		configure_output = atomisp_css_capture_configure_output;
4135  		get_frame_info = atomisp_css_capture_get_output_frame_info;
4136  		configure_pp_input = atomisp_css_capture_configure_pp_input;
4137  		pipe_id = IA_CSS_PIPE_ID_CAPTURE;
4138  
4139  		if (asd->run_mode->val != ATOMISP_RUN_MODE_STILL_CAPTURE) {
4140  			dev_err(isp->dev,
4141  				"Need to set the running mode first\n");
4142  			asd->run_mode->val = ATOMISP_RUN_MODE_STILL_CAPTURE;
4143  		}
4144  	}
4145  
4146  	if (asd->copy_mode)
4147  		ret = atomisp_css_copy_configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL,
4148  							pix->width, pix->height,
4149  							format->planar ? pix->bytesperline :
4150  							pix->bytesperline * 8 / format->depth,
4151  							format->sh_fmt);
4152  	else
4153  		ret = configure_output(asd, pix->width, pix->height,
4154  				       format->planar ? pix->bytesperline :
4155  				       pix->bytesperline * 8 / format->depth,
4156  				       format->sh_fmt);
4157  	if (ret) {
4158  		dev_err(isp->dev, "configure_output %ux%u, format %8.8x\n",
4159  			pix->width, pix->height, format->sh_fmt);
4160  		return -EINVAL;
4161  	}
4162  
4163  	ret = configure_pp_input(asd, isp_sink_crop->width, isp_sink_crop->height);
4164  	if (ret) {
4165  		dev_err(isp->dev, "configure_pp_input %ux%u\n",
4166  			isp_sink_crop->width,
4167  			isp_sink_crop->height);
4168  		return -EINVAL;
4169  	}
4170  	if (asd->copy_mode)
4171  		ret = atomisp_css_copy_get_output_frame_info(asd,
4172  							     ATOMISP_INPUT_STREAM_GENERAL,
4173  							     output_info);
4174  	else
4175  		ret = get_frame_info(asd, output_info);
4176  	if (ret) {
4177  		dev_err(isp->dev, "__get_frame_info %ux%u (padded to %u) returned %d\n",
4178  			pix->width, pix->height, pix->bytesperline, ret);
4179  		return ret;
4180  	}
4181  
4182  	atomisp_update_grid_info(asd, pipe_id);
4183  	return 0;
4184  }
4185  
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)4186  static void atomisp_get_dis_envelop(struct atomisp_sub_device *asd,
4187  				    unsigned int width, unsigned int height,
4188  				    unsigned int *dvs_env_w, unsigned int *dvs_env_h)
4189  {
4190  	if (asd->params.video_dis_en &&
4191  	    asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
4192  		/* envelope is 20% of the output resolution */
4193  		/*
4194  		 * dvs envelope cannot be round up.
4195  		 * it would cause ISP timeout and color switch issue
4196  		 */
4197  		*dvs_env_w = rounddown(width / 5, ATOM_ISP_STEP_WIDTH);
4198  		*dvs_env_h = rounddown(height / 5, ATOM_ISP_STEP_HEIGHT);
4199  	}
4200  
4201  	asd->params.dis_proj_data_valid = false;
4202  	asd->params.css_update_params_needed = true;
4203  }
4204  
atomisp_check_copy_mode(struct atomisp_sub_device * asd,const struct v4l2_pix_format * f)4205  static void atomisp_check_copy_mode(struct atomisp_sub_device *asd,
4206  				    const struct v4l2_pix_format *f)
4207  {
4208  	struct v4l2_mbus_framefmt *sink, *src;
4209  
4210  	if (!IS_ISP2401) {
4211  		/* Only used for the new input system */
4212  		asd->copy_mode = false;
4213  		return;
4214  	}
4215  
4216  	sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
4217  				       V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK);
4218  	src = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
4219  				      V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE);
4220  
4221  	if (sink->code == src->code && sink->width == f->width && sink->height == f->height)
4222  		asd->copy_mode = true;
4223  	else
4224  		asd->copy_mode = false;
4225  
4226  	dev_dbg(asd->isp->dev, "copy_mode: %d\n", asd->copy_mode);
4227  }
4228  
atomisp_set_fmt_to_snr(struct video_device * vdev,const struct v4l2_pix_format * f,unsigned int dvs_env_w,unsigned int dvs_env_h)4229  static int atomisp_set_fmt_to_snr(struct video_device *vdev, const struct v4l2_pix_format *f,
4230  				  unsigned int dvs_env_w, unsigned int dvs_env_h)
4231  {
4232  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
4233  	struct atomisp_sub_device *asd = pipe->asd;
4234  	struct atomisp_device *isp = asd->isp;
4235  	const struct atomisp_format_bridge *format;
4236  	struct v4l2_mbus_framefmt req_ffmt, ffmt = { };
4237  	struct atomisp_input_stream_info *stream_info =
4238  	    (struct atomisp_input_stream_info *)&ffmt.reserved;
4239  	int ret;
4240  
4241  	format = atomisp_get_format_bridge(f->pixelformat);
4242  	if (!format)
4243  		return -EINVAL;
4244  
4245  	v4l2_fill_mbus_format(&ffmt, f, format->mbus_code);
4246  	ffmt.height += asd->sink_pad_padding_h + dvs_env_h;
4247  	ffmt.width += asd->sink_pad_padding_w + dvs_env_w;
4248  
4249  	dev_dbg(isp->dev, "s_mbus_fmt: ask %ux%u (padding %ux%u, dvs %ux%u)\n",
4250  		ffmt.width, ffmt.height, asd->sink_pad_padding_w, asd->sink_pad_padding_h,
4251  		dvs_env_w, dvs_env_h);
4252  
4253  	__atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info);
4254  
4255  	req_ffmt = ffmt;
4256  
4257  	/* Disable dvs if resolution can't be supported by sensor */
4258  	if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) {
4259  		ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_TRY);
4260  		if (ret)
4261  			return ret;
4262  
4263  		dev_dbg(isp->dev, "video dis: sensor width: %d, height: %d\n",
4264  			ffmt.width, ffmt.height);
4265  
4266  		if (ffmt.width < req_ffmt.width ||
4267  		    ffmt.height < req_ffmt.height) {
4268  			req_ffmt.height -= dvs_env_h;
4269  			req_ffmt.width -= dvs_env_w;
4270  			ffmt = req_ffmt;
4271  			dev_warn(isp->dev,
4272  				 "can not enable video dis due to sensor limitation.");
4273  			asd->params.video_dis_en = false;
4274  		}
4275  	}
4276  
4277  	ret = atomisp_set_sensor_crop_and_fmt(isp, &ffmt, V4L2_SUBDEV_FORMAT_ACTIVE);
4278  	if (ret)
4279  		return ret;
4280  
4281  	__atomisp_update_stream_env(asd, ATOMISP_INPUT_STREAM_GENERAL, stream_info);
4282  
4283  	dev_dbg(isp->dev, "sensor width: %d, height: %d\n",
4284  		ffmt.width, ffmt.height);
4285  
4286  	if (ffmt.width < ATOM_ISP_STEP_WIDTH ||
4287  	    ffmt.height < ATOM_ISP_STEP_HEIGHT)
4288  		return -EINVAL;
4289  
4290  	if (asd->params.video_dis_en && asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO &&
4291  	    (ffmt.width < req_ffmt.width || ffmt.height < req_ffmt.height)) {
4292  		dev_warn(isp->dev,
4293  			 "can not enable video dis due to sensor limitation.");
4294  		asd->params.video_dis_en = false;
4295  	}
4296  
4297  	atomisp_subdev_set_ffmt(&asd->subdev, NULL,
4298  				V4L2_SUBDEV_FORMAT_ACTIVE,
4299  				ATOMISP_SUBDEV_PAD_SINK, &ffmt);
4300  
4301  	return css_input_resolution_changed(asd, &ffmt);
4302  }
4303  
atomisp_set_fmt(struct video_device * vdev,struct v4l2_format * f)4304  int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f)
4305  {
4306  	struct atomisp_device *isp = video_get_drvdata(vdev);
4307  	struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
4308  	struct atomisp_sub_device *asd = pipe->asd;
4309  	const struct atomisp_format_bridge *format_bridge;
4310  	const struct atomisp_format_bridge *snr_format_bridge;
4311  	struct ia_css_frame_info output_info;
4312  	unsigned int dvs_env_w = 0, dvs_env_h = 0;
4313  	struct v4l2_mbus_framefmt isp_source_fmt = {0};
4314  	struct v4l2_rect isp_sink_crop;
4315  	int ret;
4316  
4317  	ret = atomisp_pipe_check(pipe, true);
4318  	if (ret)
4319  		return ret;
4320  
4321  	dev_dbg(isp->dev,
4322  		"setting resolution %ux%u bytesperline %u\n",
4323  		f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.bytesperline);
4324  
4325  	/* Ensure that the resolution is equal or below the maximum supported */
4326  	ret = atomisp_try_fmt(isp, &f->fmt.pix, &format_bridge, &snr_format_bridge);
4327  	if (ret)
4328  		return ret;
4329  
4330  	pipe->sh_fmt = format_bridge->sh_fmt;
4331  	pipe->pix.pixelformat = format_bridge->pixelformat;
4332  
4333  	atomisp_subdev_get_ffmt(&asd->subdev, NULL,
4334  				V4L2_SUBDEV_FORMAT_ACTIVE,
4335  				ATOMISP_SUBDEV_PAD_SINK)->code =
4336  				    snr_format_bridge->mbus_code;
4337  
4338  	isp_source_fmt.code = format_bridge->mbus_code;
4339  	atomisp_subdev_set_ffmt(&asd->subdev, NULL,
4340  				V4L2_SUBDEV_FORMAT_ACTIVE,
4341  				ATOMISP_SUBDEV_PAD_SOURCE, &isp_source_fmt);
4342  
4343  	if (atomisp_subdev_format_conversion(asd)) {
4344  		atomisp_get_padding(isp, f->fmt.pix.width, f->fmt.pix.height,
4345  				    &asd->sink_pad_padding_w, &asd->sink_pad_padding_h);
4346  	} else {
4347  		asd->sink_pad_padding_w = 0;
4348  		asd->sink_pad_padding_h = 0;
4349  	}
4350  
4351  	atomisp_get_dis_envelop(asd, f->fmt.pix.width, f->fmt.pix.height,
4352  				&dvs_env_w, &dvs_env_h);
4353  
4354  	ret = atomisp_set_fmt_to_snr(vdev, &f->fmt.pix, dvs_env_w, dvs_env_h);
4355  	if (ret) {
4356  		dev_warn(isp->dev,
4357  			 "Set format to sensor failed with %d\n", ret);
4358  		return -EINVAL;
4359  	}
4360  
4361  	atomisp_csi_lane_config(isp);
4362  
4363  	atomisp_check_copy_mode(asd, &f->fmt.pix);
4364  
4365  	isp_sink_crop = *atomisp_subdev_get_rect(&asd->subdev, NULL,
4366  			V4L2_SUBDEV_FORMAT_ACTIVE,
4367  			ATOMISP_SUBDEV_PAD_SINK,
4368  			V4L2_SEL_TGT_CROP);
4369  
4370  	/* Try to enable YUV downscaling if ISP input is 10 % (either
4371  	 * width or height) bigger than the desired result. */
4372  	if (!IS_MOFD ||
4373  	    isp_sink_crop.width * 9 / 10 < f->fmt.pix.width ||
4374  	    isp_sink_crop.height * 9 / 10 < f->fmt.pix.height ||
4375  	    (atomisp_subdev_format_conversion(asd) &&
4376  	     (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO ||
4377  	      asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER))) {
4378  		isp_sink_crop.width = f->fmt.pix.width;
4379  		isp_sink_crop.height = f->fmt.pix.height;
4380  
4381  		atomisp_subdev_set_selection(&asd->subdev, NULL,
4382  					     V4L2_SUBDEV_FORMAT_ACTIVE,
4383  					     ATOMISP_SUBDEV_PAD_SOURCE, V4L2_SEL_TGT_COMPOSE,
4384  					     0, &isp_sink_crop);
4385  	} else {
4386  		struct v4l2_rect main_compose = {0};
4387  
4388  		main_compose.width = isp_sink_crop.width;
4389  		main_compose.height =
4390  		    DIV_ROUND_UP(main_compose.width * f->fmt.pix.height,
4391  				 f->fmt.pix.width);
4392  		if (main_compose.height > isp_sink_crop.height) {
4393  			main_compose.height = isp_sink_crop.height;
4394  			main_compose.width =
4395  			    DIV_ROUND_UP(main_compose.height *
4396  					 f->fmt.pix.width,
4397  					 f->fmt.pix.height);
4398  		}
4399  
4400  		atomisp_subdev_set_selection(&asd->subdev, NULL,
4401  					     V4L2_SUBDEV_FORMAT_ACTIVE,
4402  					     ATOMISP_SUBDEV_PAD_SOURCE,
4403  					     V4L2_SEL_TGT_COMPOSE, 0,
4404  					     &main_compose);
4405  	}
4406  
4407  	ret = atomisp_set_fmt_to_isp(vdev, &output_info, &f->fmt.pix);
4408  	if (ret) {
4409  		dev_warn(isp->dev, "Can't set format on ISP. Error %d\n", ret);
4410  		return -EINVAL;
4411  	}
4412  
4413  	atomisp_fill_pix_format(&pipe->pix, f->fmt.pix.width, f->fmt.pix.height, format_bridge);
4414  
4415  	f->fmt.pix = pipe->pix;
4416  
4417  	dev_dbg(isp->dev, "%s: %dx%d, image size: %d, %d bytes per line\n",
4418  		__func__,
4419  		f->fmt.pix.width, f->fmt.pix.height,
4420  		f->fmt.pix.sizeimage, f->fmt.pix.bytesperline);
4421  
4422  	return 0;
4423  }
4424  
atomisp_set_shading_table(struct atomisp_sub_device * asd,struct atomisp_shading_table * user_shading_table)4425  int atomisp_set_shading_table(struct atomisp_sub_device *asd,
4426  			      struct atomisp_shading_table *user_shading_table)
4427  {
4428  	struct ia_css_shading_table *shading_table;
4429  	struct ia_css_shading_table *free_table;
4430  	unsigned int len_table;
4431  	int i;
4432  	int ret = 0;
4433  
4434  	if (!user_shading_table)
4435  		return -EINVAL;
4436  
4437  	if (!user_shading_table->enable) {
4438  		asd->params.config.shading_table = NULL;
4439  		asd->params.sc_en = false;
4440  		return 0;
4441  	}
4442  
4443  	/* If enabling, all tables must be set */
4444  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
4445  		if (!user_shading_table->data[i])
4446  			return -EINVAL;
4447  	}
4448  
4449  	/* Shading table size per color */
4450  	if (user_shading_table->width > SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR ||
4451  	    user_shading_table->height > SH_CSS_MAX_SCTBL_HEIGHT_PER_COLOR)
4452  		return -EINVAL;
4453  
4454  	shading_table = atomisp_css_shading_table_alloc(
4455  			    user_shading_table->width, user_shading_table->height);
4456  	if (!shading_table)
4457  		return -ENOMEM;
4458  
4459  	len_table = user_shading_table->width * user_shading_table->height *
4460  		    ATOMISP_SC_TYPE_SIZE;
4461  	for (i = 0; i < ATOMISP_NUM_SC_COLORS; i++) {
4462  		ret = copy_from_user(shading_table->data[i],
4463  				     (void __user *)user_shading_table->data[i],
4464  				     len_table);
4465  		if (ret) {
4466  			free_table = shading_table;
4467  			ret = -EFAULT;
4468  			goto out;
4469  		}
4470  	}
4471  	shading_table->sensor_width = user_shading_table->sensor_width;
4472  	shading_table->sensor_height = user_shading_table->sensor_height;
4473  	shading_table->fraction_bits = user_shading_table->fraction_bits;
4474  
4475  	free_table = asd->params.css_param.shading_table;
4476  	asd->params.css_param.shading_table = shading_table;
4477  	asd->params.config.shading_table = shading_table;
4478  	asd->params.sc_en = true;
4479  
4480  out:
4481  	if (free_table)
4482  		atomisp_css_shading_table_free(free_table);
4483  
4484  	return ret;
4485  }
4486  
__checking_exp_id(struct atomisp_sub_device * asd,int exp_id)4487  static int __checking_exp_id(struct atomisp_sub_device *asd, int exp_id)
4488  {
4489  	struct atomisp_device *isp = asd->isp;
4490  
4491  	if (!asd->enable_raw_buffer_lock->val) {
4492  		dev_warn(isp->dev, "%s Raw Buffer Lock is disable.\n", __func__);
4493  		return -EINVAL;
4494  	}
4495  	if (!asd->streaming) {
4496  		dev_err(isp->dev, "%s streaming %d invalid exp_id %d.\n",
4497  			__func__, exp_id, asd->streaming);
4498  		return -EINVAL;
4499  	}
4500  	if ((exp_id > ATOMISP_MAX_EXP_ID) || (exp_id <= 0)) {
4501  		dev_err(isp->dev, "%s exp_id %d invalid.\n", __func__, exp_id);
4502  		return -EINVAL;
4503  	}
4504  	return 0;
4505  }
4506  
atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device * asd)4507  void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd)
4508  {
4509  	unsigned long flags;
4510  
4511  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
4512  	memset(asd->raw_buffer_bitmap, 0, sizeof(asd->raw_buffer_bitmap));
4513  	asd->raw_buffer_locked_count = 0;
4514  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
4515  }
4516  
__is_raw_buffer_locked(struct atomisp_sub_device * asd,int exp_id)4517  static int __is_raw_buffer_locked(struct atomisp_sub_device *asd, int exp_id)
4518  {
4519  	int *bitmap, bit;
4520  	unsigned long flags;
4521  	int ret;
4522  
4523  	if (__checking_exp_id(asd, exp_id))
4524  		return -EINVAL;
4525  
4526  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
4527  	bit = exp_id % 32;
4528  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
4529  	ret = ((*bitmap) & (1 << bit));
4530  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
4531  	return !ret;
4532  }
4533  
__clear_raw_buffer_bitmap(struct atomisp_sub_device * asd,int exp_id)4534  static int __clear_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
4535  {
4536  	int *bitmap, bit;
4537  	unsigned long flags;
4538  
4539  	if (__is_raw_buffer_locked(asd, exp_id))
4540  		return -EINVAL;
4541  
4542  	bitmap = asd->raw_buffer_bitmap + exp_id / 32;
4543  	bit = exp_id % 32;
4544  	spin_lock_irqsave(&asd->raw_buffer_bitmap_lock, flags);
4545  	(*bitmap) &= ~(1 << bit);
4546  	asd->raw_buffer_locked_count--;
4547  	spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags);
4548  
4549  	dev_dbg(asd->isp->dev, "%s: exp_id %d,  raw_buffer_locked_count %d\n",
4550  		__func__, exp_id, asd->raw_buffer_locked_count);
4551  	return 0;
4552  }
4553  
atomisp_exp_id_capture(struct atomisp_sub_device * asd,int * exp_id)4554  int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id)
4555  {
4556  	struct atomisp_device *isp = asd->isp;
4557  	int value = *exp_id;
4558  	int ret;
4559  
4560  	lockdep_assert_held(&isp->mutex);
4561  
4562  	ret = __is_raw_buffer_locked(asd, value);
4563  	if (ret) {
4564  		dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
4565  		return -EINVAL;
4566  	}
4567  
4568  	dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
4569  	ret = atomisp_css_exp_id_capture(asd, value);
4570  	if (ret) {
4571  		dev_err(isp->dev, "%s exp_id %d failed.\n", __func__, value);
4572  		return -EIO;
4573  	}
4574  	return 0;
4575  }
4576  
atomisp_exp_id_unlock(struct atomisp_sub_device * asd,int * exp_id)4577  int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id)
4578  {
4579  	struct atomisp_device *isp = asd->isp;
4580  	int value = *exp_id;
4581  	int ret;
4582  
4583  	lockdep_assert_held(&isp->mutex);
4584  
4585  	ret = __clear_raw_buffer_bitmap(asd, value);
4586  	if (ret) {
4587  		dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret);
4588  		return -EINVAL;
4589  	}
4590  
4591  	dev_dbg(isp->dev, "%s exp_id %d\n", __func__, value);
4592  	ret = atomisp_css_exp_id_unlock(asd, value);
4593  	if (ret)
4594  		dev_err(isp->dev, "%s exp_id %d failed, err %d.\n",
4595  			__func__, value, ret);
4596  
4597  	return ret;
4598  }
4599  
atomisp_enable_dz_capt_pipe(struct atomisp_sub_device * asd,unsigned int * enable)4600  int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd,
4601  				unsigned int *enable)
4602  {
4603  	bool value;
4604  
4605  	if (!enable)
4606  		return -EINVAL;
4607  
4608  	value = *enable > 0;
4609  
4610  	atomisp_en_dz_capt_pipe(asd, value);
4611  
4612  	return 0;
4613  }
4614  
atomisp_inject_a_fake_event(struct atomisp_sub_device * asd,int * event)4615  int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event)
4616  {
4617  	if (!event || !asd->streaming)
4618  		return -EINVAL;
4619  
4620  	lockdep_assert_held(&asd->isp->mutex);
4621  
4622  	dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n",
4623  		__func__, *event);
4624  
4625  	switch (*event) {
4626  	case V4L2_EVENT_FRAME_SYNC:
4627  		atomisp_sof_event(asd);
4628  		break;
4629  	case V4L2_EVENT_FRAME_END:
4630  		atomisp_eof_event(asd, 0);
4631  		break;
4632  	case V4L2_EVENT_ATOMISP_3A_STATS_READY:
4633  		atomisp_3a_stats_ready_event(asd, 0);
4634  		break;
4635  	case V4L2_EVENT_ATOMISP_METADATA_READY:
4636  		atomisp_metadata_ready_event(asd, 0);
4637  		break;
4638  	default:
4639  		return -EINVAL;
4640  	}
4641  
4642  	return 0;
4643  }
4644