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