Gfx-Display: [REVERTME] improve the SW workaround 47423
authorGeng Xiujun <xiujun.geng@intel.com>
Mon, 11 Jun 2012 08:24:31 +0000 (16:24 +0800)
committerbuildbot <buildbot@intel.com>
Wed, 20 Jun 2012 19:19:08 +0000 (12:19 -0700)
BZ: 41053

The patch move WA 47423 from pci_fixup callback to i2c driver context. Once
there's a device using I2C bus 2, then try to turn on vadd, after finishing
transfer, try to turn off vadd. The turn off vadd operation is put in a delay
work queue, it will be delayed 100ms. once there's no device accessing this i2c
bus, then vadd will be turned off, otherwise the work will be canceled. This can
reduce time consumption if there're constant bus accessing.
another change is after turn on vadd, change wait time from 260ms to 60ms per
CMI panel spec, and before enabling GPIO_BL, wait another 200ms. this can save
200ms if there's i2c accessing before panel on.

Change-Id: I5d9e9e919506da606283e9e26b4cd9ce327bb736
Signed-off-by: Geng Xiujun <xiujun.geng@intel.com>
Reviewed-on: http://android.intel.com:8080/52721
Reviewed-by: Xu, Randy <randy.xu@intel.com>
Tested-by: Xu, Randy <randy.xu@intel.com>
Reviewed-by: Mansoor, Illyas <illyas.mansoor@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/i2c/busses/i2c-designware-core.c
drivers/pci/pci.h
drivers/pci/quirks.c
drivers/staging/mrst/drv/mdfld_dsi_lvds_bridge.c
drivers/staging/mrst/drv/mdfld_dsi_lvds_bridge.h
drivers/staging/mrst/drv/psb_drv.c
drivers/staging/mrst/drv/psb_powermgmt.c
drivers/staging/mrst/drv/psb_powermgmt.h

index 7e77703..85cf7d5 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
 #include <linux/semaphore.h>
+#include <linux/pci.h>
 #include "i2c-designware-core.h"
 
 static char *abort_sources[] = {
@@ -452,6 +453,8 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
                return -EIO;
 }
 
+void (*i2c_dw_fixup_get)(unsigned short pcidev) = NULL;
+void (*i2c_dw_fixup_put)(unsigned short pcidev) = NULL;
 /*
  * Prepare controller for a transaction and call i2c_dw_xfer_msg
  */
@@ -459,11 +462,16 @@ int
 i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
        struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+       struct pci_dev *pdev = container_of(dev->dev, struct pci_dev, dev);
        int ret;
 
        dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
 
        down(&dev->lock);
+
+       if (i2c_dw_fixup_get)
+               i2c_dw_fixup_get(pdev->device);
+
        pm_runtime_get_sync(dev->dev);
 
        INIT_COMPLETION(dev->cmd_complete);
@@ -517,6 +525,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 done:
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
+
+       if (i2c_dw_fixup_put)
+               i2c_dw_fixup_put(pdev->device);
+
        up(&dev->lock);
 
        return ret;
index 2de78d3..3a39bf1 100644 (file)
@@ -314,9 +314,4 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 }
 #endif
 
-#ifdef CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE
-extern void vlcm_vadd_get(void);
-extern void vlcm_vadd_put(void);
-#endif
-
 #endif /* DRIVERS_PCI_H */
index c30224e..45ea3b8 100644 (file)
@@ -1425,24 +1425,6 @@ DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_ICH6_1,     asus_
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6_resume);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_ICH6_1,     asus_hides_smbus_lpc_ich6_resume_early);
 
-#if CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE
-static void tc35876x_lvds_panel_fixup_suspend(struct pci_dev *dev)
-{
-       vlcm_vadd_put();
-}
-DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_INTEL,
-               0x082E,
-               tc35876x_lvds_panel_fixup_suspend);
-
-static void tc35876x_lvds_panel_fixup_resume(struct pci_dev *dev)
-{
-       vlcm_vadd_get();
-}
-DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_INTEL,
-               0x082E,
-               tc35876x_lvds_panel_fixup_resume);
-#endif
-
 /*
  * SiS 96x south bridge: BIOS typically hides SMBus device...
  */
index e371131..8d449de 100644 (file)
@@ -542,7 +542,7 @@ void dsi_lvds_toshiba_bridge_panel_off(void)
        usleep_range(1000, 2000);
 
        /* try to turn vadd off */
-       vlcm_vadd_put();
+       i2c_dw_fixup_put(I2C_PCI_DEVICE_ID);
 }
 
 /* ************************************************************************* *\
@@ -557,7 +557,10 @@ void dsi_lvds_toshiba_bridge_panel_on(struct drm_device *dev)
        printk(KERN_INFO "[DISPLAY ] %s\n", __func__);
 
        /* get vadd count, and make sure vadd is on */
-       vlcm_vadd_get();
+       i2c_dw_fixup_get(I2C_PCI_DEVICE_ID);
+
+       /* before enabling GPIO_BL, need wait 200ms */
+       msleep(200);
 
        if (cmi_lcd_i2c_client) {
                int ret;
index 87d4c07..308c8ec 100644 (file)
@@ -62,6 +62,7 @@
 #define PANEL_CM_GAIN          0x711
 #define PANEL_CM_HUETABLE_START        0x730
 #define PANEL_CM_HUETABLE_END  0x747 /* inclusive */
+#define I2C_PCI_DEVICE_ID      0x082E
 
 extern struct i2c_client *cmi_lcd_i2c_client;
 
index 84066b2..328f0ba 100644 (file)
@@ -4090,6 +4090,9 @@ static const struct dev_pm_ops psb_pm_ops = {
        .runtime_idle = psb_runtime_idle,
        .suspend = psb_runtime_suspend,
        .resume = psb_runtime_resume,
+#ifdef CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE
+       .suspend_noirq = psb_lvds_panel_suspend_noirq,
+#endif
 };
 
 static struct drm_driver driver = {
index ca6639e..a6eeaec 100644 (file)
@@ -2695,12 +2695,23 @@ int psb_runtime_idle(struct device *dev)
 #ifdef CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE
 DEFINE_MUTEX(vadd_mutex);
 static int i2c_access_count;
+struct delayed_work i2c_wa_delayed_wk;
+
+int psb_lvds_panel_suspend_noirq(struct device *dev)
+{
+       /* when system enters S3 while delayed work is not executed, it will
+        * cause vadd keeps on in S3, then high power consumption in S3. to
+        * avoid this, before entering S3, flush delayed work to make sure
+        * there's no pending work */
+       flush_delayed_work_sync(&i2c_wa_delayed_wk);
+       return 0;
+}
 
 /* use access count to mark status of i2c bus 2, and make sure avdd is turned on
  * when accessing this i2c. when accaccess count reaches 1, then turn on lvds
  * panel's avdd
  */
-void vlcm_vadd_get()
+static void vlcm_vadd_get()
 {
        mutex_lock(&vadd_mutex);
        ++i2c_access_count;
@@ -2709,7 +2720,7 @@ void vlcm_vadd_get()
                        pr_err("%s: faild to pull high VADD\n", __func__);
                        goto unlock;
                }
-               msleep(260);
+               msleep(60);
        }
 unlock:
        mutex_unlock(&vadd_mutex);
@@ -2717,7 +2728,7 @@ unlock:
 
 /* decrease reference count, and turn vadd off when count reaches 0
  */
-void vlcm_vadd_put()
+static void vlcm_vadd_put(struct work_struct *work)
 {
        mutex_lock(&vadd_mutex);
        if (i2c_access_count == 0) {
@@ -2736,7 +2747,48 @@ void vlcm_vadd_put()
 unlock:
        mutex_unlock(&vadd_mutex);
 }
+
+void psb_i2c_dw_fixup_get(unsigned short pcidev)
+{
+       int ret = 0;
+
+       if (pcidev == I2C_PCI_DEVICE_ID) {
+               ret = cancel_delayed_work(&i2c_wa_delayed_wk);
+               vlcm_vadd_get();
+               /* to make get/put consist, if work is canceled, after another
+                * get, decrease access count */
+               if (ret) {
+                       mutex_lock(&vadd_mutex);
+                       --i2c_access_count;
+                       mutex_unlock(&vadd_mutex);
+               }
+       }
+}
+
+void psb_i2c_dw_fixup_put(unsigned short pcidev)
+{
+       if (pcidev ==  I2C_PCI_DEVICE_ID) {
+               /*
+                * before the scecond accessing i2c, access count will be 2,
+                * flush work will cause access count descres to 1, then
+                * the latter schedule_work can be delayed to 100ms.
+                */
+               flush_delayed_work_sync(&i2c_wa_delayed_wk);
+               schedule_delayed_work(&i2c_wa_delayed_wk, HZ/10);
+       }
+}
+
+static int __init i2c_workaround_init(void)
+{
+       INIT_DELAYED_WORK(&i2c_wa_delayed_wk, vlcm_vadd_put);
+       i2c_dw_fixup_get = psb_i2c_dw_fixup_get;
+       i2c_dw_fixup_put = psb_i2c_dw_fixup_put;
+
+       return 0;
+}
+arch_initcall(i2c_workaround_init);
 #endif
+
 void mdfld_reset_panel_handler_work(struct work_struct *work)
 {
        struct drm_psb_private *dev_priv =
index de2e078..d0c9e03 100644 (file)
@@ -128,8 +128,9 @@ void acquire_ospm_lock(void);
 void release_ospm_lock(void);
 
 #ifdef CONFIG_SUPPORT_TOSHIBA_MIPI_LVDS_BRIDGE
-extern void vlcm_vadd_get(void);
-extern void vlcm_vadd_put(void);
+extern void (*i2c_dw_fixup_get)(unsigned short pcidev);
+extern void (*i2c_dw_fixup_put)(unsigned short pcidev);
+extern int psb_lvds_panel_suspend_noirq(struct device *dev);
 #endif
 
 #endif /*_PSB_POWERMGMT_H_*/