Skip to content

Commit 49ad712

Browse files
jwrdegoedeandy-shev
authored andcommitted
platform/x86: Add Intel AtomISP2 dummy / power-management driver
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. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=196915 Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
1 parent 4104916 commit 49ad712

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7296,6 +7296,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
72967296
S: Supported
72977297
F: sound/soc/intel/
72987298

7299+
INTEL ATOMISP2 DUMMY / POWER-MANAGEMENT DRIVER
7300+
M: Hans de Goede <hdegoede@redhat.com>
7301+
L: platform-driver-x86@vger.kernel.org
7302+
S: Maintained
7303+
F: drivers/platform/x86/intel_atomisp2_pm.c
7304+
72997305
INTEL C600 SERIES SAS CONTROLLER DRIVER
73007306
M: Intel SCU Linux support <intel-linux-scu@intel.com>
73017307
M: Artur Paszkiewicz <artur.paszkiewicz@intel.com>

drivers/platform/x86/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,18 @@ config I2C_MULTI_INSTANTIATE
12741274
To compile this driver as a module, choose M here: the module
12751275
will be called i2c-multi-instantiate.
12761276

1277+
config INTEL_ATOMISP2_PM
1278+
tristate "Intel AtomISP2 dummy / power-management driver"
1279+
depends on PCI && IOSF_MBI && PM
1280+
help
1281+
Power-management driver for Intel's Image Signal Processor found on
1282+
Bay and Cherry Trail devices. This dummy driver's sole purpose is to
1283+
turn the ISP off (put it in D3) to save power and to allow entering
1284+
of S0ix modes.
1285+
1286+
To compile this driver as a module, choose M here: the module
1287+
will be called intel_atomisp2_pm.
1288+
12771289
endif # X86_PLATFORM_DEVICES
12781290

12791291
config PMC_ATOM

drivers/platform/x86/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,4 @@ obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
9595
obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
9696
obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o
9797
obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o
98+
obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Dummy driver for Intel's Image Signal Processor found on Bay and Cherry
4+
* Trail devices. The sole purpose of this driver is to allow the ISP to
5+
* be put in D3.
6+
*
7+
* Copyright (C) 2018 Hans de Goede <hdegoede@redhat.com>
8+
*
9+
* Based on various non upstream patches for ISP support:
10+
* Copyright (C) 2010-2017 Intel Corporation. All rights reserved.
11+
* Copyright (c) 2010 Silicon Hive www.siliconhive.com.
12+
*/
13+
14+
#include <linux/delay.h>
15+
#include <linux/module.h>
16+
#include <linux/mod_devicetable.h>
17+
#include <linux/pci.h>
18+
#include <linux/pm_runtime.h>
19+
#include <asm/iosf_mbi.h>
20+
21+
/* PCI configuration regs */
22+
#define PCI_INTERRUPT_CTRL 0x9c
23+
24+
#define PCI_CSI_CONTROL 0xe8
25+
#define PCI_CSI_CONTROL_PORTS_OFF_MASK 0x7
26+
27+
/* IOSF BT_MBI_UNIT_PMC regs */
28+
#define ISPSSPM0 0x39
29+
#define ISPSSPM0_ISPSSC_OFFSET 0
30+
#define ISPSSPM0_ISPSSC_MASK 0x00000003
31+
#define ISPSSPM0_ISPSSS_OFFSET 24
32+
#define ISPSSPM0_ISPSSS_MASK 0x03000000
33+
#define ISPSSPM0_IUNIT_POWER_ON 0x0
34+
#define ISPSSPM0_IUNIT_POWER_OFF 0x3
35+
36+
static int isp_probe(struct pci_dev *dev, const struct pci_device_id *id)
37+
{
38+
unsigned long timeout;
39+
u32 val;
40+
41+
pci_write_config_dword(dev, PCI_INTERRUPT_CTRL, 0);
42+
43+
/*
44+
* MRFLD IUNIT DPHY is located in an always-power-on island
45+
* MRFLD HW design need all CSI ports are disabled before
46+
* powering down the IUNIT.
47+
*/
48+
pci_read_config_dword(dev, PCI_CSI_CONTROL, &val);
49+
val |= PCI_CSI_CONTROL_PORTS_OFF_MASK;
50+
pci_write_config_dword(dev, PCI_CSI_CONTROL, val);
51+
52+
/* Write 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */
53+
iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0,
54+
ISPSSPM0_IUNIT_POWER_OFF, ISPSSPM0_ISPSSC_MASK);
55+
56+
/*
57+
* There should be no IUNIT access while power-down is
58+
* in progress HW sighting: 4567865
59+
* Wait up to 50 ms for the IUNIT to shut down.
60+
*/
61+
timeout = jiffies + msecs_to_jiffies(50);
62+
while (1) {
63+
/* Wait until ISPSSPM0 bit[25:24] shows 0x3 */
64+
iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM0, &val);
65+
val = (val & ISPSSPM0_ISPSSS_MASK) >> ISPSSPM0_ISPSSS_OFFSET;
66+
if (val == ISPSSPM0_IUNIT_POWER_OFF)
67+
break;
68+
69+
if (time_after(jiffies, timeout)) {
70+
dev_err(&dev->dev, "IUNIT power-off timeout.\n");
71+
return -EBUSY;
72+
}
73+
usleep_range(1000, 2000);
74+
}
75+
76+
pm_runtime_allow(&dev->dev);
77+
pm_runtime_put_sync_suspend(&dev->dev);
78+
79+
return 0;
80+
}
81+
82+
static void isp_remove(struct pci_dev *dev)
83+
{
84+
pm_runtime_get_sync(&dev->dev);
85+
pm_runtime_forbid(&dev->dev);
86+
}
87+
88+
static int isp_pci_suspend(struct device *dev)
89+
{
90+
return 0;
91+
}
92+
93+
static int isp_pci_resume(struct device *dev)
94+
{
95+
return 0;
96+
}
97+
98+
static UNIVERSAL_DEV_PM_OPS(isp_pm_ops, isp_pci_suspend,
99+
isp_pci_resume, NULL);
100+
101+
static const struct pci_device_id isp_id_table[] = {
102+
{ PCI_VDEVICE(INTEL, 0x22b8), },
103+
{ 0, }
104+
};
105+
MODULE_DEVICE_TABLE(pci, isp_id_table);
106+
107+
static struct pci_driver isp_pci_driver = {
108+
.name = "intel_atomisp2_pm",
109+
.id_table = isp_id_table,
110+
.probe = isp_probe,
111+
.remove = isp_remove,
112+
.driver.pm = &isp_pm_ops,
113+
};
114+
115+
module_pci_driver(isp_pci_driver);
116+
117+
MODULE_DESCRIPTION("Intel AtomISP2 dummy / power-management drv (for suspend)");
118+
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
119+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)