On Sun, Oct 14, 2018 at 8:54 PM Hans de Goede <hdegoede@xxxxxxxxxx> wrote: > > The Image Signal Processor found on Cherry Trail devices is brought up in > D0 state on devices which have camera sensors attached to it. The ISP will > not enter D3 state again without some massaging of its registers beforehand > and the ISP not being in D3 state blocks the SoC from entering S0ix modes. > > There was a driver for the ISP in drivers/staging but that got removed > again because it never worked. It does not seem likely that a real > driver for the ISP will be added to the mainline kernel anytime soon. > > This commit adds a dummy driver which contains the necessary magic from > the staging driver to powerdown the ISP, so that Cherry Trail devices where > the ISP is used will properly use S0ix modes when suspended. > > Together with other recent S0ix related fixes this allows S0ix modes to > be entered on e.g. a Chuwi Hi8 Pro and a HP x2 210. > There are might be slight improvements, but in general it's okay. Applied, thanks! P.S. It's possible we need to add Merrifield ID there, I will do it myself along with cosmetic changes as a separate patches later on. > BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=196915 > Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> > --- > Changes in v2: > -Rename the driver and Kconfig option from intel-isp-dummy to intel-atomisp2-pm > --- > MAINTAINERS | 6 ++ > drivers/platform/x86/Kconfig | 12 +++ > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/intel_atomisp2_pm.c | 119 +++++++++++++++++++++++ > 4 files changed, 138 insertions(+) > create mode 100644 drivers/platform/x86/intel_atomisp2_pm.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 2c5d5c6859b8..ba9e5da792ea 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -7306,6 +7306,12 @@ L: alsa-devel@xxxxxxxxxxxxxxxx (moderated for non-subscribers) > S: Supported > F: sound/soc/intel/ > > +INTEL ATOMISP2 DUMMY / POWER-MANAGEMENT DRIVER > +M: Hans de Goede <hdegoede@xxxxxxxxxx> > +L: platform-driver-x86@xxxxxxxxxxxxxxx > +S: Maintained > +F: drivers/platform/x86/intel_atomisp2_pm.c > + > INTEL C600 SERIES SAS CONTROLLER DRIVER > M: Intel SCU Linux support <intel-linux-scu@xxxxxxxxx> > M: Artur Paszkiewicz <artur.paszkiewicz@xxxxxxxxx> > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig > index 48bec711e5e3..5eedcec0fefe 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -1232,6 +1232,18 @@ config I2C_MULTI_INSTANTIATE > To compile this driver as a module, choose M here: the module > will be called i2c-multi-instantiate. > > +config INTEL_ATOMISP2_PM > + tristate "Intel AtomISP2 dummy / power-management driver" > + depends on PCI && IOSF_MBI && PM > + help > + Power-management driver for Intel's Image Signal Processor found on > + Bay and Cherry Trail devices. This dummy driver's sole purpose is to > + turn the ISP off (put it in D3) to save power and to allow entering > + of S0ix modes. > + > + To compile this driver as a module, choose M here: the module > + will be called intel_atomisp2_pm. > + > endif # X86_PLATFORM_DEVICES > > config PMC_ATOM > diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile > index e6d1becf81ce..dc29af4d8e2f 100644 > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -92,3 +92,4 @@ obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o > obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o > obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o > obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o > +obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o > diff --git a/drivers/platform/x86/intel_atomisp2_pm.c b/drivers/platform/x86/intel_atomisp2_pm.c > new file mode 100644 > index 000000000000..9371603a0ac9 > --- /dev/null > +++ b/drivers/platform/x86/intel_atomisp2_pm.c > @@ -0,0 +1,119 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Dummy driver for Intel's Image Signal Processor found on Bay and Cherry > + * Trail devices. The sole purpose of this driver is to allow the ISP to > + * be put in D3. > + * > + * Copyright (C) 2018 Hans de Goede <hdegoede@xxxxxxxxxx> > + * > + * Based on various non upstream patches for ISP support: > + * Copyright (C) 2010-2017 Intel Corporation. All rights reserved. > + * Copyright (c) 2010 Silicon Hive www.siliconhive.com. > + */ > + > +#include <linux/delay.h> > +#include <linux/module.h> > +#include <linux/mod_devicetable.h> > +#include <linux/pci.h> > +#include <linux/pm_runtime.h> > +#include <asm/iosf_mbi.h> > + > +/* PCI configuration regs */ > +#define PCI_INTERRUPT_CTRL 0x9c > + > +#define PCI_CSI_CONTROL 0xe8 > +#define PCI_CSI_CONTROL_PORTS_OFF_MASK 0x7 > + > +/* IOSF BT_MBI_UNIT_PMC regs */ > +#define ISPSSPM0 0x39 > +#define ISPSSPM0_ISPSSC_OFFSET 0 > +#define ISPSSPM0_ISPSSC_MASK 0x00000003 > +#define ISPSSPM0_ISPSSS_OFFSET 24 > +#define ISPSSPM0_ISPSSS_MASK 0x03000000 > +#define ISPSSPM0_IUNIT_POWER_ON 0x0 > +#define ISPSSPM0_IUNIT_POWER_OFF 0x3 > + > +static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id) > +{ > + unsigned long timeout; > + u32 val; > + > + pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, 0); > + > + /* > + * MRFLD IUNIT DPHY is located in an always-power-on island > + * MRFLD HW design need all CSI ports are disabled before > + * powering down the IUNIT. > + */ > + pci_read_config_dword(dev, PCI_CSI_CONTROL, &val); > + val |= PCI_CSI_CONTROL_PORTS_OFF_MASK; > + pci_write_config_dword(dev, PCI_CSI_CONTROL, val); > + > + /* Write 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */ > + iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, > + ISPSSPM0_IUNIT_POWER_OFF, ISPSSPM0_ISPSSC_MASK); > + > + /* > + * There should be no IUNIT access while power-down is > + * in progress HW sighting: 4567865 > + * Wait up to 50 ms for the IUNIT to shut down. > + */ > + timeout = jiffies + msecs_to_jiffies(50); > + while (1) { > + /* Wait until ISPSSPM0 bit[25:24] shows 0x3 */ > + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &val); > + val = (val & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET; > + if (val == ISPSSPM0_IUNIT_POWER_OFF) > + break; > + > + if (time_after(jiffies, timeout)) { > + dev_err(&dev->dev, "IUNIT power-off timeout.\n"); > + return -EBUSY; > + } > + usleep_range(1000, 2000); > + } > + > + pm_runtime_allow(&dev->dev); > + pm_runtime_put_sync_suspend(&dev->dev); > + > + return 0; > +} > + > +static void isp_remove(struct pci_dev *dev) > +{ > + pm_runtime_get_sync(&dev->dev); > + pm_runtime_forbid(&dev->dev); > +} > + > +static int isp_pci_suspend(struct device *dev) > +{ > + return 0; > +} > + > +static int isp_pci_resume(struct device *dev) > +{ > + return 0; > +} > + > +static UNIVERSAL_DEV_PM_OPS(isp_pm_ops, isp_pci_suspend, > + isp_pci_resume, NULL); > + > +static const struct pci_device_id isp_id_table[] = { > + { PCI_VDEVICE(INTEL, 0x22b8), }, > + { 0, } > +}; > +MODULE_DEVICE_TABLE(pci, isp_id_table); > + > +static struct pci_driver isp_pci_driver = { > + .name = "intel_atomisp2_pm", > + .id_table = isp_id_table, > + .probe = isp_probe, > + .remove = isp_remove, > + .driver.pm = &isp_pm_ops, > +}; > + > +module_pci_driver(isp_pci_driver); > + > +MODULE_DESCRIPTION("Intel AtomISP2 dummy / power-management drv (for suspend)"); > +MODULE_AUTHOR("Hans de Goede <hdegoede@xxxxxxxxxx>"); > +MODULE_LICENSE("GPL v2"); > -- > 2.19.0 > -- With Best Regards, Andy Shevchenko