summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWengang Wu <wgw@motorola.com>2014-06-15 22:06:59 -0500
committerWengang Wu <wgw@motorola.com>2014-07-01 21:59:37 +0000
commitc9f7eb0874f5381c3ac1b8b7e0223f1c95526a10 (patch)
tree095f6a02d3c108101010dbec9f0c69cc8a37cf3e
parentc482a603276273419b6f4adbcea183787dd03582 (diff)
downloadolio-linux-3.10-c9f7eb0874f5381c3ac1b8b7e0223f1c95526a10.tar.xz
olio-linux-3.10-c9f7eb0874f5381c3ac1b8b7e0223f1c95526a10.zip
IKXCLOCK-1986 Display needs to be reset after it gets blank due to ESD discharge
Change-Id: I0fef3e738bcc2ed07bc2ddbebbeade7e646f3373
-rw-r--r--arch/arm/boot/dts/omap3-minnow.dtsi2
-rw-r--r--drivers/video/omap2/displays/panel-minnow-common.h137
-rw-r--r--drivers/video/omap2/displays/panel-minnow.c1011
-rw-r--r--drivers/video/omap2/dss/dsi.c63
4 files changed, 840 insertions, 373 deletions
diff --git a/arch/arm/boot/dts/omap3-minnow.dtsi b/arch/arm/boot/dts/omap3-minnow.dtsi
index 976a7fb5020..c75d91665b6 100644
--- a/arch/arm/boot/dts/omap3-minnow.dtsi
+++ b/arch/arm/boot/dts/omap3-minnow.dtsi
@@ -79,7 +79,7 @@
/* declare it if ext_te enable */
//gpio_te = <&gpio1 0 0>; /* EXT_TE gpio-0 */
//pins = <0 1 2 3>; /* DSI Pin config */
- //esd_interval = <0>; /* ESD_INTERVAL */
+ esd_interval = <8000>; /* ESD_INTERVAL */
//pixel_clock = <4608>; /* kHZ = 320*240*60/1000*/
/* 0: RGB888
* 1: RGB666
diff --git a/drivers/video/omap2/displays/panel-minnow-common.h b/drivers/video/omap2/displays/panel-minnow-common.h
index e4b142daf8e..25557457b4a 100644
--- a/drivers/video/omap2/displays/panel-minnow-common.h
+++ b/drivers/video/omap2/displays/panel-minnow-common.h
@@ -18,14 +18,18 @@
#ifndef _MINNOW_PANEL_COMMON_HEADER_
+#define INIT_DATA_VERSION (0x060614) /*MM/DD/YY*/
/* This header file is used to sync Bootloader and Kernel Display Initialize
* Structure/Data, please make sure sync it for both Bootloader/Kernel when
- * it changes some settings for Solomon/Orise
+ * it changes some settings for Solomon/Orise. Bootloader should pass
+ * INIT_DATA_VERSION to kernel that make sure settings are same on both side.
*/
+
#ifndef u8
typedef unsigned char u8;
#endif
+
enum minnow_panel_type {
PANEL_INIT = -1, /* Not Initialize */
PANEL_DUMMY, /* None panel detected */
@@ -83,57 +87,170 @@ enum minnow_cmd_type {
static u8 panel_init_ssd2848_320x320[] = {
/*n, type, data_0, data_1 ... data_n-1*/
1, SWITCH_TO_PANEL, 0,
+/* SCM PLL Register[0x0008]
+ * POSTDIV = 5, MULT = 50, PLLOUT = 26 x 50 / (5+1) = 216.6 MHz
+ */
6, SSD2848_CMD, 0x00, 0x08, 0x01, 0xF4, 0x05, 0x32,
+/* SCM Clock Control Register[0x000C]
+ * MTXDIV = 0, MIPITX speed = 216.6 / (0 + 1) = 216.6 Mbps
+ * MIPITX clock = 216.6 / 2 = 108.3 MHz
+ * SYSDIV - 11, system clock = 216.6 / 2 / (11 + 1) = 9.0 MHz
+ */
6, SSD2848_CMD, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B,
+/* SCM Miscellaneous Control Register[0x0014]
+ * MTXVPF = 3, MIPITX Video Pixel Format = 24bpp
+ * MRXLS = 0, MIPIRX Lane Select = 1 lane
+ * MRXECC = MRXCRC = MRXEOT = MRXEE = 1
+ * enable MIPIRX ECC, CRC, EOR, Error Check
+ */
6, SSD2848_CMD, 0x00, 0x14, 0x0C, 0x07, 0x80, 0x0F,
+/* Sleep out and Waiting for SSD2848 PLL locked */
1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE,
1, WAIT_MS, 1,
+/* MIPIRX Delay Configuration Register[0x0008] */
6, SSD2848_CMD, 0x10, 0x08, 0x01, 0x20, 0x01, 0x45,
+/* VTCM Configuration Register[0x000C]
+ * TE_SEL = 1, Tear signal from display interface unit
+ * TEP = 0, vtcm_rgb_te signal Active high
+ */
6, SSD2848_CMD, 0x20, 0x0C, 0x00, 0x00, 0x00, 0x02,
+/* VTCM Pixel Clock Frequency Ratio Register[0x0010]
+ * PCLKDEN = 247, PCLKNUM = 108,
+ * Pixel clock = 9.0 x 108 / 247 = 3.93 MHz
+ * since SSD2848 uses 48 bits bus, the actual pixel clock is
+ * depend on current pixel format setting(24 bpp now)
+ * actual pix_clk = 3.93 * 48 / 24 = 7.87 MHz
+ */
6, SSD2848_CMD, 0x20, 0x10, 0x00, 0xF7, 0x00, 0x6C,
+/* VTCM Display Horizontal Configuration Register[0x0014]
+ * Horizontal Total = 392 = 20 + 42 + 320 + 10
+ * Horizontal Display Period Start = 42
+ */
6, SSD2848_CMD, 0x20, 0x14, 0x01, 0x88, 0x00, 0x2A,
+/* VTCM Vertical Display Configuration Register[0x0018]
+ * Vertical Total = 334 = 2 + 10 + 320 + 2
+ * Vertical Display Period Start = 10
+ */
6, SSD2848_CMD, 0x20, 0x18, 0x01, 0x4E, 0x00, 0x0A,
+/* VTCM Display Size Register[0x0020]
+ * Display Width = 320
+ * Display Height = 320
+ */
6, SSD2848_CMD, 0x20, 0x20, 0x01, 0x40, 0x01, 0x40,
+/* VTCM Panel Size Register[0x0024]
+ * Panel Width = 320
+ * Panel Height = 320
+ */
6, SSD2848_CMD, 0x20, 0x24, 0x01, 0x40, 0x01, 0x40,
+/* VTCM URAM Control Register[0x0030] */
6, SSD2848_CMD, 0x20, 0x30, 0x00, 0x00, 0x00, 0x15,
+/* VTCM Panel Offset Start Register[0x0034] */
6, SSD2848_CMD, 0x20, 0x34, 0x00, 0x00, 0x00, 0x00,
+/* VTCM Panel Offset End Register[0x0038] */
6, SSD2848_CMD, 0x20, 0x38, 0x01, 0x3F, 0x01, 0x3F,
+/* VTCM Image Size Register[0x003C] */
6, SSD2848_CMD, 0x20, 0x3C, 0x01, 0x40, 0x01, 0x40,
+/* VTCM Qualcomm FBC Control Register[0x00A0]
+ * DEC_MODE = COM_MODE = 0 Bypass
+ */
6, SSD2848_CMD, 0x20, 0xA0, 0x00, 0x00, 0x05, 0x00,
5, DCS_WRITE_SYNC, 0x2A, 0x00, 0x00, 0x01, 0x3F,
5, DCS_WRITE_SYNC, 0x2B, 0x00, 0x00, 0x01, 0x3F,
-6, SSD2848_CMD, 0x60, 0x08, 0x00, 0x02, 0x00, 0x0A,
+/* DSITX Control Register[0x0008]
+ * LPD = 4, LP clock = 216.6 / 8 / (4 + 1) = 5.4 MHz
+ * EOT = 1, EOT Packet Enable
+ */
+6, SSD2848_CMD, 0x60, 0x08, 0x00, 0x04, 0x00, 0x0A,
+/* DSITX Video Timing Control Register[0x000C]
+ * VBP = 10, HBP = 42, VSA = 2, HSA = 10
+ */
6, SSD2848_CMD, 0x60, 0x0C, 0x0A, 0x2A, 0x02, 0x0A,
+/* DSITX Video Timing Control 2 Register[0x0010]
+ * VACT = 320, VFP = 2, HFP = 20
+ */
6, SSD2848_CMD, 0x60, 0x10, 0x01, 0x40, 0x02, 0x14,
-6, SSD2848_CMD, 0x60, 0x14, 0x01, 0x00, 0x01, 0x00,
+/* DSITX Video Configuration Register[0x0014]
+ * VM = 00, Non burst mode with sync pulses
+ * VEC = 1, Command packet will be sent after video packet
+ are sent during Vertical blanking period for Non burst
+ video transfer or Vertical/Horizontal blanking period
+ for Burst video transfer
+ */
+6, SSD2848_CMD, 0x60, 0x14, 0x01, 0x00, 0x01, 0x40,
+/* DSITX Delay Adjustment 1 Register[0x0040]
+ * HPD = 1, HZD = 10, CPD = 1, CZD = 19
+ * byte_clk = 1000 / (216.6 / 8) = 36.9 ns
+ * Ths-prepare-HPD = 36.9 * (1 + 3) = 147.7 ns
+ * Ths-zero-HZD = 36.9 * (10 + 1.25) = 415.5 ns
+ * Tclk-prepare-CPD = 36.9 * (1 + 3) = 147.7 ns
+ * Tclk-zero-CZD = 36.9 * (19 + 1.25) = 747.9 ns
+ */
6, SSD2848_CMD, 0x60, 0x40, 0x13, 0x01, 0x0A, 0x01,
+/* DSITX Delay Adjustment 2 Register[0x0044]
+ * CPTD = 10, CPED = 4, HTD = 5, CTD = 5
+ * byte_clk = 1000 / (216.6 / 8) = 36.9 ns
+ * Tclk-post-CPTD = 36.9 * (10 + 2) = 443.2 ns
+ * Tclk-pre-CPED = 36.9 * 4 = 147.7 ns
+ * Ths-trail-HTD = 36.9 * (5 - 1.25) = 138.5 ns
+ * Tclk-trail-CTD = 36.9 * (5 + 1) - 4 = 217.6 ns
+ */
6, SSD2848_CMD, 0x60, 0x44, 0x05, 0x05, 0x04, 0x0A,
+/* DSITX DSIn Video Register[0x0080+(n*32) + 0x004]
+ * HACT = 320
+ */
6, SSD2848_CMD, 0x60, 0x84, 0x00, 0x00, 0x01, 0x40,
1, SSD2848_CMD, CMD_VERIFY_REG, /* command for verify ssd2848 registers */
1, SWITCH_TO_PANEL, 1,
+/* Orise Engineering Mode Enable (RF0h)
+ * Enable Engineering Mode
+ */
3, OTM3201_CMD, 0xF0, 0x54, 0x47,
+/* Register Read Mode Enable (RA0h)
+ * Enable to write
+ */
2, OTM3201_CMD, 0xA0, 0x00,
+/* Mux1 to 9 CKH timing structure register (RBDH) */
4, OTM3201_CMD, 0xBD, 0x00, 0x11, 0x31,
+/* Landscape MIPI Video Mode One Line Clock Number (RE9h) */
2, OTM3201_CMD, 0xE9, 0x46,
+/* Display Inversion Control (RB1h) */
2, OTM3201_CMD, 0xB1, 0x12,
+/* ??? undefined */
2, OTM3201_CMD, 0xE2, 0xF0,
+/* Display Waveform Cycle setting (RBAh) */
5, OTM3201_CMD, 0xBA, 0x06, 0x15, 0x2B, 0x01,
+/* RGB Interface Blanking Porch setting (RB3h)
+ * VFP = 2, VBP = 10, HFP = 20, HBP = 42, VSW = 2, HSW = 10
+ */
6, OTM3201_CMD, 0xB3, 0x02, 0x0A, 0x14, 0x2A, 0x2A,
+/* Gamma Voltage adjust Control (RB5h) */
5, OTM3201_CMD, 0xB5, 0x78, 0x78, 0x76, 0xF6,
+/* Gamma (‘+’polarity) Correction Characteristics Setting R gamma (RC0h) */
18, OTM3201_CMD, 0xC0, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
+/* Gamma (‘-’polarity) Correction Characteristics Setting R gamma (RC1h) */
18, OTM3201_CMD, 0xC1, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
+/* Gamma (‘+’polarity) Correction Characteristics Setting G gamma (RC2h) */
18, OTM3201_CMD, 0xC2, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
+/* Gamma (‘-’polarity) Correction Characteristics Setting G gamma (RC3h) */
18, OTM3201_CMD, 0xC3, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
+/* Gamma (‘+’polarity) Correction Characteristics Setting B gamma (RC4h) */
18, OTM3201_CMD, 0xC4, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
+/* Gamma (‘-’polarity) Correction Characteristics Setting B gamma (RC5h) */
18, OTM3201_CMD, 0xC5, 0x00, 0x06, 0x17, 0x11, 0x16, 0x25, 0x0E,
0x0C, 0x0C, 0x0E, 0x0C, 0x2F, 0x07, 0x0A, 0x3F, 0x3F, 0x3F,
1, OTM3201_CMD, CMD_VERIFY_REG, /* command for verify otm3201 registers */
+/* Register Read Mode Enable (RA0h)
+ * Enable to read, locked for write
+ */
2, OTM3201_CMD, 0xA0, 0x80,
+/* Orise Engineering Mode Enable (RF0h)
+ * Disable Engineering Mode, locked for second group register
+ */
3, OTM3201_CMD, 0xF0, 0x00, 0x00,
1, DCS_WRITE_SYNC, MIPI_DCS_EXIT_SLEEP_MODE,
1, WAIT_MS, 120,
@@ -147,6 +264,14 @@ static u8 panel_init_ssd2848_320x320[] = {
* it needs the different timing setting that apply for panel 2.0 or above
*/
static u8 panel_init_ssd2848_320x320_1[] = {
+/* DSITX Delay Adjustment 2 Register[0x0044]
+ * CPTD = 22, CPED = 4, HTD = 10, CTD = 10
+ * byte_clk = 1000 / (216.6 / 8) = 36.9 ns
+ * Tclk-post-CPTD = 36.9 * (22 + 2) = 886.4 ns
+ * Tclk-pre-CPED = 36.9 * 4 = 147.7 ns
+ * Ths-trail-HTD = 36.9 * (10 - 1.25) = 323.1 ns
+ * Tclk-trail-CTD = 36.9 * (10 + 1) - 4 = 402.2 ns
+ */
6, SSD2848_CMD, 0x60, 0x44, 0x0A, 0x0A, 0x04, 0x16,
0
};
@@ -161,7 +286,11 @@ static u8 panel_off_ssd2848_320x320[] = {
1, WAIT_MS, 50,
1, DCS_WRITE, MIPI_DCS_ENTER_SLEEP_MODE,
1, WAIT_MS, 20,
-6, GENERIC_WRITE, 0x10, 0x28, 0x00, 0x00, 0x00, 0x01, /*power cut enabled*/
+/* MIPIRX Power Cut Register[0x0028]
+ * PWC - This bit will enable power cut to the whole chip and only global
+ * reset can restore the power supply to the chip.
+ */
+6, GENERIC_WRITE, 0x10, 0x28, 0x00, 0x00, 0x00, 0x01,
1, WAIT_MS, 5,
0
};
diff --git a/drivers/video/omap2/displays/panel-minnow.c b/drivers/video/omap2/displays/panel-minnow.c
index d1a6f60db42..e77f318ffff 100644
--- a/drivers/video/omap2/displays/panel-minnow.c
+++ b/drivers/video/omap2/displays/panel-minnow.c
@@ -16,7 +16,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*#define DEBUG*/
+/*#define PANEL_DEBUG*/
+#define PANEL_PERF_TIME
#include <linux/module.h>
#include <linux/delay.h>
@@ -244,31 +245,13 @@ static struct minnow_panel_attr panel_attr_table[MINNOW_PANEL_MAX] = {
},
};
-/* panel parameter to indicate if it needs skip first time initialize */
-static enum minnow_panel_type def_panel_type = PANEL_INIT;
-module_param_named(panel_type, def_panel_type, int, 0);
-
-static irqreturn_t minnow_panel_te_isr(int irq, void *data);
-static void minnow_panel_te_timeout_work_callback(struct work_struct *work);
-static int _minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable);
-
-static int minnow_panel_reset(struct omap_dss_device *dssdev);
-static int minnow_panel_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h);
-static int minnow_panel_wake_up(struct omap_dss_device *dssdev);
-
-
+#ifdef PANEL_PERF_TIME
+#define GET_ELAPSE_TIME(last) jiffies_to_msecs((unsigned long)jiffies-last)
+#endif
struct minnow_panel_data {
struct mutex lock; /* mutex */
struct wake_lock wake_lock; /* wake_lock */
- struct backlight_device *bldev;
-
- unsigned long hw_guard_end; /* next value of jiffies when we can
- * issue the next sleep in/out command
- */
- unsigned long hw_guard_wait; /* max guard time in jiffies */
-
struct omap_dss_device *dssdev;
/* panel HW configuration from DT or platform data */
@@ -281,7 +264,10 @@ struct minnow_panel_data {
struct clk *clk_in;
bool clk_in_en;
+#ifdef CONFIG_PANEL_BACKLIGHT
bool use_dsi_backlight;
+ struct backlight_device *bldev;
+#endif
struct omap_dsi_pin_config pin_config;
struct omap_dss_dsi_config dsi_config;
@@ -298,6 +284,7 @@ struct minnow_panel_data {
/* runtime variables */
bool enabled;
bool interactive;
+ bool output_enabled;
enum minnow_panel_type panel_type;
bool te_enabled;
@@ -307,11 +294,14 @@ struct minnow_panel_data {
struct delayed_work te_timeout_work;
+#ifdef PANEL_DEBUG
unsigned cabc_mode;
+#endif
bool first_enable;
bool skip_first_init;
int panel_retry_count;
+ int esd_errors;
struct workqueue_struct *workqueue;
@@ -321,8 +311,41 @@ struct minnow_panel_data {
bool ulps_enabled;
unsigned ulps_timeout;
struct delayed_work ulps_work;
+
+ int total_update;
+ int total_error;
+ int total_esd_reset;
+#ifdef PANEL_PERF_TIME
+ unsigned long time_power_on;
+ unsigned long time_ulps;
+ unsigned long time_update;
+ unsigned long time_update_min;
+ unsigned long time_update_max;
+ unsigned long last_power_on;
+ unsigned long last_ulps;
+ unsigned long last_update;
+#endif
};
+/* panel parameter passed from boot-loader */
+static char *def_panel_param;
+module_param_named(panel_param, def_panel_param, charp, 0);
+
+static irqreturn_t minnow_panel_te_isr(int irq, void *data);
+static void minnow_panel_te_timeout_work_callback(struct work_struct *work);
+static int _minnow_panel_enable_te(struct minnow_panel_data *mpd, bool enable);
+
+static int minnow_panel_wake_up_locked(struct minnow_panel_data *mpd);
+static void minnow_panel_framedone_cb(int err, void *data);
+static int minnow_panel_enable_locked(struct minnow_panel_data *mpd);
+static void minnow_panel_disable_locked(struct minnow_panel_data *mpd,
+ bool fast_power_off);
+static int minnow_panel_update_locked(struct minnow_panel_data *mpd);
+
+static void minnow_panel_esd_work(struct work_struct *work);
+static void minnow_panel_ulps_work(struct work_struct *work);
+
+
#ifdef CONFIG_OMAP2_DSS_DEBUGFS
static void minnow_panel_dump_regs(struct seq_file *s)
{
@@ -347,7 +370,7 @@ static void minnow_panel_dump_regs(struct seq_file *s)
}
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r) {
seq_printf(s, "display wake up failed(%d)!\n", r);
goto exit;
@@ -387,9 +410,6 @@ exit1:
}
#endif
-static void minnow_panel_esd_work(struct work_struct *work);
-static void minnow_panel_ulps_work(struct work_struct *work);
-
static void minnow_panel_delay(int delay_ms)
{
if (delay_ms > 5)
@@ -429,7 +449,7 @@ static int panel_otm3201_read_reg(struct minnow_panel_data *mpd,
#define WRITE_OTM3201(mpd, cmd) \
dsi_vc_dcs_write(mpd->dssdev, mpd->channel, cmd, sizeof(cmd))
static int panel_otm3201_rewrite_reg(struct minnow_panel_data *mpd,
- u8 *data, u8 len, u8 *read)
+ u8 *data, u8 len, u8 *read)
{
/* retry to write only when it could read back */
int r, retry;
@@ -460,7 +480,8 @@ static int panel_otm3201_rewrite_reg(struct minnow_panel_data *mpd,
return r;
}
-static int minnow_panel_dcs_read_1(struct minnow_panel_data *mpd, u8 dcs_cmd, u8 *data)
+static int minnow_panel_dcs_read_1(struct minnow_panel_data *mpd,
+ u8 dcs_cmd, u8 *data)
{
int r;
u8 buf[1];
@@ -480,7 +501,8 @@ static int minnow_panel_dcs_write_0(struct minnow_panel_data *mpd, u8 dcs_cmd)
return dsi_vc_dcs_write(mpd->dssdev, mpd->channel, &dcs_cmd, 1);
}
-static int minnow_panel_dcs_write_1(struct minnow_panel_data *mpd, u8 dcs_cmd, u8 param)
+static int minnow_panel_dcs_write_1(struct minnow_panel_data *mpd,
+ u8 dcs_cmd, u8 param)
{
u8 buf[2];
buf[0] = dcs_cmd;
@@ -489,7 +511,7 @@ static int minnow_panel_dcs_write_1(struct minnow_panel_data *mpd, u8 dcs_cmd, u
}
static int minnow_panel_get_id(struct minnow_panel_data *mpd,
- u8 *id1, u8 *id2, u8 *id3)
+ u8 *id1, u8 *id2, u8 *id3)
{
int r;
@@ -519,15 +541,15 @@ static int minnow_panel_get_id(struct minnow_panel_data *mpd,
}
static int minnow_panel_set_update_window(struct minnow_panel_data *mpd,
- u16 x, u16 y, u16 w, u16 h)
+ u16 x, u16 y, u16 w, u16 h)
{
int r;
u16 x1 = x + mpd->x_offset;
u16 x2 = x + mpd->x_offset + w - 1;
u16 y1 = y + mpd->y_offset;
u16 y2 = y + mpd->y_offset + h - 1;
-
u8 buf[5];
+
buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
buf[1] = (x1 >> 8) & 0xff;
buf[2] = (x1 >> 0) & 0xff;
@@ -536,21 +558,18 @@ static int minnow_panel_set_update_window(struct minnow_panel_data *mpd,
r = dsi_vc_dcs_write_nosync(mpd->dssdev, mpd->channel,
buf, sizeof(buf));
- if (r)
- return r;
-
- buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
- buf[1] = (y1 >> 8) & 0xff;
- buf[2] = (y1 >> 0) & 0xff;
- buf[3] = (y2 >> 8) & 0xff;
- buf[4] = (y2 >> 0) & 0xff;
-
- r = dsi_vc_dcs_write_nosync(mpd->dssdev, mpd->channel,
- buf, sizeof(buf));
- if (r)
- return r;
+ if (!r) {
+ buf[0] = MIPI_DCS_SET_PAGE_ADDRESS;
+ buf[1] = (y1 >> 8) & 0xff;
+ buf[2] = (y1 >> 0) & 0xff;
+ buf[3] = (y2 >> 8) & 0xff;
+ buf[4] = (y2 >> 0) & 0xff;
- dsi_vc_send_bta_sync(mpd->dssdev, mpd->channel);
+ r = dsi_vc_dcs_write_nosync(mpd->dssdev, mpd->channel,
+ buf, sizeof(buf));
+ if (!r)
+ r = dsi_vc_send_bta_sync(mpd->dssdev, mpd->channel);
+ }
return r;
}
@@ -597,7 +616,7 @@ static int minnow_panel_clear_bottom_line(struct minnow_panel_data *mpd,
omapdss_dsi_vc_enable_hs(mpd->dssdev, mpd->channel, false);
if (r) {
- /* waiting for the rest of time */
+ /* waiting for the reset of time */
last_ms = jiffies_to_msecs(jiffies) - last_ms;
if (last_ms < delay_ms)
minnow_panel_delay(delay_ms - last_ms);
@@ -659,8 +678,8 @@ static int minnow_panel_process_cmd(struct minnow_panel_data *mpd,
r = -EINVAL;
}
- if (retrans)
- panel_ssd2848_set_retransmit(mpd, false);
+ if (retrans && !r)
+ r = panel_ssd2848_set_retransmit(mpd, false);
return r;
}
@@ -781,6 +800,8 @@ static int minnow_panel_verify_otm3201(struct minnow_panel_data *mpd,
break;
if (mpd->panel_type != OTM3201_1_0)
continue;
+ /* turn of ESD for panel 1.0 */
+ mpd->esd_interval = 0;
/* it needs replace some settings for 1.0 */
if (minnow_panel_replace_cmdbuf
(cmdbuf, panel_init_ssd2848_320x320_1)) {
@@ -788,6 +809,7 @@ static int minnow_panel_verify_otm3201(struct minnow_panel_data *mpd,
"Force reset for new settings"
" of panel 1.0!\n");
mpd->panel_retry_count = 0;
+ mpd->total_error--;
r = -EIO;
break;
}
@@ -810,10 +832,11 @@ static int minnow_panel_verify_otm3201(struct minnow_panel_data *mpd,
break;
}
}
- panel_ssd2848_set_retransmit(mpd, false);
if (r)
dev_err(&mpd->dssdev->dev, "Failed verify otm3201"
" register: %02X\n", addr);
+ else
+ r = panel_ssd2848_set_retransmit(mpd, false);
return r;
}
@@ -880,76 +903,117 @@ static int minnow_panel_process_cmdbuf(struct minnow_panel_data *mpd,
return r;
}
-static void minnow_panel_queue_esd_work(struct omap_dss_device *dssdev)
+static void minnow_panel_queue_esd_work(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
-
- if (mpd->esd_interval > 0)
- queue_delayed_work(mpd->workqueue, &mpd->esd_work,
- msecs_to_jiffies(mpd->esd_interval));
+ if (!mpd->esd_interval)
+ return;
+ queue_delayed_work(mpd->workqueue, &mpd->esd_work,
+ msecs_to_jiffies(mpd->esd_interval));
}
-static void minnow_panel_cancel_esd_work(struct omap_dss_device *dssdev)
+static void minnow_panel_cancel_esd_work(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
-
cancel_delayed_work(&mpd->esd_work);
}
-static void minnow_panel_queue_ulps_work(struct omap_dss_device *dssdev)
+static void minnow_panel_queue_ulps_work(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ if (!mpd->ulps_timeout)
+ return;
+ queue_delayed_work(mpd->workqueue, &mpd->ulps_work,
+ msecs_to_jiffies(mpd->ulps_timeout));
+}
- if (mpd->ulps_timeout > 0)
- queue_delayed_work(mpd->workqueue, &mpd->ulps_work,
- msecs_to_jiffies(mpd->ulps_timeout));
+static void minnow_panel_cancel_ulps_work(struct minnow_panel_data *mpd)
+{
+ cancel_delayed_work(&mpd->ulps_work);
}
-static void minnow_panel_cancel_ulps_work(struct omap_dss_device *dssdev)
+static int minnow_panel_dsi_recovery_locked(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ struct omap_dss_device *dssdev = mpd->dssdev;
+ int r;
- cancel_delayed_work(&mpd->ulps_work);
+ /* true/true for fast disable dsi */
+ omapdss_dsi_display_disable(mpd->dssdev, true, true);
+ mpd->ulps_enabled = false;
+ r = omapdss_dsi_display_enable(dssdev);
+ if (r) {
+ dev_err(&dssdev->dev, "DSI recovery failed to enable DSI\n");
+ goto _ret_r_;
+ }
+ omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, true);
+ r = _minnow_panel_enable_te(mpd, mpd->te_enabled);
+ /* for some reason, reset DSI may occur "false control" with bridge
+ * that will cause first command failed, so work around to try resend
+ * that check if it's still failed or not
+ */
+ if (r)
+ r = _minnow_panel_enable_te(mpd, mpd->te_enabled);
+ if (r)
+ dev_err(&dssdev->dev, "DSI recovery failed to re-init TE");
+_ret_r_:
+ return r;
}
-static int minnow_panel_enter_ulps(struct omap_dss_device *dssdev)
+static int minnow_panel_recovery_locked(struct minnow_panel_data *mpd)
+{
+ int r;
+ dev_err(&mpd->dssdev->dev, "performing LCD reset\n");
+ mpd->total_error++;
+ mpd->total_esd_reset++;
+ minnow_panel_disable_locked(mpd, true);
+ msleep(20);
+ r = minnow_panel_enable_locked(mpd);
+ dev_err(&mpd->dssdev->dev, "LCD reset done(%d)\n", r);
+ return r;
+}
+
+static int minnow_panel_enter_ulps_locked(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r;
if (mpd->ulps_enabled)
return 0;
- minnow_panel_cancel_ulps_work(dssdev);
+ minnow_panel_cancel_ulps_work(mpd);
- r = _minnow_panel_enable_te(dssdev, false);
- if (r)
- goto err;
+ r = _minnow_panel_enable_te(mpd, false);
+ if (r) {
+ /* try once to recovery DSI */
+ r = minnow_panel_dsi_recovery_locked(mpd);
+ if (r)
+ goto err;
+ r = _minnow_panel_enable_te(mpd, false);
+ if (r)
+ goto err;
+ }
if (gpio_is_valid(mpd->ext_te_gpio))
disable_irq(gpio_to_irq(mpd->ext_te_gpio));
- omapdss_dsi_display_disable(dssdev, false, true);
+ omapdss_dsi_display_disable(mpd->dssdev, false, true);
mpd->ulps_enabled = true;
- dev_dbg(&dssdev->dev, "entered ULPS mode\n");
+ dev_dbg(&mpd->dssdev->dev, "entered ULPS mode\n");
+#ifdef PANEL_PERF_TIME
+ mpd->last_ulps = jiffies;
+#endif
return 0;
err:
- dev_err(&dssdev->dev, "enter ULPS failed\n");
- minnow_panel_reset(dssdev);
+ dev_err(&mpd->dssdev->dev, "enter ULPS failed\n");
mpd->ulps_enabled = false;
-
- minnow_panel_queue_ulps_work(dssdev);
+ minnow_panel_queue_ulps_work(mpd);
return r;
}
-static int minnow_panel_exit_ulps(struct omap_dss_device *dssdev)
+static int minnow_panel_exit_ulps_locked(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ struct omap_dss_device *dssdev = mpd->dssdev;
int r;
if (!mpd->ulps_enabled)
@@ -957,56 +1021,55 @@ static int minnow_panel_exit_ulps(struct omap_dss_device *dssdev)
r = omapdss_dsi_display_enable(dssdev);
if (r) {
+ /* try once to recovery DSI */
+ r = minnow_panel_dsi_recovery_locked(mpd);
+ if (!r)
+ goto next;
dev_err(&dssdev->dev, "failed to enable DSI\n");
- goto err1;
+ goto err;
}
omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, true);
- r = _minnow_panel_enable_te(dssdev, true);
+ r = _minnow_panel_enable_te(mpd, mpd->te_enabled);
if (r) {
- dev_err(&dssdev->dev, "failed to re-enable TE");
- goto err2;
+ /* try once to recovery DSI */
+ r = minnow_panel_dsi_recovery_locked(mpd);
+ if (r)
+ goto err;
}
+next:
if (gpio_is_valid(mpd->ext_te_gpio))
enable_irq(gpio_to_irq(mpd->ext_te_gpio));
- minnow_panel_queue_ulps_work(dssdev);
+ minnow_panel_queue_ulps_work(mpd);
mpd->ulps_enabled = false;
dev_dbg(&dssdev->dev, "exited ULPS mode\n");
+#ifdef PANEL_PERF_TIME
+ mpd->time_ulps += GET_ELAPSE_TIME(mpd->last_ulps);
+#endif
return 0;
-err2:
+err:
dev_err(&dssdev->dev, "failed to exit ULPS\n");
-
- r = minnow_panel_reset(dssdev);
- if (!r) {
- if (gpio_is_valid(mpd->ext_te_gpio))
- enable_irq(gpio_to_irq(mpd->ext_te_gpio));
- mpd->ulps_enabled = false;
- }
-err1:
- minnow_panel_queue_ulps_work(dssdev);
-
return r;
}
-static int minnow_panel_wake_up(struct omap_dss_device *dssdev)
+static int minnow_panel_wake_up_locked(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
-
if (mpd->ulps_enabled)
- return minnow_panel_exit_ulps(dssdev);
+ return minnow_panel_exit_ulps_locked(mpd);
- minnow_panel_cancel_ulps_work(dssdev);
- minnow_panel_queue_ulps_work(dssdev);
+ minnow_panel_cancel_ulps_work(mpd);
+ minnow_panel_queue_ulps_work(mpd);
return 0;
}
+#ifdef CONFIG_PANEL_BACKLIGHT
static int minnow_panel_bl_update_status(struct backlight_device *dev)
{
struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -1027,9 +1090,10 @@ static int minnow_panel_bl_update_status(struct backlight_device *dev)
if (mpd->enabled) {
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (!r)
- r = minnow_panel_dcs_write_1(mpd, DCS_BRIGHTNESS, level);
+ r = minnow_panel_dcs_write_1(mpd, DCS_BRIGHTNESS,
+ level);
dsi_bus_unlock(dssdev);
} else {
@@ -1044,7 +1108,7 @@ static int minnow_panel_bl_update_status(struct backlight_device *dev)
static int minnow_panel_bl_get_intensity(struct backlight_device *dev)
{
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
- dev->props.power == FB_BLANK_UNBLANK)
+ dev->props.power == FB_BLANK_UNBLANK)
return dev->props.brightness;
return 0;
@@ -1054,6 +1118,7 @@ static const struct backlight_ops minnow_panel_bl_ops = {
.get_brightness = minnow_panel_bl_get_intensity,
.update_status = minnow_panel_bl_update_status,
};
+#endif
static void minnow_panel_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
@@ -1062,38 +1127,66 @@ static void minnow_panel_get_resolution(struct omap_dss_device *dssdev,
*yres = dssdev->panel.timings.y_res;
}
-static ssize_t minnow_panel_num_errors_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t minnow_panel_errors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
- u8 errors = 0;
- int r;
+ static struct { u16 addr; const char *name; } dump[] = {
+ {0x1018, "MIPIRX-Phy Error"},
+ {0x102C, "MIPIRX-DSI Error"},
+ {0x1030, "MIPIRX-DSI Error Count"},
+ {0x608C, "MIPITX-DSI0 Status"},
+ };
+ u8 read[6];
+ int i, r, len = 0;
mutex_lock(&mpd->lock);
+ len += snprintf(buf+len, PAGE_SIZE-len, "Updates: %d\n",
+ mpd->total_update);
+ len += snprintf(buf+len, PAGE_SIZE-len, "Errors: %d\n",
+ mpd->total_error);
+ len += snprintf(buf+len, PAGE_SIZE-len, "ESD RST: %d\n",
+ mpd->total_esd_reset);
+ dsi_bus_lock(dssdev);
- if (mpd->enabled) {
- dsi_bus_lock(dssdev);
+ if (!mpd->enabled || (mpd->id_panel != MINNOW_PANEL_CM_BRIDGE_320X320))
+ goto _ret_;
- r = minnow_panel_wake_up(dssdev);
- if (!r)
- r = minnow_panel_dcs_read_1(mpd, DCS_READ_NUM_ERRORS, &errors);
+ r = minnow_panel_wake_up_locked(mpd);
+ if (r) {
+ len += snprintf(buf+len, PAGE_SIZE-len, "Failed to wakeup!\n");
+ goto _ret_;
+ }
- dsi_bus_unlock(dssdev);
- } else {
- r = -ENODEV;
+ for (i = 0; i < sizeof(dump)/sizeof(dump[0]); i++) {
+ r = panel_ssd2848_read_reg(mpd, dump[i].addr, read+2);
+ if (r)
+ len += snprintf(buf+len, PAGE_SIZE-len,
+ "Failed read register %s\n",
+ dump[i].name);
+ else
+ len += snprintf(buf+len, PAGE_SIZE-len,
+ "%s:\t%02X%02X%02X%02X\n",
+ dump[i].name, read[2], read[3],
+ read[4], read[5]);
+ if (dump[i].addr != 0x608C)
+ continue;
+ /* Cleaning MIPITX-DSI0 Status */
+ read[0] = 0x60;
+ read[1] = 0x8C;
+ dsi_vc_generic_write(mpd->dssdev, mpd->channel, read, 6);
}
+_ret_:
+ dsi_bus_unlock(dssdev);
mutex_unlock(&mpd->lock);
- if (r)
- return r;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", errors);
+ return len;
}
static ssize_t minnow_panel_hw_revision_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1105,7 +1198,7 @@ static ssize_t minnow_panel_hw_revision_show(struct device *dev,
if (mpd->enabled) {
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (!r)
r = minnow_panel_get_id(mpd, &id1, &id2, &id3);
@@ -1122,6 +1215,7 @@ static ssize_t minnow_panel_hw_revision_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
}
+#ifdef PANEL_DEBUG
static const char *cabc_modes[] = {
"off", /* used also always when CABC is not supported */
"ui",
@@ -1130,28 +1224,24 @@ static const char *cabc_modes[] = {
};
static ssize_t show_cabc_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
const char *mode_str;
int mode;
- int len;
mode = mpd->cabc_mode;
mode_str = "unknown";
if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
mode_str = cabc_modes[mode];
- len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
- return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
+ return snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
}
static ssize_t store_cabc_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1171,7 +1261,7 @@ static ssize_t store_cabc_mode(struct device *dev,
if (mpd->enabled) {
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r)
goto err;
@@ -1194,24 +1284,22 @@ err:
}
static ssize_t show_cabc_available_modes(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
- int len;
- int i;
+ int i, len;
for (i = 0, len = 0;
len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
- len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
+ len += snprintf(&buf[len], PAGE_SIZE-len, "%s%s%s",
i ? " " : "", cabc_modes[i],
i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
- return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
+ return len;
}
+#endif
static ssize_t minnow_panel_store_esd_interval(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1224,18 +1312,66 @@ static ssize_t minnow_panel_store_esd_interval(struct device *dev,
return r;
mutex_lock(&mpd->lock);
- minnow_panel_cancel_esd_work(dssdev);
- mpd->esd_interval = t;
+ minnow_panel_cancel_esd_work(mpd);
+ /* special settings for test purpose */
+ switch (t) {
+ case 1: case 2:
+ /* active panel/bridge reset to force ESD */
+ t--;
+ dev_info(&mpd->dssdev->dev, "ESD test to force %s reset\n",
+ t == MINNOW_PANEL ? "panel" : "bridge");
+ gpio_set_value(mpd->reset_gpio[t],
+ mpd->hw_reset[t].active ? 1 : 0);
+ break;
+ case 3:
+ dsi_bus_lock(dssdev);
+ dev_info(&mpd->dssdev->dev, "ESD test for DSI recovery\n");
+ r = minnow_panel_exit_ulps_locked(mpd);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_exit_ulps_locked = %d\n", r);
+ r = minnow_panel_dsi_recovery_locked(mpd);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_dsi_recovery_locked = %d\n", r);
+ r = minnow_panel_enter_ulps_locked(mpd);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_enter_ulps_locked = %d\n", r);
+ r = minnow_panel_dsi_recovery_locked(mpd);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_dsi_recovery_locked = %d\n", r);
+ dsi_bus_unlock(dssdev);
+ break;
+ case 4:
+ dsi_bus_lock(dssdev);
+ dev_info(&mpd->dssdev->dev, "ESD test for panel recovery\n");
+ minnow_panel_disable_locked(mpd, true);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_disable_locked done\n");
+ msleep(20);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_enable_locked start\n");
+ r = minnow_panel_enable_locked(mpd);
+ dev_info(&mpd->dssdev->dev,
+ "minnow_panel_enable_locked = %d\n", r);
+ if (!r) {
+ r = minnow_panel_update_locked(mpd);
+ /* no dsi_bus_unlock when update start successfully */
+ if (!r)
+ break;
+ }
+ dsi_bus_unlock(dssdev);
+ default:
+ mpd->esd_interval = t;
+ break;
+ }
if (mpd->enabled)
- minnow_panel_queue_esd_work(dssdev);
+ minnow_panel_queue_esd_work(mpd);
mutex_unlock(&mpd->lock);
return count;
}
static ssize_t minnow_panel_show_esd_interval(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1249,8 +1385,7 @@ static ssize_t minnow_panel_show_esd_interval(struct device *dev,
}
static ssize_t minnow_panel_store_ulps(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1267,24 +1402,20 @@ static ssize_t minnow_panel_store_ulps(struct device *dev,
dsi_bus_lock(dssdev);
if (t)
- r = minnow_panel_enter_ulps(dssdev);
+ r = minnow_panel_enter_ulps_locked(mpd);
else
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
dsi_bus_unlock(dssdev);
}
mutex_unlock(&mpd->lock);
- if (r)
- return r;
-
- return count;
+ return r ? r : count;
}
static ssize_t minnow_panel_show_ulps(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1298,8 +1429,7 @@ static ssize_t minnow_panel_show_ulps(struct device *dev,
}
static ssize_t minnow_panel_store_ulps_timeout(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1314,23 +1444,19 @@ static ssize_t minnow_panel_store_ulps_timeout(struct device *dev,
mpd->ulps_timeout = t;
if (mpd->enabled) {
- /* minnow_panel_wake_up will restart the timer */
+ /* minnow_panel_wake_up_locked will restart the timer */
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
dsi_bus_unlock(dssdev);
}
mutex_unlock(&mpd->lock);
- if (r)
- return r;
-
- return count;
+ return r ? r : count;
}
static ssize_t minnow_panel_show_ulps_timeout(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1343,10 +1469,9 @@ static ssize_t minnow_panel_show_ulps_timeout(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", t);
}
-#ifdef DEBUG
+#ifdef PANEL_DEBUG
static ssize_t minnow_panel_store_init_data(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1374,8 +1499,7 @@ static ssize_t minnow_panel_store_init_data(struct device *dev,
}
static ssize_t minnow_panel_show_init_data(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1387,24 +1511,22 @@ static ssize_t minnow_panel_show_init_data(struct device *dev,
mutex_unlock(&mpd->lock);
for (i = 0; i < PAGE_SIZE && *data; ) {
- snprintf(buf+i, PAGE_SIZE-i, "%02d %02d:", data[0], data[1]);
- i += 6;
+ i += snprintf(buf+i, PAGE_SIZE-i,
+ "%02d %02d:", data[0], data[1]);
for (j = 0; j < *data && i < PAGE_SIZE; j++) {
- snprintf(buf+i, PAGE_SIZE-i, " %02X", data[2+j]);
- i += 3;
+ i + snprintf(buf+i, PAGE_SIZE-i, " %02X", data[2+j]);
}
snprintf(buf+i, PAGE_SIZE-i, "\n");
i++;
data += *data + 2;
}
- return i < PAGE_SIZE ? i : PAGE_SIZE;
+ return i;
}
#endif
static ssize_t minnow_panel_show_interactivemode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr, char *buf)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1418,8 +1540,7 @@ static ssize_t minnow_panel_show_interactivemode(struct device *dev,
}
static ssize_t minnow_panel_store_interactivemode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf, size_t count)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -1438,9 +1559,9 @@ static ssize_t minnow_panel_store_interactivemode(struct device *dev,
mpd->interactive = enable;
dsi_bus_lock(dssdev);
if (enable)
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
else
- r = minnow_panel_enter_ulps(dssdev);
+ r = minnow_panel_enter_ulps_locked(mpd);
dsi_bus_unlock(dssdev);
}
mutex_unlock(&mpd->lock);
@@ -1451,37 +1572,78 @@ static ssize_t minnow_panel_store_interactivemode(struct device *dev,
return r ? r : count;
}
-static DEVICE_ATTR(num_dsi_errors, S_IRUGO, minnow_panel_num_errors_show, NULL);
+#ifdef PANEL_PERF_TIME
+static ssize_t minnow_panel_perftime_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ int len = 0;
+
+ mutex_lock(&mpd->lock);
+ if (mpd->enabled) {
+ mpd->time_power_on += GET_ELAPSE_TIME(mpd->last_power_on);
+ mpd->last_power_on = jiffies;
+ }
+ len += snprintf(buf+len, PAGE_SIZE-len, "Power On: %lu ms\n",
+ mpd->time_power_on);
+ len += snprintf(buf+len, PAGE_SIZE-len, "Enter ULPS: %lu ms\n",
+ mpd->time_ulps);
+ len += snprintf(buf+len, PAGE_SIZE-len, "Update Frame: %lu ms\n",
+ mpd->time_update);
+ len += snprintf(buf+len, PAGE_SIZE-len, " Frame Min: %lu ms\n",
+ mpd->time_update_min);
+ len += snprintf(buf+len, PAGE_SIZE-len, " Frame Max: %lu ms\n",
+ mpd->time_update_max);
+ len += snprintf(buf+len, PAGE_SIZE-len, " Frame Avg: %lu ms\n",
+ mpd->time_update / mpd->total_update);
+ mutex_unlock(&mpd->lock);
+
+ return len;
+}
+#endif
+
+static DEVICE_ATTR(errors, S_IRUGO, minnow_panel_errors_show, NULL);
static DEVICE_ATTR(hw_revision, S_IRUGO, minnow_panel_hw_revision_show, NULL);
-static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
- show_cabc_mode, store_cabc_mode);
-static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
- show_cabc_available_modes, NULL);
static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
- minnow_panel_show_esd_interval, minnow_panel_store_esd_interval);
+ minnow_panel_show_esd_interval,
+ minnow_panel_store_esd_interval);
static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
- minnow_panel_show_ulps, minnow_panel_store_ulps);
+ minnow_panel_show_ulps, minnow_panel_store_ulps);
static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
- minnow_panel_show_ulps_timeout, minnow_panel_store_ulps_timeout);
-#ifdef DEBUG
+ minnow_panel_show_ulps_timeout,
+ minnow_panel_store_ulps_timeout);
+#ifdef PANEL_DEBUG
+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
+ show_cabc_mode, store_cabc_mode);
+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
+ show_cabc_available_modes, NULL);
static DEVICE_ATTR(init_data, S_IRUGO | S_IWUSR,
- minnow_panel_show_init_data, minnow_panel_store_init_data);
+ minnow_panel_show_init_data,
+ minnow_panel_store_init_data);
#endif
static DEVICE_ATTR(interactivemode, S_IRUGO | S_IWUSR,
- minnow_panel_show_interactivemode, minnow_panel_store_interactivemode);
+ minnow_panel_show_interactivemode,
+ minnow_panel_store_interactivemode);
+#ifdef PANEL_PERF_TIME
+static DEVICE_ATTR(perftime, S_IRUGO, minnow_panel_perftime_show, NULL);
+#endif
static struct attribute *minnow_panel_attrs[] = {
- &dev_attr_num_dsi_errors.attr,
+ &dev_attr_errors.attr,
&dev_attr_hw_revision.attr,
- &dev_attr_cabc_mode.attr,
- &dev_attr_cabc_available_modes.attr,
&dev_attr_esd_interval.attr,
&dev_attr_ulps.attr,
&dev_attr_ulps_timeout.attr,
-#ifdef DEBUG
+#ifdef PANEL_DEBUG
+ &dev_attr_cabc_mode.attr,
+ &dev_attr_cabc_available_modes.attr,
&dev_attr_init_data.attr,
#endif
&dev_attr_interactivemode.attr,
+#ifdef PANEL_PERF_TIME
+ &dev_attr_perftime.attr,
+#endif
NULL,
};
@@ -1507,9 +1669,8 @@ static void _minnow_panel_hw_active_reset(struct minnow_panel_data *mpd)
minnow_panel_delay(mpd->reset_ms);
}
-static void _minnow_panel_hw_reset(struct omap_dss_device *dssdev)
+static void _minnow_panel_hw_reset(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int i;
_minnow_panel_hw_active_reset(mpd);
@@ -1675,7 +1836,9 @@ static int minnow_panel_dt_init(struct minnow_panel_data *mpd)
}
/* automatically go to ULPS mode for none-update within 250ms */
mpd->ulps_timeout = 250;
+#ifdef CONFIG_PANEL_BACKLIGHT
mpd->use_dsi_backlight = false;
+#endif
mpd->pin_config.num_pins = 4;
mpd->pin_config.pins[0] = 0;
@@ -1760,11 +1923,35 @@ static int minnow_panel_dt_init(struct minnow_panel_data *mpd)
return 0;
}
+static int minnow_panel_parse_panel_param(char *param, int *ptype, int *pver)
+{
+ char *p, *start = (char *)param;
+ int ver, type;
+
+ if (!param)
+ return -EINVAL;
+ type = simple_strtoul(start, &p, 10);
+ if (start == p)
+ return -EINVAL;
+ if (*p != '#')
+ return -EINVAL;
+ start = p + 1;
+ ver = simple_strtoul(start, &p, 10);
+ if (start == p)
+ return -EINVAL;
+ if (*p != '\0')
+ return -EINVAL;
+ *ptype = type;
+ *pver = ver;
+ return 0;
+}
+
static int minnow_panel_probe(struct omap_dss_device *dssdev)
{
- struct backlight_properties props;
struct minnow_panel_data *mpd;
+#ifdef CONFIG_PANEL_BACKLIGHT
struct backlight_device *bldev = NULL;
+#endif
int i, r;
dev_dbg(&dssdev->dev, "probe\n");
@@ -1784,17 +1971,27 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
mutex_init(&mpd->lock);
atomic_set(&mpd->do_update, 0);
-
+#ifdef PANEL_PERF_TIME
+ mpd->time_update_min = (unsigned long)(-1);
+ mpd->time_update_max = 0;
+#endif
/* it will reset bridge/panel if boot-loader does not initialize it */
mpd->skip_first_init = false;
- mpd->panel_type = def_panel_type;
- switch (def_panel_type) {
+ if (minnow_panel_parse_panel_param(def_panel_param, &i, &r)) {
+ dev_err(&dssdev->dev, "wrong panel parameter %s\n",
+ def_panel_param);
+ i = PANEL_INIT;
+ }
+ mpd->panel_type = i;
+ switch (mpd->panel_type) {
case PANEL_INIT:
case PANEL_DUMMY:
dev_info(&dssdev->dev,
"There is not panel id coming from boot-loader\n");
break;
case OTM3201_1_0:
+ /* turn of ESD for panel 1.0 */
+ mpd->esd_interval = 0;
/* it needs replace the settings for panel 1.0 */
if (minnow_panel_replace_cmdbuf(mpd->power_on.cmdbuf,
panel_init_ssd2848_320x320_1)){
@@ -1803,12 +2000,16 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
}
case OTM3201_2_0:
case OTM3201_2_1:
- mpd->skip_first_init = true;
+ if (r == INIT_DATA_VERSION)
+ mpd->skip_first_init = true;
+ else
+ dev_err(&dssdev->dev, "Initialize version mismatch"
+ " (%d-%d)!\n", r, INIT_DATA_VERSION);
break;
default:
dev_err(&dssdev->dev,
"Wrong panel id(%d) got from boot-loader\n",
- def_panel_type);
+ mpd->panel_type);
break;
}
dev_info(&dssdev->dev, "skip first time initialization is %s\n",
@@ -1927,13 +2128,17 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
INIT_DEFERRABLE_WORK(&mpd->esd_work, minnow_panel_esd_work);
INIT_DELAYED_WORK(&mpd->ulps_work, minnow_panel_ulps_work);
+#ifdef CONFIG_PANEL_BACKLIGHT
if (mpd->use_dsi_backlight) {
+ struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = 255;
props.type = BACKLIGHT_RAW;
bldev = backlight_device_register(dev_name(&dssdev->dev),
- &dssdev->dev, dssdev, &minnow_panel_bl_ops, &props);
+ &dssdev->dev, dssdev,
+ &minnow_panel_bl_ops,
+ &props);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
goto err_bl;
@@ -1947,6 +2152,7 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
minnow_panel_bl_update_status(bldev);
}
+#endif
r = omap_dsi_request_vc(dssdev, &mpd->channel);
if (r) {
@@ -1977,9 +2183,11 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
err_vc_id:
omap_dsi_release_vc(dssdev, mpd->channel);
err_req_vc:
+#ifdef CONFIG_PANEL_BACKLIGHT
if (bldev != NULL)
backlight_device_unregister(bldev);
err_bl:
+#endif
destroy_workqueue(mpd->workqueue);
return r;
}
@@ -1987,29 +2195,36 @@ err_bl:
static void __exit minnow_panel_remove(struct omap_dss_device *dssdev)
{
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bldev;
dev_dbg(&dssdev->dev, "remove\n");
sysfs_remove_group(&dssdev->dev.kobj, &minnow_panel_attr_group);
omap_dsi_release_vc(dssdev, mpd->channel);
- bldev = mpd->bldev;
- if (bldev != NULL) {
+#ifdef CONFIG_PANEL_BACKLIGHT
+ if (mpd->bldev != NULL) {
+ struct backlight_device *bldev = mpd->bldev;
bldev->props.power = FB_BLANK_POWERDOWN;
minnow_panel_bl_update_status(bldev);
backlight_device_unregister(bldev);
}
+#endif
- minnow_panel_cancel_ulps_work(dssdev);
- minnow_panel_cancel_esd_work(dssdev);
+ minnow_panel_cancel_ulps_work(mpd);
+ minnow_panel_cancel_esd_work(mpd);
destroy_workqueue(mpd->workqueue);
/* reset, to be sure that the panel is in a valid state */
- _minnow_panel_hw_reset(dssdev);
+ _minnow_panel_hw_reset(mpd);
}
#define DCS_POWER_MODE_NORMAL 0x1C
+#define ERROR_UNEXPECT_MODE(mode) (0x12345600 | (mode))
+/* panel 1.0 has timing issue that may occur missing command or ECC error
+ * then it will receive 00 from Solomon, so for this case, retry to read
+ * might be better
+ */
+#define IS_ERR_UNEXPECT_MODE_00(err) ((err) == 0x12345600)
static int minnow_panel_check_panel_status(struct minnow_panel_data *mpd)
{
u8 mode;
@@ -2022,29 +2237,31 @@ static int minnow_panel_check_panel_status(struct minnow_panel_data *mpd)
if (!r) {
r = panel_otm3201_read_reg(mpd, MIPI_DCS_GET_POWER_MODE,
&mode, 1);
- panel_ssd2848_set_retransmit(mpd, false);
+ if (!r)
+ r = panel_ssd2848_set_retransmit(mpd, false);
}
if (r)
dev_dbg(&mpd->dssdev->dev, "unable to get panel power mode\n");
else if (mode != DCS_POWER_MODE_NORMAL) {
- dev_dbg(&mpd->dssdev->dev,
+ dev_err(&mpd->dssdev->dev,
"panel is not On, power mode is 0x%02x\n", mode);
- r = -EIO;
+ r = ERROR_UNEXPECT_MODE(mode);
}
return r;
}
#define POWER_ON_RETRY_TIMES 3
-static int minnow_panel_power_on(struct omap_dss_device *dssdev)
+static int minnow_panel_power_on(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ struct omap_dss_device *dssdev = mpd->dssdev;
u8 id1, id2, id3;
int r;
bool need_verify = true;
mpd->panel_retry_count = 0;
+ mpd->esd_errors = 0;
init_start:
mpd->panel_retry_count++;
@@ -2066,6 +2283,10 @@ init_start:
dev_err(&dssdev->dev, "failed to enable DSI\n");
goto err0;
}
+ if (mpd->output_enabled) {
+ dsi_disable_video_output(mpd->dssdev, mpd->channel);
+ mpd->output_enabled = false;
+ }
omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, false);
@@ -2073,12 +2294,19 @@ init_start:
if (mpd->first_enable && mpd->skip_first_init) {
dsi_vc_send_bta_sync(dssdev, mpd->channel);
} else {
- _minnow_panel_hw_reset(dssdev);
+ _minnow_panel_hw_reset(mpd);
r = minnow_panel_process_cmdbuf(mpd, &mpd->power_on,
need_verify);
- if (!r) {
- if (mpd->panel_type != PANEL_DUMMY)
+ if (!r && (mpd->panel_type != PANEL_DUMMY)) {
+ /* check if panel power on correctly, it may
+ * get power on mode with 0 sometimes, but it
+ * could not prove panel does not work, needs
+ * retry to check it again.
+ */
+ int retry = 3;
+ do {
r = minnow_panel_check_panel_status(mpd);
+ } while (retry-- && IS_ERR_UNEXPECT_MODE_00(r));
}
if (r) {
if (mpd->panel_retry_count >= POWER_ON_RETRY_TIMES) {
@@ -2094,15 +2322,17 @@ init_start:
/* try without read back check */
need_verify = false;
}
+ mpd->total_error++;
dev_err(&dssdev->dev, "Reset hardware to retry ...\n");
- omapdss_dsi_display_disable(dssdev, true, false);
+ /* true/true for fast disable dsi */
+ omapdss_dsi_display_disable(dssdev, true, true);
goto init_start;
}
}
/* it needed enable TE to force update after display enabled */
mpd->te_enabled = true;
- r = _minnow_panel_enable_te(dssdev, mpd->te_enabled);
+ r = _minnow_panel_enable_te(mpd, mpd->te_enabled);
if (r)
goto err;
@@ -2124,100 +2354,164 @@ init_start:
mpd->enabled = true;
mpd->interactive = true;
+ mpd->output_enabled = true;
if (mpd->first_enable)
dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n",
- id1, id2, id3);
-
+ id1, id2, id3);
+#ifdef PANEL_PERF_TIME
+ mpd->last_power_on = jiffies;
+#endif
return 0;
err:
- dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n");
-
- _minnow_panel_hw_reset(dssdev);
+ mpd->total_error++;
+ dev_err(&dssdev->dev,
+ "error while enabling panel, issuing HW reset\n");
+ _minnow_panel_hw_active_reset(mpd);
omapdss_dsi_display_disable(dssdev, true, false);
err0:
return r;
}
-static void minnow_panel_power_off(struct omap_dss_device *dssdev)
+static void minnow_panel_power_off(struct minnow_panel_data *mpd,
+ bool fast_power_off)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r;
- dsi_disable_video_output(dssdev, mpd->channel);
-
- r = minnow_panel_process_cmdbuf(mpd, &mpd->power_off, false);
- if (r)
- dev_err(&dssdev->dev,
- "error disabling panel, return %d\n", r);
+#ifdef PANEL_PERF_TIME
+ if (mpd->enabled)
+ mpd->time_power_on += GET_ELAPSE_TIME(mpd->last_power_on);
+#endif
+ if (!fast_power_off) {
+ dsi_disable_video_output(mpd->dssdev, mpd->channel);
+ mpd->output_enabled = false;
- omapdss_dsi_display_disable(dssdev, true, false);
+ r = minnow_panel_process_cmdbuf(mpd, &mpd->power_off, false);
+ if (r)
+ dev_err(&mpd->dssdev->dev,
+ "error disabling panel, return %d\n", r);
+ }
+ /* true/true for fast disable DSI */
+ omapdss_dsi_display_disable(mpd->dssdev, true, fast_power_off);
mpd->enabled = false;
mpd->interactive = false;
+ mpd->ulps_enabled = false;
}
-static int minnow_panel_reset(struct omap_dss_device *dssdev)
+static void minnow_panel_disable_locked(struct minnow_panel_data *mpd,
+ bool fast_power_off)
{
- dev_err(&dssdev->dev, "performing LCD reset\n");
+ minnow_panel_cancel_ulps_work(mpd);
+ minnow_panel_power_off(mpd, fast_power_off);
+ mpd->dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
- minnow_panel_power_off(dssdev);
- _minnow_panel_hw_reset(dssdev);
- return minnow_panel_power_on(dssdev);
+ _minnow_panel_hw_active_reset(mpd);
+ minnow_panel_enable_clkin(mpd, false);
+ minnow_panel_enable_vio(mpd, false);
+ minnow_panel_set_regulators(mpd, regulator_disable);
}
-static int minnow_panel_enable(struct omap_dss_device *dssdev)
+static int minnow_panel_enable_locked(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r;
- dev_info(&dssdev->dev, "%s: current state = %d\n",
- __func__, dssdev->state);
-
- mutex_lock(&mpd->lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- r = -EINVAL;
+ r = minnow_panel_set_regulators(mpd, regulator_enable);
+ if (r)
goto err;
- }
-
+ minnow_panel_enable_vio(mpd, true);
r = minnow_panel_enable_clkin(mpd, true);
if (r)
goto err;
- r = minnow_panel_set_regulators(mpd, regulator_enable);
+
+ r = minnow_panel_power_on(mpd);
if (r)
goto err;
- minnow_panel_enable_vio(mpd, true);
- dsi_bus_lock(dssdev);
+ minnow_panel_queue_esd_work(mpd);
+ mpd->dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
- r = minnow_panel_power_on(dssdev);
+ return 0;
- dsi_bus_unlock(dssdev);
+err:
+ dev_err(&mpd->dssdev->dev, "Display enable failed, err = %d\n", r);
+
+ /* clean up clk/power */
+ minnow_panel_disable_locked(mpd, true);
+ return r;
+}
+
+static int minnow_panel_update_locked(struct minnow_panel_data *mpd)
+{
+ int r = 0;
+
+ /* hold wake_lock to avoid kernel suspend */
+ wake_lock(&mpd->wake_lock);
+ /* XXX no need to send this every frame, but dsi break if not done */
+ r = minnow_panel_set_update_window(mpd, 0, 0,
+ mpd->dssdev->panel.timings.x_res,
+ mpd->dssdev->panel.timings.y_res);
if (r)
goto err;
- minnow_panel_queue_esd_work(dssdev);
+ if (mpd->te_enabled && gpio_is_valid(mpd->ext_te_gpio)) {
+ schedule_delayed_work(&mpd->te_timeout_work,
+ msecs_to_jiffies(250));
+ atomic_set(&mpd->do_update, 1);
+ } else {
+ r = omap_dsi_update(mpd->dssdev, mpd->channel,
+ minnow_panel_framedone_cb, mpd->dssdev);
+ if (r)
+ goto err;
+ }
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+#ifdef PANEL_PERF_TIME
+ mpd->last_update = jiffies;
+#endif
+ /* No wake_unlock here, unlock will be done in framedone_cb */
+ return r;
+err:
+ wake_unlock(&mpd->wake_lock);
+ return r;
+}
- mutex_unlock(&mpd->lock);
+static int minnow_panel_enable(struct omap_dss_device *dssdev)
+{
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ bool update;
+ int r = -EINVAL;
- /* do not force update at first time if it needs keep logo on */
- if (!(mpd->first_enable && mpd->skip_first_init))
- r = minnow_panel_update(dssdev, 0, 0,
- dssdev->panel.timings.x_res,
- dssdev->panel.timings.y_res);
+ dev_info(&dssdev->dev, "%s: current state = %d\n",
+ __func__, dssdev->state);
- dev_info(&dssdev->dev, "Display enabled, manual update ret = %d\n", r);
- mpd->first_enable = false;
+ if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) {
+ mutex_lock(&mpd->lock);
+ minnow_panel_cancel_ulps_work(mpd);
+ minnow_panel_cancel_esd_work(mpd);
+
+ dsi_bus_lock(dssdev);
+ r = minnow_panel_enable_locked(mpd);
+ /* do not force update at first time to keep boot logo on */
+ update = !r && !(mpd->first_enable && mpd->skip_first_init);
+ mpd->first_enable = false;
+ if (update)
+ update = !minnow_panel_update_locked(mpd);
+ /* it will release dsi_bus_unlock in frame done callback when
+ * update start successfully
+ */
+ if (!update)
+ dsi_bus_unlock(dssdev);
+ if (!r) {
+ minnow_panel_queue_ulps_work(mpd);
+ minnow_panel_queue_esd_work(mpd);
+ dev_info(&dssdev->dev, "Display enabled successfully "
+ "%s update!\n", update ? "with" : "without");
+ }
+ mutex_unlock(&mpd->lock);
+ }
- return 0;
-err:
- dev_err(&dssdev->dev, "Display enable failed, err = %d\n", r);
- mutex_unlock(&mpd->lock);
return r;
}
@@ -2229,29 +2523,17 @@ static void minnow_panel_disable(struct omap_dss_device *dssdev)
__func__, dssdev->state);
mutex_lock(&mpd->lock);
-
- minnow_panel_cancel_ulps_work(dssdev);
- minnow_panel_cancel_esd_work(dssdev);
+ minnow_panel_cancel_ulps_work(mpd);
+ minnow_panel_cancel_esd_work(mpd);
dsi_bus_lock(dssdev);
-
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- int r;
-
- r = minnow_panel_wake_up(dssdev);
- if (!r)
- minnow_panel_power_off(dssdev);
+ /* if it can not wakeup, do fast disable */
+ bool fast = minnow_panel_wake_up_locked(mpd) != 0;
+ minnow_panel_disable_locked(mpd, fast);
}
-
dsi_bus_unlock(dssdev);
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
- _minnow_panel_hw_active_reset(mpd);
- minnow_panel_enable_vio(mpd, false);
- minnow_panel_set_regulators(mpd, regulator_disable);
- minnow_panel_enable_clkin(mpd, false);
-
mutex_unlock(&mpd->lock);
}
@@ -2265,7 +2547,7 @@ static int minnow_panel_suspend(struct omap_dss_device *dssdev)
mutex_lock(&mpd->lock);
if (mpd->enabled) {
dsi_bus_lock(dssdev);
- minnow_panel_enter_ulps(dssdev);
+ minnow_panel_enter_ulps_locked(mpd);
dsi_bus_unlock(dssdev);
}
mutex_unlock(&mpd->lock);
@@ -2278,6 +2560,17 @@ static void minnow_panel_framedone_cb(int err, void *data)
struct omap_dss_device *dssdev = data;
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
+ mpd->total_update++;
+#ifdef PANEL_PERF_TIME
+{
+ unsigned long ms = GET_ELAPSE_TIME(mpd->last_update);
+ if (ms < mpd->time_update_min)
+ mpd->time_update_min = ms;
+ if (ms > mpd->time_update_max)
+ mpd->time_update_max = ms;
+ mpd->time_update += ms;
+}
+#endif
dsi_bus_unlock(dssdev);
wake_unlock(&mpd->wake_lock);
}
@@ -2319,52 +2612,43 @@ static void minnow_panel_te_timeout_work_callback(struct work_struct *work)
}
static int minnow_panel_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h)
+ u16 x, u16 y, u16 w, u16 h)
{
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r = 0;
/* if driver is disabled ot it's video mode, do not manual update */
mutex_lock(&mpd->lock);
- if (!mpd->enabled || (mpd->dsi_config.mode == OMAP_DSS_DSI_VIDEO_MODE))
- goto err_ret;
-
- dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
-
- wake_lock(&mpd->wake_lock);
- dsi_bus_lock(dssdev);
-
- r = minnow_panel_wake_up(dssdev);
- if (r)
- goto err;
-
- /* XXX no need to send this every frame, but dsi break if not done */
- r = minnow_panel_set_update_window(mpd, 0, 0,
- dssdev->panel.timings.x_res,
- dssdev->panel.timings.y_res);
- if (r)
- goto err;
+ if (mpd->enabled && (mpd->dsi_config.mode!=OMAP_DSS_DSI_VIDEO_MODE)) {
+ int recovered = 0;
+ dev_dbg(&dssdev->dev, "update %d, %d, %d-%d\n", x, y, w, h);
- if (mpd->te_enabled && gpio_is_valid(mpd->ext_te_gpio)) {
- schedule_delayed_work(&mpd->te_timeout_work,
- msecs_to_jiffies(250));
- atomic_set(&mpd->do_update, 1);
- } else {
- r = omap_dsi_update(dssdev, mpd->channel, minnow_panel_framedone_cb,
- dssdev);
+ dsi_bus_lock(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
+ if (!r)
+ goto _update_;
+ _recovery_:
+ /* try recovery panel if it can't wake up */
+ r = minnow_panel_recovery_locked(mpd);
if (r)
- goto err;
+ goto _dsi_unlock_;
+ _update_:
+ r = minnow_panel_update_locked(mpd);
+ /* no dsi_bus_unlock when update start successfully */
+ if (!r)
+ goto _mutex_unlock_;
+ /* try if it need recovery once */
+ if (recovered++)
+ goto _dsi_unlock_;
+ /* be safety, check the panel status to make sure it's stuck now */
+ r = minnow_panel_check_panel_status(mpd);
+ if (r)
+ goto _recovery_;
+ _dsi_unlock_:
+ dev_err(&dssdev->dev, "update %d, %d, %d-%d failed(%d)\n", x, y, w, h, r);
+ dsi_bus_unlock(dssdev);
}
-
- /* note: no dsi_bus_unlock and wake_unlock here.
- * unlock is in framedone_cb
- */
- mutex_unlock(&mpd->lock);
- return 0;
-err:
- dsi_bus_unlock(dssdev);
- wake_unlock(&mpd->wake_lock);
-err_ret:
+_mutex_unlock_:
mutex_unlock(&mpd->lock);
return r;
}
@@ -2385,9 +2669,8 @@ static int minnow_panel_sync(struct omap_dss_device *dssdev)
return 0;
}
-static int _minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable)
+static int _minnow_panel_enable_te(struct minnow_panel_data *mpd, bool enable)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r;
if (enable)
@@ -2396,7 +2679,7 @@ static int _minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable)
r = minnow_panel_dcs_write_0(mpd, MIPI_DCS_SET_TEAR_OFF);
if (!gpio_is_valid(mpd->ext_te_gpio))
- omapdss_dsi_enable_te(dssdev, enable);
+ omapdss_dsi_enable_te(mpd->dssdev, enable);
return r;
}
@@ -2414,11 +2697,11 @@ static int minnow_panel_enable_te(struct omap_dss_device *dssdev, bool enable)
dsi_bus_lock(dssdev);
if (mpd->enabled) {
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r)
goto err;
- r = _minnow_panel_enable_te(dssdev, enable);
+ r = _minnow_panel_enable_te(mpd, enable);
if (r)
goto err;
}
@@ -2449,6 +2732,7 @@ static int minnow_panel_get_te(struct omap_dss_device *dssdev)
return r;
}
+#ifdef PANEL_DEBUG
static int minnow_panel_run_test(struct omap_dss_device *dssdev, int test_num)
{
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
@@ -2464,7 +2748,7 @@ static int minnow_panel_run_test(struct omap_dss_device *dssdev, int test_num)
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r)
goto err2;
@@ -2489,8 +2773,7 @@ err1:
}
static int minnow_panel_memory_read(struct omap_dss_device *dssdev,
- void *buf, size_t size,
- u16 x, u16 y, u16 w, u16 h)
+ void *buf, size_t size, u16 x, u16 y, u16 w, u16 h)
{
int r;
int plen;
@@ -2511,12 +2794,12 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev,
}
size = min(w * h * plen,
- dssdev->panel.timings.x_res *
- dssdev->panel.timings.y_res * plen);
+ dssdev->panel.timings.x_res *
+ dssdev->panel.timings.y_res * plen);
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r)
goto err2;
@@ -2531,7 +2814,7 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev,
size = size / plen * plen;
for (; buf_used < size; dcs_cmd = MIPI_DCS_READ_MEMORY_CONTINUE) {
r = dsi_vc_dcs_read(dssdev, mpd->channel, dcs_cmd,
- buf + buf_used, plen);
+ buf + buf_used, plen);
if (r) {
dev_err(&dssdev->dev,
"read failed at %u err=%d\n", buf_used, r);
@@ -2540,7 +2823,7 @@ static int minnow_panel_memory_read(struct omap_dss_device *dssdev,
buf_used += plen;
if (signal_pending(current)) {
dev_err(&dssdev->dev, "signal pending, "
- "aborting memory read\n");
+ "aborting memory read\n");
r = -ERESTARTSYS;
goto err3;
}
@@ -2555,6 +2838,7 @@ err1:
mutex_unlock(&mpd->lock);
return r;
}
+#endif
static void minnow_panel_ulps_work(struct work_struct *work)
{
@@ -2570,10 +2854,9 @@ static void minnow_panel_ulps_work(struct work_struct *work)
}
dsi_bus_lock(dssdev);
-
- minnow_panel_enter_ulps(dssdev);
-
+ minnow_panel_enter_ulps_locked(mpd);
dsi_bus_unlock(dssdev);
+
mutex_unlock(&mpd->lock);
}
@@ -2593,35 +2876,55 @@ static void minnow_panel_esd_work(struct work_struct *work)
dsi_bus_lock(dssdev);
- r = minnow_panel_wake_up(dssdev);
+ r = minnow_panel_wake_up_locked(mpd);
if (r) {
dev_err(&dssdev->dev, "failed to exit ULPS\n");
- goto err;
+ goto _reset_;
}
+ omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, false);
r = minnow_panel_check_panel_status(mpd);
if (r) {
+ if (IS_ERR_UNEXPECT_MODE_00(r)) {
+ /* workaround to assume panel is good till it gets
+ * power state 00 for 3 continue times
+ */
+ if (++mpd->esd_errors < 3)
+ goto _next_;
+ }
dev_err(&dssdev->dev, "failed to read minnow-panel status\n");
- goto err;
+ goto _reset_;
}
+ mpd->esd_errors = 0;
+_next_:
+ omapdss_dsi_vc_enable_hs(dssdev, mpd->channel, true);
if (!mpd->interactive)
- minnow_panel_enter_ulps(dssdev);
+ minnow_panel_enter_ulps_locked(mpd);
+ else
+ minnow_panel_queue_ulps_work(mpd);
dsi_bus_unlock(dssdev);
-
- minnow_panel_queue_esd_work(dssdev);
mutex_unlock(&mpd->lock);
-
return;
-err:
- dev_err(&dssdev->dev, "performing LCD reset\n");
+_reset_:
+ r = minnow_panel_recovery_locked(mpd);
+ if (!r) {
+ r = minnow_panel_update_locked(mpd);
+ /* it will release dsi_bus_unlock in frame done callback when
+ * update start successfully
+ */
+ if (!r)
+ goto _munlock_;
+ if (!mpd->interactive)
+ minnow_panel_enter_ulps_locked(mpd);
+ else
+ minnow_panel_queue_ulps_work(mpd);
+ }
dsi_bus_unlock(dssdev);
+_munlock_:
mutex_unlock(&mpd->lock);
-
- minnow_panel_disable(dssdev);
- minnow_panel_enable(dssdev);
}
static struct omap_dss_driver minnow_panel_driver = {
@@ -2643,8 +2946,10 @@ static struct omap_dss_driver minnow_panel_driver = {
.enable_te = minnow_panel_enable_te,
.get_te = minnow_panel_get_te,
+#ifdef PANEL_DEBUG
.run_test = minnow_panel_run_test,
.memory_read = minnow_panel_memory_read,
+#endif
.driver = {
.name = "minnow-panel",
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 85d86ad7961..1e1da1bc88e 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -46,6 +46,7 @@
#include "dss_features.h"
#define DSI_CATCH_MISSING_TE
+#define DSI_DISABLE_LP_RX_TO
struct dsi_reg { u16 idx; };
@@ -339,6 +340,7 @@ struct dsi_data {
int debug_read;
int debug_write;
atomic_t update_pending;
+ atomic_t runtime_active;
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
@@ -1098,9 +1100,14 @@ int dsi_runtime_get(struct platform_device *dsidev)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
DSSDBG("dsi_runtime_get\n");
-
- r = pm_runtime_get_sync(&dsi->pdev->dev);
- WARN_ON(r < 0);
+ r = atomic_xchg(&dsi->runtime_active, 1);
+ if (!r) {
+ r = pm_runtime_get_sync(&dsi->pdev->dev);
+ if (r < 0) {
+ atomic_set(&dsi->runtime_active, 0);
+ WARN(1, "dsi_runtime_get ret = %d\n", r);
+ }
+ }
return r < 0 ? r : 0;
}
@@ -1110,9 +1117,11 @@ void dsi_runtime_put(struct platform_device *dsidev)
int r;
DSSDBG("dsi_runtime_put\n");
-
- r = pm_runtime_put_sync(&dsi->pdev->dev);
- WARN_ON(r < 0 && r != -ENOSYS);
+ r = atomic_xchg(&dsi->runtime_active, 0);
+ if (r) {
+ r = pm_runtime_put_sync(&dsi->pdev->dev);
+ WARN(r < 0 && r != -ENOSYS, "dsi_runtime_put ret = %d\n", r);
+ }
}
/* source clock for DSI PLL. this could also be PCLKFREE */
@@ -2832,6 +2841,8 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
int r = 0;
u32 err;
+ dsi_sync_vc(dsidev, channel);
+
r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
&completion, DSI_VC_IRQ_BTA);
if (r)
@@ -2847,7 +2858,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
goto err2;
if (wait_for_completion_timeout(&completion,
- msecs_to_jiffies(500)) == 0) {
+ msecs_to_jiffies(50)) == 0) {
DSSERR("Failed to receive BTA\n");
r = -EIO;
goto err2;
@@ -3526,7 +3537,11 @@ static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
fck = dsi_fclk_rate(dsidev);
r = dsi_read_reg(dsidev, DSI_TIMING2);
+#ifdef DSI_DISABLE_LP_RX_TO
+ r = FLD_MOD(r, 0, 15, 15); /* LP_RX_TO */
+#else
r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
+#endif
r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
@@ -4283,9 +4298,11 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev)
dss_mgr_start_update(mgr);
if (dsi->te_enabled) {
+#ifndef DSI_DISABLE_LP_RX_TO
/* disable LP_RX_TO, so that we can receive TE. Time to wait
* for TE is longer than the timer allows */
REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
+#endif
dsi_vc_send_bta(dsidev, channel);
@@ -4329,8 +4346,10 @@ static void dsi_handle_framedone(struct platform_device *dsidev, int error)
dispc_enable_sidle();
if (dsi->te_enabled) {
+#ifndef DSI_DISABLE_LP_RX_TO
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+#endif
}
dsi->framedone_callback(error, dsi->framedone_data);
@@ -4592,7 +4611,10 @@ static void dsi_display_uninit_dsi(struct platform_device *dsidev,
static int dsi_soft_reset(struct platform_device *dsidev)
{
- int i = 5;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int i = 10;
+
+ dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
/* enable DSI soft reset */
REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
/* waiting for DSI soft reset done*/
@@ -4665,19 +4687,30 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
WARN_ON(!dsi_bus_is_locked(dsidev));
mutex_lock(&dsi->lock);
+ /*do nothing if it did not enabled */
+ if (!atomic_read(&dsi->runtime_active))
+ goto exit;
- dsi_sync_vc(dsidev, 0);
- dsi_sync_vc(dsidev, 1);
- dsi_sync_vc(dsidev, 2);
- dsi_sync_vc(dsidev, 3);
-
- dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
+ /* special fast rest DSI for disconnect_lanes/enter_ulps all true
+ * it will save 150 ms
+ */
+ if (disconnect_lanes && enter_ulps) {
+ dsi_soft_reset(dsidev);
+ dsi_cio_uninit(dsidev);
+ dsi_pll_uninit(dsidev, true);
+ } else {
+ dsi_sync_vc(dsidev, 0);
+ dsi_sync_vc(dsidev, 1);
+ dsi_sync_vc(dsidev, 2);
+ dsi_sync_vc(dsidev, 3);
+ dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
+ }
dsi_runtime_put(dsidev);
dsi_enable_pll_clock(dsidev, 0);
omap_dss_stop_device(dssdev);
-
+exit:
mutex_unlock(&dsi->lock);
}
EXPORT_SYMBOL(omapdss_dsi_display_disable);