summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/Makefile2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c59
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c39
-rw-r--r--drivers/video/omap2/displays/panel-lgphilips-lb035q02.c58
-rw-r--r--drivers/video/omap2/displays/panel-n8x0.c95
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c135
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.c49
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c126
-rw-r--r--drivers/video/omap2/displays/panel-taal.c300
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c4
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c58
-rw-r--r--drivers/video/omap2/dss/apply.c15
-rw-r--r--drivers/video/omap2/dss/core.c25
-rw-r--r--drivers/video/omap2/dss/dispc.c176
-rw-r--r--drivers/video/omap2/dss/dispc.h1
-rw-r--r--drivers/video/omap2/dss/dpi.c351
-rw-r--r--drivers/video/omap2/dss/dsi.c1256
-rw-r--r--drivers/video/omap2/dss/dss.c181
-rw-r--r--drivers/video/omap2/dss/dss.h59
-rw-r--r--drivers/video/omap2/dss/dss_features.c14
-rw-r--r--drivers/video/omap2/dss/hdmi.c72
-rw-r--r--drivers/video/omap2/dss/output.c1
-rw-r--r--drivers/video/omap2/dss/rfbi.c34
-rw-r--r--drivers/video/omap2/dss/sdi.c103
-rw-r--r--drivers/video/omap2/dss/venc.c56
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c65
-rw-r--r--drivers/video/omap2/vrfb.c18
27 files changed, 1750 insertions, 1602 deletions
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
index 5ea7cb9aed1..296e5c5281c 100644
--- a/drivers/video/omap2/Makefile
+++ b/drivers/video/omap2/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
obj-$(CONFIG_OMAP2_DSS) += dss/
-obj-$(CONFIG_FB_OMAP2) += omapfb/
obj-y += displays/
+obj-$(CONFIG_FB_OMAP2) += omapfb/
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
index 72699f88c00..d7f69c09ecf 100644
--- a/drivers/video/omap2/displays/panel-acx565akm.c
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -29,8 +29,10 @@
#include <linux/sched.h>
#include <linux/backlight.h>
#include <linux/fb.h>
+#include <linux/gpio.h>
#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
#define MIPID_CMD_READ_DISP_ID 0x04
#define MIPID_CMD_READ_RED 0x06
@@ -336,8 +338,6 @@ static int acx565akm_bl_update_status(struct backlight_device *dev)
r = 0;
if (md->has_bc)
acx565akm_set_brightness(md, level);
- else if (md->dssdev->set_backlight)
- r = md->dssdev->set_backlight(md->dssdev, level);
else
r = -ENODEV;
@@ -352,7 +352,7 @@ static int acx565akm_bl_get_intensity(struct backlight_device *dev)
dev_dbg(&dev->dev, "%s\n", __func__);
- if (!md->has_bc && md->dssdev->set_backlight == NULL)
+ if (!md->has_bc)
return -ENODEV;
if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
@@ -496,21 +496,38 @@ static struct omap_video_timings acx_panel_timings = {
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
};
+static struct panel_acx565akm_data *get_panel_data(struct omap_dss_device *dssdev)
+{
+ return (struct panel_acx565akm_data *) dssdev->data;
+}
+
static int acx_panel_probe(struct omap_dss_device *dssdev)
{
int r;
struct acx565akm_device *md = &acx_dev;
+ struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
struct backlight_device *bldev;
int max_brightness, brightness;
struct backlight_properties props;
dev_dbg(&dssdev->dev, "%s\n", __func__);
+ if (!panel_data)
+ return -EINVAL;
+
/* FIXME AC bias ? */
dssdev->panel.timings = acx_panel_timings;
- if (dssdev->platform_enable)
- dssdev->platform_enable(dssdev);
+ if (gpio_is_valid(panel_data->reset_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd reset");
+ if (r)
+ return r;
+ }
+
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_set_value(panel_data->reset_gpio, 1);
+
/*
* After reset we have to wait 5 msec before the first
* command can be sent.
@@ -522,8 +539,9 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
r = panel_detect(md);
if (r) {
dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
- if (!md->enabled && dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ if (!md->enabled && gpio_is_valid(panel_data->reset_gpio))
+ gpio_set_value(panel_data->reset_gpio, 0);
+
return r;
}
@@ -532,8 +550,8 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
mutex_unlock(&acx_dev.mutex);
if (!md->enabled) {
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_set_value(panel_data->reset_gpio, 0);
}
/*------- Backlight control --------*/
@@ -557,15 +575,10 @@ static int acx_panel_probe(struct omap_dss_device *dssdev)
md->cabc_mode = get_hw_cabc_mode(md);
}
- if (md->has_bc)
- max_brightness = 255;
- else
- max_brightness = dssdev->max_backlight_level;
+ max_brightness = 255;
if (md->has_bc)
brightness = acx565akm_get_actual_brightness(md);
- else if (dssdev->get_backlight)
- brightness = dssdev->get_backlight(dssdev);
else
brightness = 0;
@@ -591,6 +604,7 @@ static void acx_panel_remove(struct omap_dss_device *dssdev)
static int acx_panel_power_on(struct omap_dss_device *dssdev)
{
struct acx565akm_device *md = &acx_dev;
+ struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "%s\n", __func__);
@@ -612,11 +626,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
/*FIXME tweak me */
msleep(50);
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto fail;
- }
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_set_value(panel_data->reset_gpio, 1);
if (md->enabled) {
dev_dbg(&md->spi->dev, "panel already enabled\n");
@@ -645,8 +656,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
mutex_unlock(&md->mutex);
return acx565akm_bl_update_status(md->bl_dev);
-fail:
- omapdss_sdi_display_disable(dssdev);
+
fail_unlock:
mutex_unlock(&md->mutex);
return r;
@@ -655,6 +665,7 @@ fail_unlock:
static void acx_panel_power_off(struct omap_dss_device *dssdev)
{
struct acx565akm_device *md = &acx_dev;
+ struct panel_acx565akm_data *panel_data = get_panel_data(dssdev);
dev_dbg(&dssdev->dev, "%s\n", __func__);
@@ -678,8 +689,8 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev)
*/
msleep(50);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_set_value(panel_data->reset_gpio, 0);
/* FIXME need to tweak this delay */
msleep(100);
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c
index c904f42d81c..97363f73368 100644
--- a/drivers/video/omap2/displays/panel-generic-dpi.c
+++ b/drivers/video/omap2/displays/panel-generic-dpi.c
@@ -33,9 +33,10 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <video/omapdss.h>
-#include <video/omap-panel-generic-dpi.h>
+#include <video/omap-panel-data.h>
struct panel_config {
struct omap_video_timings timings;
@@ -533,7 +534,7 @@ static inline struct panel_generic_dpi_data
static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
{
- int r;
+ int r, i;
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
struct panel_config *panel_config = drv_data->panel_config;
@@ -552,15 +553,13 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
if (panel_config->power_on_delay)
msleep(panel_config->power_on_delay);
- if (panel_data->platform_enable) {
- r = panel_data->platform_enable(dssdev);
- if (r)
- goto err1;
+ for (i = 0; i < panel_data->num_gpios; ++i) {
+ gpio_set_value_cansleep(panel_data->gpios[i],
+ panel_data->gpio_invert[i] ? 0 : 1);
}
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
+
err0:
return r;
}
@@ -570,12 +569,15 @@ static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
struct panel_config *panel_config = drv_data->panel_config;
+ int i;
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (panel_data->platform_disable)
- panel_data->platform_disable(dssdev);
+ for (i = panel_data->num_gpios - 1; i >= 0; --i) {
+ gpio_set_value_cansleep(panel_data->gpios[i],
+ panel_data->gpio_invert[i] ? 1 : 0);
+ }
/* wait couple of vsyncs after disabling the LCD */
if (panel_config->power_off_delay)
@@ -589,7 +591,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct panel_config *panel_config = NULL;
struct panel_drv_data *drv_data = NULL;
- int i;
+ int i, r;
dev_dbg(&dssdev->dev, "probe\n");
@@ -606,9 +608,18 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
if (!panel_config)
return -EINVAL;
+ for (i = 0; i < panel_data->num_gpios; ++i) {
+ r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
+ panel_data->gpio_invert[i] ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+ "panel gpio");
+ if (r)
+ return r;
+ }
+
dssdev->panel.timings = panel_config->timings;
- drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+ drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
@@ -624,12 +635,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
{
- struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
-
dev_dbg(&dssdev->dev, "remove\n");
- kfree(drv_data);
-
dev_set_drvdata(&dssdev->dev, NULL);
}
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
index 6e5abe8fd2d..4ea6548c0ae 100644
--- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
+++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
@@ -20,8 +20,10 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/mutex.h>
+#include <linux/gpio.h>
#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
struct lb035q02_data {
struct mutex lock;
@@ -48,9 +50,16 @@ static struct omap_video_timings lb035q02_timings = {
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
};
+static inline struct panel_generic_dpi_data
+*get_panel_data(const struct omap_dss_device *dssdev)
+{
+ return (struct panel_generic_dpi_data *) dssdev->data;
+}
+
static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
{
- int r;
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ int r, i;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
@@ -62,54 +71,65 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev)
if (r)
goto err0;
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
+ for (i = 0; i < panel_data->num_gpios; ++i) {
+ gpio_set_value_cansleep(panel_data->gpios[i],
+ panel_data->gpio_invert[i] ? 0 : 1);
}
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
+
err0:
return r;
}
static void lb035q02_panel_power_off(struct omap_dss_device *dssdev)
{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
+ int i;
+
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ for (i = panel_data->num_gpios - 1; i >= 0; --i) {
+ gpio_set_value_cansleep(panel_data->gpios[i],
+ panel_data->gpio_invert[i] ? 1 : 0);
+ }
omapdss_dpi_display_disable(dssdev);
}
static int lb035q02_panel_probe(struct omap_dss_device *dssdev)
{
+ struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
struct lb035q02_data *ld;
- int r;
+ int r, i;
+
+ if (!panel_data)
+ return -EINVAL;
dssdev->panel.timings = lb035q02_timings;
- ld = kzalloc(sizeof(*ld), GFP_KERNEL);
- if (!ld) {
- r = -ENOMEM;
- goto err;
+ ld = devm_kzalloc(&dssdev->dev, sizeof(*ld), GFP_KERNEL);
+ if (!ld)
+ return -ENOMEM;
+
+ for (i = 0; i < panel_data->num_gpios; ++i) {
+ r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
+ panel_data->gpio_invert[i] ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+ "panel gpio");
+ if (r)
+ return r;
}
+
mutex_init(&ld->lock);
dev_set_drvdata(&dssdev->dev, ld);
+
return 0;
-err:
- return r;
}
static void lb035q02_panel_remove(struct omap_dss_device *dssdev)
{
- struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev);
-
- kfree(ld);
}
static int lb035q02_panel_enable(struct omap_dss_device *dssdev)
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c
index dd129475080..f94ead6a318 100644
--- a/drivers/video/omap2/displays/panel-n8x0.c
+++ b/drivers/video/omap2/displays/panel-n8x0.c
@@ -5,11 +5,10 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
-#include <linux/backlight.h>
#include <linux/fb.h>
#include <video/omapdss.h>
-#include <video/omap-panel-n8x0.h>
+#include <video/omap-panel-data.h>
#define BLIZZARD_REV_CODE 0x00
#define BLIZZARD_CONFIG 0x02
@@ -69,7 +68,6 @@ static struct panel_drv_data {
struct omap_dss_device *dssdev;
struct spi_device *spidev;
- struct backlight_device *bldev;
int blizzard_ver;
} s_drv_data;
@@ -297,12 +295,6 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
gpio_direction_output(bdata->ctrl_pwrdown, 1);
- if (bdata->platform_enable) {
- r = bdata->platform_enable(dssdev);
- if (r)
- goto err_plat_en;
- }
-
omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size);
@@ -375,9 +367,6 @@ err_inv_panel:
err_inv_chip:
omapdss_rfbi_display_disable(dssdev);
err_rfbi_en:
- if (bdata->platform_disable)
- bdata->platform_disable(dssdev);
-err_plat_en:
gpio_direction_output(bdata->ctrl_pwrdown, 0);
return r;
}
@@ -394,9 +383,6 @@ static void n8x0_panel_power_off(struct omap_dss_device *dssdev)
send_display_off(spi);
send_sleep_in(spi);
- if (bdata->platform_disable)
- bdata->platform_disable(dssdev);
-
/*
* HACK: we should turn off the panel here, but there is some problem
* with the initialization sequence, and we fail to init the panel if we
@@ -424,54 +410,10 @@ static const struct rfbi_timings n8x0_panel_timings = {
.cs_pulse_width = 0,
};
-static int n8x0_bl_update_status(struct backlight_device *dev)
-{
- struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
- struct panel_n8x0_data *bdata = get_board_data(dssdev);
- struct panel_drv_data *ddata = get_drv_data(dssdev);
- int r;
- int level;
-
- mutex_lock(&ddata->lock);
-
- if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
- dev->props.power == FB_BLANK_UNBLANK)
- level = dev->props.brightness;
- else
- level = 0;
-
- dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
-
- if (!bdata->set_backlight)
- r = -EINVAL;
- else
- r = bdata->set_backlight(dssdev, level);
-
- mutex_unlock(&ddata->lock);
-
- return r;
-}
-
-static int n8x0_bl_get_intensity(struct backlight_device *dev)
-{
- if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
- dev->props.power == FB_BLANK_UNBLANK)
- return dev->props.brightness;
-
- return 0;
-}
-
-static const struct backlight_ops n8x0_bl_ops = {
- .get_brightness = n8x0_bl_get_intensity,
- .update_status = n8x0_bl_update_status,
-};
-
static int n8x0_panel_probe(struct omap_dss_device *dssdev)
{
struct panel_n8x0_data *bdata = get_board_data(dssdev);
struct panel_drv_data *ddata;
- struct backlight_device *bldev;
- struct backlight_properties props;
int r;
dev_dbg(&dssdev->dev, "probe\n");
@@ -491,40 +433,27 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev)
dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
- memset(&props, 0, sizeof(props));
- props.max_brightness = 127;
- props.type = BACKLIGHT_PLATFORM;
- bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
- dssdev, &n8x0_bl_ops, &props);
- if (IS_ERR(bldev)) {
- r = PTR_ERR(bldev);
- dev_err(&dssdev->dev, "register backlight failed\n");
- return r;
+ if (gpio_is_valid(bdata->panel_reset)) {
+ r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset,
+ GPIOF_OUT_INIT_LOW, "PANEL RESET");
+ if (r)
+ return r;
}
- ddata->bldev = bldev;
-
- bldev->props.fb_blank = FB_BLANK_UNBLANK;
- bldev->props.power = FB_BLANK_UNBLANK;
- bldev->props.brightness = 127;
-
- n8x0_bl_update_status(bldev);
+ if (gpio_is_valid(bdata->ctrl_pwrdown)) {
+ r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown,
+ GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN");
+ if (r)
+ return r;
+ }
return 0;
}
static void n8x0_panel_remove(struct omap_dss_device *dssdev)
{
- struct panel_drv_data *ddata = get_drv_data(dssdev);
- struct backlight_device *bldev;
-
dev_dbg(&dssdev->dev, "remove\n");
- bldev = ddata->bldev;
- bldev->props.power = FB_BLANK_POWERDOWN;
- n8x0_bl_update_status(bldev);
- backlight_device_unregister(bldev);
-
dev_set_drvdata(&dssdev->dev, NULL);
}
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
index c4e9c2b1b46..20c3cd91ff9 100644
--- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
+++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
@@ -19,10 +19,11 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <linux/backlight.h>
#include <linux/fb.h>
+#include <linux/gpio.h>
#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
#define LCD_XRES 800
#define LCD_YRES 480
@@ -32,10 +33,6 @@
*/
#define LCD_PIXEL_CLOCK 23800
-struct nec_8048_data {
- struct backlight_device *bl;
-};
-
static const struct {
unsigned char addr;
unsigned char dat;
@@ -84,93 +81,47 @@ static struct omap_video_timings nec_8048_panel_timings = {
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
};
-static int nec_8048_bl_update_status(struct backlight_device *bl)
-{
- struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
- int level;
-
- if (!dssdev->set_backlight)
- return -EINVAL;
-
- if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
- bl->props.power == FB_BLANK_UNBLANK)
- level = bl->props.brightness;
- else
- level = 0;
-
- return dssdev->set_backlight(dssdev, level);
-}
-
-static int nec_8048_bl_get_brightness(struct backlight_device *bl)
+static inline struct panel_nec_nl8048_data
+*get_panel_data(const struct omap_dss_device *dssdev)
{
- if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
- bl->props.power == FB_BLANK_UNBLANK)
- return bl->props.brightness;
-
- return 0;
+ return (struct panel_nec_nl8048_data *) dssdev->data;
}
-static const struct backlight_ops nec_8048_bl_ops = {
- .get_brightness = nec_8048_bl_get_brightness,
- .update_status = nec_8048_bl_update_status,
-};
-
static int nec_8048_panel_probe(struct omap_dss_device *dssdev)
{
- struct backlight_device *bl;
- struct nec_8048_data *necd;
- struct backlight_properties props;
+ struct panel_nec_nl8048_data *pd = get_panel_data(dssdev);
int r;
- dssdev->panel.timings = nec_8048_panel_timings;
-
- necd = kzalloc(sizeof(*necd), GFP_KERNEL);
- if (!necd)
- return -ENOMEM;
-
- dev_set_drvdata(&dssdev->dev, necd);
+ if (!pd)
+ return -EINVAL;
- memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = 255;
+ dssdev->panel.timings = nec_8048_panel_timings;
- bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev,
- &nec_8048_bl_ops, &props);
- if (IS_ERR(bl)) {
- r = PTR_ERR(bl);
- kfree(necd);
- return r;
+ if (gpio_is_valid(pd->qvga_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->qvga_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd QVGA");
+ if (r)
+ return r;
}
- necd->bl = bl;
-
- bl->props.fb_blank = FB_BLANK_UNBLANK;
- bl->props.power = FB_BLANK_UNBLANK;
- bl->props.max_brightness = dssdev->max_backlight_level;
- bl->props.brightness = dssdev->max_backlight_level;
- r = nec_8048_bl_update_status(bl);
- if (r < 0)
- dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+ if (gpio_is_valid(pd->res_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->res_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd RES");
+ if (r)
+ return r;
+ }
return 0;
}
static void nec_8048_panel_remove(struct omap_dss_device *dssdev)
{
- struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bl = necd->bl;
-
- bl->props.power = FB_BLANK_POWERDOWN;
- nec_8048_bl_update_status(bl);
- backlight_device_unregister(bl);
-
- kfree(necd);
}
static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
{
+ struct panel_nec_nl8048_data *pd = get_panel_data(dssdev);
int r;
- struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bl = necd->bl;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
return 0;
@@ -182,36 +133,24 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev)
if (r)
goto err0;
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
-
- r = nec_8048_bl_update_status(bl);
- if (r < 0)
- dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+ if (gpio_is_valid(pd->res_gpio))
+ gpio_set_value_cansleep(pd->res_gpio, 1);
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
+
err0:
return r;
}
static void nec_8048_panel_power_off(struct omap_dss_device *dssdev)
{
- struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bl = necd->bl;
+ struct panel_nec_nl8048_data *pd = get_panel_data(dssdev);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- bl->props.brightness = 0;
- nec_8048_bl_update_status(bl);
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ if (gpio_is_valid(pd->res_gpio))
+ gpio_set_value_cansleep(pd->res_gpio, 0);
omapdss_dpi_display_disable(dssdev);
}
@@ -303,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi)
return 0;
}
-static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+
+static int nec_8048_spi_suspend(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
+
nec_8048_spi_send(spi, 2, 0x01);
mdelay(40);
return 0;
}
-static int nec_8048_spi_resume(struct spi_device *spi)
+static int nec_8048_spi_resume(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
+
/* reinitialize the panel */
spi_setup(spi);
nec_8048_spi_send(spi, 2, 0x00);
@@ -321,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi)
return 0;
}
+static SIMPLE_DEV_PM_OPS(nec_8048_spi_pm_ops, nec_8048_spi_suspend,
+ nec_8048_spi_resume);
+#define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops)
+#else
+#define NEC_8048_SPI_PM_OPS NULL
+#endif
+
static struct spi_driver nec_8048_spi_driver = {
.probe = nec_8048_spi_probe,
.remove = nec_8048_spi_remove,
- .suspend = nec_8048_spi_suspend,
- .resume = nec_8048_spi_resume,
.driver = {
.name = "nec_8048_spi",
.owner = THIS_MODULE,
+ .pm = NEC_8048_SPI_PM_OPS,
},
};
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c
index 1b94018aac3..62f2db04fbc 100644
--- a/drivers/video/omap2/displays/panel-picodlp.c
+++ b/drivers/video/omap2/displays/panel-picodlp.c
@@ -31,7 +31,7 @@
#include <linux/gpio.h>
#include <video/omapdss.h>
-#include <video/omap-panel-picodlp.h>
+#include <video/omap-panel-data.h>
#include "panel-picodlp.h"
@@ -354,12 +354,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev);
struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- return r;
- }
-
gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
msleep(1);
gpio_set_value(picodlp_pdata->pwrgood_gpio, 1);
@@ -398,9 +392,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev)
err:
omapdss_dpi_display_disable(dssdev);
err1:
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
return r;
}
@@ -412,9 +403,6 @@ static void picodlp_panel_power_off(struct omap_dss_device *dssdev)
gpio_set_value(picodlp_pdata->emu_done_gpio, 0);
gpio_set_value(picodlp_pdata->pwrgood_gpio, 0);
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
}
static int picodlp_panel_probe(struct omap_dss_device *dssdev)
@@ -423,11 +411,14 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev);
struct i2c_adapter *adapter;
struct i2c_client *picodlp_i2c_client;
- int r = 0, picodlp_adapter_id;
+ int r, picodlp_adapter_id;
dssdev->panel.timings = pico_ls_timings;
- picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL);
+ if (!picodlp_pdata)
+ return -EINVAL;
+
+ picod = devm_kzalloc(&dssdev->dev, sizeof(*picod), GFP_KERNEL);
if (!picod)
return -ENOMEM;
@@ -438,25 +429,37 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev)
adapter = i2c_get_adapter(picodlp_adapter_id);
if (!adapter) {
dev_err(&dssdev->dev, "can't get i2c adapter\n");
- r = -ENODEV;
- goto err;
+ return -ENODEV;
}
picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info);
if (!picodlp_i2c_client) {
dev_err(&dssdev->dev, "can't add i2c device::"
" picodlp_i2c_client is NULL\n");
- r = -ENODEV;
- goto err;
+ return -ENODEV;
}
picod->picodlp_i2c_client = picodlp_i2c_client;
dev_set_drvdata(&dssdev->dev, picod);
- return r;
-err:
- kfree(picod);
- return r;
+
+ if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev,
+ picodlp_pdata->emu_done_gpio,
+ GPIOF_IN, "DLP EMU DONE");
+ if (r)
+ return r;
+ }
+
+ if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev,
+ picodlp_pdata->pwrgood_gpio,
+ GPIOF_OUT_INIT_LOW, "DLP PWRGOOD");
+ if (r)
+ return r;
+ }
+
+ return 0;
}
static void picodlp_panel_remove(struct omap_dss_device *dssdev)
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index cada8c621e0..74cb0eb4531 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -20,16 +20,13 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <video/omapdss.h>
-
-struct sharp_data {
- struct backlight_device *bl;
-};
+#include <video/omap-panel-data.h>
static struct omap_video_timings sharp_ls_timings = {
.x_res = 480,
@@ -52,91 +49,67 @@ static struct omap_video_timings sharp_ls_timings = {
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
};
-static int sharp_ls_bl_update_status(struct backlight_device *bl)
+static inline struct panel_sharp_ls037v7dw01_data
+*get_panel_data(const struct omap_dss_device *dssdev)
{
- struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
- int level;
-
- if (!dssdev->set_backlight)
- return -EINVAL;
-
- if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
- bl->props.power == FB_BLANK_UNBLANK)
- level = bl->props.brightness;
- else
- level = 0;
-
- return dssdev->set_backlight(dssdev, level);
+ return (struct panel_sharp_ls037v7dw01_data *) dssdev->data;
}
-static int sharp_ls_bl_get_brightness(struct backlight_device *bl)
-{
- if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
- bl->props.power == FB_BLANK_UNBLANK)
- return bl->props.brightness;
-
- return 0;
-}
-
-static const struct backlight_ops sharp_ls_bl_ops = {
- .get_brightness = sharp_ls_bl_get_brightness,
- .update_status = sharp_ls_bl_update_status,
-};
-
-
-
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
{
- struct backlight_properties props;
- struct backlight_device *bl;
- struct sharp_data *sd;
+ struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev);
int r;
+ if (!pd)
+ return -EINVAL;
+
dssdev->panel.timings = sharp_ls_timings;
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd)
- return -ENOMEM;
+ if (gpio_is_valid(pd->mo_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->mo_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd MO");
+ if (r)
+ return r;
+ }
- dev_set_drvdata(&dssdev->dev, sd);
+ if (gpio_is_valid(pd->lr_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->lr_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd LR");
+ if (r)
+ return r;
+ }
- memset(&props, 0, sizeof(struct backlight_properties));
- props.max_brightness = dssdev->max_backlight_level;
- props.type = BACKLIGHT_RAW;
+ if (gpio_is_valid(pd->ud_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->ud_gpio,
+ GPIOF_OUT_INIT_HIGH, "lcd UD");
+ if (r)
+ return r;
+ }
- bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev,
- &sharp_ls_bl_ops, &props);
- if (IS_ERR(bl)) {
- r = PTR_ERR(bl);
- kfree(sd);
- return r;
+ if (gpio_is_valid(pd->resb_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->resb_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd RESB");
+ if (r)
+ return r;
}
- sd->bl = bl;
- bl->props.fb_blank = FB_BLANK_UNBLANK;
- bl->props.power = FB_BLANK_UNBLANK;
- bl->props.brightness = dssdev->max_backlight_level;
- r = sharp_ls_bl_update_status(bl);
- if (r < 0)
- dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+ if (gpio_is_valid(pd->ini_gpio)) {
+ r = devm_gpio_request_one(&dssdev->dev, pd->ini_gpio,
+ GPIOF_OUT_INIT_LOW, "lcd INI");
+ if (r)
+ return r;
+ }
return 0;
}
static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev)
{
- struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
- struct backlight_device *bl = sd->bl;
-
- bl->props.power = FB_BLANK_POWERDOWN;
- sharp_ls_bl_update_status(bl);
- backlight_device_unregister(bl);
-
- kfree(sd);
}
static int sharp_ls_power_on(struct omap_dss_device *dssdev)
{
+ struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev);
int r = 0;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
@@ -152,26 +125,29 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev)
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
+ if (gpio_is_valid(pd->resb_gpio))
+ gpio_set_value_cansleep(pd->resb_gpio, 1);
+
+ if (gpio_is_valid(pd->ini_gpio))
+ gpio_set_value_cansleep(pd->ini_gpio, 1);
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
static void sharp_ls_power_off(struct omap_dss_device *dssdev)
{
+ struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev);
+
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ if (gpio_is_valid(pd->ini_gpio))
+ gpio_set_value_cansleep(pd->ini_gpio, 0);
+
+ if (gpio_is_valid(pd->resb_gpio))
+ gpio_set_value_cansleep(pd->resb_gpio, 0);
/* wait at least 5 vsyncs after disabling the LCD */
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index a32407a5735..c4f78bda115 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -33,7 +33,7 @@
#include <linux/mutex.h>
#include <video/omapdss.h>
-#include <video/omap-panel-nokia-dsi.h>
+#include <video/omap-panel-data.h>
#include <video/mipi_display.h>
/* DSI Virtual channel. Hardcoded for now. */
@@ -54,61 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
static int taal_panel_reset(struct omap_dss_device *dssdev);
-/**
- * struct panel_config - panel configuration
- * @name: panel name
- * @type: panel type
- * @timings: panel resolution
- * @sleep: various panel specific delays, passed to msleep() if non-zero
- * @reset_sequence: reset sequence timings, passed to udelay() if non-zero
- * @regulators: array of panel regulators
- * @num_regulators: number of regulators in the array
- */
-struct panel_config {
- const char *name;
- int type;
-
- struct omap_video_timings timings;
-
- struct {
- unsigned int sleep_in;
- unsigned int sleep_out;
- unsigned int hw_reset;
- unsigned int enable_te;
- } sleep;
-
- struct {
- unsigned int high;
- unsigned int low;
- } reset_sequence;
-
-};
-
-enum {
- PANEL_TAAL,
-};
-
-static struct panel_config panel_configs[] = {
- {
- .name = "taal",
- .type = PANEL_TAAL,
- .timings = {
- .x_res = 864,
- .y_res = 480,
- },
- .sleep = {
- .sleep_in = 5,
- .sleep_out = 5,
- .hw_reset = 5,
- .enable_te = 100, /* possible panel bug */
- },
- .reset_sequence = {
- .high = 10,
- .low = 10,
- },
- },
-};
-
struct taal_data {
struct mutex lock;
@@ -121,9 +66,6 @@ struct taal_data {
struct omap_dss_device *dssdev;
- /* panel specific HW info */
- struct panel_config *panel_config;
-
/* panel HW configuration from DT or platform data */
int reset_gpio;
int ext_te_gpio;
@@ -134,8 +76,6 @@ struct taal_data {
/* runtime variables */
bool enabled;
- u8 rotate;
- bool mirror;
bool te_enabled;
@@ -221,8 +161,7 @@ static int taal_sleep_in(struct taal_data *td)
hw_guard_start(td, 120);
- if (td->panel_config->sleep.sleep_in)
- msleep(td->panel_config->sleep.sleep_in);
+ msleep(5);
return 0;
}
@@ -239,8 +178,7 @@ static int taal_sleep_out(struct taal_data *td)
hw_guard_start(td, 120);
- if (td->panel_config->sleep.sleep_out)
- msleep(td->panel_config->sleep.sleep_out);
+ msleep(5);
return 0;
}
@@ -262,49 +200,6 @@ static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3)
return 0;
}
-static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror)
-{
- int r;
- u8 mode;
- int b5, b6, b7;
-
- r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode);
- if (r)
- return r;
-
- switch (rotate) {
- default:
- case 0:
- b7 = 0;
- b6 = 0;
- b5 = 0;
- break;
- case 1:
- b7 = 0;
- b6 = 1;
- b5 = 1;
- break;
- case 2:
- b7 = 1;
- b6 = 1;
- b5 = 0;
- break;
- case 3:
- b7 = 1;
- b6 = 0;
- b5 = 1;
- break;
- }
-
- if (mirror)
- b6 = !b6;
-
- mode &= ~((1<<7) | (1<<6) | (1<<5));
- mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
-
- return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode);
-}
-
static int taal_set_update_window(struct taal_data *td,
u16 x, u16 y, u16 w, u16 h)
{
@@ -515,15 +410,8 @@ static const struct backlight_ops taal_bl_ops = {
static void taal_get_resolution(struct omap_dss_device *dssdev,
u16 *xres, u16 *yres)
{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-
- if (td->rotate == 0 || td->rotate == 2) {
- *xres = dssdev->panel.timings.x_res;
- *yres = dssdev->panel.timings.y_res;
- } else {
- *yres = dssdev->panel.timings.x_res;
- *xres = dssdev->panel.timings.y_res;
- }
+ *xres = dssdev->panel.timings.x_res;
+ *yres = dssdev->panel.timings.y_res;
}
static ssize_t taal_num_errors_show(struct device *dev,
@@ -845,17 +733,14 @@ static void taal_hw_reset(struct omap_dss_device *dssdev)
return;
gpio_set_value(td->reset_gpio, 1);
- if (td->panel_config->reset_sequence.high)
- udelay(td->panel_config->reset_sequence.high);
+ udelay(10);
/* reset the panel */
gpio_set_value(td->reset_gpio, 0);
/* assert reset */
- if (td->panel_config->reset_sequence.low)
- udelay(td->panel_config->reset_sequence.low);
+ udelay(10);
gpio_set_value(td->reset_gpio, 1);
/* wait after releasing reset */
- if (td->panel_config->sleep.hw_reset)
- msleep(td->panel_config->sleep.hw_reset);
+ msleep(5);
}
static void taal_probe_pdata(struct taal_data *td,
@@ -881,8 +766,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
struct backlight_properties props;
struct taal_data *td;
struct backlight_device *bldev = NULL;
- int r, i;
- const char *panel_name;
+ int r;
dev_dbg(&dssdev->dev, "probe\n");
@@ -897,26 +781,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
const struct nokia_dsi_panel_data *pdata = dssdev->data;
taal_probe_pdata(td, pdata);
-
- panel_name = pdata->name;
} else {
return -ENODEV;
}
- if (panel_name == NULL)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
- if (strcmp(panel_name, panel_configs[i].name) == 0) {
- td->panel_config = &panel_configs[i];
- break;
- }
- }
-
- if (!td->panel_config)
- return -EINVAL;
-
- dssdev->panel.timings = td->panel_config->timings;
+ dssdev->panel.timings.x_res = 864;
+ dssdev->panel.timings.y_res = 480;
+ dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000);
dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888;
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
@@ -1049,6 +920,15 @@ static int taal_power_on(struct omap_dss_device *dssdev)
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
+ struct omap_dss_dsi_config dsi_config = {
+ .mode = OMAP_DSS_DSI_CMD_MODE,
+ .pixel_format = OMAP_DSS_DSI_FMT_RGB888,
+ .timings = &dssdev->panel.timings,
+ .hs_clk_min = 150000000,
+ .hs_clk_max = 300000000,
+ .lp_clk_min = 7000000,
+ .lp_clk_max = 10000000,
+ };
r = omapdss_dsi_configure_pins(dssdev, &td->pin_config);
if (r) {
@@ -1056,14 +936,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
goto err0;
};
- omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res,
- dssdev->panel.timings.y_res);
- omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
- omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
-
- r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
+ r = omapdss_dsi_set_config(dssdev, &dsi_config);
if (r) {
- dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
+ dev_err(&dssdev->dev, "failed to configure DSI\n");
goto err0;
}
@@ -1086,8 +961,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
goto err;
/* on early Taal revisions CABC is broken */
- if (td->panel_config->type == PANEL_TAAL &&
- (id2 == 0x00 || id2 == 0xff || id2 == 0x81))
+ if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
td->cabc_broken = true;
r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff);
@@ -1104,10 +978,6 @@ static int taal_power_on(struct omap_dss_device *dssdev)
if (r)
goto err;
- r = taal_set_addr_mode(td, td->rotate, td->mirror);
- if (r)
- goto err;
-
if (!td->cabc_broken) {
r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode);
if (r)
@@ -1129,8 +999,8 @@ static int taal_power_on(struct omap_dss_device *dssdev)
td->enabled = 1;
if (!td->intro_printed) {
- dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n",
- td->panel_config->name, id1, id2, id3);
+ dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n",
+ id1, id2, id3);
if (td->cabc_broken)
dev_info(&dssdev->dev,
"old Taal version, CABC disabled\n");
@@ -1311,8 +1181,8 @@ static int taal_update(struct omap_dss_device *dssdev,
/* XXX no need to send this every frame, but dsi break if not done */
r = taal_set_update_window(td, 0, 0,
- td->panel_config->timings.x_res,
- td->panel_config->timings.y_res);
+ dssdev->panel.timings.x_res,
+ dssdev->panel.timings.y_res);
if (r)
goto err;
@@ -1365,8 +1235,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
if (!gpio_is_valid(td->ext_te_gpio))
omapdss_dsi_enable_te(dssdev, enable);
- if (td->panel_config->sleep.enable_te)
- msleep(td->panel_config->sleep.enable_te);
+ /* possible panel bug */
+ msleep(100);
return r;
}
@@ -1419,112 +1289,6 @@ static int taal_get_te(struct omap_dss_device *dssdev)
return r;
}
-static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
-{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- u16 dw, dh;
- int r;
-
- dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
-
- mutex_lock(&td->lock);
-
- if (td->rotate == rotate)
- goto end;
-
- dsi_bus_lock(dssdev);
-
- if (td->enabled) {
- r = taal_wake_up(dssdev);
- if (r)
- goto err;
-
- r = taal_set_addr_mode(td, rotate, td->mirror);
- if (r)
- goto err;
- }
-
- if (rotate == 0 || rotate == 2) {
- dw = dssdev->panel.timings.x_res;
- dh = dssdev->panel.timings.y_res;
- } else {
- dw = dssdev->panel.timings.y_res;
- dh = dssdev->panel.timings.x_res;
- }
-
- omapdss_dsi_set_size(dssdev, dw, dh);
-
- td->rotate = rotate;
-
- dsi_bus_unlock(dssdev);
-end:
- mutex_unlock(&td->lock);
- return 0;
-err:
- dsi_bus_unlock(dssdev);
- mutex_unlock(&td->lock);
- return r;
-}
-
-static u8 taal_get_rotate(struct omap_dss_device *dssdev)
-{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- int r;
-
- mutex_lock(&td->lock);
- r = td->rotate;
- mutex_unlock(&td->lock);
-
- return r;
-}
-
-static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
-{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- int r;
-
- dev_dbg(&dssdev->dev, "mirror %d\n", enable);
-
- mutex_lock(&td->lock);
-
- if (td->mirror == enable)
- goto end;
-
- dsi_bus_lock(dssdev);
- if (td->enabled) {
- r = taal_wake_up(dssdev);
- if (r)
- goto err;
-
- r = taal_set_addr_mode(td, td->rotate, enable);
- if (r)
- goto err;
- }
-
- td->mirror = enable;
-
- dsi_bus_unlock(dssdev);
-end:
- mutex_unlock(&td->lock);
- return 0;
-err:
- dsi_bus_unlock(dssdev);
- mutex_unlock(&td->lock);
- return r;
-}
-
-static bool taal_get_mirror(struct omap_dss_device *dssdev)
-{
- struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- int r;
-
- mutex_lock(&td->lock);
- r = td->mirror;
- mutex_unlock(&td->lock);
-
- return r;
-}
-
static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
@@ -1758,10 +1522,6 @@ static struct omap_dss_driver taal_driver = {
.enable_te = taal_enable_te,
.get_te = taal_get_te,
- .set_rotate = taal_rotate,
- .get_rotate = taal_get_rotate,
- .set_mirror = taal_mirror,
- .get_mirror = taal_get_mirror,
.run_test = taal_run_test,
.memory_read = taal_memory_read,
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c
index 8281baafe1e..46039c4bf1e 100644
--- a/drivers/video/omap2/displays/panel-tfp410.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -24,7 +24,7 @@
#include <linux/gpio.h>
#include <drm/drm_edid.h>
-#include <video/omap-panel-tfp410.h>
+#include <video/omap-panel-data.h>
static const struct omap_video_timings tfp410_default_timings = {
.x_res = 640,
@@ -135,7 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev)
if (!adapter) {
dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n",
i2c_bus_num);
- return -EINVAL;
+ return -EPROBE_DEFER;
}
ddata->i2c_adapter = adapter;
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index 6b6643911d2..abf2bc4a18a 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
#define TPO_R02_MODE(x) ((x) & 7)
#define TPO_R02_MODE_800x480 7
@@ -63,6 +64,9 @@ struct tpo_td043_device {
u32 power_on_resume:1;
};
+/* used to pass spi_device from SPI to DSS portion of the driver */
+static struct tpo_td043_device *g_tpo_td043;
+
static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
{
struct spi_message m;
@@ -275,9 +279,14 @@ static const struct omap_video_timings tpo_td043_timings = {
.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
};
+static inline struct panel_tpo_td043_data
+*get_panel_data(const struct omap_dss_device *dssdev)
+{
+ return (struct panel_tpo_td043_data *) dssdev->data;
+}
+
static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
{
- int nreset_gpio = tpo_td043->nreset_gpio;
int r;
if (tpo_td043->powered_on)
@@ -290,8 +299,8 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
/* wait for panel to stabilize */
msleep(160);
- if (gpio_is_valid(nreset_gpio))
- gpio_set_value(nreset_gpio, 1);
+ if (gpio_is_valid(tpo_td043->nreset_gpio))
+ gpio_set_value(tpo_td043->nreset_gpio, 1);
tpo_td043_write(tpo_td043->spi, 2,
TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
@@ -308,16 +317,14 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043)
static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043)
{
- int nreset_gpio = tpo_td043->nreset_gpio;
-
if (!tpo_td043->powered_on)
return;
tpo_td043_write(tpo_td043->spi, 3,
TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
- if (gpio_is_valid(nreset_gpio))
- gpio_set_value(nreset_gpio, 0);
+ if (gpio_is_valid(tpo_td043->nreset_gpio))
+ gpio_set_value(tpo_td043->nreset_gpio, 0);
/* wait for at least 2 vsyncs before cutting off power */
msleep(50);
@@ -344,12 +351,6 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev)
if (r)
goto err0;
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err1;
- }
-
/*
* If we are resuming from system suspend, SPI clocks might not be
* enabled yet, so we'll program the LCD from SPI PM resume callback.
@@ -376,9 +377,6 @@ static void tpo_td043_disable_dss(struct omap_dss_device *dssdev)
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
omapdss_dpi_display_disable(dssdev);
if (!tpo_td043->spi_suspended)
@@ -403,8 +401,8 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
static int tpo_td043_probe(struct omap_dss_device *dssdev)
{
- struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
- int nreset_gpio = dssdev->reset_gpio;
+ struct tpo_td043_device *tpo_td043 = g_tpo_td043;
+ struct panel_tpo_td043_data *pdata = get_panel_data(dssdev);
int ret = 0;
dev_dbg(&dssdev->dev, "probe\n");
@@ -414,6 +412,11 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
return -ENODEV;
}
+ if (!pdata)
+ return -EINVAL;
+
+ tpo_td043->nreset_gpio = pdata->nreset_gpio;
+
dssdev->panel.timings = tpo_td043_timings;
dssdev->ctrl.pixel_size = 24;
@@ -427,9 +430,10 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
goto fail_regulator;
}
- if (gpio_is_valid(nreset_gpio)) {
- ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW,
- "lcd reset");
+ if (gpio_is_valid(tpo_td043->nreset_gpio)) {
+ ret = devm_gpio_request_one(&dssdev->dev,
+ tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd reset");
if (ret < 0) {
dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
goto fail_gpio_req;
@@ -440,6 +444,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
if (ret)
dev_warn(&dssdev->dev, "failed to create sysfs files\n");
+ dev_set_drvdata(&dssdev->dev, tpo_td043);
+
return 0;
fail_gpio_req:
@@ -452,14 +458,11 @@ fail_regulator:
static void tpo_td043_remove(struct omap_dss_device *dssdev)
{
struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
- int nreset_gpio = dssdev->reset_gpio;
dev_dbg(&dssdev->dev, "remove\n");
sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
regulator_put(tpo_td043->vcc_reg);
- if (gpio_is_valid(nreset_gpio))
- gpio_free(nreset_gpio);
}
static void tpo_td043_set_timings(struct omap_dss_device *dssdev,
@@ -505,6 +508,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
return -ENODEV;
}
+ if (g_tpo_td043 != NULL)
+ return -EBUSY;
+
spi->bits_per_word = 16;
spi->mode = SPI_MODE_0;
@@ -519,9 +525,8 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
return -ENOMEM;
tpo_td043->spi = spi;
- tpo_td043->nreset_gpio = dssdev->reset_gpio;
dev_set_drvdata(&spi->dev, tpo_td043);
- dev_set_drvdata(&dssdev->dev, tpo_td043);
+ g_tpo_td043 = tpo_td043;
omap_dss_register_driver(&tpo_td043_driver);
@@ -534,6 +539,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi)
omap_dss_unregister_driver(&tpo_td043_driver);
kfree(tpo_td043);
+ g_tpo_td043 = NULL;
return 0;
}
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index d446bdfc4c8..a4b356a9780 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man
static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
- struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq;
int r;
+ if (mgr->output == NULL)
+ return -ENODEV;
+
r = dispc_runtime_get();
if (r)
return r;
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
+ switch (mgr->output->id) {
+ case OMAP_DSS_OUTPUT_VENC:
irq = DISPC_IRQ_EVSYNC_ODD;
- else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
+ break;
+ case OMAP_DSS_OUTPUT_HDMI:
irq = DISPC_IRQ_EVSYNC_EVEN;
- else
+ break;
+ default:
irq = dispc_mgr_get_vsync_irq(mgr->id);
+ break;
+ }
r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index f8779d4750b..c9c2252e371 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -53,6 +53,8 @@ static char *def_disp_name;
module_param_named(def_disp, def_disp_name, charp, 0);
MODULE_PARM_DESC(def_disp, "default display name");
+static bool dss_initialized;
+
const char *omapdss_get_default_display_name(void)
{
return core.default_display_name;
@@ -66,6 +68,12 @@ enum omapdss_version omapdss_get_version(void)
}
EXPORT_SYMBOL(omapdss_get_version);
+bool omapdss_is_initialized(void)
+{
+ return dss_initialized;
+}
+EXPORT_SYMBOL(omapdss_is_initialized);
+
struct platform_device *dss_get_core_pdev(void)
{
return core.pdev;
@@ -181,10 +189,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
write, &dss_debug_fops);
- if (IS_ERR(d))
- return PTR_ERR(d);
-
- return 0;
+ return PTR_RET(d);
}
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
static inline int dss_initialize_debugfs(void)
@@ -606,6 +611,8 @@ static int __init omap_dss_init(void)
return r;
}
+ dss_initialized = true;
+
return 0;
}
@@ -636,7 +643,15 @@ static int __init omap_dss_init(void)
static int __init omap_dss_init2(void)
{
- return omap_dss_register_drivers();
+ int r;
+
+ r = omap_dss_register_drivers();
+ if (r)
+ return r;
+
+ dss_initialized = true;
+
+ return 0;
}
core_initcall(omap_dss_init);
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index 05ff2b91d9e..b33b0169bb3 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -69,6 +69,8 @@ struct dispc_features {
u8 mgr_height_start;
u16 mgr_width_max;
u16 mgr_height_max;
+ unsigned long max_lcd_pclk;
+ unsigned long max_tv_pclk;
int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
@@ -85,6 +87,9 @@ struct dispc_features {
/* no DISPC_IRQ_FRAMEDONETV on this SoC */
bool no_framedone_tv:1;
+
+ /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
+ bool mstandby_workaround:1;
};
#define DISPC_MAX_NR_FIFOS 5
@@ -97,6 +102,8 @@ static struct {
int irq;
+ unsigned long core_clk_rate;
+
u32 fifo_size[DISPC_MAX_NR_FIFOS];
/* maps which plane is using a fifo. fifo-id -> plane-id */
int fifo_assignment[DISPC_MAX_NR_FIFOS];
@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane,
}
static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
+ enum omap_dss_rotation_type rotation_type,
bool mirroring, enum omap_color_mode color_mode)
{
bool row_repeat = false;
@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
if (dss_has_feature(FEAT_ROWREPEATENABLE))
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
row_repeat ? 1 : 0, 18, 18);
+
+ if (color_mode == OMAP_DSS_COLOR_NV12) {
+ bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
+ (rotation == OMAP_DSS_ROT_0 ||
+ rotation == OMAP_DSS_ROT_180);
+ /* DOUBLESTRIDE */
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
+ }
+
}
static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
dispc_ovl_set_vid_color_conv(plane, cconv);
}
- dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode);
+ dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
+ color_mode);
dispc_ovl_set_zorder(plane, caps, zorder);
dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
return true;
}
+static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
+ unsigned long pclk)
+{
+ if (dss_mgr_is_lcd(channel))
+ return pclk <= dispc.feat->max_lcd_pclk ? true : false;
+ else
+ return pclk <= dispc.feat->max_tv_pclk ? true : false;
+}
+
bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings)
{
@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
- if (dss_mgr_is_lcd(channel))
- timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
- timings->hfp, timings->hbp,
- timings->vsw, timings->vfp,
- timings->vbp);
+ timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000);
+
+ if (dss_mgr_is_lcd(channel)) {
+ timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
+ timings->hbp, timings->vsw, timings->vfp,
+ timings->vbp);
+ }
return timings_ok;
}
@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
dispc_write_reg(DISPC_DIVISORo(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
+
+ if (dss_has_feature(FEAT_CORE_CLK_DIV) == false &&
+ channel == OMAP_DSS_CHANNEL_LCD)
+ dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
}
static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
unsigned long dispc_core_clk_rate(void)
{
- int lcd;
- unsigned long fclk = dispc_fclk_rate();
-
- if (dss_has_feature(FEAT_CORE_CLK_DIV))
- lcd = REG_GET(DISPC_DIVISOR, 23, 16);
- else
- lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16);
-
- return fclk / lcd;
+ return dispc.core_clk_rate;
}
static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG
}
-/* with fck as input clock rate, find dispc dividers that produce req_pck */
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
+/* calculate clock rates using dividers in cinfo */
+int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo)
{
- u16 pcd_min, pcd_max;
- unsigned long best_pck;
- u16 best_ld, cur_ld;
- u16 best_pd, cur_pd;
+ if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
+ return -EINVAL;
+ if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
+ return -EINVAL;
- pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
- pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
+ cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
+ cinfo->pck = cinfo->lck / cinfo->pck_div;
- best_pck = 0;
- best_ld = 0;
- best_pd = 0;
+ return 0;
+}
- for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
- unsigned long lck = fck / cur_ld;
+bool dispc_div_calc(unsigned long dispc,
+ unsigned long pck_min, unsigned long pck_max,
+ dispc_div_calc_func func, void *data)
+{
+ int lckd, lckd_start, lckd_stop;
+ int pckd, pckd_start, pckd_stop;
+ unsigned long pck, lck;
+ unsigned long lck_max;
+ unsigned long pckd_hw_min, pckd_hw_max;
+ unsigned min_fck_per_pck;
+ unsigned long fck;
- for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
- unsigned long pck = lck / cur_pd;
- long old_delta = abs(best_pck - req_pck);
- long new_delta = abs(pck - req_pck);
+#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
+ min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
+#else
+ min_fck_per_pck = 0;
+#endif
- if (best_pck == 0 || new_delta < old_delta) {
- best_pck = pck;
- best_ld = cur_ld;
- best_pd = cur_pd;
+ pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
+ pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
- if (pck == req_pck)
- goto found;
- }
+ lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
- if (pck < req_pck)
- break;
- }
+ pck_min = pck_min ? pck_min : 1;
+ pck_max = pck_max ? pck_max : ULONG_MAX;
- if (lck / pcd_min < req_pck)
- break;
- }
+ lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
+ lckd_stop = min(dispc / pck_min, 255ul);
-found:
- cinfo->lck_div = best_ld;
- cinfo->pck_div = best_pd;
- cinfo->lck = fck / cinfo->lck_div;
- cinfo->pck = cinfo->lck / cinfo->pck_div;
-}
+ for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
+ lck = dispc / lckd;
-/* calculate clock rates using dividers in cinfo */
-int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
- struct dispc_clock_info *cinfo)
-{
- if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
- return -EINVAL;
- if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
- return -EINVAL;
+ pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
+ pckd_stop = min(lck / pck_min, pckd_hw_max);
- cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
- cinfo->pck = cinfo->lck / cinfo->pck_div;
+ for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
+ pck = lck / pckd;
- return 0;
+ /*
+ * For OMAP2/3 the DISPC fclk is the same as LCD's logic
+ * clock, which means we're configuring DISPC fclk here
+ * also. Thus we need to use the calculated lck. For
+ * OMAP4+ the DISPC fclk is a separate clock.
+ */
+ if (dss_has_feature(FEAT_CORE_CLK_DIV))
+ fck = dispc_core_clk_rate();
+ else
+ fck = lck;
+
+ if (fck < pck * min_fck_per_pck)
+ continue;
+
+ if (func(lckd, pckd, lck, pck, data))
+ return true;
+ }
+ }
+
+ return false;
}
void dispc_mgr_set_clock_div(enum omap_channel channel,
@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void)
l = FLD_MOD(l, 1, 0, 0);
l = FLD_MOD(l, 1, 23, 16);
dispc_write_reg(DISPC_DIVISOR, l);
+
+ dispc.core_clk_rate = dispc_fclk_rate();
}
/* FUNCGATED */
@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void)
dispc_configure_burst_sizes();
dispc_ovl_enable_zorder_planes();
+
+ if (dispc.feat->mstandby_workaround)
+ REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
}
static const struct dispc_features omap24xx_dispc_feats __initconst = {
@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = {
.mgr_height_start = 26,
.mgr_width_max = 2048,
.mgr_height_max = 2048,
+ .max_lcd_pclk = 66500000,
.calc_scaling = dispc_ovl_calc_scaling_24xx,
.calc_core_clk = calc_core_clk_24xx,
.num_fifos = 3,
@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
.mgr_height_start = 26,
.mgr_width_max = 2048,
.mgr_height_max = 2048,
+ .max_lcd_pclk = 173000000,
+ .max_tv_pclk = 59000000,
.calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3,
@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
.mgr_height_start = 26,
.mgr_width_max = 2048,
.mgr_height_max = 2048,
+ .max_lcd_pclk = 173000000,
+ .max_tv_pclk = 59000000,
.calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3,
@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = {
.mgr_height_start = 26,
.mgr_width_max = 2048,
.mgr_height_max = 2048,
+ .max_lcd_pclk = 170000000,
+ .max_tv_pclk = 185625000,
.calc_scaling = dispc_ovl_calc_scaling_44xx,
.calc_core_clk = calc_core_clk_44xx,
.num_fifos = 5,
@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = {
.mgr_height_start = 27,
.mgr_width_max = 4096,
.mgr_height_max = 4096,
+ .max_lcd_pclk = 170000000,
+ .max_tv_pclk = 186000000,
.calc_scaling = dispc_ovl_calc_scaling_44xx,
.calc_core_clk = calc_core_clk_44xx,
.num_fifos = 5,
.gfx_fifo_workaround = true,
+ .mstandby_workaround = true,
};
static int __init dispc_init_features(struct platform_device *pdev)
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index 222363c6e62..de4863d21ab 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -39,6 +39,7 @@
#define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C
+#define DISPC_MSTANDBY_CTRL 0x0858
/* DISPC overlay registers */
#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 4af136a04e5..757b57f7275 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -63,15 +63,29 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
return NULL;
- default:
- break;
- }
- switch (channel) {
- case OMAP_DSS_CHANNEL_LCD:
- return dsi_get_dsidev_from_id(0);
- case OMAP_DSS_CHANNEL_LCD2:
- return dsi_get_dsidev_from_id(1);
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return dsi_get_dsidev_from_id(0);
+ case OMAP_DSS_CHANNEL_LCD2:
+ return dsi_get_dsidev_from_id(1);
+ default:
+ return NULL;
+ }
+
+ case OMAPDSS_VER_OMAP5:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ return dsi_get_dsidev_from_id(0);
+ case OMAP_DSS_CHANNEL_LCD3:
+ return dsi_get_dsidev_from_id(1);
+ default:
+ return NULL;
+ }
+
default:
return NULL;
}
@@ -91,75 +105,211 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
}
}
-static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
+struct dpi_clk_calc_ctx {
+ struct platform_device *dsidev;
+
+ /* inputs */
+
+ unsigned long pck_min, pck_max;
+
+ /* outputs */
+
+ struct dsi_clock_info dsi_cinfo;
+ struct dss_clock_info dss_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (ctx->pck_min >= 1000000) {
+ if (lckd > 1 && lckd % 2 != 0)
+ return false;
+
+ if (pckd > 1 && pckd % 2 != 0)
+ return false;
+ }
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+
+static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ /*
+ * Odd dividers give us uneven duty cycle, causing problem when level
+ * shifted. So skip all odd dividers when the pixel clock is on the
+ * higher side.
+ */
+ if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
+ return false;
+
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+ return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+
+static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll,
+ void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
+ dpi_calc_hsdiv_cb, ctx);
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+ struct dpi_clk_calc_ctx *ctx = data;
+
+ ctx->dss_cinfo.fck = fck;
+ ctx->dss_cinfo.fck_div = fckd;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+ unsigned long clkin;
+ unsigned long pll_min, pll_max;
+
+ clkin = dsi_get_pll_clkin(dpi.dsidev);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dpi.dsidev;
+ ctx->pck_min = pck - 1000;
+ ctx->pck_max = pck + 1000;
+ ctx->dsi_cinfo.clkin = clkin;
+
+ pll_min = 0;
+ pll_max = 0;
+
+ return dsi_pll_calc(dpi.dsidev, clkin,
+ pll_min, pll_max,
+ dpi_calc_pll_cb, ctx);
+}
+
+static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+{
+ int i;
+
+ /*
+ * DSS fck gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- ~15MHz.
+ */
+
+ for (i = 0; i < 25; ++i) {
+ bool ok;
+
+ memset(ctx, 0, sizeof(*ctx));
+ if (pck > 1000 * i * i * i)
+ ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
+ else
+ ctx->pck_min = 0;
+ ctx->pck_max = pck + 1000 * i * i * i;
+
+ ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx);
+ if (ok)
+ return ok;
+ }
+
+ return false;
+}
+
+
+
+static int dpi_set_dsi_clk(enum omap_channel channel,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
- struct omap_overlay_manager *mgr = dssdev->output->manager;
- struct dsi_clock_info dsi_cinfo;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
int r;
+ bool ok;
- r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
- &dispc_cinfo);
- if (r)
- return r;
+ ok = dpi_dsi_clk_calc(pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
- r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
+ r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
if (r)
return r;
- dss_select_lcd_clk_source(mgr->id,
- dpi_get_alt_clk_src(mgr->id));
+ dss_select_lcd_clk_source(channel,
+ dpi_get_alt_clk_src(channel));
- dpi.mgr_config.clock_info = dispc_cinfo;
+ dpi.mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
- *lck_div = dispc_cinfo.lck_div;
- *pck_div = dispc_cinfo.pck_div;
+ *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
-static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
- unsigned long pck_req, unsigned long *fck, int *lck_div,
- int *pck_div)
+static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
+ int *lck_div, int *pck_div)
{
- struct dss_clock_info dss_cinfo;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
int r;
+ bool ok;
- r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
- if (r)
- return r;
+ ok = dpi_dss_clk_calc(pck_req, &ctx);
+ if (!ok)
+ return -EINVAL;
- r = dss_set_clock_div(&dss_cinfo);
+ r = dss_set_clock_div(&ctx.dss_cinfo);
if (r)
return r;
- dpi.mgr_config.clock_info = dispc_cinfo;
+ dpi.mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = dss_cinfo.fck;
- *lck_div = dispc_cinfo.lck_div;
- *pck_div = dispc_cinfo.pck_div;
+ *fck = ctx.dss_cinfo.fck;
+ *lck_div = ctx.dispc_cinfo.lck_div;
+ *pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
-static int dpi_set_mode(struct omap_dss_device *dssdev)
+static int dpi_set_mode(struct omap_overlay_manager *mgr)
{
struct omap_video_timings *t = &dpi.timings;
- struct omap_overlay_manager *mgr = dssdev->output->manager;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
int r = 0;
if (dpi.dsidev)
- r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
+ r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck,
&lck_div, &pck_div);
else
- r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
+ r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck,
&lck_div, &pck_div);
if (r)
return r;
@@ -179,10 +329,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
return 0;
}
-static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
+static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
{
- struct omap_overlay_manager *mgr = dssdev->output->manager;
-
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.stallmode = false;
@@ -197,7 +345,7 @@ static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_output *out = dssdev->output;
+ struct omap_dss_output *out = &dpi.output;
int r;
mutex_lock(&dpi.lock);
@@ -230,7 +378,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
- r = dss_dpi_select_source(dssdev->channel);
+ r = dss_dpi_select_source(out->manager->id);
if (r)
goto err_src_sel;
@@ -244,11 +392,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err_dsi_pll_init;
}
- r = dpi_set_mode(dssdev);
+ r = dpi_set_mode(out->manager);
if (r)
goto err_set_mode;
- dpi_config_lcd_manager(dssdev);
+ dpi_config_lcd_manager(out->manager);
mdelay(2);
@@ -285,7 +433,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = dpi.output.manager;
mutex_lock(&dpi.lock);
@@ -324,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings);
int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- int r;
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = dpi.output.manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
- struct dispc_clock_info dispc_cinfo;
+ struct dpi_clk_calc_ctx ctx;
+ bool ok;
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
return -EINVAL;
@@ -338,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
return -EINVAL;
if (dpi.dsidev) {
- struct dsi_clock_info dsi_cinfo;
- r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
- timings->pixel_clock * 1000,
- &dsi_cinfo, &dispc_cinfo);
+ ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx);
+ if (!ok)
+ return -EINVAL;
- if (r)
- return r;
-
- fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
} else {
- struct dss_clock_info dss_cinfo;
- r = dss_calc_clock_div(timings->pixel_clock * 1000,
- &dss_cinfo, &dispc_cinfo);
+ ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx);
+ if (!ok)
+ return -EINVAL;
- if (r)
- return r;
-
- fck = dss_cinfo.fck;
+ fck = ctx.dss_cinfo.fck;
}
- lck_div = dispc_cinfo.lck_div;
- pck_div = dispc_cinfo.pck_div;
+ lck_div = ctx.dispc_cinfo.lck_div;
+ pck_div = ctx.dispc_cinfo.pck_div;
pck = fck / lck_div / pck_div / 1000;
@@ -379,7 +520,7 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
}
EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
-static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
+static int dpi_verify_dsi_pll(struct platform_device *dsidev)
{
int r;
@@ -401,7 +542,37 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev)
return 0;
}
-static int __init dpi_init_display(struct omap_dss_device *dssdev)
+/*
+ * Return a hardcoded channel for the DPI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dpi_get_channel(void)
+{
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ return OMAP_DSS_CHANNEL_LCD2;
+
+ case OMAPDSS_VER_OMAP5:
+ return OMAP_DSS_CHANNEL_LCD3;
+
+ default:
+ DSSWARN("unsupported DSS version\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+}
+
+static int dpi_init_display(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev;
@@ -421,12 +592,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
dpi.vdds_dsi_reg = vdds_dsi;
}
- /*
- * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
- * source for DPI is SoC integration detail, not something that should
- * be configured in the dssdev
- */
- dsidev = dpi_get_dsidev(dssdev->channel);
+ dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
if (dsidev && dpi_verify_dsi_pll(dsidev)) {
dsidev = NULL;
@@ -441,7 +607,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = omapdss_get_default_display_name();
@@ -469,7 +635,7 @@ static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *p
return def_dssdev;
}
-static void __init dpi_probe_pdata(struct platform_device *dpidev)
+static int dpi_probe_pdata(struct platform_device *dpidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
@@ -478,11 +644,11 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev)
plat_dssdev = dpi_find_dssdev(dpidev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&dpidev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
@@ -490,7 +656,7 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev)
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&dpi.output, dssdev);
@@ -498,7 +664,7 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -506,17 +672,21 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev)
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&dpi.output);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init dpi_init_output(struct platform_device *pdev)
+static void dpi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &dpi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->type = OMAP_DISPLAY_TYPE_DPI;
+ out->name = "dpi.0";
+ out->dispc_channel = dpi_get_channel();
dss_register_output(out);
}
@@ -528,13 +698,19 @@ static void __exit dpi_uninit_output(struct platform_device *pdev)
dss_unregister_output(out);
}
-static int __init omap_dpi_probe(struct platform_device *pdev)
+static int omap_dpi_probe(struct platform_device *pdev)
{
+ int r;
+
mutex_init(&dpi.lock);
dpi_init_output(pdev);
- dpi_probe_pdata(pdev);
+ r = dpi_probe_pdata(pdev);
+ if (r) {
+ dpi_uninit_output(pdev);
+ return r;
+ }
return 0;
}
@@ -549,6 +725,7 @@ static int __exit omap_dpi_remove(struct platform_device *pdev)
}
static struct platform_driver omap_dpi_driver = {
+ .probe = omap_dpi_probe,
.remove = __exit_p(omap_dpi_remove),
.driver = {
.name = "omapdss_dpi",
@@ -558,7 +735,7 @@ static struct platform_driver omap_dpi_driver = {
int __init dpi_init_platform_driver(void)
{
- return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe);
+ return platform_driver_register(&omap_dpi_driver);
}
void __exit dpi_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 28d41d16b7b..a73dedc3310 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -200,6 +200,11 @@ struct dsi_reg { u16 idx; };
typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr);
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr);
+
#define DSI_MAX_NR_ISRS 2
#define DSI_MAX_NR_LANES 5
@@ -250,6 +255,24 @@ struct dsi_isr_tables {
struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
};
+struct dsi_clk_calc_ctx {
+ struct platform_device *dsidev;
+
+ /* inputs */
+
+ const struct omap_dss_dsi_config *config;
+
+ unsigned long req_pck_min, req_pck_nom, req_pck_max;
+
+ /* outputs */
+
+ struct dsi_clock_info dsi_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+
+ struct omap_video_timings dispc_vm;
+ struct omap_dss_dsi_videomode_timings dsi_vm;
+};
+
struct dsi_data {
struct platform_device *pdev;
void __iomem *base;
@@ -261,6 +284,9 @@ struct dsi_data {
struct clk *dss_clk;
struct clk *sys_clk;
+ struct dispc_clock_info user_dispc_cinfo;
+ struct dsi_clock_info user_dsi_cinfo;
+
struct dsi_clock_info current_cinfo;
bool vdds_dsi_enabled;
@@ -324,6 +350,7 @@ struct dsi_data {
unsigned long lpdiv_max;
unsigned num_lanes_supported;
+ unsigned line_buffer_size;
struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
unsigned num_lanes_used;
@@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
return r;
}
-static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
+static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
+ unsigned long lp_clk_min, unsigned long lp_clk_max)
+{
+ unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
+ unsigned lp_clk_div;
+ unsigned long lp_clk;
+
+ lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
+ lp_clk = dsi_fclk / 2 / lp_clk_div;
+
+ if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
+ return -EINVAL;
+
+ cinfo->lp_clk_div = lp_clk_div;
+ cinfo->lp_clk = lp_clk;
+
+ return 0;
+}
+
+static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
unsigned long dsi_fclk;
unsigned lp_clk_div;
unsigned long lp_clk;
- lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
+ lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
return -EINVAL;
@@ -1272,6 +1317,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
return 0;
}
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ return clk_get_rate(dsi->sys_clk);
+}
+
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+ unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int regm, regm_start, regm_stop;
+ unsigned long out_max;
+ unsigned long out;
+
+ out_min = out_min ? out_min : 1;
+ out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+
+ regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
+ regm_stop = min(pll / out_min, dsi->regm_dispc_max);
+
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
+ out = pll / regm;
+
+ if (func(regm, out, data))
+ return true;
+ }
+
+ return false;
+}
+
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dsi_pll_calc_func func, void *data)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int regn, regn_start, regn_stop;
+ int regm, regm_start, regm_stop;
+ unsigned long fint, pll;
+ const unsigned long pll_hw_max = 1800000000;
+ unsigned long fint_hw_min, fint_hw_max;
+
+ fint_hw_min = dsi->fint_min;
+ fint_hw_max = dsi->fint_max;
+
+ regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+ regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
+
+ pll_max = pll_max ? pll_max : ULONG_MAX;
+
+ for (regn = regn_start; regn <= regn_stop; ++regn) {
+ fint = clkin / regn;
+
+ regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+ 1ul);
+ regm_stop = min3(pll_max / fint / 2,
+ pll_hw_max / fint / 2,
+ dsi->regm_max);
+
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
+ pll = 2 * regm * fint;
+
+ if (func(regn, regm, fint, pll, data))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* calculate clock rates using dividers in cinfo */
static int dsi_calc_clock_rates(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
@@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,
return 0;
}
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cur, best;
- struct dispc_clock_info best_dispc;
- int min_fck_per_pck;
- int match = 0;
- unsigned long dss_sys_clk, max_dss_fck;
-
- dss_sys_clk = clk_get_rate(dsi->sys_clk);
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- if (req_pck == dsi->cache_req_pck &&
- dsi->cache_cinfo.clkin == dss_sys_clk) {
- DSSDBG("DSI clock info found from cache\n");
- *dsi_cinfo = dsi->cache_cinfo;
- dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk,
- dispc_cinfo);
- return 0;
- }
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
- DSSDBG("dsi_pll_calc\n");
-
-retry:
- memset(&best, 0, sizeof(best));
- memset(&best_dispc, 0, sizeof(best_dispc));
-
- memset(&cur, 0, sizeof(cur));
- cur.clkin = dss_sys_clk;
-
- /* 0.75MHz < Fint = clkin / regn < 2.1MHz */
- /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
- for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
- cur.fint = cur.clkin / cur.regn;
-
- if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
- continue;
-
- /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
- for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
- unsigned long a, b;
-
- a = 2 * cur.regm * (cur.clkin/1000);
- b = cur.regn;
- cur.clkin4ddr = a / b * 1000;
-
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
- break;
-
- /* dsi_pll_hsdiv_dispc_clk(MHz) =
- * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
- for (cur.regm_dispc = 1; cur.regm_dispc <
- dsi->regm_dispc_max; ++cur.regm_dispc) {
- struct dispc_clock_info cur_dispc;
- cur.dsi_pll_hsdiv_dispc_clk =
- cur.clkin4ddr / cur.regm_dispc;
-
- if (cur.regm_dispc > 1 &&
- cur.regm_dispc % 2 != 0 &&
- req_pck >= 1000000)
- continue;
-
- /* this will narrow down the search a bit,
- * but still give pixclocks below what was
- * requested */
- if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
- break;
-
- if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
- continue;
-
- if (min_fck_per_pck &&
- cur.dsi_pll_hsdiv_dispc_clk <
- req_pck * min_fck_per_pck)
- continue;
-
- match = 1;
-
- dispc_find_clk_divs(req_pck,
- cur.dsi_pll_hsdiv_dispc_clk,
- &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
- best = cur;
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck == req_pck)
- goto found;
- }
- }
- }
- }
-found:
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-
- /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
- best.regm_dsi = 0;
- best.dsi_pll_hsdiv_dsi_clk = 0;
-
- if (dsi_cinfo)
- *dsi_cinfo = best;
- if (dispc_cinfo)
- *dispc_cinfo = best_dispc;
-
- dsi->cache_req_pck = req_pck;
- dsi->cache_clk_freq = 0;
- dsi->cache_cinfo = best;
-
- return 0;
-}
-
-static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
- unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cur, best;
-
- DSSDBG("dsi_pll_calc_ddrfreq\n");
-
- memset(&best, 0, sizeof(best));
- memset(&cur, 0, sizeof(cur));
-
- cur.clkin = clk_get_rate(dsi->sys_clk);
-
- for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
- cur.fint = cur.clkin / cur.regn;
-
- if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
- continue;
-
- /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
- for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
- unsigned long a, b;
-
- a = 2 * cur.regm * (cur.clkin/1000);
- b = cur.regn;
- cur.clkin4ddr = a / b * 1000;
-
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
- break;
-
- if (abs(cur.clkin4ddr - req_clkin4ddr) <
- abs(best.clkin4ddr - req_clkin4ddr)) {
- best = cur;
- DSSDBG("best %ld\n", best.clkin4ddr);
- }
-
- if (cur.clkin4ddr == req_clkin4ddr)
- goto found;
- }
- }
-found:
- if (cinfo)
- *cinfo = best;
-
- return 0;
-}
-
-static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo)
+static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
{
unsigned long max_dsi_fck;
@@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
}
-static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- unsigned regm_dispc, best_regm_dispc;
- unsigned long dispc_clk, best_dispc_clk;
- int min_fck_per_pck;
- unsigned long max_dss_fck;
- struct dispc_clock_info best_dispc;
- bool match;
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
-retry:
- best_regm_dispc = 0;
- best_dispc_clk = 0;
- memset(&best_dispc, 0, sizeof(best_dispc));
- match = false;
-
- for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
- struct dispc_clock_info cur_dispc;
-
- dispc_clk = cinfo->clkin4ddr / regm_dispc;
-
- /* this will narrow down the search a bit,
- * but still give pixclocks below what was
- * requested */
- if (dispc_clk < req_pck)
- break;
-
- if (dispc_clk > max_dss_fck)
- continue;
-
- if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
- continue;
-
- match = true;
-
- dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
- best_regm_dispc = regm_dispc;
- best_dispc_clk = dispc_clk;
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck == req_pck)
- goto found;
- }
- }
-
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-found:
- cinfo->regm_dispc = best_regm_dispc;
- cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
-
- *dispc_cinfo = best_dispc;
-
- return 0;
-}
-
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
{
@@ -2783,6 +2628,7 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel,
static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 r;
DSSDBG("Initial config of virtual channel %d", channel);
@@ -2807,6 +2653,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
+
+ dsi->vc[channel].source = DSI_VC_SOURCE_L4;
}
static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
@@ -3777,13 +3625,12 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
- unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
struct omap_video_timings *timings = &dsi->timings;
/*
* Don't use line buffers if width is greater than the video
* port's line buffer size
*/
- if (line_buf_size <= timings->x_res * bpp / 8)
+ if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
num_line_buffers = 0;
else
num_line_buffers = 2;
@@ -3799,18 +3646,22 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
static void dsi_config_vp_sync_events(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- bool vsync_end = dsi->vm_timings.vp_vsync_end;
- bool hsync_end = dsi->vm_timings.vp_hsync_end;
+ bool sync_end;
u32 r;
+ if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
+ sync_end = true;
+ else
+ sync_end = false;
+
r = dsi_read_reg(dsidev, DSI_CTRL);
r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
- r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */
+ r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */
r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
- r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */
+ r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */
dsi_write_reg(dsidev, DSI_CTRL, r);
}
@@ -3897,9 +3748,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
return max(lp_inter, 0);
}
-static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
+static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int blanking_mode;
int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
@@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
struct omap_video_timings *timings = &dsi->timings;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int ndl = dsi->num_lanes_used - 1;
- int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
+ int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1;
int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
@@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
}
-static int dsi_proto_config(struct omap_dss_device *dssdev)
+static int dsi_proto_config(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 r;
int buswidth = 0;
@@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_config_vp_sync_events(dsidev);
dsi_config_blanking_modes(dsidev);
- dsi_config_cmd_mode_interleaving(dssdev);
+ dsi_config_cmd_mode_interleaving(dsidev);
}
dsi_vc_initial_config(dsidev, 0);
@@ -4159,11 +4008,12 @@ static void dsi_proto_timings(struct platform_device *dsidev)
int vfp = dsi->vm_timings.vfp;
int vbp = dsi->vm_timings.vbp;
int window_sync = dsi->vm_timings.window_sync;
- bool hsync_end = dsi->vm_timings.vp_hsync_end;
+ bool hsync_end;
struct omap_video_timings *timings = &dsi->timings;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int tl, t_he, width_bytes;
+ hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
t_he = hsync_end ?
((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
@@ -4266,82 +4116,26 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_dsi_configure_pins);
-int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
- unsigned long ddr_clk, unsigned long lp_clk)
-{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cinfo;
- struct dispc_clock_info dispc_cinfo;
- unsigned lp_clk_div;
- unsigned long dsi_fclk;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
- unsigned long pck;
- int r;
-
- DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
-
- mutex_lock(&dsi->lock);
-
- /* Calculate PLL output clock */
- r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
- if (r)
- goto err;
-
- /* Calculate PLL's DSI clock */
- dsi_pll_calc_dsi_fck(dsidev, &cinfo);
-
- /* Calculate PLL's DISPC clock and pck & lck divs */
- pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
- DSSDBG("finding dispc dividers for pck %lu\n", pck);
- r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
- if (r)
- goto err;
-
- /* Calculate LP clock */
- dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
- lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
-
- dssdev->clocks.dsi.regn = cinfo.regn;
- dssdev->clocks.dsi.regm = cinfo.regm;
- dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
- dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
-
- dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
-
- dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
- dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
-
- dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
-
- dssdev->clocks.dispc.channel.lcd_clk_src =
- dsi->module_id == 0 ?
- OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
- OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
-
- dssdev->clocks.dsi.dsi_fclk_src =
- dsi->module_id == 0 ?
- OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
- OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI;
-
- mutex_unlock(&dsi->lock);
- return 0;
-err:
- mutex_unlock(&dsi->lock);
- return r;
-}
-EXPORT_SYMBOL(omapdss_dsi_set_clocks);
-
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = dsi->output.manager;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
+ struct omap_dss_output *out = &dsi->output;
u8 data_type;
u16 word_count;
int r;
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ return -ENODEV;
+ }
+
+ r = dsi_display_init_dispc(dsidev, mgr);
+ if (r)
+ goto err_init_dispc;
+
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
switch (dsi->pix_fmt) {
case OMAP_DSS_DSI_FMT_RGB888:
@@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
break;
default:
- BUG();
- return -EINVAL;
+ r = -EINVAL;
+ goto err_pix_fmt;
};
dsi_if_enable(dsidev, false);
@@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
}
r = dss_mgr_enable(mgr);
- if (r) {
- if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
- dsi_if_enable(dsidev, false);
- dsi_vc_enable(dsidev, channel, false);
- }
-
- return r;
- }
+ if (r)
+ goto err_mgr_enable;
return 0;
+
+err_mgr_enable:
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ dsi_if_enable(dsidev, false);
+ dsi_vc_enable(dsidev, channel, false);
+ }
+err_pix_fmt:
+ dsi_display_uninit_dispc(dsidev, mgr);
+err_init_dispc:
+ return r;
}
EXPORT_SYMBOL(dsi_enable_video_output);
@@ -4394,7 +4192,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = dsi->output.manager;
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_if_enable(dsidev, false);
@@ -4408,14 +4206,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
}
dss_mgr_disable(mgr);
+
+ dsi_display_uninit_dispc(dsidev, mgr);
}
EXPORT_SYMBOL(dsi_disable_video_output);
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
+static void dsi_update_screen_dispc(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
+ struct omap_overlay_manager *mgr = dsi->output.manager;
unsigned bytespp;
unsigned bytespl;
unsigned bytespf;
@@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
u32 l;
int r;
const unsigned channel = dsi->update_channel;
- const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+ const unsigned line_buf_size = dsi->line_buffer_size;
u16 w = dsi->timings.x_res;
u16 h = dsi->timings.y_res;
@@ -4571,7 +4370,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
dsi->update_bytes = dw * dh *
dsi_get_pixel_size(dsi->pix_fmt) / 8;
#endif
- dsi_update_screen_dispc(dssdev);
+ dsi_update_screen_dispc(dsidev);
return 0;
}
@@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update);
/* Display funcs */
-static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct dispc_clock_info dispc_cinfo;
int r;
- unsigned long long fck;
+ unsigned long fck;
fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
- dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
- dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
+ dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
+ dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
r = dispc_calc_clock_rates(fck, &dispc_cinfo);
if (r) {
@@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
return 0;
}
-static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
+static int dsi_display_init_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
- if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
- dsi->timings.hsw = 1;
- dsi->timings.hfp = 1;
- dsi->timings.hbp = 1;
- dsi->timings.vsw = 1;
- dsi->timings.vfp = 0;
- dsi->timings.vbp = 0;
+ dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
r = dss_mgr_register_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
if (r) {
@@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dss_mgr_set_timings(mgr, &dsi->timings);
- r = dsi_configure_dispc_clocks(dssdev);
+ r = dsi_configure_dispc_clocks(dsidev);
if (r)
goto err1;
@@ -4662,30 +4456,30 @@ err1:
dss_mgr_unregister_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
err:
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
return r;
}
-static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
+ struct omap_overlay_manager *mgr)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
dss_mgr_unregister_framedone_handler(mgr,
dsi_framedone_irq_callback, dsidev);
+
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
}
-static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
+static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct dsi_clock_info cinfo;
int r;
- cinfo.regn = dssdev->clocks.dsi.regn;
- cinfo.regm = dssdev->clocks.dsi.regm;
- cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
- cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
+ cinfo = dsi->user_dsi_cinfo;
+
r = dsi_calc_clock_rates(dsidev, &cinfo);
if (r) {
DSSERR("Failed to calc dsi clocks\n");
@@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
return 0;
}
-static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
+static int dsi_display_init_dsi(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
r = dsi_pll_init(dsidev, true, true);
if (r)
goto err0;
- r = dsi_configure_dsi_clocks(dssdev);
+ r = dsi_configure_dsi_clocks(dsidev);
if (r)
goto err1;
- dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
- dss_select_lcd_clk_source(mgr->id,
- dssdev->clocks.dispc.channel.lcd_clk_src);
+ dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
DSSDBG("PLL OK\n");
@@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
_dsi_print_reset_status(dsidev);
dsi_proto_timings(dsidev);
- dsi_set_lp_clk_divisor(dssdev);
+ dsi_set_lp_clk_divisor(dsidev);
if (1)
_dsi_print_reset_status(dsidev);
- r = dsi_proto_config(dssdev);
+ r = dsi_proto_config(dsidev);
if (r)
goto err3;
@@ -4751,20 +4543,16 @@ err3:
dsi_cio_uninit(dsidev);
err2:
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
-
err1:
dsi_pll_uninit(dsidev, true);
err0:
return r;
}
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
+static void dsi_display_uninit_dsi(struct platform_device *dsidev,
bool disconnect_lanes, bool enter_ulps)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_overlay_manager *mgr = dssdev->output->manager;
if (enter_ulps && !dsi->ulps_enabled)
dsi_enter_ulps(dsidev);
@@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dsi_vc_enable(dsidev, 3, 0);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_cio_uninit(dsidev);
dsi_pll_uninit(dsidev, disconnect_lanes);
}
@@ -4786,7 +4573,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_dss_output *out = dssdev->output;
int r = 0;
DSSDBG("dsi_display_enable\n");
@@ -4795,12 +4581,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&dsi->lock);
- if (out == NULL || out->manager == NULL) {
- DSSERR("failed to enable display: no output/manager\n");
- r = -ENODEV;
- goto err_start_dev;
- }
-
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
@@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
_dsi_initialize_irq(dsidev);
- r = dsi_display_init_dispc(dssdev);
- if (r)
- goto err_init_dispc;
-
- r = dsi_display_init_dsi(dssdev);
+ r = dsi_display_init_dsi(dsidev);
if (r)
goto err_init_dsi;
@@ -4828,8 +4604,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
return 0;
err_init_dsi:
- dsi_display_uninit_dispc(dssdev);
-err_init_dispc:
dsi_enable_pll_clock(dsidev, 0);
dsi_runtime_put(dsidev);
err_get_dsi:
@@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
dsi_sync_vc(dsidev, 2);
dsi_sync_vc(dsidev, 3);
- dsi_display_uninit_dispc(dssdev);
-
- dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
+ dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
dsi_runtime_put(dsidev);
dsi_enable_pll_clock(dsidev, 0);
@@ -4881,77 +4653,579 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
}
EXPORT_SYMBOL(omapdss_dsi_enable_te);
-void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+static void print_dsi_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ unsigned long byteclk = t->hsclk / 4;
+ int bl, wc, pps, tot;
+
+ wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
+ pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
+ bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
+ tot = bl + pps;
+
+#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
+
+ pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ byteclk,
+ t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
+ bl, pps, tot,
+ TO_DSI_T(t->hss),
+ TO_DSI_T(t->hsa),
+ TO_DSI_T(t->hse),
+ TO_DSI_T(t->hbp),
+ TO_DSI_T(pps),
+ TO_DSI_T(t->hfp),
+
+ TO_DSI_T(bl),
+ TO_DSI_T(pps),
+
+ TO_DSI_T(tot));
+#undef TO_DSI_T
+}
+
+static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
+{
+ unsigned long pck = t->pixel_clock * 1000;
+ int hact, bl, tot;
+
+ hact = t->x_res;
+ bl = t->hsw + t->hbp + t->hfp;
+ tot = hact + bl;
+
+#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
+
+ pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
+ "%u/%u/%u/%u = %u + %u = %u\n",
+ str,
+ pck,
+ t->hsw, t->hbp, hact, t->hfp,
+ bl, hact, tot,
+ TO_DISPC_T(t->hsw),
+ TO_DISPC_T(t->hbp),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(t->hfp),
+ TO_DISPC_T(bl),
+ TO_DISPC_T(hact),
+ TO_DISPC_T(tot));
+#undef TO_DISPC_T
+}
+
+/* note: this is not quite accurate */
+static void print_dsi_dispc_vm(const char *str,
+ const struct omap_dss_dsi_videomode_timings *t)
+{
+ struct omap_video_timings vm = { 0 };
+ unsigned long byteclk = t->hsclk / 4;
+ unsigned long pck;
+ u64 dsi_tput;
+ int dsi_hact, dsi_htot;
+
+ dsi_tput = (u64)byteclk * t->ndl * 8;
+ pck = (u32)div64_u64(dsi_tput, t->bitspp);
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
+ dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
+
+ vm.pixel_clock = pck / 1000;
+ vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
+ vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
+ vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
+ vm.x_res = t->hact;
+
+ print_dispc_vm(str, &vm);
+}
+#endif /* PRINT_VERBOSE_VM_TIMINGS */
+
+static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clk_calc_ctx *ctx = data;
+ struct omap_video_timings *t = &ctx->dispc_vm;
- mutex_lock(&dsi->lock);
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
- dsi->timings = *timings;
+ *t = *ctx->config->timings;
+ t->pixel_clock = pck / 1000;
+ t->x_res = ctx->config->timings->x_res;
+ t->y_res = ctx->config->timings->y_res;
+ t->hsw = t->hfp = t->hbp = t->vsw = 1;
+ t->vfp = t->vbp = 0;
- mutex_unlock(&dsi->lock);
+ return true;
}
-EXPORT_SYMBOL(omapdss_dsi_set_timings);
-void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clk_calc_ctx *ctx = data;
- mutex_lock(&dsi->lock);
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
- dsi->timings.x_res = w;
- dsi->timings.y_res = h;
+ return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
+ dsi_cm_calc_dispc_cb, ctx);
+}
- mutex_unlock(&dsi->lock);
+static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ dsi_cm_calc_hsdiv_cb, ctx);
}
-EXPORT_SYMBOL(omapdss_dsi_set_size);
-void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
- enum omap_dss_dsi_pixel_format fmt)
+static bool dsi_cm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ unsigned long clkin;
+ int bitspp, ndl;
+ unsigned long pll_min, pll_max;
+ unsigned long pck, txbyteclk;
- mutex_lock(&dsi->lock);
+ clkin = clk_get_rate(dsi->sys_clk);
+ bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ ndl = dsi->num_lanes_used - 1;
- dsi->pix_fmt = fmt;
+ /*
+ * Here we should calculate minimum txbyteclk to be able to send the
+ * frame in time, and also to handle TE. That's not very simple, though,
+ * especially as we go to LP between each pixel packet due to HW
+ * "feature". So let's just estimate very roughly and multiply by 1.5.
+ */
+ pck = cfg->timings->pixel_clock * 1000;
+ pck = pck * 3 / 2;
+ txbyteclk = pck * bitspp / 8 / ndl;
- mutex_unlock(&dsi->lock);
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->config = cfg;
+ ctx->req_pck_min = pck;
+ ctx->req_pck_nom = pck;
+ ctx->req_pck_max = pck * 3 / 2;
+ ctx->dsi_cinfo.clkin = clkin;
+
+ pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
+ pll_max = cfg->hs_clk_max * 4;
+
+ return dsi_pll_calc(dsi->pdev, clkin,
+ pll_min, pll_max,
+ dsi_cm_calc_pll_cb, ctx);
}
-EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
-void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
- enum omap_dss_dsi_mode mode)
+static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
+ const struct omap_dss_dsi_config *cfg = ctx->config;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ int ndl = dsi->num_lanes_used - 1;
+ unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
+ unsigned long byteclk = hsclk / 4;
- mutex_lock(&dsi->lock);
+ unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
+ int xres;
+ int panel_htot, panel_hbl; /* pixels */
+ int dispc_htot, dispc_hbl; /* pixels */
+ int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
+ int hfp, hsa, hbp;
+ const struct omap_video_timings *req_vm;
+ struct omap_video_timings *dispc_vm;
+ struct omap_dss_dsi_videomode_timings *dsi_vm;
+ u64 dsi_tput, dispc_tput;
- dsi->mode = mode;
+ dsi_tput = (u64)byteclk * ndl * 8;
- mutex_unlock(&dsi->lock);
+ req_vm = cfg->timings;
+ req_pck_min = ctx->req_pck_min;
+ req_pck_max = ctx->req_pck_max;
+ req_pck_nom = ctx->req_pck_nom;
+
+ dispc_pck = ctx->dispc_cinfo.pck;
+ dispc_tput = (u64)dispc_pck * bitspp;
+
+ xres = req_vm->x_res;
+
+ panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
+ panel_htot = xres + panel_hbl;
+
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
+
+ /*
+ * When there are no line buffers, DISPC and DSI must have the
+ * same tput. Otherwise DISPC tput needs to be higher than DSI's.
+ */
+ if (dsi->line_buffer_size < xres * bitspp / 8) {
+ if (dispc_tput != dsi_tput)
+ return false;
+ } else {
+ if (dispc_tput < dsi_tput)
+ return false;
+ }
+
+ /* DSI tput must be over the min requirement */
+ if (dsi_tput < (u64)bitspp * req_pck_min)
+ return false;
+
+ /* When non-burst mode, DSI tput must be below max requirement. */
+ if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
+ if (dsi_tput > (u64)bitspp * req_pck_max)
+ return false;
+ }
+
+ hss = DIV_ROUND_UP(4, ndl);
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+ if (ndl == 3 && req_vm->hsw == 0)
+ hse = 1;
+ else
+ hse = DIV_ROUND_UP(4, ndl);
+ } else {
+ hse = 0;
+ }
+
+ /* DSI htot to match the panel's nominal pck */
+ dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
+
+ /* fail if there would be no time for blanking */
+ if (dsi_htot < hss + hse + dsi_hact)
+ return false;
+
+ /* total DSI blanking needed to achieve panel's TL */
+ dsi_hbl = dsi_htot - dsi_hact;
+
+ /* DISPC htot to match the DSI TL */
+ dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
+
+ /* verify that the DSI and DISPC TLs are the same */
+ if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
+ return false;
+
+ dispc_hbl = dispc_htot - xres;
+
+ /* setup DSI videomode */
+
+ dsi_vm = &ctx->dsi_vm;
+ memset(dsi_vm, 0, sizeof(*dsi_vm));
+
+ dsi_vm->hsclk = hsclk;
+
+ dsi_vm->ndl = ndl;
+ dsi_vm->bitspp = bitspp;
+
+ if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
+ hsa = 0;
+ } else if (ndl == 3 && req_vm->hsw == 0) {
+ hsa = 0;
+ } else {
+ hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
+ hsa = max(hsa - hse, 1);
+ }
+
+ hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
+ hbp = max(hbp, 1);
+
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+ if (hfp < 1) {
+ int t;
+ /* we need to take cycles from hbp */
+
+ t = 1 - hfp;
+ hbp = max(hbp - t, 1);
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+
+ if (hfp < 1 && hsa > 0) {
+ /* we need to take cycles from hsa */
+ t = 1 - hfp;
+ hsa = max(hsa - t, 1);
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
+ }
+ }
+
+ if (hfp < 1)
+ return false;
+
+ dsi_vm->hss = hss;
+ dsi_vm->hsa = hsa;
+ dsi_vm->hse = hse;
+ dsi_vm->hbp = hbp;
+ dsi_vm->hact = xres;
+ dsi_vm->hfp = hfp;
+
+ dsi_vm->vsa = req_vm->vsw;
+ dsi_vm->vbp = req_vm->vbp;
+ dsi_vm->vact = req_vm->y_res;
+ dsi_vm->vfp = req_vm->vfp;
+
+ dsi_vm->trans_mode = cfg->trans_mode;
+
+ dsi_vm->blanking_mode = 0;
+ dsi_vm->hsa_blanking_mode = 1;
+ dsi_vm->hfp_blanking_mode = 1;
+ dsi_vm->hbp_blanking_mode = 1;
+
+ dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
+ dsi_vm->window_sync = 4;
+
+ /* setup DISPC videomode */
+
+ dispc_vm = &ctx->dispc_vm;
+ *dispc_vm = *req_vm;
+ dispc_vm->pixel_clock = dispc_pck / 1000;
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
+ hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
+ req_pck_nom);
+ hsa = max(hsa, 1);
+ } else {
+ hsa = 1;
+ }
+
+ hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
+ hbp = max(hbp, 1);
+
+ hfp = dispc_hbl - hsa - hbp;
+ if (hfp < 1) {
+ int t;
+ /* we need to take cycles from hbp */
+
+ t = 1 - hfp;
+ hbp = max(hbp - t, 1);
+ hfp = dispc_hbl - hsa - hbp;
+
+ if (hfp < 1) {
+ /* we need to take cycles from hsa */
+ t = 1 - hfp;
+ hsa = max(hsa - t, 1);
+ hfp = dispc_hbl - hsa - hbp;
+ }
+ }
+
+ if (hfp < 1)
+ return false;
+
+ dispc_vm->hfp = hfp;
+ dispc_vm->hsw = hsa;
+ dispc_vm->hbp = hbp;
+
+ return true;
}
-EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
-void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
- struct omap_dss_dsi_videomode_timings *timings)
+
+static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ if (dsi_vm_calc_blanking(ctx) == false)
+ return false;
+
+#ifdef PRINT_VERBOSE_VM_TIMINGS
+ print_dispc_vm("dispc", &ctx->dispc_vm);
+ print_dsi_vm("dsi ", &ctx->dsi_vm);
+ print_dispc_vm("req ", ctx->config->timings);
+ print_dsi_dispc_vm("act ", &ctx->dsi_vm);
+#endif
+
+ return true;
+}
+
+static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+ void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+ unsigned long pck_max;
+
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+
+ /*
+ * In burst mode we can let the dispc pck be arbitrarily high, but it
+ * limits our scaling abilities. So for now, don't aim too high.
+ */
+
+ if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
+ pck_max = ctx->req_pck_max + 10000000;
+ else
+ pck_max = ctx->req_pck_max;
+
+ return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
+ dsi_vm_calc_dispc_cb, ctx);
+}
+
+static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data)
+{
+ struct dsi_clk_calc_ctx *ctx = data;
+
+ ctx->dsi_cinfo.regn = regn;
+ ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.fint = fint;
+ ctx->dsi_cinfo.clkin4ddr = pll;
+
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ dsi_vm_calc_hsdiv_cb, ctx);
+}
+
+static bool dsi_vm_calc(struct dsi_data *dsi,
+ const struct omap_dss_dsi_config *cfg,
+ struct dsi_clk_calc_ctx *ctx)
+{
+ const struct omap_video_timings *t = cfg->timings;
+ unsigned long clkin;
+ unsigned long pll_min;
+ unsigned long pll_max;
+ int ndl = dsi->num_lanes_used - 1;
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
+ unsigned long byteclk_min;
+
+ clkin = clk_get_rate(dsi->sys_clk);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->dsidev = dsi->pdev;
+ ctx->config = cfg;
+
+ ctx->dsi_cinfo.clkin = clkin;
+
+ /* these limits should come from the panel driver */
+ ctx->req_pck_min = t->pixel_clock * 1000 - 1000;
+ ctx->req_pck_nom = t->pixel_clock * 1000;
+ ctx->req_pck_max = t->pixel_clock * 1000 + 1000;
+
+ byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
+ pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
+
+ if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
+ pll_max = cfg->hs_clk_max * 4;
+ } else {
+ unsigned long byteclk_max;
+ byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
+ ndl * 8);
+
+ pll_max = byteclk_max * 4 * 4;
+ }
+
+ return dsi_pll_calc(dsi->pdev, clkin,
+ pll_min, pll_max,
+ dsi_vm_calc_pll_cb, ctx);
+}
+
+int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
+ const struct omap_dss_dsi_config *config)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_clk_calc_ctx ctx;
+ bool ok;
+ int r;
mutex_lock(&dsi->lock);
- dsi->vm_timings = *timings;
+ dsi->pix_fmt = config->pixel_format;
+ dsi->mode = config->mode;
+
+ if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
+ ok = dsi_vm_calc(dsi, config, &ctx);
+ else
+ ok = dsi_cm_calc(dsi, config, &ctx);
+
+ if (!ok) {
+ DSSERR("failed to find suitable DSI clock settings\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
+
+ r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
+ config->lp_clk_max);
+ if (r) {
+ DSSERR("failed to find suitable DSI LP clock settings\n");
+ goto err;
+ }
+
+ dsi->user_dsi_cinfo = ctx.dsi_cinfo;
+ dsi->user_dispc_cinfo = ctx.dispc_cinfo;
+
+ dsi->timings = ctx.dispc_vm;
+ dsi->vm_timings = ctx.dsi_vm;
mutex_unlock(&dsi->lock);
+
+ return 0;
+err:
+ mutex_unlock(&dsi->lock);
+
+ return r;
}
-EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
+EXPORT_SYMBOL(omapdss_dsi_set_config);
+
+/*
+ * Return a hardcoded channel for the DSI output. This should work for
+ * current use cases, but this can be later expanded to either resolve
+ * the channel in some more dynamic manner, or get the channel as a user
+ * parameter.
+ */
+static enum omap_channel dsi_get_channel(int module_id)
+{
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP24xx:
+ DSSWARN("DSI not supported\n");
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ return OMAP_DSS_CHANNEL_LCD;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ switch (module_id) {
+ case 0:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ default:
+ DSSWARN("unsupported module id\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+
+ case OMAPDSS_VER_OMAP5:
+ switch (module_id) {
+ case 0:
+ return OMAP_DSS_CHANNEL_LCD;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD3;
+ default:
+ DSSWARN("unsupported module id\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
-static int __init dsi_init_display(struct omap_dss_device *dssdev)
+ default:
+ DSSWARN("unsupported DSS version\n");
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+}
+
+static int dsi_init_display(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev =
dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
@@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct clk *clk;
- clk = clk_get(&dsidev->dev, "fck");
+ clk = devm_clk_get(&dsidev->dev, "fck");
if (IS_ERR(clk)) {
DSSERR("can't get fck\n");
return PTR_ERR(clk);
@@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev)
dsi->dss_clk = clk;
- clk = clk_get(&dsidev->dev, "sys_clk");
+ clk = devm_clk_get(&dsidev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
- clk_put(dsi->dss_clk);
- dsi->dss_clk = NULL;
return PTR_ERR(clk);
}
@@ -5094,17 +5366,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
return 0;
}
-static void dsi_put_clocks(struct platform_device *dsidev)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
- if (dsi->dss_clk)
- clk_put(dsi->dss_clk);
- if (dsi->sys_clk)
- clk_put(dsi->sys_clk);
-}
-
-static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *dsi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
@@ -5136,7 +5398,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p
return def_dssdev;
}
-static void __init dsi_probe_pdata(struct platform_device *dsidev)
+static int dsi_probe_pdata(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_dss_device *plat_dssdev;
@@ -5146,11 +5408,11 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
plat_dssdev = dsi_find_dssdev(dsidev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&dsidev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
@@ -5158,7 +5420,7 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&dsi->output, dssdev);
@@ -5166,7 +5428,7 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -5174,11 +5436,13 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&dsi->output);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init dsi_init_output(struct platform_device *dsidev)
+static void dsi_init_output(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_dss_output *out = &dsi->output;
@@ -5188,11 +5452,13 @@ static void __init dsi_init_output(struct platform_device *dsidev)
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
out->type = OMAP_DISPLAY_TYPE_DSI;
+ out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
+ out->dispc_channel = dsi_get_channel(dsi->module_id);
dss_register_output(out);
}
-static void __exit dsi_uninit_output(struct platform_device *dsidev)
+static void dsi_uninit_output(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct omap_dss_output *out = &dsi->output;
@@ -5201,7 +5467,7 @@ static void __exit dsi_uninit_output(struct platform_device *dsidev)
}
/* DSI1 HW IP initialisation */
-static int __init omap_dsihw_probe(struct platform_device *dsidev)
+static int omap_dsihw_probe(struct platform_device *dsidev)
{
u32 rev;
int r, i;
@@ -5293,9 +5559,17 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
else
dsi->num_lanes_supported = 3;
+ dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
+
dsi_init_output(dsidev);
- dsi_probe_pdata(dsidev);
+ r = dsi_probe_pdata(dsidev);
+ if (r) {
+ dsi_runtime_put(dsidev);
+ dsi_uninit_output(dsidev);
+ pm_runtime_disable(&dsidev->dev);
+ return r;
+ }
dsi_runtime_put(dsidev);
@@ -5314,7 +5588,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
err_runtime_get:
pm_runtime_disable(&dsidev->dev);
- dsi_put_clocks(dsidev);
return r;
}
@@ -5330,8 +5603,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
pm_runtime_disable(&dsidev->dev);
- dsi_put_clocks(dsidev);
-
if (dsi->vdds_dsi_reg != NULL) {
if (dsi->vdds_dsi_enabled) {
regulator_disable(dsi->vdds_dsi_reg);
@@ -5369,6 +5640,7 @@ static const struct dev_pm_ops dsi_pm_ops = {
};
static struct platform_driver omap_dsihw_driver = {
+ .probe = omap_dsihw_probe,
.remove = __exit_p(omap_dsihw_remove),
.driver = {
.name = "omapdss_dsi",
@@ -5379,7 +5651,7 @@ static struct platform_driver omap_dsihw_driver = {
int __init dsi_init_platform_driver(void)
{
- return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe);
+ return platform_driver_register(&omap_dsihw_driver);
}
void __exit dsi_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 054c2a22b3f..94f66f9f10a 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
return 0;
}
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data)
+{
+ int fckd, fckd_start, fckd_stop;
+ unsigned long fck;
+ unsigned long fck_hw_max;
+ unsigned long fckd_hw_max;
+ unsigned long prate;
+ unsigned m;
+
+ if (dss.dpll4_m4_ck == NULL) {
+ /*
+ * TODO: dss1_fclk can be changed on OMAP2, but the available
+ * dividers are not continuous. We just use the pre-set rate for
+ * now.
+ */
+ fck = clk_get_rate(dss.dss_clk);
+ fckd = 1;
+ return func(fckd, fck, data);
+ }
+
+ fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
+ fckd_hw_max = dss.feat->fck_div_max;
+
+ m = dss.feat->dss_fck_multiplier;
+ prate = dss_get_dpll4_rate();
+
+ fck_min = fck_min ? fck_min : 1;
+
+ fckd_start = min(prate * m / fck_min, fckd_hw_max);
+ fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
+
+ for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
+ fck = prate / fckd * m;
+
+ if (func(fckd, fck, data))
+ return true;
+ }
+
+ return false;
+}
+
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
DSSDBG("dpll4_m4 = %ld\n", prate);
- r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
+ r = clk_set_rate(dss.dpll4_m4_ck,
+ DIV_ROUND_UP(prate, cinfo->fck_div));
if (r)
return r;
} else {
@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
- WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch");
+ WARN_ONCE(dss.dss_clk_rate != cinfo->fck,
+ "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
+ cinfo->fck);
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void)
return 0;
}
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- unsigned long prate;
- struct dss_clock_info best_dss;
- struct dispc_clock_info best_dispc;
-
- unsigned long fck, max_dss_fck;
-
- u16 fck_div;
-
- int match = 0;
- int min_fck_per_pck;
-
- prate = dss_get_dpll4_rate();
-
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- fck = clk_get_rate(dss.dss_clk);
- if (req_pck == dss.cache_req_pck && prate == dss.cache_prate &&
- dss.cache_dss_cinfo.fck == fck) {
- DSSDBG("dispc clock info found from cache.\n");
- *dss_cinfo = dss.cache_dss_cinfo;
- *dispc_cinfo = dss.cache_dispc_cinfo;
- return 0;
- }
-
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
-
- if (min_fck_per_pck &&
- req_pck * min_fck_per_pck > max_dss_fck) {
- DSSERR("Requested pixel clock not possible with the current "
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
- "the constraint off.\n");
- min_fck_per_pck = 0;
- }
-
-retry:
- memset(&best_dss, 0, sizeof(best_dss));
- memset(&best_dispc, 0, sizeof(best_dispc));
-
- if (dss.dpll4_m4_ck == NULL) {
- struct dispc_clock_info cur_dispc;
- /* XXX can we change the clock on omap2? */
- fck = clk_get_rate(dss.dss_clk);
- fck_div = 1;
-
- dispc_find_clk_divs(req_pck, fck, &cur_dispc);
- match = 1;
-
- best_dss.fck = fck;
- best_dss.fck_div = fck_div;
-
- best_dispc = cur_dispc;
-
- goto found;
- } else {
- for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
- struct dispc_clock_info cur_dispc;
-
- fck = prate / fck_div * dss.feat->dss_fck_multiplier;
-
- if (fck > max_dss_fck)
- continue;
-
- if (min_fck_per_pck &&
- fck < req_pck * min_fck_per_pck)
- continue;
-
- match = 1;
-
- dispc_find_clk_divs(req_pck, fck, &cur_dispc);
-
- if (abs(cur_dispc.pck - req_pck) <
- abs(best_dispc.pck - req_pck)) {
-
- best_dss.fck = fck;
- best_dss.fck_div = fck_div;
-
- best_dispc = cur_dispc;
-
- if (cur_dispc.pck == req_pck)
- goto found;
- }
- }
- }
-
-found:
- if (!match) {
- if (min_fck_per_pck) {
- DSSERR("Could not find suitable clock settings.\n"
- "Turning FCK/PCK constraint off and"
- "trying again.\n");
- min_fck_per_pck = 0;
- goto retry;
- }
-
- DSSERR("Could not find suitable clock settings.\n");
-
- return -EINVAL;
- }
-
- if (dss_cinfo)
- *dss_cinfo = best_dss;
- if (dispc_cinfo)
- *dispc_cinfo = best_dispc;
-
- dss.cache_req_pck = req_pck;
- dss.cache_prate = prate;
- dss.cache_dss_cinfo = best_dss;
- dss.cache_dispc_cinfo = best_dispc;
-
- return 0;
-}
-
void dss_set_venc_output(enum omap_dss_venc_type type)
{
int l = 0;
@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel)
static int dss_get_clocks(void)
{
struct clk *clk;
- int r;
- clk = clk_get(&dss.pdev->dev, "fck");
+ clk = devm_clk_get(&dss.pdev->dev, "fck");
if (IS_ERR(clk)) {
DSSERR("can't get clock fck\n");
- r = PTR_ERR(clk);
- goto err;
+ return PTR_ERR(clk);
}
dss.dss_clk = clk;
@@ -782,8 +709,7 @@ static int dss_get_clocks(void)
clk = clk_get(NULL, dss.feat->clk_name);
if (IS_ERR(clk)) {
DSSERR("Failed to get %s\n", dss.feat->clk_name);
- r = PTR_ERR(clk);
- goto err;
+ return PTR_ERR(clk);
}
} else {
clk = NULL;
@@ -792,21 +718,12 @@ static int dss_get_clocks(void)
dss.dpll4_m4_ck = clk;
return 0;
-
-err:
- if (dss.dss_clk)
- clk_put(dss.dss_clk);
- if (dss.dpll4_m4_ck)
- clk_put(dss.dpll4_m4_ck);
-
- return r;
}
static void dss_put_clocks(void)
{
if (dss.dpll4_m4_ck)
clk_put(dss.dpll4_m4_ck);
- clk_put(dss.dss_clk);
}
static int dss_runtime_get(void)
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 610c8e563da..84758936429 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -268,14 +268,21 @@ void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo);
-int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
- struct dispc_clock_info *dispc_cinfo);
+
+typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data);
+bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data);
/* SDI */
int sdi_init_platform_driver(void) __init;
void sdi_uninit_platform_driver(void) __exit;
/* DSI */
+
+typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
+ unsigned long pll, void *data);
+typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
+ void *data);
+
#ifdef CONFIG_OMAP2_DSS_DSI
struct dentry;
@@ -292,12 +299,17 @@ void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
+
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
+ unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dsi_pll_calc_func func, void *data);
+
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck, struct dsi_clock_info *cinfo,
- struct dispc_clock_info *dispc_cinfo);
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
@@ -328,14 +340,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
-static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
- unsigned long req_pck,
- struct dsi_clock_info *dsi_cinfo,
- struct dispc_clock_info *dispc_cinfo)
-{
- WARN("%s: DSI not compiled in\n", __func__);
- return -ENODEV;
-}
static inline int dsi_pll_init(struct platform_device *dsidev,
bool enable_hsclk, bool enable_hsdiv)
{
@@ -356,6 +360,27 @@ static inline struct platform_device *dsi_get_dsidev_from_id(int module)
{
return NULL;
}
+
+static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
+{
+ return 0;
+}
+
+static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
+ unsigned long pll, unsigned long out_min,
+ dsi_hsdiv_calc_func func, void *data)
+{
+ return false;
+}
+
+static inline bool dsi_pll_calc(struct platform_device *dsidev,
+ unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dsi_pll_calc_func func, void *data)
+{
+ return false;
+}
+
#endif
/* DPI */
@@ -376,11 +401,15 @@ void dispc_enable_fifomerge(bool enable);
void dispc_enable_gamma_table(bool enable);
void dispc_set_loadmode(enum omap_dss_load_mode mode);
+typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data);
+bool dispc_div_calc(unsigned long dispc,
+ unsigned long pck_min, unsigned long pck_max,
+ dispc_div_calc_func func, void *data);
+
bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void);
-void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
- struct dispc_clock_info *cinfo);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index d7d66ef5cb5..77dbe0cfb34 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -202,12 +202,10 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
- OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
- OMAP_DSS_OUTPUT_DSI1,
+ OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
- OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
- OMAP_DSS_OUTPUT_DPI,
+ OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
@@ -416,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = {
};
static const struct dss_param_range omap2_dss_param_range[] = {
- [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
+ [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
@@ -461,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = {
};
static const struct dss_param_range omap5_dss_param_range[] = {
- [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
+ [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
- [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
};
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 72923645dcc..a109934c047 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -328,7 +328,7 @@ static void hdmi_runtime_put(void)
WARN_ON(r < 0 && r != -ENOSYS);
}
-static int __init hdmi_init_display(struct omap_dss_device *dssdev)
+static int hdmi_init_display(struct omap_dss_device *dssdev)
{
int r;
@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
* Input clock is predivided by N + 1
* out put of which is reference clk
*/
- if (dssdev->clocks.hdmi.regn == 0)
- pi->regn = HDMI_DEFAULT_REGN;
- else
- pi->regn = dssdev->clocks.hdmi.regn;
+
+ pi->regn = HDMI_DEFAULT_REGN;
refclk = clkin / pi->regn;
- if (dssdev->clocks.hdmi.regm2 == 0)
- pi->regm2 = HDMI_DEFAULT_REGM2;
- else
- pi->regm2 = dssdev->clocks.hdmi.regm2;
+ pi->regm2 = HDMI_DEFAULT_REGM2;
/*
* multiplier is pixel_clk/ref_clk
@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
- clk = clk_get(&pdev->dev, "sys_clk");
+ clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev)
return 0;
}
-static void hdmi_put_clocks(void)
-{
- if (hdmi.sys_clk)
- clk_put(hdmi.sys_clk);
-}
-
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
{
@@ -965,7 +954,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
#endif
-static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *hdmi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = omapdss_get_default_display_name();
@@ -993,7 +982,7 @@ static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *
return def_dssdev;
}
-static void __init hdmi_probe_pdata(struct platform_device *pdev)
+static int hdmi_probe_pdata(struct platform_device *pdev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
@@ -1003,11 +992,11 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
plat_dssdev = hdmi_find_dssdev(pdev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&pdev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
@@ -1017,13 +1006,11 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
hdmi.ls_oe_gpio = priv->ls_oe_gpio;
hdmi.hpd_gpio = priv->hpd_gpio;
- dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
-
r = hdmi_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&hdmi.output, dssdev);
@@ -1031,7 +1018,7 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -1040,17 +1027,21 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
omapdss_output_unset_device(&hdmi.output);
hdmi_uninit_display(dssdev);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init hdmi_init_output(struct platform_device *pdev)
+static void hdmi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &hdmi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI;
+ out->name = "hdmi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
dss_register_output(out);
}
@@ -1063,7 +1054,7 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev)
}
/* HDMI HW IP initialisation */
-static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
+static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
struct resource *res;
int r;
@@ -1074,10 +1065,6 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
mutex_init(&hdmi.ip_data.lock);
res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get IORESOURCE_MEM HDMI\n");
- return -EINVAL;
- }
/* Base address taken from platform */
hdmi.ip_data.base_wp = devm_ioremap_resource(&pdev->dev, res);
@@ -1097,23 +1084,25 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
+ hdmi_init_output(pdev);
+
r = hdmi_panel_init();
if (r) {
DSSERR("can't init panel\n");
- goto err_panel_init;
+ return r;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
- hdmi_init_output(pdev);
-
- hdmi_probe_pdata(pdev);
+ r = hdmi_probe_pdata(pdev);
+ if (r) {
+ hdmi_panel_exit();
+ hdmi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
return 0;
-
-err_panel_init:
- hdmi_put_clocks();
- return r;
}
static int __exit hdmi_remove_child(struct device *dev, void *data)
@@ -1135,8 +1124,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
- hdmi_put_clocks();
-
return 0;
}
@@ -1168,6 +1155,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
};
static struct platform_driver omapdss_hdmihw_driver = {
+ .probe = omapdss_hdmihw_probe,
.remove = __exit_p(omapdss_hdmihw_remove),
.driver = {
.name = "omapdss_hdmi",
@@ -1178,7 +1166,7 @@ static struct platform_driver omapdss_hdmihw_driver = {
int __init hdmi_init_platform_driver(void)
{
- return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe);
+ return platform_driver_register(&omapdss_hdmihw_driver);
}
void __exit hdmi_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
index 79dea1a1a73..5214df63e0a 100644
--- a/drivers/video/omap2/dss/output.c
+++ b/drivers/video/omap2/dss/output.c
@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
return NULL;
}
+EXPORT_SYMBOL(omap_dss_get_output);
static const struct dss_mgr_ops *dss_mgr_ops;
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index e903dd3f54d..1a17dd1447d 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -943,13 +943,13 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omapdss_rfbi_display_disable);
-static int __init rfbi_init_display(struct omap_dss_device *dssdev)
+static int rfbi_init_display(struct omap_dss_device *dssdev)
{
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
return 0;
}
-static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *rfbi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = omapdss_get_default_display_name();
@@ -977,7 +977,7 @@ static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *
return def_dssdev;
}
-static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
+static int rfbi_probe_pdata(struct platform_device *rfbidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
@@ -986,11 +986,11 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
plat_dssdev = rfbi_find_dssdev(rfbidev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&rfbidev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
@@ -998,7 +998,7 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&rfbi.output, dssdev);
@@ -1006,7 +1006,7 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -1014,17 +1014,21 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&rfbi.output);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init rfbi_init_output(struct platform_device *pdev)
+static void rfbi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &rfbi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_DBI;
out->type = OMAP_DISPLAY_TYPE_DBI;
+ out->name = "rfbi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
dss_register_output(out);
}
@@ -1037,7 +1041,7 @@ static void __exit rfbi_uninit_output(struct platform_device *pdev)
}
/* RFBI HW IP initialisation */
-static int __init omap_rfbihw_probe(struct platform_device *pdev)
+static int omap_rfbihw_probe(struct platform_device *pdev)
{
u32 rev;
struct resource *rfbi_mem;
@@ -1089,7 +1093,12 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev)
rfbi_init_output(pdev);
- rfbi_probe_pdata(pdev);
+ r = rfbi_probe_pdata(pdev);
+ if (r) {
+ rfbi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
return 0;
@@ -1133,6 +1142,7 @@ static const struct dev_pm_ops rfbi_pm_ops = {
};
static struct platform_driver omap_rfbihw_driver = {
+ .probe = omap_rfbihw_probe,
.remove = __exit_p(omap_rfbihw_remove),
.driver = {
.name = "omapdss_rfbi",
@@ -1143,7 +1153,7 @@ static struct platform_driver omap_rfbihw_driver = {
int __init rfbi_init_platform_driver(void)
{
- return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe);
+ return platform_driver_register(&omap_rfbihw_driver);
}
void __exit rfbi_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 62b5374ce43..0bcd30272f6 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -41,6 +41,72 @@ static struct {
struct omap_dss_output output;
} sdi;
+struct sdi_clk_calc_ctx {
+ unsigned long pck_min, pck_max;
+
+ struct dss_clock_info dss_cinfo;
+ struct dispc_clock_info dispc_cinfo;
+};
+
+static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
+ unsigned long pck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->dispc_cinfo.lck_div = lckd;
+ ctx->dispc_cinfo.pck_div = pckd;
+ ctx->dispc_cinfo.lck = lck;
+ ctx->dispc_cinfo.pck = pck;
+
+ return true;
+}
+
+static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
+{
+ struct sdi_clk_calc_ctx *ctx = data;
+
+ ctx->dss_cinfo.fck = fck;
+ ctx->dss_cinfo.fck_div = fckd;
+
+ return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
+ dpi_calc_dispc_cb, ctx);
+}
+
+static int sdi_calc_clock_div(unsigned long pclk,
+ struct dss_clock_info *dss_cinfo,
+ struct dispc_clock_info *dispc_cinfo)
+{
+ int i;
+ struct sdi_clk_calc_ctx ctx;
+
+ /*
+ * DSS fclk gives us very few possibilities, so finding a good pixel
+ * clock may not be possible. We try multiple times to find the clock,
+ * each time widening the pixel clock range we look for, up to
+ * +/- 1MHz.
+ */
+
+ for (i = 0; i < 10; ++i) {
+ bool ok;
+
+ memset(&ctx, 0, sizeof(ctx));
+ if (pclk > 1000 * i * i * i)
+ ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
+ else
+ ctx.pck_min = 0;
+ ctx.pck_max = pclk + 1000 * i * i * i;
+
+ ok = dss_div_calc(ctx.pck_min, dpi_calc_dss_cb, &ctx);
+ if (ok) {
+ *dss_cinfo = ctx.dss_cinfo;
+ *dispc_cinfo = ctx.dispc_cinfo;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = dssdev->output->manager;
@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
+ r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
if (r)
goto err_calc_clock_div;
@@ -182,7 +248,7 @@ void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
}
EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
-static int __init sdi_init_display(struct omap_dss_device *dssdev)
+static int sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
@@ -202,7 +268,7 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *sdi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = omapdss_get_default_display_name();
@@ -230,7 +296,7 @@ static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *p
return def_dssdev;
}
-static void __init sdi_probe_pdata(struct platform_device *sdidev)
+static int sdi_probe_pdata(struct platform_device *sdidev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
@@ -239,11 +305,11 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev)
plat_dssdev = sdi_find_dssdev(sdidev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&sdidev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
@@ -251,7 +317,7 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev)
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&sdi.output, dssdev);
@@ -259,7 +325,7 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -267,17 +333,21 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev)
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&sdi.output);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init sdi_init_output(struct platform_device *pdev)
+static void sdi_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &sdi.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_SDI;
out->type = OMAP_DISPLAY_TYPE_SDI;
+ out->name = "sdi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
dss_register_output(out);
}
@@ -289,11 +359,17 @@ static void __exit sdi_uninit_output(struct platform_device *pdev)
dss_unregister_output(out);
}
-static int __init omap_sdi_probe(struct platform_device *pdev)
+static int omap_sdi_probe(struct platform_device *pdev)
{
+ int r;
+
sdi_init_output(pdev);
- sdi_probe_pdata(pdev);
+ r = sdi_probe_pdata(pdev);
+ if (r) {
+ sdi_uninit_output(pdev);
+ return r;
+ }
return 0;
}
@@ -308,6 +384,7 @@ static int __exit omap_sdi_remove(struct platform_device *pdev)
}
static struct platform_driver omap_sdi_driver = {
+ .probe = omap_sdi_probe,
.remove = __exit_p(omap_sdi_remove),
.driver = {
.name = "omapdss_sdi",
@@ -317,7 +394,7 @@ static struct platform_driver omap_sdi_driver = {
int __init sdi_init_platform_driver(void)
{
- return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe);
+ return platform_driver_register(&omap_sdi_driver);
}
void __exit sdi_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 006caf3cb50..74fdb3ee209 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -519,10 +519,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->platform_enable)
- dssdev->platform_enable(dssdev);
-
-
r = venc_power_on(dssdev);
if (r)
goto err1;
@@ -533,8 +529,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
return 0;
err1:
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
omap_dss_stop_device(dssdev);
err0:
mutex_unlock(&venc.venc_lock);
@@ -551,9 +545,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
omap_dss_stop_device(dssdev);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
mutex_unlock(&venc.venc_lock);
}
@@ -642,7 +633,7 @@ void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
mutex_unlock(&venc.venc_lock);
}
-static int __init venc_init_display(struct omap_dss_device *dssdev)
+static int venc_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
@@ -721,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev)
struct clk *clk;
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
- clk = clk_get(&pdev->dev, "tv_dac_clk");
+ clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
if (IS_ERR(clk)) {
DSSERR("can't get tv_dac_clk\n");
return PTR_ERR(clk);
@@ -735,13 +726,7 @@ static int venc_get_clocks(struct platform_device *pdev)
return 0;
}
-static void venc_put_clocks(void)
-{
- if (venc.tv_dac_clk)
- clk_put(venc.tv_dac_clk);
-}
-
-static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
+static struct omap_dss_device *venc_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
const char *def_disp_name = omapdss_get_default_display_name();
@@ -769,7 +754,7 @@ static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *
return def_dssdev;
}
-static void __init venc_probe_pdata(struct platform_device *vencdev)
+static int venc_probe_pdata(struct platform_device *vencdev)
{
struct omap_dss_device *plat_dssdev;
struct omap_dss_device *dssdev;
@@ -778,21 +763,19 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
plat_dssdev = venc_find_dssdev(vencdev);
if (!plat_dssdev)
- return;
+ return 0;
dssdev = dss_alloc_and_init_device(&vencdev->dev);
if (!dssdev)
- return;
+ return -ENOMEM;
dss_copy_device_pdata(dssdev, plat_dssdev);
- dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
-
r = venc_init_display(dssdev);
if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r);
dss_put_device(dssdev);
- return;
+ return r;
}
r = omapdss_output_set_device(&venc.output, dssdev);
@@ -800,7 +783,7 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
DSSERR("failed to connect output to new device: %s\n",
dssdev->name);
dss_put_device(dssdev);
- return;
+ return r;
}
r = dss_add_device(dssdev);
@@ -808,17 +791,21 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
DSSERR("device %s register failed: %d\n", dssdev->name, r);
omapdss_output_unset_device(&venc.output);
dss_put_device(dssdev);
- return;
+ return r;
}
+
+ return 0;
}
-static void __init venc_init_output(struct platform_device *pdev)
+static void venc_init_output(struct platform_device *pdev)
{
struct omap_dss_output *out = &venc.output;
out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_VENC;
out->type = OMAP_DISPLAY_TYPE_VENC;
+ out->name = "venc.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
dss_register_output(out);
}
@@ -831,7 +818,7 @@ static void __exit venc_uninit_output(struct platform_device *pdev)
}
/* VENC HW IP initialisation */
-static int __init omap_venchw_probe(struct platform_device *pdev)
+static int omap_venchw_probe(struct platform_device *pdev)
{
u8 rev_id;
struct resource *venc_mem;
@@ -879,14 +866,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
venc_init_output(pdev);
- venc_probe_pdata(pdev);
+ r = venc_probe_pdata(pdev);
+ if (r) {
+ venc_panel_exit();
+ venc_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
return 0;
err_panel_init:
err_runtime_get:
pm_runtime_disable(&pdev->dev);
- venc_put_clocks();
return r;
}
@@ -904,7 +896,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
venc_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
- venc_put_clocks();
return 0;
}
@@ -939,6 +930,7 @@ static const struct dev_pm_ops venc_pm_ops = {
};
static struct platform_driver omap_venchw_driver = {
+ .probe = omap_venchw_probe,
.remove = __exit_p(omap_venchw_remove),
.driver = {
.name = "omapdss_venc",
@@ -949,7 +941,7 @@ static struct platform_driver omap_venchw_driver = {
int __init venc_init_platform_driver(void)
{
- return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
+ return platform_driver_register(&omap_venchw_driver);
}
void __exit venc_uninit_platform_driver(void)
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index ca585ef37f2..856917b3361 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1101,41 +1101,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_fix_screeninfo *fix = &fbi->fix;
struct omapfb2_mem_region *rg;
- unsigned long off;
unsigned long start;
u32 len;
- int r = -EINVAL;
-
- if (vma->vm_end - vma->vm_start == 0)
- return 0;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
+ int r;
rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len;
- if (off >= len)
- goto error;
- if ((vma->vm_end - vma->vm_start + off) > len)
- goto error;
- off += start;
+ DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
+ vma->vm_pgoff << PAGE_SHIFT);
- DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
-
- vma->vm_pgoff = off >> PAGE_SHIFT;
- /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = rg;
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot)) {
- r = -EAGAIN;
+
+ r = vm_iomap_memory(vma, start, len);
+ if (r)
goto error;
- }
/* vm_ops.open won't be called for mmap itself. */
atomic_inc(&rg->map_count);
@@ -1144,7 +1128,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
- error:
+error:
omapfb_put_mem_region(ofbi->region);
return r;
@@ -2388,7 +2372,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
struct omap_dss_output *out = dssdev->output;
- mgr = omap_dss_get_overlay_manager(dssdev->channel);
+ mgr = omap_dss_get_overlay_manager(out->dispc_channel);
if (!mgr || !out)
continue;
@@ -2422,7 +2406,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
return 0;
}
-static int __init omapfb_probe(struct platform_device *pdev)
+static int omapfb_probe(struct platform_device *pdev)
{
struct omapfb2_device *fbdev = NULL;
int r = 0;
@@ -2432,6 +2416,9 @@ static int __init omapfb_probe(struct platform_device *pdev)
DBG("omapfb_probe\n");
+ if (omapdss_is_initialized() == false)
+ return -EPROBE_DEFER;
+
if (pdev->num_resources != 0) {
dev_err(&pdev->dev, "probed for an unknown device\n");
r = -ENODEV;
@@ -2484,7 +2471,7 @@ static int __init omapfb_probe(struct platform_device *pdev)
if (fbdev->num_displays == 0) {
dev_err(&pdev->dev, "no displays\n");
- r = -EINVAL;
+ r = -EPROBE_DEFER;
goto cleanup;
}
@@ -2595,6 +2582,7 @@ static int __exit omapfb_remove(struct platform_device *pdev)
}
static struct platform_driver omapfb_driver = {
+ .probe = omapfb_probe,
.remove = __exit_p(omapfb_remove),
.driver = {
.name = "omapfb",
@@ -2602,36 +2590,13 @@ static struct platform_driver omapfb_driver = {
},
};
-static int __init omapfb_init(void)
-{
- DBG("omapfb_init\n");
-
- if (platform_driver_probe(&omapfb_driver, omapfb_probe)) {
- printk(KERN_ERR "failed to register omapfb driver\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __exit omapfb_exit(void)
-{
- DBG("omapfb_exit\n");
- platform_driver_unregister(&omapfb_driver);
-}
-
module_param_named(mode, def_mode, charp, 0);
module_param_named(vram, def_vram, charp, 0);
module_param_named(rotate, def_rotate, int, 0);
module_param_named(vrfb, def_vrfb, bool, 0);
module_param_named(mirror, def_mirror, bool, 0);
-/* late_initcall to let panel/ctrl drivers loaded first.
- * I guess better option would be a more dynamic approach,
- * so that omapfb reacts to new panels when they are loaded */
-late_initcall(omapfb_init);
-/*module_init(omapfb_init);*/
-module_exit(omapfb_exit);
+module_platform_driver(omapfb_driver);
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
index 10560efeb35..f346b02eee1 100644
--- a/drivers/video/omap2/vrfb.c
+++ b/drivers/video/omap2/vrfb.c
@@ -353,11 +353,6 @@ static int __init vrfb_probe(struct platform_device *pdev)
/* first resource is the register res, the rest are vrfb contexts */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "can't get vrfb base address\n");
- return -EINVAL;
- }
-
vrfb_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(vrfb_base))
return PTR_ERR(vrfb_base);
@@ -397,18 +392,7 @@ static struct platform_driver vrfb_driver = {
.remove = __exit_p(vrfb_remove),
};
-static int __init vrfb_init(void)
-{
- return platform_driver_probe(&vrfb_driver, &vrfb_probe);
-}
-
-static void __exit vrfb_exit(void)
-{
- platform_driver_unregister(&vrfb_driver);
-}
-
-module_init(vrfb_init);
-module_exit(vrfb_exit);
+module_platform_driver_probe(vrfb_driver, vrfb_probe);
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("OMAP VRFB");