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