summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/displays/panel-minnow.c161
1 files changed, 126 insertions, 35 deletions
diff --git a/drivers/video/omap2/displays/panel-minnow.c b/drivers/video/omap2/displays/panel-minnow.c
index cf8e31b5391..fe7297f8dc1 100644
--- a/drivers/video/omap2/displays/panel-minnow.c
+++ b/drivers/video/omap2/displays/panel-minnow.c
@@ -252,6 +252,7 @@ SWITCH_TO_BRIDGE,
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*/
0
};
@@ -358,6 +359,8 @@ 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);
struct minnow_panel_data {
@@ -386,10 +389,13 @@ struct minnow_panel_data {
struct omap_dss_dsi_config dsi_config;
struct minnow_panel_cmd_buf power_on;
struct minnow_panel_cmd_buf power_off;
+ u8 *last_init_data;
int id_panel;
int x_offset;
int y_offset;
+ int reset_ms;
+ int release_ms;
/* runtime variables */
bool enabled;
@@ -857,26 +863,39 @@ static int minnow_panel_verify_cmdbuf(struct minnow_panel_data *mpd,
return r;
}
-static int minnow_panel_process_cmdbuf(struct minnow_panel_data *mpd,
- struct minnow_panel_cmd_buf *cmd_buf)
+static int minnow_panel_check_cmdbuf(struct minnow_panel_data *mpd,
+ u8 *data, int count)
{
- u8 *data;
int i, r = 0;
- for (i = cmd_buf->count, data = cmd_buf->cmdbuf; *data && (i > 0); ) {
+ for (i = count; *data && (i > 0); ) {
if (data[1] >= CMD_TYPE_MAX)
break;
i -= ((u32)*data + 2);
data += (*data + 2);
}
- /* Init command data shall end with 0 */
+ /* command data shall end with 0 */
if (*data || (i != 1)) {
dev_err(&mpd->dssdev->dev, "Invalid command data(0x%02x) "
- "found at offset %d", *data, cmd_buf->count - i);
- return -EINVAL;
+ "found at offset %d", *data, count - i);
+ r = -EINVAL;
}
+ return r;
+}
+
+static int minnow_panel_process_cmdbuf(struct minnow_panel_data *mpd,
+ struct minnow_panel_cmd_buf *cmd_buf)
+{
+ u8 *data;
+ int i, r;
+
+ /* be safe to check command data every time before sent to driver */
+ r = minnow_panel_check_cmdbuf(mpd, cmd_buf->cmdbuf, cmd_buf->count);
+ if (r)
+ return r;
+
for (i = 0, data = cmd_buf->cmdbuf; *data; i++, data += *data+2) {
if (data[1] == CHECK_MS)
r = minnow_panel_verify_cmdbuf(mpd, cmd_buf);
@@ -1354,6 +1373,63 @@ static ssize_t minnow_panel_show_ulps_timeout(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", t);
}
+static ssize_t minnow_panel_store_init_data(struct device *dev,
+ 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);
+ u8 *data;
+ int r;
+
+ r = minnow_panel_check_cmdbuf(mpd, (u8 *)buf, count);
+ if (r)
+ return r;
+
+ data = devm_kzalloc(&dssdev->dev, count, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ memcpy(data, buf, count);
+
+ mutex_lock(&mpd->lock);
+ mpd->power_on.count = count;
+ mpd->power_on.cmdbuf = data;
+ if (mpd->last_init_data)
+ devm_kfree(&dssdev->dev, mpd->last_init_data);
+ mpd->last_init_data = data;
+ mutex_unlock(&mpd->lock);
+
+ return count;
+}
+
+static ssize_t minnow_panel_show_init_data(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 i, j;
+ u8 *data;
+
+ mutex_lock(&mpd->lock);
+ data = mpd->power_on.cmdbuf;
+ 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;
+ for (j = 0; j < *data && i < PAGE_SIZE; j++) {
+ snprintf(buf+i, PAGE_SIZE-i, " %02X", data[2+j]);
+ i += 3;
+ }
+ snprintf(buf+i, PAGE_SIZE-i, "\n");
+ i++;
+ data += *data + 2;
+ }
+
+ return i < PAGE_SIZE ? i : PAGE_SIZE;
+}
+
static DEVICE_ATTR(num_dsi_errors, S_IRUGO, minnow_panel_num_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,
@@ -1366,6 +1442,8 @@ static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
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);
+static DEVICE_ATTR(init_data, S_IRUGO | S_IWUSR,
+ minnow_panel_show_init_data, minnow_panel_store_init_data);
static struct attribute *minnow_panel_attrs[] = {
&dev_attr_num_dsi_errors.attr,
@@ -1375,6 +1453,7 @@ static struct attribute *minnow_panel_attrs[] = {
&dev_attr_esd_interval.attr,
&dev_attr_ulps.attr,
&dev_attr_ulps_timeout.attr,
+ &dev_attr_init_data.attr,
NULL,
};
@@ -1382,24 +1461,11 @@ static struct attribute_group minnow_panel_attr_group = {
.attrs = minnow_panel_attrs,
};
-static void _minnow_panel_hw_reset(struct omap_dss_device *dssdev)
+static void _minnow_panel_hw_active_reset(struct minnow_panel_data *mpd)
{
- struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
- int i, ms_rst = -1, ms_rel = -1;
-
- for (i = 0; i < MINNOW_COMPONENT_MAX; i++) {
- if (!gpio_is_valid(mpd->reset_gpio[i]))
- continue;
- gpio_set_value(mpd->reset_gpio[i],
- mpd->hw_reset[i].active ? 0 : 1);
- if (ms_rst < mpd->hw_reset[i].reset_ms)
- ms_rst = mpd->hw_reset[i].reset_ms;
- if (ms_rel < mpd->hw_reset[i].wait_ms)
- ms_rel = mpd->hw_reset[i].wait_ms;
- }
- if (ms_rst == -1)
+ int i;
+ if (mpd->reset_ms < 0)
return;
- msleep(5);
/* reset the device */
for (i = 0; i < MINNOW_COMPONENT_MAX; i++) {
@@ -1408,8 +1474,18 @@ static void _minnow_panel_hw_reset(struct omap_dss_device *dssdev)
gpio_set_value(mpd->reset_gpio[i],
mpd->hw_reset[i].active ? 1 : 0);
}
+
/* wait device reset */
- msleep(ms_rst);
+ msleep(mpd->reset_ms);
+}
+
+static void _minnow_panel_hw_reset(struct omap_dss_device *dssdev)
+{
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ int i;
+
+ _minnow_panel_hw_active_reset(mpd);
+
/* assert reset */
for (i = 0; i < MINNOW_COMPONENT_MAX; i++) {
if (!gpio_is_valid(mpd->reset_gpio[i]))
@@ -1417,8 +1493,10 @@ static void _minnow_panel_hw_reset(struct omap_dss_device *dssdev)
gpio_set_value(mpd->reset_gpio[i],
mpd->hw_reset[i].active ? 0 : 1);
}
+
/* wait after releasing reset */
- msleep(ms_rel);
+ if (mpd->release_ms > 0)
+ msleep(mpd->release_ms);
}
static int minnow_panel_set_regulators(struct minnow_panel_data *mpd,
@@ -1663,6 +1741,8 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
}
}
+ mpd->reset_ms = -1;
+ mpd->release_ms = -1;
for (i = 0; i < MINNOW_COMPONENT_MAX; i++) {
static const char * const name[MINNOW_COMPONENT_MAX] = {
"minnow-panel reset",
@@ -1671,13 +1751,17 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
if (!gpio_is_valid(mpd->reset_gpio[i]))
continue;
r = devm_gpio_request_one(&dssdev->dev, mpd->reset_gpio[i],
- mpd->hw_reset[i].active ? GPIOF_OUT_INIT_LOW
- : GPIOF_OUT_INIT_HIGH, name[i]);
+ mpd->hw_reset[i].active ? GPIOF_OUT_INIT_HIGH
+ : GPIOF_OUT_INIT_LOW, name[i]);
if (r) {
dev_err(&dssdev->dev,
"failed to request %s gpio\n", name[i]);
return r;
}
+ if (mpd->reset_ms < mpd->hw_reset[i].reset_ms)
+ mpd->reset_ms = mpd->hw_reset[i].reset_ms;
+ if (mpd->release_ms < mpd->hw_reset[i].wait_ms)
+ mpd->release_ms = mpd->hw_reset[i].wait_ms;
}
if (gpio_is_valid(mpd->ext_te_gpio)) {
@@ -1891,6 +1975,8 @@ init_start:
if (r)
goto err;
+ /* it needed enable TE to force update after display enabled */
+ mpd->te_enabled = true;
r = _minnow_panel_enable_te(dssdev, mpd->te_enabled);
if (r)
goto err;
@@ -1932,11 +2018,9 @@ static void minnow_panel_power_off(struct omap_dss_device *dssdev)
dsi_disable_video_output(dssdev, mpd->channel);
r = minnow_panel_process_cmdbuf(mpd, &mpd->power_off);
- if (r) {
+ if (r)
dev_err(&dssdev->dev,
- "error disabling panel, issuing HW reset\n");
- _minnow_panel_hw_reset(dssdev);
- }
+ "error disabling panel, return %d\n", r);
omapdss_dsi_display_disable(dssdev, true, false);
@@ -1957,7 +2041,8 @@ static int minnow_panel_enable(struct omap_dss_device *dssdev)
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
int r;
- dev_dbg(&dssdev->dev, "enable\n");
+ dev_info(&dssdev->dev, "%s: current state = %d\n",
+ __func__, dssdev->state);
mutex_lock(&mpd->lock);
@@ -1986,9 +2071,14 @@ static int minnow_panel_enable(struct omap_dss_device *dssdev)
mutex_unlock(&mpd->lock);
+ r = minnow_panel_update(dssdev, 0, 0,
+ dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
+ dev_info(&dssdev->dev, "Display enabled, manual update ret = %d\n", r);
+
return 0;
err:
- dev_dbg(&dssdev->dev, "enable failed\n");
+ dev_err(&dssdev->dev, "Display enable failed, err = %d\n", r);
mutex_unlock(&mpd->lock);
return r;
}
@@ -1997,7 +2087,8 @@ static void minnow_panel_disable(struct omap_dss_device *dssdev)
{
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
- dev_dbg(&dssdev->dev, "disable\n");
+ dev_info(&dssdev->dev, "%s: current state = %d\n",
+ __func__, dssdev->state);
mutex_lock(&mpd->lock);
@@ -2018,10 +2109,10 @@ static void minnow_panel_disable(struct omap_dss_device *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);
-
mutex_unlock(&mpd->lock);
}