about summary refs log tree commit diff
path: root/modules/hardware
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2016-12-15 23:18:58 +0100
committeraszlig <aszlig@redmoonstudios.org>2016-12-15 23:45:01 +0100
commit4a27d62243942c4be181c7129fb532a709a15a8e (patch)
treee82d0c718950270f19efa269b8e09b607b516bc6 /modules/hardware
parent9cadb695e14a573cd9badc18da39bf62ada96365 (diff)
hardware/t100ha: Add Linux 4.9 fixes for intel DRM
This is essentially a cherry-pick of the three commits mentioned in:

https://bugs.freedesktop.org/show_bug.cgi?id=97529#c33

Plus a backport against Linux 4.9 of the following patch:

https://bugs.freedesktop.org/attachment.cgi?id=128410
(essentially https://patchwork.freedesktop.org/series/16242/)

And also the backlight.patch (a PMIC hack) we had before all combined
into one patch, which now should fix the following bug:

https://bugs.freedesktop.org/show_bug.cgi?id=97529

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'modules/hardware')
-rw-r--r--modules/hardware/t100ha/backlight.patch224
-rw-r--r--modules/hardware/t100ha/default.nix4
-rw-r--r--modules/hardware/t100ha/drm.patch767
3 files changed, 769 insertions, 226 deletions
diff --git a/modules/hardware/t100ha/backlight.patch b/modules/hardware/t100ha/backlight.patch
deleted file mode 100644
index 41d7b019..00000000
--- a/modules/hardware/t100ha/backlight.patch
+++ /dev/null
@@ -1,224 +0,0 @@
-diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
-index 3562bf3..4ae5430 100644
---- a/drivers/gpu/drm/i915/intel_dsi.c
-+++ b/drivers/gpu/drm/i915/intel_dsi.c
-@@ -551,6 +551,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
- 	struct drm_device *dev = encoder->base.dev;
- 	struct drm_i915_private *dev_priv = dev->dev_private;
- 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-+	struct intel_connector *intel_connector =
-+		intel_dsi->attached_connector;
- 	enum port port;
- 	u32 temp;
- 
-@@ -564,6 +566,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
- 		msleep(2);
- 	}
- 
-+	intel_panel_disable_backlight(intel_connector);
-+
- 	for_each_dsi_port(port, intel_dsi->ports) {
- 		/* Panel commands can be sent when clock is in LP11 */
- 		I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
-@@ -1093,6 +1097,7 @@ static void intel_dsi_connector_destroy(struct drm_connector *connector)
- 
- 	DRM_DEBUG_KMS("\n");
- 	intel_panel_fini(&intel_connector->panel);
-+	intel_panel_destroy_backlight(connector);
- 	drm_connector_cleanup(connector);
- 	kfree(connector);
- }
-diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
-index 8c8996f..4c8678a 100644
---- a/drivers/gpu/drm/i915/intel_panel.c
-+++ b/drivers/gpu/drm/i915/intel_panel.c
-@@ -32,6 +32,7 @@
- 
- #include <linux/kernel.h>
- #include <linux/moduleparam.h>
-+#include <linux/mfd/intel_soc_pmic.h>
- #include <linux/pwm.h>
- #include "intel_drv.h"
- 
-@@ -544,6 +545,11 @@ static u32 pwm_get_backlight(struct intel_connector *connector)
- 	return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
- }
- 
-+static u32 vlv_pmic_get_backlight(struct intel_connector *connector)
-+{
-+	return intel_soc_pmic_readb(0x4E);
-+}
-+
- static u32 intel_panel_get_backlight(struct intel_connector *connector)
- {
- 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-@@ -635,6 +641,11 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level)
- 	pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
- }
- 
-+static void vlv_pmic_set_backlight(struct intel_connector *connector, u32 level)
-+{
-+	intel_soc_pmic_writeb(0x4E, level);
-+}
-+
- static void
- intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
- {
-@@ -808,6 +819,14 @@ static void pwm_disable_backlight(struct intel_connector *connector)
- 	pwm_disable(panel->backlight.pwm);
- }
- 
-+static void vlv_pmic_disable_backlight(struct intel_connector *connector)
-+{
-+	intel_panel_actually_set_backlight(connector, 0);
-+
-+	intel_soc_pmic_writeb(0x51, 0x00);
-+	intel_soc_pmic_writeb(0x4B, 0x7F);
-+}
-+
- void intel_panel_disable_backlight(struct intel_connector *connector)
- {
- 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-@@ -1073,6 +1092,17 @@ static void pwm_enable_backlight(struct intel_connector *connector)
- 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
- }
- 
-+static void vlv_pmic_enable_backlight(struct intel_connector *connector)
-+{
-+	struct intel_panel *panel = &connector->panel;
-+
-+	intel_soc_pmic_writeb(0x4B, 0xFF);
-+	intel_soc_pmic_writeb(0x4E, 0xFF);
-+	intel_soc_pmic_writeb(0x51, 0x01);
-+
-+	intel_panel_actually_set_backlight(connector, panel->backlight.level);
-+}
-+
- void intel_panel_enable_backlight(struct intel_connector *connector)
- {
- 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-@@ -1657,6 +1687,20 @@ static int pwm_setup_backlight(struct intel_connector *connector,
- 	return 0;
- }
- 
-+static int vlv_pmic_setup_backlight(struct intel_connector *connector,
-+		enum pipe unused)
-+{
-+	struct intel_panel *panel = &connector->panel;
-+
-+	panel->backlight.present = 1;
-+	panel->backlight.min = 0x00;
-+	panel->backlight.max = 0xFF;
-+	panel->backlight.level = 0x5A;
-+	panel->backlight.enabled = 1;
-+
-+	return 0;
-+}
-+
- int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
- {
- 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
-@@ -1664,6 +1708,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
- 	struct intel_panel *panel = &intel_connector->panel;
- 	int ret;
- 
-+	intel_backlight_device_register(intel_connector);
-+
- 	if (!dev_priv->vbt.backlight.present) {
- 		if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
- 			DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n");
-@@ -1744,18 +1790,17 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
- 		panel->backlight.hz_to_pwm = pch_hz_to_pwm;
- 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- 		if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
--			panel->backlight.setup = pwm_setup_backlight;
--			panel->backlight.enable = pwm_enable_backlight;
--			panel->backlight.disable = pwm_disable_backlight;
--			panel->backlight.set = pwm_set_backlight;
--			panel->backlight.get = pwm_get_backlight;
-+			panel->backlight.setup = vlv_pmic_setup_backlight;
-+			panel->backlight.enable = vlv_pmic_enable_backlight;
-+			panel->backlight.disable = vlv_pmic_disable_backlight;
-+			panel->backlight.set = vlv_pmic_set_backlight;
-+			panel->backlight.get = vlv_pmic_get_backlight;
- 		} else {
- 			panel->backlight.setup = vlv_setup_backlight;
- 			panel->backlight.enable = vlv_enable_backlight;
- 			panel->backlight.disable = vlv_disable_backlight;
- 			panel->backlight.set = vlv_set_backlight;
- 			panel->backlight.get = vlv_get_backlight;
--			panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
- 		}
- 	} else if (IS_GEN4(dev_priv)) {
- 		panel->backlight.setup = i965_setup_backlight;
-diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
-index d9e15cf..8af5afd 100644
---- a/drivers/mfd/intel_soc_pmic_core.c
-+++ b/drivers/mfd/intel_soc_pmic_core.c
-@@ -43,6 +43,8 @@ static struct pwm_lookup crc_pwm_lookup[] = {
- 	PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL),
- };
- 
-+static struct intel_soc_pmic *pmic_hack = NULL;
-+
- static int intel_soc_pmic_find_gpio_irq(struct device *dev)
- {
- 	struct gpio_desc *desc;
-@@ -76,6 +78,7 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
- 	config = (struct intel_soc_pmic_config *)id->driver_data;
- 
- 	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
-+	pmic_hack = pmic;
- 	if (!pmic)
- 		return -ENOMEM;
- 
-@@ -167,6 +170,37 @@ static int intel_soc_pmic_resume(struct device *dev)
- }
- #endif
- 
-+int intel_soc_pmic_readb(int reg)
-+{
-+	int ret;
-+	unsigned int val;
-+
-+	if (!pmic_hack) {
-+		ret = -EIO;
-+	} else {
-+		ret = regmap_read(pmic_hack->regmap, reg, &val);
-+		if (!ret) {
-+			ret = val;
-+		}
-+	}
-+
-+	return ret;
-+}
-+EXPORT_SYMBOL(intel_soc_pmic_readb);
-+
-+int intel_soc_pmic_writeb(int reg, u8 val)
-+{
-+	int ret;
-+
-+	if (!pmic_hack) {
-+		ret = -EIO;
-+	} else {
-+		ret = regmap_write(pmic_hack->regmap, reg, val);
-+	}
-+	return ret;
-+}
-+EXPORT_SYMBOL(intel_soc_pmic_writeb);
-+
- static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend,
- 			 intel_soc_pmic_resume);
- 
-diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
-index cf619db..52ad034 100644
---- a/include/linux/mfd/intel_soc_pmic.h
-+++ b/include/linux/mfd/intel_soc_pmic.h
-@@ -29,4 +29,7 @@ struct intel_soc_pmic {
- 	struct device *dev;
- };
- 
-+int intel_soc_pmic_readb(int reg);
-+int intel_soc_pmic_writeb(int reg, u8 val);
-+
- #endif	/* __INTEL_SOC_PMIC_H__ */
diff --git a/modules/hardware/t100ha/default.nix b/modules/hardware/t100ha/default.nix
index ac0a0be4..00a5855d 100644
--- a/modules/hardware/t100ha/default.nix
+++ b/modules/hardware/t100ha/default.nix
@@ -18,8 +18,8 @@ in {
     '');
 
     boot.kernelPatches = [
-      { name = "backlight";
-        patch = ./backlight.patch;
+      { name = "drm";
+        patch = ./drm.patch;
       }
       { name = "meta-keys";
         patch = ./meta-keys.patch;
diff --git a/modules/hardware/t100ha/drm.patch b/modules/hardware/t100ha/drm.patch
new file mode 100644
index 00000000..b33d4b03
--- /dev/null
+++ b/modules/hardware/t100ha/drm.patch
@@ -0,0 +1,767 @@
+diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
+index 8405b5a367d7..7e3545f65257 100644
+--- a/drivers/gpu/drm/i915/intel_bios.h
++++ b/drivers/gpu/drm/i915/intel_bios.h
+@@ -46,14 +46,20 @@ struct edp_power_seq {
+ 	u16 t11_t12;
+ } __packed;
+ 
+-/* MIPI Sequence Block definitions */
++/*
++ * MIPI Sequence Block definitions
++ *
++ * Note the VBT spec has AssertReset / DeassertReset swapped from their
++ * usual naming, we use the proper names here to avoid confusion when
++ * reading the code.
++ */
+ enum mipi_seq {
+ 	MIPI_SEQ_END = 0,
+-	MIPI_SEQ_ASSERT_RESET,
++	MIPI_SEQ_DEASSERT_RESET,	/* Spec says MipiAssertResetPin */
+ 	MIPI_SEQ_INIT_OTP,
+ 	MIPI_SEQ_DISPLAY_ON,
+ 	MIPI_SEQ_DISPLAY_OFF,
+-	MIPI_SEQ_DEASSERT_RESET,
++	MIPI_SEQ_ASSERT_RESET,		/* Spec says MipiDeassertResetPin */
+ 	MIPI_SEQ_BACKLIGHT_ON,		/* sequence block v2+ */
+ 	MIPI_SEQ_BACKLIGHT_OFF,		/* sequence block v2+ */
+ 	MIPI_SEQ_TEAR_ON,		/* sequence block v2+ */
+diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
+index 3cb70d73239b..0ca7a684267c 100644
+--- a/drivers/gpu/drm/i915/intel_display.c
++++ b/drivers/gpu/drm/i915/intel_display.c
+@@ -13775,6 +13775,13 @@ static void update_scanline_offset(struct intel_crtc *crtc)
+ 	 * type. For DP ports it behaves like most other platforms, but on HDMI
+ 	 * there's an extra 1 line difference. So we need to add two instead of
+ 	 * one to the value.
++	 *
++	 * On VLV/CHV DSI the scanline counter would appear to increment
++	 * approx. 1/3 of a scanline before start of vblank. Unfortunately
++	 * that we can't tell whether we're in vblank or not while we're
++	 * on that particular line. We must set scanline_offset to 1 so
++	 * that the vblank timestamps come out correct when we query
++	 * the scanline counter from the vblank interrupt handler.
+ 	 */
+ 	if (IS_GEN2(dev)) {
+ 		const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
+index b2e3d3a334f7..c07ef5e9de95 100644
+--- a/drivers/gpu/drm/i915/intel_dsi.c
++++ b/drivers/gpu/drm/i915/intel_dsi.c
+@@ -80,7 +80,7 @@ enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt)
+ 	}
+ }
+ 
+-static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
++void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
+ {
+ 	struct drm_encoder *encoder = &intel_dsi->base.base;
+ 	struct drm_device *dev = encoder->dev;
+@@ -505,37 +505,83 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder)
+ 	}
+ }
+ 
+-static void intel_dsi_enable(struct intel_encoder *encoder)
+-{
+-	struct drm_device *dev = encoder->base.dev;
+-	struct drm_i915_private *dev_priv = to_i915(dev);
+-	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+-	enum port port;
+-
+-	DRM_DEBUG_KMS("\n");
+-
+-	if (is_cmd_mode(intel_dsi)) {
+-		for_each_dsi_port(port, intel_dsi->ports)
+-			I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
+-	} else {
+-		msleep(20); /* XXX */
+-		for_each_dsi_port(port, intel_dsi->ports)
+-			dpi_send_cmd(intel_dsi, TURN_ON, false, port);
+-		msleep(100);
+-
+-		drm_panel_enable(intel_dsi->panel);
++static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
++			      struct intel_crtc_state *pipe_config);
+ 
+-		for_each_dsi_port(port, intel_dsi->ports)
+-			wait_for_dsi_fifo_empty(intel_dsi, port);
++static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
++{
++	struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+ 
+-		intel_dsi_port_enable(encoder);
+-	}
++	/* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
++	if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
++		return;
+ 
+-	intel_panel_enable_backlight(intel_dsi->attached_connector);
++	msleep(msec);
+ }
+ 
+-static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
+-			      struct intel_crtc_state *pipe_config);
++/*
++ * Panel enable/disable sequences from the spec:
++ *
++ * v2 sequence for video mode:
++ * - power on
++ * - wait t1+t2
++ * - MIPIDeassertResetPin
++ * - clk/data lines to lp-11
++ * - MIPISendInitialDcsCmds
++ * - turn on DPI
++ * - MIPIDisplayOn
++ * - wait t5
++ * - backlight on
++ * ...
++ * - backlight off
++ * - wait t6
++ * - MIPIDisplayOff
++ * - turn off DPI
++ * - clk/data lines to lp-00
++ * - MIPIAssertResetPin
++ * - wait t3
++ * - power off
++ * - wait t4
++ *
++ * v3 sequence for video mode:
++ * - MIPIPanelPowerOn
++ * - MIPIDeassertResetPin
++ * - set clk/data lines to lp-11
++ * - MIPISendInitialDcsCmds (LP)
++ * - turn on DPI
++ * - MIPITearOn (command mode only) + MIPIDisplayOn (LP and HS)
++ * - MIPIBacklightOn
++ * ...
++ * - MIPIBacklightOff
++ * - turn off DPI
++ * - MIPITearOff + MIPIDisplayOff (LP)
++ * - clk/data lines to lp-00
++ * - MIPIAssertResetPin
++ * - MIPIPanelPowerOff
++ *
++ * sequence for command mode:
++ * - power on
++ * - wait t1+t2
++ * - MIPIDeassertResetPin
++ * - clk/data lines to lp-11
++ * - MIPISendInitialDcsCmds
++ * - MIPITearOn
++ * - MIPIDisplayOn
++ * - set pipe to dsr mode
++ * - wait t5
++ * - backlight on
++ * ... issue write_mem_start/write_mem_continue commands ...
++ * - backlight off
++ * - wait t6
++ * - disable pipe dsr mode
++ * - MIPITearOff
++ * - MIPIDisplayOff
++ * - clk/data lines to lp-00
++ * - MIPIAssertResetPin
++ * - wait t3
++ * - power off
++ * - wait t4
++ */
+ 
+ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
+ 				 struct intel_crtc_state *pipe_config,
+@@ -554,14 +600,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
+ 	intel_disable_dsi_pll(encoder);
+ 	intel_enable_dsi_pll(encoder, pipe_config);
+ 
+-	intel_dsi_prepare(encoder, pipe_config);
+-
+-	/* Panel Enable over CRC PMIC */
+-	if (intel_dsi->gpio_panel)
+-		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
+-
+-	msleep(intel_dsi->panel_on_delay);
+-
+ 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ 		u32 val;
+ 
+@@ -571,17 +609,44 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder,
+ 		I915_WRITE(DSPCLK_GATE_D, val);
+ 	}
+ 
+-	/* put device in ready state */
+-	intel_dsi_device_ready(encoder);
++	intel_dsi_prepare(encoder, pipe_config);
++
++	/* Power on, try both CRC pmic gpio and VBT */
++	if (intel_dsi->gpio_panel)
++		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
++	intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
+ 
+-	drm_panel_prepare(intel_dsi->panel);
++	/* Deassert reset */
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
+ 
+-	for_each_dsi_port(port, intel_dsi->ports)
+-		wait_for_dsi_fifo_empty(intel_dsi, port);
++	/* Put device in ready state (LP-11) */
++	intel_dsi_device_ready(encoder);
++
++	/* Send initialization commands in LP mode */
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
+ 
+ 	/* Enable port in pre-enable phase itself because as per hw team
+ 	 * recommendation, port should be enabled befor plane & pipe */
+-	intel_dsi_enable(encoder);
++	if (is_cmd_mode(intel_dsi)) {
++		for_each_dsi_port(port, intel_dsi->ports)
++			I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
++		intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_TEAR_ON);
++		intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
++	} else {
++		msleep(20); /* XXX */
++		for_each_dsi_port(port, intel_dsi->ports)
++			dpi_send_cmd(intel_dsi, TURN_ON, false, port);
++		intel_dsi_msleep(intel_dsi, 100);
++
++		intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
++
++		intel_dsi_port_enable(encoder);
++	}
++
++	/* Enable backlight, both pwm and VBT */
++	intel_panel_enable_backlight(intel_dsi->attached_connector);
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
+ }
+ 
+ static void intel_dsi_enable_nop(struct intel_encoder *encoder,
+@@ -605,8 +670,15 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder,
+ 
+ 	DRM_DEBUG_KMS("\n");
+ 
++	/* Disable backlight, both VBT and pwm */
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
+ 	intel_panel_disable_backlight(intel_dsi->attached_connector);
+ 
++	/*
++	 * XXX: According to the spec we should send SHUTDOWN before
++	 * MIPI_SEQ_DISPLAY_OFF only for v3+ VBTs, but testing in the field
++	 * has shown that we should do this for v2 VBTs too?
++	 */
+ 	if (is_vid_mode(intel_dsi)) {
+ 		/* Send Shutdown command to the panel in LP mode */
+ 		for_each_dsi_port(port, intel_dsi->ports)
+@@ -615,45 +687,6 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder,
+ 	}
+ }
+ 
+-static void intel_dsi_disable(struct intel_encoder *encoder)
+-{
+-	struct drm_device *dev = encoder->base.dev;
+-	struct drm_i915_private *dev_priv = to_i915(dev);
+-	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+-	enum port port;
+-	u32 temp;
+-
+-	DRM_DEBUG_KMS("\n");
+-
+-	if (is_vid_mode(intel_dsi)) {
+-		for_each_dsi_port(port, intel_dsi->ports)
+-			wait_for_dsi_fifo_empty(intel_dsi, port);
+-
+-		intel_dsi_port_disable(encoder);
+-		msleep(2);
+-	}
+-
+-	for_each_dsi_port(port, intel_dsi->ports) {
+-		/* Panel commands can be sent when clock is in LP11 */
+-		I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
+-
+-		intel_dsi_reset_clocks(encoder, port);
+-		I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
+-
+-		temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
+-		temp &= ~VID_MODE_FORMAT_MASK;
+-		I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp);
+-
+-		I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
+-	}
+-	/* if disable packets are sent before sending shutdown packet then in
+-	 * some next enable sequence send turn on packet error is observed */
+-	drm_panel_disable(intel_dsi->panel);
+-
+-	for_each_dsi_port(port, intel_dsi->ports)
+-		wait_for_dsi_fifo_empty(intel_dsi, port);
+-}
+-
+ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
+ {
+ 	struct drm_device *dev = encoder->base.dev;
+@@ -696,8 +729,6 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
+ 		I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
+ 		usleep_range(2000, 2500);
+ 	}
+-
+-	intel_disable_dsi_pll(encoder);
+ }
+ 
+ static void intel_dsi_post_disable(struct intel_encoder *encoder,
+@@ -706,13 +737,50 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder,
+ {
+ 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
++	struct intel_connector *intel_connector = intel_dsi->attached_connector;
++	enum port port;
++	u32 temp;
+ 
+ 	DRM_DEBUG_KMS("\n");
+ 
+-	intel_dsi_disable(encoder);
++	if (is_vid_mode(intel_dsi)) {
++		for_each_dsi_port(port, intel_dsi->ports)
++			wait_for_dsi_fifo_empty(intel_dsi, port);
++
++		intel_dsi_port_disable(encoder);
++		usleep_range(2000, 5000);
++	}
++
++	intel_panel_disable_backlight(intel_connector);
++
++	for_each_dsi_port(port, intel_dsi->ports) {
++		/* Panel commands can be sent when clock is in LP11 */
++		I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
+ 
++		intel_dsi_reset_clocks(encoder, port);
++		I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
++
++		temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
++		temp &= ~VID_MODE_FORMAT_MASK;
++		I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp);
++
++		I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
++	}
++
++	/*
++	 * if disable packets are sent before sending shutdown packet then in
++	 * some next enable sequence send turn on packet error is observed
++	 * XXX spec specifies SHUTDOWN before MIPI_SEQ_DISPLAY_OFF for
++	 * v3 VBTs, but not for v2 VBTs?
++	 */
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_TEAR_OFF);
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
++
++	/* Transition to LP-00 */
+ 	intel_dsi_clear_device_ready(encoder);
+ 
++	intel_disable_dsi_pll(encoder);
++
+ 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ 		u32 val;
+ 
+@@ -721,11 +789,12 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder,
+ 		I915_WRITE(DSPCLK_GATE_D, val);
+ 	}
+ 
+-	drm_panel_unprepare(intel_dsi->panel);
+-
+-	msleep(intel_dsi->panel_off_delay);
++	/* Assert reset */
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
+ 
+-	/* Panel Disable over CRC PMIC */
++	/* Power off, try both CRC pmic gpio and VBT */
++	intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay);
++	intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
+ 	if (intel_dsi->gpio_panel)
+ 		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0);
+ 
+@@ -733,7 +802,7 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder,
+ 	 * FIXME As we do with eDP, just make a note of the time here
+ 	 * and perform the wait before the next panel power on.
+ 	 */
+-	msleep(intel_dsi->panel_pwr_cycle_delay);
++	intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
+ }
+ 
+ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
+@@ -1376,6 +1445,7 @@ static void intel_dsi_connector_destroy(struct drm_connector *connector)
+ 
+ 	DRM_DEBUG_KMS("\n");
+ 	intel_panel_fini(&intel_connector->panel);
++	intel_panel_destroy_backlight(connector);
+ 	drm_connector_cleanup(connector);
+ 	kfree(connector);
+ }
+diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
+index 5967ea6d6045..548649158abd 100644
+--- a/drivers/gpu/drm/i915/intel_dsi.h
++++ b/drivers/gpu/drm/i915/intel_dsi.h
+@@ -130,6 +130,11 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
+ 	return container_of(encoder, struct intel_dsi, base.base);
+ }
+ 
++void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
++
++void intel_dsi_exec_vbt_sequence(struct intel_dsi *intel_dsi,
++				 enum mipi_seq seq_id);
++
+ bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
+ int intel_compute_dsi_pll(struct intel_encoder *encoder,
+ 			  struct intel_crtc_state *config);
+diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+index cd154ce6b6c1..a4e3c642b39a 100644
+--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
++++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+@@ -189,6 +189,8 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
+ 		break;
+ 	}
+ 
++	wait_for_dsi_fifo_empty(intel_dsi, port);
++
+ out:
+ 	data += len;
+ 
+@@ -296,7 +298,8 @@ static void chv_exec_gpio(struct drm_i915_private *dev_priv,
+ 	mutex_lock(&dev_priv->sb_lock);
+ 	vlv_iosf_sb_write(dev_priv, port, cfg1, 0);
+ 	vlv_iosf_sb_write(dev_priv, port, cfg0,
+-			  CHV_GPIO_GPIOCFG_GPO | CHV_GPIO_GPIOTXSTATE(value));
++			  CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO |
++			  CHV_GPIO_GPIOTXSTATE(value));
+ 	mutex_unlock(&dev_priv->sb_lock);
+ }
+ 
+@@ -352,11 +355,11 @@ static const fn_mipi_elem_exec exec_elem[] = {
+  */
+ 
+ static const char * const seq_name[] = {
+-	[MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
++	[MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
+ 	[MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
+ 	[MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
+ 	[MIPI_SEQ_DISPLAY_OFF]  = "MIPI_SEQ_DISPLAY_OFF",
+-	[MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
++	[MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
+ 	[MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
+ 	[MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
+ 	[MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
+@@ -373,10 +376,9 @@ static const char *sequence_name(enum mipi_seq seq_id)
+ 		return "(unknown)";
+ }
+ 
+-static void generic_exec_sequence(struct drm_panel *panel, enum mipi_seq seq_id)
++void intel_dsi_exec_vbt_sequence(struct intel_dsi *intel_dsi,
++				 enum mipi_seq seq_id)
+ {
+-	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+-	struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ 	struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
+ 	const u8 *data;
+ 	fn_mipi_elem_exec mipi_elem_exec;
+@@ -435,35 +437,6 @@ static void generic_exec_sequence(struct drm_panel *panel, enum mipi_seq seq_id)
+ 	}
+ }
+ 
+-static int vbt_panel_prepare(struct drm_panel *panel)
+-{
+-	generic_exec_sequence(panel, MIPI_SEQ_ASSERT_RESET);
+-	generic_exec_sequence(panel, MIPI_SEQ_INIT_OTP);
+-
+-	return 0;
+-}
+-
+-static int vbt_panel_unprepare(struct drm_panel *panel)
+-{
+-	generic_exec_sequence(panel, MIPI_SEQ_DEASSERT_RESET);
+-
+-	return 0;
+-}
+-
+-static int vbt_panel_enable(struct drm_panel *panel)
+-{
+-	generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_ON);
+-
+-	return 0;
+-}
+-
+-static int vbt_panel_disable(struct drm_panel *panel)
+-{
+-	generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_OFF);
+-
+-	return 0;
+-}
+-
+ static int vbt_panel_get_modes(struct drm_panel *panel)
+ {
+ 	struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+@@ -487,10 +460,6 @@ static int vbt_panel_get_modes(struct drm_panel *panel)
+ }
+ 
+ static const struct drm_panel_funcs vbt_panel_funcs = {
+-	.disable = vbt_panel_disable,
+-	.unprepare = vbt_panel_unprepare,
+-	.prepare = vbt_panel_prepare,
+-	.enable = vbt_panel_enable,
+ 	.get_modes = vbt_panel_get_modes,
+ };
+ 
+diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
+index be4b4d546fd9..5aac10c3239f 100644
+--- a/drivers/gpu/drm/i915/intel_panel.c
++++ b/drivers/gpu/drm/i915/intel_panel.c
+@@ -32,6 +32,7 @@
+ 
+ #include <linux/kernel.h>
+ #include <linux/moduleparam.h>
++#include <linux/mfd/intel_soc_pmic.h>
+ #include <linux/pwm.h>
+ #include "intel_drv.h"
+ 
+@@ -544,6 +545,11 @@ static u32 pwm_get_backlight(struct intel_connector *connector)
+ 	return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS);
+ }
+ 
++static u32 vlv_pmic_get_backlight(struct intel_connector *connector)
++{
++	return intel_soc_pmic_readb(0x4E);
++}
++
+ static u32 intel_panel_get_backlight(struct intel_connector *connector)
+ {
+ 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+@@ -635,6 +641,11 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level)
+ 	pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS);
+ }
+ 
++static void vlv_pmic_set_backlight(struct intel_connector *connector, u32 level)
++{
++	intel_soc_pmic_writeb(0x4E, level);
++}
++
+ static void
+ intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
+ {
+@@ -808,6 +819,14 @@ static void pwm_disable_backlight(struct intel_connector *connector)
+ 	pwm_disable(panel->backlight.pwm);
+ }
+ 
++static void vlv_pmic_disable_backlight(struct intel_connector *connector)
++{
++	intel_panel_actually_set_backlight(connector, 0);
++
++	intel_soc_pmic_writeb(0x51, 0x00);
++	intel_soc_pmic_writeb(0x4B, 0x7F);
++}
++
+ void intel_panel_disable_backlight(struct intel_connector *connector)
+ {
+ 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+@@ -1089,6 +1108,17 @@ static void pwm_enable_backlight(struct intel_connector *connector)
+ 	intel_panel_actually_set_backlight(connector, panel->backlight.level);
+ }
+ 
++static void vlv_pmic_enable_backlight(struct intel_connector *connector)
++{
++	struct intel_panel *panel = &connector->panel;
++
++	intel_soc_pmic_writeb(0x4B, 0xFF);
++	intel_soc_pmic_writeb(0x4E, 0xFF);
++	intel_soc_pmic_writeb(0x51, 0x01);
++
++	intel_panel_actually_set_backlight(connector, panel->backlight.level);
++}
++
+ void intel_panel_enable_backlight(struct intel_connector *connector)
+ {
+ 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+@@ -1687,6 +1717,20 @@ static int pwm_setup_backlight(struct intel_connector *connector,
+ 	return 0;
+ }
+ 
++static int vlv_pmic_setup_backlight(struct intel_connector *connector,
++		enum pipe unused)
++{
++	struct intel_panel *panel = &connector->panel;
++
++	panel->backlight.present = 1;
++	panel->backlight.min = 0x00;
++	panel->backlight.max = 0xFF;
++	panel->backlight.level = 0x5A;
++	panel->backlight.enabled = 1;
++
++	return 0;
++}
++
+ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
+ {
+ 	struct drm_i915_private *dev_priv = to_i915(connector->dev);
+@@ -1694,6 +1738,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
+ 	struct intel_panel *panel = &intel_connector->panel;
+ 	int ret;
+ 
++	intel_backlight_device_register(intel_connector);
++
+ 	if (!dev_priv->vbt.backlight.present) {
+ 		if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) {
+ 			DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n");
+@@ -1783,18 +1829,17 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel)
+ 		panel->backlight.hz_to_pwm = pch_hz_to_pwm;
+ 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ 		if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) {
+-			panel->backlight.setup = pwm_setup_backlight;
+-			panel->backlight.enable = pwm_enable_backlight;
+-			panel->backlight.disable = pwm_disable_backlight;
+-			panel->backlight.set = pwm_set_backlight;
+-			panel->backlight.get = pwm_get_backlight;
++			panel->backlight.setup = vlv_pmic_setup_backlight;
++			panel->backlight.enable = vlv_pmic_enable_backlight;
++			panel->backlight.disable = vlv_pmic_disable_backlight;
++			panel->backlight.set = vlv_pmic_set_backlight;
++			panel->backlight.get = vlv_pmic_get_backlight;
+ 		} else {
+ 			panel->backlight.setup = vlv_setup_backlight;
+ 			panel->backlight.enable = vlv_enable_backlight;
+ 			panel->backlight.disable = vlv_disable_backlight;
+ 			panel->backlight.set = vlv_set_backlight;
+ 			panel->backlight.get = vlv_get_backlight;
+-			panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
+ 		}
+ 	} else if (IS_GEN4(dev_priv)) {
+ 		panel->backlight.setup = i965_setup_backlight;
+diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
+index a38c2fefe85a..23ed3f5972fa 100644
+--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
++++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
+@@ -1065,7 +1065,18 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
+ 
+ static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv)
+ {
+-	I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
++	u32 val;
++
++	/*
++	 * On driver load, a pipe may be active and driving a DSI display.
++	 * Preserve DPOUNIT_CLOCK_GATE_DISABLE to avoid the pipe getting stuck
++	 * (and never recovering) in this case. intel_dsi_post_disable() will
++	 * clear it when we turn off the display.
++	 */
++	val = I915_READ(DSPCLK_GATE_D);
++	val &= DPOUNIT_CLOCK_GATE_DISABLE;
++	val |= VRHUNIT_CLOCK_GATE_DISABLE;
++	I915_WRITE(DSPCLK_GATE_D, val);
+ 
+ 	/*
+ 	 * Disable trickle feed and enable pnd deadline calculation
+diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
+index dbed12c484c9..a2f9a4671193 100644
+--- a/drivers/gpu/drm/i915/intel_sprite.c
++++ b/drivers/gpu/drm/i915/intel_sprite.c
+@@ -81,10 +81,13 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+  */
+ void intel_pipe_update_start(struct intel_crtc *crtc)
+ {
++	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ 	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+ 	long timeout = msecs_to_jiffies_timeout(1);
+ 	int scanline, min, max, vblank_start;
+ 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
++	bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
++		intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI);
+ 	DEFINE_WAIT(wait);
+ 
+ 	vblank_start = adjusted_mode->crtc_vblank_start;
+@@ -136,6 +139,25 @@ void intel_pipe_update_start(struct intel_crtc *crtc)
+ 
+ 	drm_crtc_vblank_put(&crtc->base);
+ 
++	/*
++	 * On VLV/CHV DSI the scanline counter would appear to
++	 * increment approx. 1/3 of a scanline before start of vblank.
++	 * The registers still get latched at start of vblank however.
++	 * This means we must not write any registers on the first
++	 * line of vblank (since not the whole line is actually in
++	 * vblank). And unfortunately we can't use the interrupt to
++	 * wait here since it may have already fired before we check
++	 * the scanline. We could use the frame start interrupt instead
++	 * since it will fire after the critical scanline, but that would
++	 * require more changes in the interrupt code. So for now we'll
++	 * just do the nasty thing and poll for the bad scanline to
++	 * pass us by.
++	 *
++	 * FIXME figure out if BXT+ DSI suffers from this as well
++	 */
++	while (need_vlv_dsi_wa && scanline == vblank_start)
++		scanline = intel_get_crtc_scanline(crtc);
++
+ 	crtc->debug.scanline_start = scanline;
+ 	crtc->debug.start_vbl_time = ktime_get();
+ 	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
+diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
+index 12d6ebb4ae5d..8583e77deae0 100644
+--- a/drivers/mfd/intel_soc_pmic_core.c
++++ b/drivers/mfd/intel_soc_pmic_core.c
+@@ -44,6 +44,8 @@ static struct pwm_lookup crc_pwm_lookup[] = {
+ 	PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL),
+ };
+ 
++static struct intel_soc_pmic *pmic_hack = NULL;
++
+ static int intel_soc_pmic_find_gpio_irq(struct device *dev)
+ {
+ 	struct gpio_desc *desc;
+@@ -77,6 +79,7 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
+ 	config = (struct intel_soc_pmic_config *)id->driver_data;
+ 
+ 	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
++	pmic_hack = pmic;
+ 	if (!pmic)
+ 		return -ENOMEM;
+ 
+@@ -168,6 +171,37 @@ static int intel_soc_pmic_resume(struct device *dev)
+ }
+ #endif
+ 
++int intel_soc_pmic_readb(int reg)
++{
++	int ret;
++	unsigned int val;
++
++	if (!pmic_hack) {
++		ret = -EIO;
++	} else {
++		ret = regmap_read(pmic_hack->regmap, reg, &val);
++		if (!ret) {
++			ret = val;
++		}
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL(intel_soc_pmic_readb);
++
++int intel_soc_pmic_writeb(int reg, u8 val)
++{
++	int ret;
++
++	if (!pmic_hack) {
++		ret = -EIO;
++	} else {
++		ret = regmap_write(pmic_hack->regmap, reg, val);
++	}
++	return ret;
++}
++EXPORT_SYMBOL(intel_soc_pmic_writeb);
++
+ static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend,
+ 			 intel_soc_pmic_resume);
+ 
+diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
+index cf619dbeace2..52ad034f606a 100644
+--- a/include/linux/mfd/intel_soc_pmic.h
++++ b/include/linux/mfd/intel_soc_pmic.h
+@@ -29,4 +29,7 @@ struct intel_soc_pmic {
+ 	struct device *dev;
+ };
+ 
++int intel_soc_pmic_readb(int reg);
++int intel_soc_pmic_writeb(int reg, u8 val);
++
+ #endif	/* __INTEL_SOC_PMIC_H__ */