media: atomisp: Bind and do power-management without firmware
authorHans de Goede <hdegoede@redhat.com>
Sat, 30 Dec 2023 14:31:41 +0000 (15:31 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Thu, 1 Feb 2024 06:04:58 +0000 (07:04 +0100)
The ISP needs to be turned off in a special manner for the SoC
to be able to reach S0i3 during suspend.

When the firmware is missing still bind to the PCI device and
run in pm-only mode which takes care of turning the ISP off
(including turning it off again if the firmware has turned it
on during resume).

In this new pm-only mode the atomisp driver works exactly the same
as the non-staging, pm-only drivers/platform/x86/intel/atomisp2/pm.c
driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/staging/media/atomisp/pci/atomisp_internal.h
drivers/staging/media/atomisp/pci/atomisp_v4l2.c

index d5b077e602caec6ac2863780f660f7aac751ff02..bba9bc64d44745a6313da0ebcae8333b3d5a57b8 100644 (file)
@@ -192,6 +192,7 @@ struct atomisp_device {
        struct dev_pm_domain pm_domain;
        struct pm_qos_request pm_qos;
        s32 max_isr_latency;
+       bool pm_only;
 
        struct atomisp_mipi_csi2_device csi2_port[ATOMISP_CAMERA_NR_PORTS];
        struct atomisp_tpg_device tpg;
index f44be2d656a860b770b6fad7cff8346454d9fe14..7e241f4e9e93aacdfc397f8500485850f62fc609 100644 (file)
@@ -548,7 +548,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
        dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off");
 
        /* WA for P-Unit, if DVFS enabled, ISP timeout observed */
-       if (IS_CHT && enable) {
+       if (IS_CHT && enable && !isp->pm_only) {
                punit_ddr_dvfs_enable(false);
                msleep(20);
        }
@@ -558,7 +558,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable)
                        val, MRFLD_ISPSSPM0_ISPSSC_MASK);
 
        /* WA:Enable DVFS */
-       if (IS_CHT && !enable)
+       if (IS_CHT && !enable && !isp->pm_only)
                punit_ddr_dvfs_enable(true);
 
        /*
@@ -601,11 +601,15 @@ int atomisp_power_off(struct device *dev)
        int ret;
        u32 reg;
 
-       atomisp_css_uninit(isp);
+       if (isp->pm_only) {
+               pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, 0);
+       } else {
+               atomisp_css_uninit(isp);
 
-       ret = atomisp_mrfld_pre_power_down(isp);
-       if (ret)
-               return ret;
+               ret = atomisp_mrfld_pre_power_down(isp);
+               if (ret)
+                       return ret;
+       }
 
        /*
         * MRFLD IUNIT DPHY is located in an always-power-on island
@@ -634,6 +638,9 @@ int atomisp_power_on(struct device *dev)
        pci_restore_state(to_pci_dev(dev));
        cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency);
 
+       if (isp->pm_only)
+               return 0;
+
        /*restore register values for iUnit and iUnitPHY registers*/
        if (isp->saved_regs.pcicmdsts)
                atomisp_restore_iunit_reg(isp);
@@ -1252,6 +1259,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 
        isp->dev = &pdev->dev;
        isp->saved_regs.ispmmadr = start;
+       isp->asd.isp = isp;
 
        mutex_init(&isp->mutex);
        spin_lock_init(&isp->lock);
@@ -1368,8 +1376,13 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 
        /* Load isp firmware from user space */
        isp->firmware = atomisp_load_firmware(isp);
-       if (!isp->firmware)
-               return -ENOENT;
+       if (!isp->firmware) {
+               /* No firmware continue in pm-only mode for S0i3 support */
+               dev_info(&pdev->dev, "Continuing in power-management only mode\n");
+               isp->pm_only = true;
+               atomisp_pm_init(isp);
+               return 0;
+       }
 
        err = sh_css_check_firmware_version(isp->dev, isp->firmware->data);
        if (err) {
@@ -1507,6 +1520,9 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
 
        atomisp_pm_uninit(isp);
 
+       if (isp->pm_only)
+               return;
+
        /* Undo ia_css_init() from atomisp_power_on() */
        atomisp_css_uninit(isp);
        ia_css_unload_firmware();