aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c')
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c1573
1 files changed, 0 insertions, 1573 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
deleted file mode 100644
index ba20344ec560..000000000000
--- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c
+++ /dev/null
@@ -1,1573 +0,0 @@
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010-2017 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- */
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-
-#include <asm/iosf_mbi.h>
-
-#include "../../include/linux/atomisp_gmin_platform.h"
-
-#include "atomisp_cmd.h"
-#include "atomisp_common.h"
-#include "atomisp_fops.h"
-#include "atomisp_file.h"
-#include "atomisp_ioctl.h"
-#include "atomisp_internal.h"
-#include "atomisp_acc.h"
-#include "atomisp-regs.h"
-#include "atomisp_dfs_tables.h"
-#include "atomisp_drvfs.h"
-#include "hmm/hmm.h"
-#include "atomisp_trace_event.h"
-
-#include "hrt/hive_isp_css_mm_hrt.h"
-
-#include "device_access.h"
-
-/* G-Min addition: pull this in from intel_mid_pm.h */
-#define CSTATE_EXIT_LATENCY_C1 1
-
-static uint skip_fwload;
-module_param(skip_fwload, uint, 0644);
-MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load");
-
-/* set reserved memory pool size in page */
-static unsigned int repool_pgnr;
-module_param(repool_pgnr, uint, 0644);
-MODULE_PARM_DESC(repool_pgnr,
- "Set the reserved memory pool size in page (default:0)");
-
-/* set dynamic memory pool size in page */
-unsigned int dypool_pgnr = UINT_MAX;
-module_param(dypool_pgnr, uint, 0644);
-MODULE_PARM_DESC(dypool_pgnr,
- "Set the dynamic memory pool size in page (default:0)");
-
-bool dypool_enable;
-module_param(dypool_enable, bool, 0644);
-MODULE_PARM_DESC(dypool_enable,
- "dynamic memory pool enable/disable (default:disable)");
-
-/* memory optimization: deferred firmware loading */
-bool defer_fw_load;
-module_param(defer_fw_load, bool, 0644);
-MODULE_PARM_DESC(defer_fw_load,
- "Defer FW loading until device is opened (default:disable)");
-
-/* cross componnet debug message flag */
-int dbg_level;
-module_param(dbg_level, int, 0644);
-MODULE_PARM_DESC(dbg_level, "debug message on/off (default:off)");
-
-/* log function switch */
-int dbg_func = 2;
-module_param(dbg_func, int, 0644);
-MODULE_PARM_DESC(dbg_func,
- "log function switch non/trace_printk/printk (default:printk)");
-
-int mipicsi_flag;
-module_param(mipicsi_flag, int, 0644);
-MODULE_PARM_DESC(mipicsi_flag, "mipi csi compression predictor algorithm");
-
-/*set to 16x16 since this is the amount of lines and pixels the sensor
-exports extra. If these are kept at the 10x8 that they were on, in yuv
-downscaling modes incorrect resolutions where requested to the sensor
-driver with strange outcomes as a result. The proper way tot do this
-would be to have a list of tables the specify the sensor res, mipi rec,
-output res, and isp output res. however since we do not have this yet,
-the chosen solution is the next best thing. */
-int pad_w = 16;
-module_param(pad_w, int, 0644);
-MODULE_PARM_DESC(pad_w, "extra data for ISP processing");
-
-int pad_h = 16;
-module_param(pad_h, int, 0644);
-MODULE_PARM_DESC(pad_h, "extra data for ISP processing");
-
-struct device *atomisp_dev;
-
-void __iomem *atomisp_io_base;
-
-int atomisp_video_init(struct atomisp_video_pipe *video, const char *name)
-{
- int ret;
- const char *direction;
-
- switch (video->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- direction = "output";
- video->pad.flags = MEDIA_PAD_FL_SINK;
- video->vdev.fops = &atomisp_fops;
- video->vdev.ioctl_ops = &atomisp_ioctl_ops;
- break;
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
- direction = "input";
- video->pad.flags = MEDIA_PAD_FL_SOURCE;
- video->vdev.fops = &atomisp_file_fops;
- video->vdev.ioctl_ops = &atomisp_file_ioctl_ops;
- break;
- default:
- return -EINVAL;
- }
-
- ret = media_entity_pads_init(&video->vdev.entity, 1, &video->pad);
- if (ret < 0)
- return ret;
-
- /* Initialize the video device. */
- snprintf(video->vdev.name, sizeof(video->vdev.name),
- "ATOMISP ISP %s %s", name, direction);
- video->vdev.release = video_device_release_empty;
- video_set_drvdata(&video->vdev, video->isp);
-
- return 0;
-}
-
-void atomisp_acc_init(struct atomisp_acc_pipe *video, const char *name)
-{
- video->vdev.fops = &atomisp_fops;
- video->vdev.ioctl_ops = &atomisp_ioctl_ops;
-
- /* Initialize the video device. */
- snprintf(video->vdev.name, sizeof(video->vdev.name),
- "ATOMISP ISP %s", name);
- video->vdev.release = video_device_release_empty;
- video_set_drvdata(&video->vdev, video->isp);
-}
-
-int atomisp_video_register(struct atomisp_video_pipe *video,
- struct v4l2_device *vdev)
-{
- int ret;
-
- video->vdev.v4l2_dev = vdev;
-
- ret = video_register_device(&video->vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0)
- dev_err(vdev->dev, "%s: could not register video device (%d)\n",
- __func__, ret);
-
- return ret;
-}
-
-int atomisp_acc_register(struct atomisp_acc_pipe *video,
- struct v4l2_device *vdev)
-{
- int ret;
-
- video->vdev.v4l2_dev = vdev;
-
- ret = video_register_device(&video->vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0)
- dev_err(vdev->dev, "%s: could not register video device (%d)\n",
- __func__, ret);
-
- return ret;
-}
-
-void atomisp_video_unregister(struct atomisp_video_pipe *video)
-{
- if (video_is_registered(&video->vdev)) {
- media_entity_cleanup(&video->vdev.entity);
- video_unregister_device(&video->vdev);
- }
-}
-
-void atomisp_acc_unregister(struct atomisp_acc_pipe *video)
-{
- if (video_is_registered(&video->vdev))
- video_unregister_device(&video->vdev);
-}
-
-static int atomisp_save_iunit_reg(struct atomisp_device *isp)
-{
- struct pci_dev *dev = isp->pdev;
-
- dev_dbg(isp->dev, "%s\n", __func__);
-
- pci_read_config_word(dev, PCI_COMMAND, &isp->saved_regs.pcicmdsts);
- /* isp->saved_regs.ispmmadr is set from the atomisp_pci_probe() */
- pci_read_config_dword(dev, PCI_MSI_CAPID, &isp->saved_regs.msicap);
- pci_read_config_dword(dev, PCI_MSI_ADDR, &isp->saved_regs.msi_addr);
- pci_read_config_word(dev, PCI_MSI_DATA, &isp->saved_regs.msi_data);
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &isp->saved_regs.intr);
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL,
- &isp->saved_regs.interrupt_control);
-
- pci_read_config_dword(dev, MRFLD_PCI_PMCS,
- &isp->saved_regs.pmcs);
- /* Ensure read/write combining is enabled. */
- pci_read_config_dword(dev, PCI_I_CONTROL,
- &isp->saved_regs.i_control);
- isp->saved_regs.i_control |=
- MRFLD_PCI_I_CONTROL_ENABLE_READ_COMBINING |
- MRFLD_PCI_I_CONTROL_ENABLE_WRITE_COMBINING;
- pci_read_config_dword(dev, MRFLD_PCI_CSI_ACCESS_CTRL_VIOL,
- &isp->saved_regs.csi_access_viol);
- pci_read_config_dword(dev, MRFLD_PCI_CSI_RCOMP_CONTROL,
- &isp->saved_regs.csi_rcomp_config);
- /*
- * Hardware bugs require setting CSI_HS_OVR_CLK_GATE_ON_UPDATE.
- * ANN/CHV: RCOMP updates do not happen when using CSI2+ path
- * and sensor sending "continuous clock".
- * TNG/ANN/CHV: MIPI packets are lost if the HS entry sequence
- * is missed, and IUNIT can hang.
- * For both issues, setting this bit is a workaround.
- */
- isp->saved_regs.csi_rcomp_config |=
- MRFLD_PCI_CSI_HS_OVR_CLK_GATE_ON_UPDATE;
- pci_read_config_dword(dev, MRFLD_PCI_CSI_AFE_TRIM_CONTROL,
- &isp->saved_regs.csi_afe_dly);
- pci_read_config_dword(dev, MRFLD_PCI_CSI_CONTROL,
- &isp->saved_regs.csi_control);
- if (isp->media_dev.hw_revision >=
- (ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT))
- isp->saved_regs.csi_control |=
- MRFLD_PCI_CSI_CONTROL_PARPATHEN;
- /*
- * On CHT CSI_READY bit should be enabled before stream on
- */
- if (IS_CHT && (isp->media_dev.hw_revision >= ((ATOMISP_HW_REVISION_ISP2401 <<
- ATOMISP_HW_REVISION_SHIFT) | ATOMISP_HW_STEPPING_B0)))
- isp->saved_regs.csi_control |=
- MRFLD_PCI_CSI_CONTROL_CSI_READY;
- pci_read_config_dword(dev, MRFLD_PCI_CSI_AFE_RCOMP_CONTROL,
- &isp->saved_regs.csi_afe_rcomp_config);
- pci_read_config_dword(dev, MRFLD_PCI_CSI_AFE_HS_CONTROL,
- &isp->saved_regs.csi_afe_hs_control);
- pci_read_config_dword(dev, MRFLD_PCI_CSI_DEADLINE_CONTROL,
- &isp->saved_regs.csi_deadline_control);
- return 0;
-}
-
-static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp)
-{
- struct pci_dev *dev = isp->pdev;
-
- dev_dbg(isp->dev, "%s\n", __func__);
-
- pci_write_config_word(dev, PCI_COMMAND, isp->saved_regs.pcicmdsts);
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
- isp->saved_regs.ispmmadr);
- pci_write_config_dword(dev, PCI_MSI_CAPID, isp->saved_regs.msicap);
- pci_write_config_dword(dev, PCI_MSI_ADDR, isp->saved_regs.msi_addr);
- pci_write_config_word(dev, PCI_MSI_DATA, isp->saved_regs.msi_data);
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, isp->saved_regs.intr);
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL,
- isp->saved_regs.interrupt_control);
- pci_write_config_dword(dev, PCI_I_CONTROL,
- isp->saved_regs.i_control);
-
- pci_write_config_dword(dev, MRFLD_PCI_PMCS,
- isp->saved_regs.pmcs);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_ACCESS_CTRL_VIOL,
- isp->saved_regs.csi_access_viol);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_RCOMP_CONTROL,
- isp->saved_regs.csi_rcomp_config);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_AFE_TRIM_CONTROL,
- isp->saved_regs.csi_afe_dly);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_CONTROL,
- isp->saved_regs.csi_control);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_AFE_RCOMP_CONTROL,
- isp->saved_regs.csi_afe_rcomp_config);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_AFE_HS_CONTROL,
- isp->saved_regs.csi_afe_hs_control);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_DEADLINE_CONTROL,
- isp->saved_regs.csi_deadline_control);
-
- /*
- * for MRFLD, Software/firmware needs to write a 1 to bit0
- * of the register at CSI_RECEIVER_SELECTION_REG to enable
- * SH CSI backend write 0 will enable Arasan CSI backend,
- * which has bugs(like sighting:4567697 and 4567699) and
- * will be removed in B0
- */
- atomisp_store_uint32(MRFLD_CSI_RECEIVER_SELECTION_REG, 1);
- return 0;
-}
-
-static int atomisp_mrfld_pre_power_down(struct atomisp_device *isp)
-{
- struct pci_dev *dev = isp->pdev;
- u32 irq;
- unsigned long flags;
-
- spin_lock_irqsave(&isp->lock, flags);
- if (isp->sw_contex.power_state == ATOM_ISP_POWER_DOWN) {
- spin_unlock_irqrestore(&isp->lock, flags);
- dev_dbg(isp->dev, "<%s %d.\n", __func__, __LINE__);
- return 0;
- }
- /*
- * MRFLD HAS requirement: cannot power off i-unit if
- * ISP has IRQ not serviced.
- * So, here we need to check if there is any pending
- * IRQ, if so, waiting for it to be served
- */
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- irq = irq & 1 << INTR_IIR;
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, irq);
-
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- if (!(irq & (1 << INTR_IIR)))
- goto done;
-
- atomisp_store_uint32(MRFLD_INTR_CLEAR_REG, 0xFFFFFFFF);
- atomisp_load_uint32(MRFLD_INTR_STATUS_REG, &irq);
- if (irq != 0) {
- dev_err(isp->dev,
- "%s: fail to clear isp interrupt status reg=0x%x\n",
- __func__, irq);
- spin_unlock_irqrestore(&isp->lock, flags);
- return -EAGAIN;
- } else {
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- irq = irq & 1 << INTR_IIR;
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, irq);
-
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- if (!(irq & (1 << INTR_IIR))) {
- atomisp_store_uint32(MRFLD_INTR_ENABLE_REG, 0x0);
- goto done;
- }
- dev_err(isp->dev,
- "%s: error in iunit interrupt. status reg=0x%x\n",
- __func__, irq);
- spin_unlock_irqrestore(&isp->lock, flags);
- return -EAGAIN;
- }
-done:
- /*
- * MRFLD WORKAROUND:
- * before powering off IUNIT, clear the pending interrupts
- * and disable the interrupt. driver should avoid writing 0
- * to IIR. It could block subsequent interrupt messages.
- * HW sighting:4568410.
- */
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- irq &= ~(1 << INTR_IER);
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, irq);
-
- atomisp_msi_irq_uninit(isp, dev);
- atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, true);
- spin_unlock_irqrestore(&isp->lock, flags);
-
- return 0;
-}
-
-
- /*
- * WA for DDR DVFS enable/disable
- * By default, ISP will force DDR DVFS 1600MHz before disable DVFS
- */
-static void punit_ddr_dvfs_enable(bool enable)
-{
- int door_bell = 1 << 8;
- int max_wait = 30;
- int reg;
-
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
- if (enable) {
- reg &= ~(MRFLD_BIT0 | MRFLD_BIT1);
- } else {
- reg |= (MRFLD_BIT1 | door_bell);
- reg &= ~(MRFLD_BIT0);
- }
- iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg);
-
- /* Check Req_ACK to see freq status, wait until door_bell is cleared */
- while ((reg & door_bell) && max_wait--) {
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, &reg);
- usleep_range(100, 500);
- }
-
- if (max_wait == -1)
- pr_info("DDR DVFS, door bell is not cleared within 3ms\n");
-}
-
-/* Workaround for pmu_nc_set_power_state not ready in MRFLD */
-int atomisp_mrfld_power_down(struct atomisp_device *isp)
-{
- unsigned long timeout;
- u32 reg_value;
-
- /* writing 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, &reg_value);
- reg_value &= ~MRFLD_ISPSSPM0_ISPSSC_MASK;
- reg_value |= MRFLD_ISPSSPM0_IUNIT_POWER_OFF;
- iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSPM0, reg_value);
-
- /*WA:Enable DVFS*/
- if (IS_CHT)
- punit_ddr_dvfs_enable(true);
-
- /*
- * There should be no iunit access while power-down is
- * in progress HW sighting: 4567865
- * FIXME: msecs_to_jiffies(50)- experienced value
- */
- timeout = jiffies + msecs_to_jiffies(50);
- while (1) {
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, &reg_value);
- dev_dbg(isp->dev, "power-off in progress, ISPSSPM0: 0x%x\n",
- reg_value);
- /* wait until ISPSSPM0 bit[25:24] shows 0x3 */
- if ((reg_value >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) ==
- MRFLD_ISPSSPM0_IUNIT_POWER_OFF) {
- trace_ipu_cstate(0);
- return 0;
- }
-
- if (time_after(jiffies, timeout)) {
- dev_err(isp->dev, "power-off iunit timeout.\n");
- return -EBUSY;
- }
- /* FIXME: experienced value for delay */
- usleep_range(100, 150);
- }
-}
-
-
-/* Workaround for pmu_nc_set_power_state not ready in MRFLD */
-int atomisp_mrfld_power_up(struct atomisp_device *isp)
-{
- unsigned long timeout;
- u32 reg_value;
-
- /*WA for PUNIT, if DVFS enabled, ISP timeout observed*/
- if (IS_CHT)
- punit_ddr_dvfs_enable(false);
-
- /*
- * FIXME:WA for ECS28A, with this sleep, CTS
- * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort
- * PASS, no impact on other platforms
- */
- if (IS_BYT)
- msleep(10);
-
- /* writing 0x0 to ISPSSPM0 bit[1:0] to power off the IUNIT */
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, &reg_value);
- reg_value &= ~MRFLD_ISPSSPM0_ISPSSC_MASK;
- iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSPM0, reg_value);
-
- /* FIXME: experienced value for delay */
- timeout = jiffies + msecs_to_jiffies(50);
- while (1) {
- iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, &reg_value);
- dev_dbg(isp->dev, "power-on in progress, ISPSSPM0: 0x%x\n",
- reg_value);
- /* wait until ISPSSPM0 bit[25:24] shows 0x0 */
- if ((reg_value >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) ==
- MRFLD_ISPSSPM0_IUNIT_POWER_ON) {
- trace_ipu_cstate(1);
- return 0;
- }
-
- if (time_after(jiffies, timeout)) {
- dev_err(isp->dev, "power-on iunit timeout.\n");
- return -EBUSY;
- }
- /* FIXME: experienced value for delay */
- usleep_range(100, 150);
- }
-}
-
-int atomisp_runtime_suspend(struct device *dev)
-{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
- int ret;
-
- ret = atomisp_mrfld_pre_power_down(isp);
- if (ret)
- return ret;
-
- /*Turn off the ISP d-phy*/
- ret = atomisp_ospm_dphy_down(isp);
- if (ret)
- return ret;
- pm_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
- return atomisp_mrfld_power_down(isp);
-}
-
-int atomisp_runtime_resume(struct device *dev)
-{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
- int ret;
-
- ret = atomisp_mrfld_power_up(isp);
- if (ret)
- return ret;
-
- pm_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
- if (isp->sw_contex.power_state == ATOM_ISP_POWER_DOWN) {
- /*Turn on ISP d-phy */
- ret = atomisp_ospm_dphy_up(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to power up ISP!.\n");
- return -EINVAL;
- }
- }
-
- /*restore register values for iUnit and iUnitPHY registers*/
- if (isp->saved_regs.pcicmdsts)
- atomisp_restore_iunit_reg(isp);
-
- atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, true);
- return 0;
-}
-
-static int __maybe_unused atomisp_suspend(struct device *dev)
-{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
- /* FIXME: only has one isp_subdev at present */
- struct atomisp_sub_device *asd = &isp->asd[0];
- unsigned long flags;
- int ret;
-
- /*
- * FIXME: Suspend is not supported by sensors. Abort if any video
- * node was opened.
- */
- if (atomisp_dev_users(isp))
- return -EBUSY;
-
- spin_lock_irqsave(&isp->lock, flags);
- if (asd->streaming != ATOMISP_DEVICE_STREAMING_DISABLED) {
- spin_unlock_irqrestore(&isp->lock, flags);
- dev_err(isp->dev, "atomisp cannot suspend at this time.\n");
- return -EINVAL;
- }
- spin_unlock_irqrestore(&isp->lock, flags);
-
- ret = atomisp_mrfld_pre_power_down(isp);
- if (ret)
- return ret;
-
- /*Turn off the ISP d-phy */
- ret = atomisp_ospm_dphy_down(isp);
- if (ret) {
- dev_err(isp->dev, "fail to power off ISP\n");
- return ret;
- }
- pm_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE);
- return atomisp_mrfld_power_down(isp);
-}
-
-static int __maybe_unused atomisp_resume(struct device *dev)
-{
- struct atomisp_device *isp = (struct atomisp_device *)
- dev_get_drvdata(dev);
- int ret;
-
- ret = atomisp_mrfld_power_up(isp);
- if (ret)
- return ret;
-
- pm_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
-
- /*Turn on ISP d-phy */
- ret = atomisp_ospm_dphy_up(isp);
- if (ret) {
- dev_err(isp->dev, "Failed to power up ISP!.\n");
- return -EINVAL;
- }
-
- /*restore register values for iUnit and iUnitPHY registers*/
- if (isp->saved_regs.pcicmdsts)
- atomisp_restore_iunit_reg(isp);
-
- atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, true);
- return 0;
-}
-
-int atomisp_csi_lane_config(struct atomisp_device *isp)
-{
- static const struct {
- u8 code;
- u8 lanes[MRFLD_PORT_NUM];
- } portconfigs[] = {
- /* Tangier/Merrifield available lane configurations */
- { 0x00, { 4, 1, 0 } }, /* 00000 */
- { 0x01, { 3, 1, 0 } }, /* 00001 */
- { 0x02, { 2, 1, 0 } }, /* 00010 */
- { 0x03, { 1, 1, 0 } }, /* 00011 */
- { 0x04, { 2, 1, 2 } }, /* 00100 */
- { 0x08, { 3, 1, 1 } }, /* 01000 */
- { 0x09, { 2, 1, 1 } }, /* 01001 */
- { 0x0a, { 1, 1, 1 } }, /* 01010 */
-
- /* Anniedale/Moorefield only configurations */
- { 0x10, { 4, 2, 0 } }, /* 10000 */
- { 0x11, { 3, 2, 0 } }, /* 10001 */
- { 0x12, { 2, 2, 0 } }, /* 10010 */
- { 0x13, { 1, 2, 0 } }, /* 10011 */
- { 0x14, { 2, 2, 2 } }, /* 10100 */
- { 0x18, { 3, 2, 1 } }, /* 11000 */
- { 0x19, { 2, 2, 1 } }, /* 11001 */
- { 0x1a, { 1, 2, 1 } }, /* 11010 */
- };
-
- unsigned int i, j;
- u8 sensor_lanes[MRFLD_PORT_NUM] = { 0 };
- u32 csi_control;
- int nportconfigs;
- u32 port_config_mask;
- int port3_lanes_shift;
-
- if (isp->media_dev.hw_revision <
- ATOMISP_HW_REVISION_ISP2401_LEGACY <<
- ATOMISP_HW_REVISION_SHIFT) {
- /* Merrifield */
- port_config_mask = MRFLD_PORT_CONFIG_MASK;
- port3_lanes_shift = MRFLD_PORT3_LANES_SHIFT;
- } else {
- /* Moorefield / Cherryview */
- port_config_mask = CHV_PORT_CONFIG_MASK;
- port3_lanes_shift = CHV_PORT3_LANES_SHIFT;
- }
-
- if (isp->media_dev.hw_revision <
- ATOMISP_HW_REVISION_ISP2401 <<
- ATOMISP_HW_REVISION_SHIFT) {
- /* Merrifield / Moorefield legacy input system */
- nportconfigs = MRFLD_PORT_CONFIG_NUM;
- } else {
- /* Moorefield / Cherryview new input system */
- nportconfigs = ARRAY_SIZE(portconfigs);
- }
-
- for (i = 0; i < isp->input_cnt; i++) {
- struct camera_mipi_info *mipi_info;
-
- if (isp->inputs[i].type != RAW_CAMERA &&
- isp->inputs[i].type != SOC_CAMERA)
- continue;
-
- mipi_info = atomisp_to_sensor_mipi_info(isp->inputs[i].camera);
- if (!mipi_info)
- continue;
-
- switch (mipi_info->port) {
- case ATOMISP_CAMERA_PORT_PRIMARY:
- sensor_lanes[0] = mipi_info->num_lanes;
- break;
- case ATOMISP_CAMERA_PORT_SECONDARY:
- sensor_lanes[1] = mipi_info->num_lanes;
- break;
- case ATOMISP_CAMERA_PORT_TERTIARY:
- sensor_lanes[2] = mipi_info->num_lanes;
- break;
- default:
- dev_err(isp->dev,
- "%s: invalid port: %d for the %dth sensor\n",
- __func__, mipi_info->port, i);
- return -EINVAL;
- }
- }
-
- for (i = 0; i < nportconfigs; i++) {
- for (j = 0; j < MRFLD_PORT_NUM; j++)
- if (sensor_lanes[j] &&
- sensor_lanes[j] != portconfigs[i].lanes[j])
- break;
-
- if (j == MRFLD_PORT_NUM)
- break; /* Found matching setting */
- }
-
- if (i >= nportconfigs) {
- dev_err(isp->dev,
- "%s: could not find the CSI port setting for %d-%d-%d\n",
- __func__,
- sensor_lanes[0], sensor_lanes[1], sensor_lanes[2]);
- return -EINVAL;
- }
-
- pci_read_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, &csi_control);
- csi_control &= ~port_config_mask;
- csi_control |= (portconfigs[i].code << MRFLD_PORT_CONFIGCODE_SHIFT)
- | (portconfigs[i].lanes[0] ? 0 : (1 << MRFLD_PORT1_ENABLE_SHIFT))
- | (portconfigs[i].lanes[1] ? 0 : (1 << MRFLD_PORT2_ENABLE_SHIFT))
- | (portconfigs[i].lanes[2] ? 0 : (1 << MRFLD_PORT3_ENABLE_SHIFT))
- | (((1 << portconfigs[i].lanes[0]) - 1) << MRFLD_PORT1_LANES_SHIFT)
- | (((1 << portconfigs[i].lanes[1]) - 1) << MRFLD_PORT2_LANES_SHIFT)
- | (((1 << portconfigs[i].lanes[2]) - 1) << port3_lanes_shift);
-
- pci_write_config_dword(isp->pdev, MRFLD_PCI_CSI_CONTROL, csi_control);
-
- dev_dbg(isp->dev,
- "%s: the portconfig is %d-%d-%d, CSI_CONTROL is 0x%08X\n",
- __func__, portconfigs[i].lanes[0], portconfigs[i].lanes[1],
- portconfigs[i].lanes[2], csi_control);
-
- return 0;
-}
-
-static int atomisp_subdev_probe(struct atomisp_device *isp)
-{
- const struct atomisp_platform_data *pdata;
- struct intel_v4l2_subdev_table *subdevs;
- int ret, raw_index = -1;
-
- pdata = atomisp_get_platform_data();
- if (pdata == NULL) {
- dev_err(isp->dev, "no platform data available\n");
- return 0;
- }
-
- for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) {
- struct v4l2_subdev *subdev;
- struct i2c_board_info *board_info =
- &subdevs->v4l2_subdev.board_info;
- struct i2c_adapter *adapter =
- i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id);
- int sensor_num, i;
-
- if (adapter == NULL) {
- dev_err(isp->dev,
- "Failed to find i2c adapter for subdev %s\n",
- board_info->type);
- break;
- }
-
- /* In G-Min, the sensor devices will already be probed
- * (via ACPI) and registered, do not create new
- * ones */
- subdev = atomisp_gmin_find_subdev(adapter, board_info);
- ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev);
- if (ret) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- if (subdev == NULL) {
- dev_warn(isp->dev, "Subdev %s detection fail\n",
- board_info->type);
- continue;
- }
-
- dev_info(isp->dev, "Subdev %s successfully register\n",
- board_info->type);
-
- switch (subdevs->type) {
- case RAW_CAMERA:
- raw_index = isp->input_cnt;
- dev_dbg(isp->dev, "raw_index: %d\n", raw_index);
- case SOC_CAMERA:
- dev_dbg(isp->dev, "SOC_INDEX: %d\n", isp->input_cnt);
- if (isp->input_cnt >= ATOM_ISP_MAX_INPUTS) {
- dev_warn(isp->dev,
- "too many atomisp inputs, ignored\n");
- break;
- }
-
- isp->inputs[isp->input_cnt].type = subdevs->type;
- isp->inputs[isp->input_cnt].port = subdevs->port;
- isp->inputs[isp->input_cnt].camera = subdev;
- isp->inputs[isp->input_cnt].sensor_index = 0;
- /*
- * initialize the subdev frame size, then next we can
- * judge whether frame_size store effective value via
- * pixel_format.
- */
- isp->inputs[isp->input_cnt].frame_size.pixel_format = 0;
- isp->inputs[isp->input_cnt].camera_caps =
- atomisp_get_default_camera_caps();
- sensor_num = isp->inputs[isp->input_cnt]
- .camera_caps->sensor_num;
- isp->input_cnt++;
- for (i = 1; i < sensor_num; i++) {
- if (isp->input_cnt >= ATOM_ISP_MAX_INPUTS) {
- dev_warn(isp->dev,
- "atomisp inputs out of range\n");
- break;
- }
- isp->inputs[isp->input_cnt] =
- isp->inputs[isp->input_cnt - 1];
- isp->inputs[isp->input_cnt].sensor_index = i;
- isp->input_cnt++;
- }
- break;
- case CAMERA_MOTOR:
- isp->motor = subdev;
- break;
- case LED_FLASH:
- case XENON_FLASH:
- isp->flash = subdev;
- break;
- default:
- dev_dbg(isp->dev, "unknown subdev probed\n");
- break;
- }
-
- }
-
- /*
- * HACK: Currently VCM belongs to primary sensor only, but correct
- * approach must be to acquire from platform code which sensor
- * owns it.
- */
- if (isp->motor && raw_index >= 0)
- isp->inputs[raw_index].motor = isp->motor;
-
- /* Proceed even if no modules detected. For COS mode and no modules. */
- if (!isp->inputs[0].camera)
- dev_warn(isp->dev, "no camera attached or fail to detect\n");
-
- return atomisp_csi_lane_config(isp);
-}
-
-static void atomisp_unregister_entities(struct atomisp_device *isp)
-{
- unsigned int i;
- struct v4l2_subdev *sd, *next;
-
- for (i = 0; i < isp->num_of_streams; i++)
- atomisp_subdev_unregister_entities(&isp->asd[i]);
- atomisp_tpg_unregister_entities(&isp->tpg);
- atomisp_file_input_unregister_entities(&isp->file_dev);
- for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++)
- atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]);
-
- list_for_each_entry_safe(sd, next, &isp->v4l2_dev.subdevs, list)
- v4l2_device_unregister_subdev(sd);
-
- v4l2_device_unregister(&isp->v4l2_dev);
- media_device_unregister(&isp->media_dev);
-}
-
-static int atomisp_register_entities(struct atomisp_device *isp)
-{
- int ret = 0;
- unsigned int i;
-
- isp->media_dev.dev = isp->dev;
-
- strlcpy(isp->media_dev.model, "Intel Atom ISP",
- sizeof(isp->media_dev.model));
-
- media_device_init(&isp->media_dev);
- isp->v4l2_dev.mdev = &isp->media_dev;
- ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
- if (ret < 0) {
- dev_err(isp->dev, "%s: V4L2 device registration failed (%d)\n",
- __func__, ret);
- goto v4l2_device_failed;
- }
-
- ret = atomisp_subdev_probe(isp);
- if (ret < 0)
- goto csi_and_subdev_probe_failed;
-
- /* Register internal entities */
- for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) {
- ret = atomisp_mipi_csi2_register_entities(&isp->csi2_port[i],
- &isp->v4l2_dev);
- if (ret == 0)
- continue;
-
- /* error case */
- dev_err(isp->dev, "failed to register the CSI port: %d\n", i);
- /* deregister all registered CSI ports */
- while (i--)
- atomisp_mipi_csi2_unregister_entities(
- &isp->csi2_port[i]);
-
- goto csi_and_subdev_probe_failed;
- }
-
- ret =
- atomisp_file_input_register_entities(&isp->file_dev, &isp->v4l2_dev);
- if (ret < 0) {
- dev_err(isp->dev, "atomisp_file_input_register_entities\n");
- goto file_input_register_failed;
- }
-
- ret = atomisp_tpg_register_entities(&isp->tpg, &isp->v4l2_dev);
- if (ret < 0) {
- dev_err(isp->dev, "atomisp_tpg_register_entities\n");
- goto tpg_register_failed;
- }
-
- for (i = 0; i < isp->num_of_streams; i++) {
- struct atomisp_sub_device *asd = &isp->asd[i];
-
- ret = atomisp_subdev_register_entities(asd, &isp->v4l2_dev);
- if (ret < 0) {
- dev_err(isp->dev,
- "atomisp_subdev_register_entities fail\n");
- for (; i > 0; i--)
- atomisp_subdev_unregister_entities(
- &isp->asd[i - 1]);
- goto subdev_register_failed;
- }
- }
-
- for (i = 0; i < isp->num_of_streams; i++) {
- struct atomisp_sub_device *asd = &isp->asd[i];
-
- init_completion(&asd->init_done);
-
- asd->delayed_init_workq =
- alloc_workqueue(isp->v4l2_dev.name, WQ_CPU_INTENSIVE,
- 1);
- if (asd->delayed_init_workq == NULL) {
- dev_err(isp->dev,
- "Failed to initialize delayed init workq\n");
- ret = -ENOMEM;
-
- for (; i > 0; i--)
- destroy_workqueue(isp->asd[i - 1].
- delayed_init_workq);
- goto wq_alloc_failed;
- }
- INIT_WORK(&asd->delayed_init_work, atomisp_delayed_init_work);
- }
-
- for (i = 0; i < isp->input_cnt; i++) {
- if (isp->inputs[i].port >= ATOMISP_CAMERA_NR_PORTS) {
- dev_err(isp->dev, "isp->inputs port %d not supported\n",
- isp->inputs[i].port);
- ret = -EINVAL;
- goto link_failed;
- }
- }
-
- dev_dbg(isp->dev,
- "FILE_INPUT enable, camera_cnt: %d\n", isp->input_cnt);
- isp->inputs[isp->input_cnt].type = FILE_INPUT;
- isp->inputs[isp->input_cnt].port = -1;
- isp->inputs[isp->input_cnt].camera_caps =
- atomisp_get_default_camera_caps();
- isp->inputs[isp->input_cnt++].camera = &isp->file_dev.sd;
-
- if (isp->input_cnt < ATOM_ISP_MAX_INPUTS) {
- dev_dbg(isp->dev,
- "TPG detected, camera_cnt: %d\n", isp->input_cnt);
- isp->inputs[isp->input_cnt].type = TEST_PATTERN;
- isp->inputs[isp->input_cnt].port = -1;
- isp->inputs[isp->input_cnt].camera_caps =
- atomisp_get_default_camera_caps();
- isp->inputs[isp->input_cnt++].camera = &isp->tpg.sd;
- } else {
- dev_warn(isp->dev, "too many atomisp inputs, TPG ignored.\n");
- }
-
- ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
- if (ret < 0)
- goto link_failed;
-
- return media_device_register(&isp->media_dev);
-
-link_failed:
- for (i = 0; i < isp->num_of_streams; i++)
- destroy_workqueue(isp->asd[i].
- delayed_init_workq);
-wq_alloc_failed:
- for (i = 0; i < isp->num_of_streams; i++)
- atomisp_subdev_unregister_entities(
- &isp->asd[i]);
-subdev_register_failed:
- atomisp_tpg_unregister_entities(&isp->tpg);
-tpg_register_failed:
- atomisp_file_input_unregister_entities(&isp->file_dev);
-file_input_register_failed:
- for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++)
- atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]);
-csi_and_subdev_probe_failed:
- v4l2_device_unregister(&isp->v4l2_dev);
-v4l2_device_failed:
- media_device_unregister(&isp->media_dev);
- media_device_cleanup(&isp->media_dev);
- return ret;
-}
-
-static int atomisp_initialize_modules(struct atomisp_device *isp)
-{
- int ret;
-
- ret = atomisp_mipi_csi2_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "mipi csi2 initialization failed\n");
- goto error_mipi_csi2;
- }
-
- ret = atomisp_file_input_init(isp);
- if (ret < 0) {
- dev_err(isp->dev,
- "file input device initialization failed\n");
- goto error_file_input;
- }
-
- ret = atomisp_tpg_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "tpg initialization failed\n");
- goto error_tpg;
- }
-
- ret = atomisp_subdev_init(isp);
- if (ret < 0) {
- dev_err(isp->dev, "ISP subdev initialization failed\n");
- goto error_isp_subdev;
- }
-
-
- return 0;
-
-error_isp_subdev:
-error_tpg:
- atomisp_tpg_cleanup(isp);
-error_file_input:
- atomisp_file_input_cleanup(isp);
-error_mipi_csi2:
- atomisp_mipi_csi2_cleanup(isp);
- return ret;
-}
-
-static void atomisp_uninitialize_modules(struct atomisp_device *isp)
-{
- atomisp_tpg_cleanup(isp);
- atomisp_file_input_cleanup(isp);
- atomisp_mipi_csi2_cleanup(isp);
-}
-
-const struct firmware *
-atomisp_load_firmware(struct atomisp_device *isp)
-{
- const struct firmware *fw;
- int rc;
- char *fw_path = NULL;
-
- if (skip_fwload)
- return NULL;
-
- if (isp->media_dev.hw_revision ==
- ((ATOMISP_HW_REVISION_ISP2401 << ATOMISP_HW_REVISION_SHIFT)
- | ATOMISP_HW_STEPPING_A0))
- fw_path = "shisp_2401a0_v21.bin";
-
- if (isp->media_dev.hw_revision ==
- ((ATOMISP_HW_REVISION_ISP2401_LEGACY << ATOMISP_HW_REVISION_SHIFT)
- | ATOMISP_HW_STEPPING_A0))
- fw_path = "shisp_2401a0_legacy_v21.bin";
-
- if (isp->media_dev.hw_revision ==
- ((ATOMISP_HW_REVISION_ISP2400 << ATOMISP_HW_REVISION_SHIFT)
- | ATOMISP_HW_STEPPING_B0))
- fw_path = "shisp_2400b0_v21.bin";
-
- if (!fw_path) {
- dev_err(isp->dev, "Unsupported hw_revision 0x%x\n",
- isp->media_dev.hw_revision);
- return NULL;
- }
-
- rc = request_firmware(&fw, fw_path, isp->dev);
- if (rc) {
- dev_err(isp->dev,
- "atomisp: Error %d while requesting firmware %s\n",
- rc, fw_path);
- return NULL;
- }
-
- return fw;
-}
-
-/*
- * Check for flags the driver was compiled with against the PCI
- * device. Always returns true on other than ISP 2400.
- */
-static bool is_valid_device(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- unsigned int a0_max_id;
-
- switch (id->device & ATOMISP_PCI_DEVICE_SOC_MASK) {
- case ATOMISP_PCI_DEVICE_SOC_MRFLD:
- a0_max_id = ATOMISP_PCI_REV_MRFLD_A0_MAX;
- break;
- case ATOMISP_PCI_DEVICE_SOC_BYT:
- a0_max_id = ATOMISP_PCI_REV_BYT_A0_MAX;
- break;
- default:
- return true;
- }
-
- return dev->revision > a0_max_id;
-}
-
-static int init_atomisp_wdts(struct atomisp_device *isp)
-{
- int i, err;
-
- atomic_set(&isp->wdt_work_queued, 0);
- isp->wdt_work_queue = alloc_workqueue(isp->v4l2_dev.name, 0, 1);
- if (isp->wdt_work_queue == NULL) {
- dev_err(isp->dev, "Failed to initialize wdt work queue\n");
- err = -ENOMEM;
- goto alloc_fail;
- }
- INIT_WORK(&isp->wdt_work, atomisp_wdt_work);
-
- for (i = 0; i < isp->num_of_streams; i++) {
- struct atomisp_sub_device *asd = &isp->asd[i];
-#ifndef ISP2401
- timer_setup(&asd->wdt, atomisp_wdt, 0);
-#else
- timer_setup(&asd->video_out_capture.wdt, atomisp_wdt, 0);
- timer_setup(&asd->video_out_preview.wdt, atomisp_wdt, 0);
- timer_setup(&asd->video_out_vf.wdt, atomisp_wdt, 0);
- timer_setup(&asd->video_out_video_capture.wdt, atomisp_wdt, 0);
-#endif
- }
- return 0;
-alloc_fail:
- return err;
-}
-
-#define ATOM_ISP_PCI_BAR 0
-
-static int atomisp_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- const struct atomisp_platform_data *pdata;
- struct atomisp_device *isp;
- unsigned int start;
- void __iomem *base;
- int err, val;
- u32 irq;
-
- if (!dev) {
- dev_err(&dev->dev, "atomisp: error device ptr\n");
- return -EINVAL;
- }
-
- if (!is_valid_device(dev, id))
- return -ENODEV;
- /* Pointer to struct device. */
- atomisp_dev = &dev->dev;
-
- pdata = atomisp_get_platform_data();
- if (pdata == NULL)
- dev_warn(&dev->dev, "no platform data available\n");
-
- err = pcim_enable_device(dev);
- if (err) {
- dev_err(&dev->dev, "Failed to enable CI ISP device (%d)\n",
- err);
- return err;
- }
-
- start = pci_resource_start(dev, ATOM_ISP_PCI_BAR);
- dev_dbg(&dev->dev, "start: 0x%x\n", start);
-
- err = pcim_iomap_regions(dev, 1 << ATOM_ISP_PCI_BAR, pci_name(dev));
- if (err) {
- dev_err(&dev->dev, "Failed to I/O memory remapping (%d)\n",
- err);
- return err;
- }
-
- base = pcim_iomap_table(dev)[ATOM_ISP_PCI_BAR];
- dev_dbg(&dev->dev, "base: %p\n", base);
-
- atomisp_io_base = base;
-
- dev_dbg(&dev->dev, "atomisp_io_base: %p\n", atomisp_io_base);
-
- isp = devm_kzalloc(&dev->dev, sizeof(struct atomisp_device), GFP_KERNEL);
- if (!isp) {
- dev_err(&dev->dev, "Failed to alloc CI ISP structure\n");
- return -ENOMEM;
- }
- isp->pdev = dev;
- isp->dev = &dev->dev;
- isp->sw_contex.power_state = ATOM_ISP_POWER_UP;
- isp->saved_regs.ispmmadr = start;
-
- rt_mutex_init(&isp->mutex);
- mutex_init(&isp->streamoff_mutex);
- spin_lock_init(&isp->lock);
-
- /* This is not a true PCI device on SoC, so the delay is not needed. */
- isp->pdev->d3_delay = 0;
-
- switch (id->device & ATOMISP_PCI_DEVICE_SOC_MASK) {
- case ATOMISP_PCI_DEVICE_SOC_MRFLD:
- isp->media_dev.hw_revision =
- (ATOMISP_HW_REVISION_ISP2400
- << ATOMISP_HW_REVISION_SHIFT) |
- ATOMISP_HW_STEPPING_B0;
-
- switch (id->device) {
- case ATOMISP_PCI_DEVICE_SOC_MRFLD_1179:
- isp->dfs = &dfs_config_merr_1179;
- break;
- case ATOMISP_PCI_DEVICE_SOC_MRFLD_117A:
- isp->dfs = &dfs_config_merr_117a;
- break;
- default:
- isp->dfs = &dfs_config_merr;
- break;
- }
- isp->hpll_freq = HPLL_FREQ_1600MHZ;
- break;
- case ATOMISP_PCI_DEVICE_SOC_BYT:
- isp->media_dev.hw_revision =
- (ATOMISP_HW_REVISION_ISP2400
- << ATOMISP_HW_REVISION_SHIFT) |
- ATOMISP_HW_STEPPING_B0;
-#ifdef FIXME
- if (INTEL_MID_BOARD(3, TABLET, BYT, BLK, PRO, CRV2) ||
- INTEL_MID_BOARD(3, TABLET, BYT, BLK, ENG, CRV2)) {
- isp->dfs = &dfs_config_byt_cr;
- isp->hpll_freq = HPLL_FREQ_2000MHZ;
- } else
-#endif
- {
- isp->dfs = &dfs_config_byt;
- isp->hpll_freq = HPLL_FREQ_1600MHZ;
- }
- /* HPLL frequency is known to be device-specific, but we don't
- * have specs yet for exactly how it varies. Default to
- * BYT-CR but let provisioning set it via EFI variable */
- isp->hpll_freq = gmin_get_var_int(&dev->dev, "HpllFreq",
- HPLL_FREQ_2000MHZ);
-
- /*
- * for BYT/CHT we are put isp into D3cold to avoid pci registers access
- * in power off. Set d3cold_delay to 0 since default 100ms is not
- * necessary.
- */
- isp->pdev->d3cold_delay = 0;
- break;
- case ATOMISP_PCI_DEVICE_SOC_ANN:
- isp->media_dev.hw_revision = (
-#ifdef ISP2401_NEW_INPUT_SYSTEM
- ATOMISP_HW_REVISION_ISP2401
-#else
- ATOMISP_HW_REVISION_ISP2401_LEGACY
-#endif
- << ATOMISP_HW_REVISION_SHIFT);
- isp->media_dev.hw_revision |= isp->pdev->revision < 2 ?
- ATOMISP_HW_STEPPING_A0 : ATOMISP_HW_STEPPING_B0;
- isp->dfs = &dfs_config_merr;
- isp->hpll_freq = HPLL_FREQ_1600MHZ;
- break;
- case ATOMISP_PCI_DEVICE_SOC_CHT:
- isp->media_dev.hw_revision = (
-#ifdef ISP2401_NEW_INPUT_SYSTEM
- ATOMISP_HW_REVISION_ISP2401
-#else
- ATOMISP_HW_REVISION_ISP2401_LEGACY
-#endif
- << ATOMISP_HW_REVISION_SHIFT);
- isp->media_dev.hw_revision |= isp->pdev->revision < 2 ?
- ATOMISP_HW_STEPPING_A0 : ATOMISP_HW_STEPPING_B0;
-
- isp->dfs = &dfs_config_cht;
- isp->pdev->d3cold_delay = 0;
-
- iosf_mbi_read(CCK_PORT, MBI_REG_READ, CCK_FUSE_REG_0, &val);
- switch (val & CCK_FUSE_HPLL_FREQ_MASK) {
- case 0x00:
- isp->hpll_freq = HPLL_FREQ_800MHZ;
- break;
- case 0x01:
- isp->hpll_freq = HPLL_FREQ_1600MHZ;
- break;
- case 0x02:
- isp->hpll_freq = HPLL_FREQ_2000MHZ;
- break;
- default:
- isp->hpll_freq = HPLL_FREQ_1600MHZ;
- dev_warn(isp->dev,
- "read HPLL from cck failed.default 1600MHz.\n");
- }
- break;
- default:
- dev_err(&dev->dev, "un-supported IUNIT device\n");
- return -ENODEV;
- }
-
- dev_info(&dev->dev, "ISP HPLL frequency base = %d MHz\n",
- isp->hpll_freq);
-
- isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY;
-
- /* Load isp firmware from user space */
- if (!defer_fw_load) {
- isp->firmware = atomisp_load_firmware(isp);
- if (!isp->firmware) {
- err = -ENOENT;
- goto load_fw_fail;
- }
-
- err = atomisp_css_check_firmware_version(isp);
- if (err) {
- dev_dbg(&dev->dev, "Firmware version check failed\n");
- goto fw_validation_fail;
- }
- }
-
- pci_set_master(dev);
- pci_set_drvdata(dev, isp);
-
- err = pci_enable_msi(dev);
- if (err) {
- dev_err(&dev->dev, "Failed to enable msi (%d)\n", err);
- goto enable_msi_fail;
- }
-
- atomisp_msi_irq_init(isp, dev);
-
- pm_qos_add_request(&isp->pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- /*
- * for MRFLD, Software/firmware needs to write a 1 to bit 0 of
- * the register at CSI_RECEIVER_SELECTION_REG to enable SH CSI
- * backend write 0 will enable Arasan CSI backend, which has
- * bugs(like sighting:4567697 and 4567699) and will be removed
- * in B0
- */
- atomisp_store_uint32(MRFLD_CSI_RECEIVER_SELECTION_REG, 1);
-
- if ((id->device & ATOMISP_PCI_DEVICE_SOC_MASK) ==
- ATOMISP_PCI_DEVICE_SOC_MRFLD) {
- u32 csi_afe_trim;
-
- /*
- * Workaround for imbalance data eye issue which is observed
- * on TNG B0.
- */
- pci_read_config_dword(dev, MRFLD_PCI_CSI_AFE_TRIM_CONTROL,
- &csi_afe_trim);
- csi_afe_trim &= ~((MRFLD_PCI_CSI_HSRXCLKTRIM_MASK <<
- MRFLD_PCI_CSI1_HSRXCLKTRIM_SHIFT) |
- (MRFLD_PCI_CSI_HSRXCLKTRIM_MASK <<
- MRFLD_PCI_CSI2_HSRXCLKTRIM_SHIFT) |
- (MRFLD_PCI_CSI_HSRXCLKTRIM_MASK <<
- MRFLD_PCI_CSI3_HSRXCLKTRIM_SHIFT));
- csi_afe_trim |= (MRFLD_PCI_CSI1_HSRXCLKTRIM <<
- MRFLD_PCI_CSI1_HSRXCLKTRIM_SHIFT) |
- (MRFLD_PCI_CSI2_HSRXCLKTRIM <<
- MRFLD_PCI_CSI2_HSRXCLKTRIM_SHIFT) |
- (MRFLD_PCI_CSI3_HSRXCLKTRIM <<
- MRFLD_PCI_CSI3_HSRXCLKTRIM_SHIFT);
- pci_write_config_dword(dev, MRFLD_PCI_CSI_AFE_TRIM_CONTROL,
- csi_afe_trim);
- }
-
- err = atomisp_initialize_modules(isp);
- if (err < 0) {
- dev_err(&dev->dev, "atomisp_initialize_modules (%d)\n", err);
- goto initialize_modules_fail;
- }
-
- err = atomisp_register_entities(isp);
- if (err < 0) {
- dev_err(&dev->dev, "atomisp_register_entities failed (%d)\n",
- err);
- goto register_entities_fail;
- }
- err = atomisp_create_pads_links(isp);
- if (err < 0)
- goto register_entities_fail;
- /* init atomisp wdts */
- if (init_atomisp_wdts(isp) != 0)
- goto wdt_work_queue_fail;
-
- /* save the iunit context only once after all the values are init'ed. */
- atomisp_save_iunit_reg(isp);
-
- pm_runtime_put_noidle(&dev->dev);
- pm_runtime_allow(&dev->dev);
-
- hmm_init_mem_stat(repool_pgnr, dypool_enable, dypool_pgnr);
- err = hmm_pool_register(repool_pgnr, HMM_POOL_TYPE_RESERVED);
- if (err) {
- dev_err(&dev->dev, "Failed to register reserved memory pool.\n");
- goto hmm_pool_fail;
- }
-
- /* Init ISP memory management */
- hmm_init();
-
- err = devm_request_threaded_irq(&dev->dev, dev->irq,
- atomisp_isr, atomisp_isr_thread,
- IRQF_SHARED, "isp_irq", isp);
- if (err) {
- dev_err(&dev->dev, "Failed to request irq (%d)\n", err);
- goto request_irq_fail;
- }
-
- /* Load firmware into ISP memory */
- if (!defer_fw_load) {
- err = atomisp_css_load_firmware(isp);
- if (err) {
- dev_err(&dev->dev, "Failed to init css.\n");
- goto css_init_fail;
- }
- } else {
- dev_dbg(&dev->dev, "Skip css init.\n");
- }
- /* Clear FW image from memory */
- release_firmware(isp->firmware);
- isp->firmware = NULL;
- isp->css_env.isp_css_fw.data = NULL;
-
- atomisp_drvfs_init(&dev->driver->driver, isp);
-
- return 0;
-
-css_init_fail:
- devm_free_irq(&dev->dev, dev->irq, isp);
-request_irq_fail:
- hmm_cleanup();
- hmm_pool_unregister(HMM_POOL_TYPE_RESERVED);
-hmm_pool_fail:
- destroy_workqueue(isp->wdt_work_queue);
-wdt_work_queue_fail:
- atomisp_acc_cleanup(isp);
- atomisp_unregister_entities(isp);
-register_entities_fail:
- atomisp_uninitialize_modules(isp);
-initialize_modules_fail:
- pm_qos_remove_request(&isp->pm_qos);
- atomisp_msi_irq_uninit(isp, dev);
-enable_msi_fail:
-fw_validation_fail:
- release_firmware(isp->firmware);
-load_fw_fail:
- /*
- * Switch off ISP, as keeping it powered on would prevent
- * reaching S0ix states.
- *
- * The following lines have been copied from atomisp suspend path
- */
-
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- irq = irq & 1 << INTR_IIR;
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, irq);
-
- pci_read_config_dword(dev, PCI_INTERRUPT_CTRL, &irq);
- irq &= ~(1 << INTR_IER);
- pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, irq);
-
- atomisp_msi_irq_uninit(isp, dev);
-
- atomisp_ospm_dphy_down(isp);
-
- /* Address later when we worry about the ...field chips */
- if (IS_ENABLED(CONFIG_PM) && atomisp_mrfld_power_down(isp))
- dev_err(&dev->dev, "Failed to switch off ISP\n");
- return err;
-}
-
-static void atomisp_pci_remove(struct pci_dev *dev)
-{
- struct atomisp_device *isp = (struct atomisp_device *)
- pci_get_drvdata(dev);
-
- atomisp_drvfs_exit();
-
- atomisp_acc_cleanup(isp);
-
- atomisp_css_unload_firmware(isp);
- hmm_cleanup();
-
- pm_runtime_forbid(&dev->dev);
- pm_runtime_get_noresume(&dev->dev);
- pm_qos_remove_request(&isp->pm_qos);
-
- atomisp_msi_irq_uninit(isp, dev);
- atomisp_unregister_entities(isp);
-
- destroy_workqueue(isp->wdt_work_queue);
- atomisp_file_input_cleanup(isp);
-
- release_firmware(isp->firmware);
-
- hmm_pool_unregister(HMM_POOL_TYPE_RESERVED);
-}
-
-static const struct pci_device_id atomisp_pci_tbl[] = {
-#if defined(ISP2400) || defined(ISP2400B0)
- /* Merrifield */
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1178)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1179)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x117a)},
- /* Baytrail */
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0f38)},
-#elif defined(ISP2401)
- /* Anniedale (Merrifield+ / Moorefield) */
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1478)},
- /* Cherrytrail */
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x22b8)},
-#endif
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl);
-
-static const struct dev_pm_ops atomisp_pm_ops = {
- .runtime_suspend = atomisp_runtime_suspend,
- .runtime_resume = atomisp_runtime_resume,
- .suspend = atomisp_suspend,
- .resume = atomisp_resume,
-};
-
-static struct pci_driver atomisp_pci_driver = {
- .driver = {
- .pm = &atomisp_pm_ops,
- },
- .name = "atomisp-isp2",
- .id_table = atomisp_pci_tbl,
- .probe = atomisp_pci_probe,
- .remove = atomisp_pci_remove,
-};
-
-static int __init atomisp_init(void)
-{
- return pci_register_driver(&atomisp_pci_driver);
-}
-
-static void __exit atomisp_exit(void)
-{
- pci_unregister_driver(&atomisp_pci_driver);
-}
-
-module_init(atomisp_init);
-module_exit(atomisp_exit);
-
-MODULE_AUTHOR("Wen Wang <wen.w.wang@intel.com>");
-MODULE_AUTHOR("Xiaolin Zhang <xiaolin.zhang@intel.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver");