summaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2/dss
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r--drivers/video/omap2/dss/Kconfig2
-rw-r--r--drivers/video/omap2/dss/Makefile4
-rw-r--r--drivers/video/omap2/dss/apply.c330
-rw-r--r--drivers/video/omap2/dss/core.c91
-rw-r--r--drivers/video/omap2/dss/dispc.c1018
-rw-r--r--drivers/video/omap2/dss/dispc.h37
-rw-r--r--drivers/video/omap2/dss/display.c108
-rw-r--r--drivers/video/omap2/dss/dpi.c181
-rw-r--r--drivers/video/omap2/dss/dsi.c675
-rw-r--r--drivers/video/omap2/dss/dss.c257
-rw-r--r--drivers/video/omap2/dss/dss.h79
-rw-r--r--drivers/video/omap2/dss/dss_features.c278
-rw-r--r--drivers/video/omap2/dss/dss_features.h7
-rw-r--r--drivers/video/omap2/dss/hdmi.c247
-rw-r--r--drivers/video/omap2/dss/hdmi_panel.c31
-rw-r--r--drivers/video/omap2/dss/manager-sysfs.c512
-rw-r--r--drivers/video/omap2/dss/manager.c473
-rw-r--r--drivers/video/omap2/dss/output.c148
-rw-r--r--drivers/video/omap2/dss/overlay-sysfs.c456
-rw-r--r--drivers/video/omap2/dss/overlay.c492
-rw-r--r--drivers/video/omap2/dss/rfbi.c222
-rw-r--r--drivers/video/omap2/dss/sdi.c126
-rw-r--r--drivers/video/omap2/dss/venc.c337
-rw-r--r--drivers/video/omap2/dss/venc_panel.c251
24 files changed, 4129 insertions, 2233 deletions
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index b337a8469fd..80f5390aa13 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -84,7 +84,7 @@ config OMAP2_DSS_SDI
config OMAP2_DSS_DSI
bool "DSI support"
- depends on ARCH_OMAP3 || ARCH_OMAP4
+ depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5
default n
help
MIPI DSI (Display Serial Interface) support.
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 5c450b0f94d..4549869bfe1 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,9 +1,9 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
- manager.o overlay.o apply.o
+ manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
-omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
+omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c
index 0fefc68372b..19d66f471b4 100644
--- a/drivers/video/omap2/dss/apply.c
+++ b/drivers/video/omap2/dss/apply.c
@@ -111,9 +111,6 @@ static struct {
struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
- bool fifo_merge_dirty;
- bool fifo_merge;
-
bool irq_enabled;
} dss_data;
@@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void)
int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
{
unsigned long timeout = msecs_to_jiffies(500);
- struct mgr_priv_data *mp;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
u32 irq;
+ unsigned long flags;
int r;
int i;
- struct omap_dss_device *dssdev = mgr->device;
- if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mgr_manual_update(mgr)) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
- if (mgr_manual_update(mgr))
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
irq = dispc_mgr_get_vsync_irq(mgr->id);
- mp = get_mgr_priv(mgr);
i = 0;
while (1) {
- unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
{
unsigned long timeout = msecs_to_jiffies(500);
struct ovl_priv_data *op;
- struct omap_dss_device *dssdev;
+ struct mgr_priv_data *mp;
u32 irq;
+ unsigned long flags;
int r;
int i;
if (!ovl->manager)
return 0;
- dssdev = ovl->manager->device;
+ mp = get_mgr_priv(ovl->manager);
+
+ spin_lock_irqsave(&data_lock, flags);
- if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+ if (ovl_manual_update(ovl)) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
- if (ovl_manual_update(ovl))
+ if (!mp->enabled) {
+ spin_unlock_irqrestore(&data_lock, flags);
return 0;
+ }
+
+ spin_unlock_irqrestore(&data_lock, flags);
r = dispc_runtime_get();
if (r)
@@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
op = get_ovl_priv(ovl);
i = 0;
while (1) {
- unsigned long flags;
bool shadow_dirty, dirty;
spin_lock_irqsave(&data_lock, flags);
@@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl)
replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
- r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings);
+ r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
if (r) {
/*
* We can't do much here, as this function can be called from
@@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
mp->shadow_extra_info_dirty = true;
}
-static void dss_write_regs_common(void)
-{
- const int num_mgrs = omap_dss_get_num_overlay_managers();
- int i;
-
- if (!dss_data.fifo_merge_dirty)
- return;
-
- for (i = 0; i < num_mgrs; ++i) {
- struct omap_overlay_manager *mgr;
- struct mgr_priv_data *mp;
-
- mgr = omap_dss_get_overlay_manager(i);
- mp = get_mgr_priv(mgr);
-
- if (mp->enabled) {
- if (dss_data.fifo_merge_dirty) {
- dispc_enable_fifomerge(dss_data.fifo_merge);
- dss_data.fifo_merge_dirty = false;
- }
-
- if (mp->updating)
- mp->shadow_info_dirty = true;
- }
- }
-}
-
static void dss_write_regs(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
int i;
- dss_write_regs_common();
-
for (i = 0; i < num_mgrs; ++i) {
struct omap_overlay_manager *mgr;
struct mgr_priv_data *mp;
@@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr)
dss_mgr_write_regs(mgr);
dss_mgr_write_regs_extra(mgr);
- dss_write_regs_common();
-
mp->updating = true;
if (!dss_data.irq_enabled && need_isr())
@@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
op->extra_info_dirty = true;
}
-static void dss_apply_fifo_merge(bool use_fifo_merge)
-{
- if (dss_data.fifo_merge == use_fifo_merge)
- return;
-
- dss_data.fifo_merge = use_fifo_merge;
- dss_data.fifo_merge_dirty = true;
-}
-
-static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
- bool use_fifo_merge)
+static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
u32 fifo_low, fifo_high;
+ bool use_fifo_merge = false;
if (!op->enabled && !op->enabling)
return;
@@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl,
dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
}
-static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
- bool use_fifo_merge)
+static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
{
struct omap_overlay *ovl;
struct mgr_priv_data *mp;
@@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr,
return;
list_for_each_entry(ovl, &mgr->overlays, list)
- dss_ovl_setup_fifo(ovl, use_fifo_merge);
-}
-
-static void dss_setup_fifos(bool use_fifo_merge)
-{
- const int num_mgrs = omap_dss_get_num_overlay_managers();
- struct omap_overlay_manager *mgr;
- int i;
-
- for (i = 0; i < num_mgrs; ++i) {
- mgr = omap_dss_get_overlay_manager(i);
- dss_mgr_setup_fifos(mgr, use_fifo_merge);
- }
+ dss_ovl_setup_fifo(ovl);
}
-static int get_num_used_managers(void)
+static void dss_setup_fifos(void)
{
const int num_mgrs = omap_dss_get_num_overlay_managers();
struct omap_overlay_manager *mgr;
- struct mgr_priv_data *mp;
int i;
- int enabled_mgrs;
-
- enabled_mgrs = 0;
for (i = 0; i < num_mgrs; ++i) {
mgr = omap_dss_get_overlay_manager(i);
- mp = get_mgr_priv(mgr);
-
- if (!mp->enabled)
- continue;
-
- enabled_mgrs++;
+ dss_mgr_setup_fifos(mgr);
}
-
- return enabled_mgrs;
-}
-
-static int get_num_used_overlays(void)
-{
- const int num_ovls = omap_dss_get_num_overlays();
- struct omap_overlay *ovl;
- struct ovl_priv_data *op;
- struct mgr_priv_data *mp;
- int i;
- int enabled_ovls;
-
- enabled_ovls = 0;
-
- for (i = 0; i < num_ovls; ++i) {
- ovl = omap_dss_get_overlay(i);
- op = get_ovl_priv(ovl);
-
- if (!op->enabled && !op->enabling)
- continue;
-
- mp = get_mgr_priv(ovl->manager);
-
- if (!mp->enabled)
- continue;
-
- enabled_ovls++;
- }
-
- return enabled_ovls;
-}
-
-static bool get_use_fifo_merge(void)
-{
- int enabled_mgrs = get_num_used_managers();
- int enabled_ovls = get_num_used_overlays();
-
- if (!dss_has_feature(FEAT_FIFO_MERGE))
- return false;
-
- /*
- * In theory the only requirement for fifomerge is enabled_ovls <= 1.
- * However, if we have two managers enabled and set/unset the fifomerge,
- * we need to set the GO bits in particular sequence for the managers,
- * and wait in between.
- *
- * This is rather difficult as new apply calls can happen at any time,
- * so we simplify the problem by requiring also that enabled_mgrs <= 1.
- * In practice this shouldn't matter, because when only one overlay is
- * enabled, most likely only one output is enabled.
- */
-
- return enabled_mgrs <= 1 && enabled_ovls <= 1;
}
int dss_mgr_enable(struct omap_overlay_manager *mgr)
@@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
int r;
- bool fifo_merge;
mutex_lock(&apply_lock);
@@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr)
goto err;
}
- /* step 1: setup fifos/fifomerge before enabling the manager */
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
+ dss_setup_fifos();
dss_write_regs();
dss_set_go_bits();
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait until fifo config is in */
- wait_pending_extra_info_updates();
-
- /* step 2: enable the manager */
- spin_lock_irqsave(&data_lock, flags);
-
if (!mgr_manual_update(mgr))
mp->updating = true;
@@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
unsigned long flags;
- bool fifo_merge;
mutex_lock(&apply_lock);
@@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr)
mp->updating = false;
mp->enabled = false;
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
spin_unlock_irqrestore(&data_lock, flags);
- wait_pending_extra_info_updates();
out:
mutex_unlock(&apply_lock);
}
@@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
spin_unlock_irqrestore(&data_lock, flags);
}
-int dss_mgr_set_device(struct omap_overlay_manager *mgr,
- struct omap_dss_device *dssdev)
+int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *output)
{
int r;
mutex_lock(&apply_lock);
- if (dssdev->manager) {
- DSSERR("display '%s' already has a manager '%s'\n",
- dssdev->name, dssdev->manager->name);
+ if (mgr->output) {
+ DSSERR("manager %s is already connected to an output\n",
+ mgr->name);
r = -EINVAL;
goto err;
}
- if ((mgr->supported_displays & dssdev->type) == 0) {
- DSSERR("display '%s' does not support manager '%s'\n",
- dssdev->name, mgr->name);
+ if ((mgr->supported_outputs & output->id) == 0) {
+ DSSERR("output does not support manager %s\n",
+ mgr->name);
r = -EINVAL;
goto err;
}
- dssdev->manager = mgr;
- mgr->device = dssdev;
+ output->manager = mgr;
+ mgr->output = output;
mutex_unlock(&apply_lock);
@@ -1269,40 +1142,46 @@ err:
return r;
}
-int dss_mgr_unset_device(struct omap_overlay_manager *mgr)
+int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
{
int r;
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
+ unsigned long flags;
mutex_lock(&apply_lock);
- if (!mgr->device) {
- DSSERR("failed to unset display, display not set.\n");
+ if (!mgr->output) {
+ DSSERR("failed to unset output, output not set\n");
r = -EINVAL;
goto err;
}
- /*
- * Don't allow currently enabled displays to have the overlay manager
- * pulled out from underneath them
- */
- if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+ spin_lock_irqsave(&data_lock, flags);
+
+ if (mp->enabled) {
+ DSSERR("output can't be unset when manager is enabled\n");
r = -EINVAL;
- goto err;
+ goto err1;
}
- mgr->device->manager = NULL;
- mgr->device = NULL;
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ mgr->output->manager = NULL;
+ mgr->output = NULL;
mutex_unlock(&apply_lock);
return 0;
+err1:
+ spin_unlock_irqrestore(&data_lock, flags);
err:
mutex_unlock(&apply_lock);
+
return r;
}
static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings)
+ const struct omap_video_timings *timings)
{
struct mgr_priv_data *mp = get_mgr_priv(mgr);
@@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
}
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings)
+ const struct omap_video_timings *timings)
{
unsigned long flags;
-
- mutex_lock(&apply_lock);
+ struct mgr_priv_data *mp = get_mgr_priv(mgr);
spin_lock_irqsave(&data_lock, flags);
- dss_apply_mgr_timings(mgr, timings);
-
- dss_write_regs();
- dss_set_go_bits();
+ if (mp->updating) {
+ DSSERR("cannot set timings for %s: manager needs to be disabled\n",
+ mgr->name);
+ goto out;
+ }
+ dss_apply_mgr_timings(mgr, timings);
+out:
spin_unlock_irqrestore(&data_lock, flags);
-
- wait_pending_extra_info_updates();
-
- mutex_unlock(&apply_lock);
}
static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
@@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
unsigned long flags;
struct mgr_priv_data *mp = get_mgr_priv(mgr);
- mutex_lock(&apply_lock);
+ spin_lock_irqsave(&data_lock, flags);
if (mp->enabled) {
DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
@@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
goto out;
}
- spin_lock_irqsave(&data_lock, flags);
-
dss_apply_mgr_lcd_config(mgr, config);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- wait_pending_extra_info_updates();
-
out:
- mutex_unlock(&apply_lock);
+ spin_unlock_irqrestore(&data_lock, flags);
}
int dss_ovl_set_info(struct omap_overlay *ovl,
@@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl)
goto err;
}
+ spin_unlock_irqrestore(&data_lock, flags);
+
+ /* wait for pending extra_info updates to ensure the ovl is disabled */
+ wait_pending_extra_info_updates();
+
+ spin_lock_irqsave(&data_lock, flags);
+
op->channel = -1;
ovl->manager = NULL;
@@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
- bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err1;
}
- if (ovl->manager == NULL || ovl->manager->device == NULL) {
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err1;
}
@@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl)
goto err2;
}
- /* step 1: configure fifos/fifomerge for currently enabled ovls */
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait for fifo configs to go in */
- wait_pending_extra_info_updates();
-
- /* step 2: enable the overlay */
- spin_lock_irqsave(&data_lock, flags);
+ dss_setup_fifos();
op->enabling = false;
dss_apply_ovl_enable(ovl, true);
@@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl)
spin_unlock_irqrestore(&data_lock, flags);
- /* wait for overlay to be enabled */
- wait_pending_extra_info_updates();
-
mutex_unlock(&apply_lock);
return 0;
@@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl)
{
struct ovl_priv_data *op = get_ovl_priv(ovl);
unsigned long flags;
- bool fifo_merge;
int r;
mutex_lock(&apply_lock);
@@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl)
goto err;
}
- if (ovl->manager == NULL || ovl->manager->device == NULL) {
+ if (ovl->manager == NULL || ovl->manager->output == NULL) {
r = -EINVAL;
goto err;
}
- /* step 1: disable the overlay */
spin_lock_irqsave(&data_lock, flags);
dss_apply_ovl_enable(ovl, false);
-
dss_write_regs();
dss_set_go_bits();
spin_unlock_irqrestore(&data_lock, flags);
- /* wait for the overlay to be disabled */
- wait_pending_extra_info_updates();
-
- /* step 2: configure fifos/fifomerge */
- spin_lock_irqsave(&data_lock, flags);
-
- fifo_merge = get_use_fifo_merge();
- dss_setup_fifos(fifo_merge);
- dss_apply_fifo_merge(fifo_merge);
-
- dss_write_regs();
- dss_set_go_bits();
-
- spin_unlock_irqrestore(&data_lock, flags);
-
- /* wait for fifo config to go in */
- wait_pending_extra_info_updates();
-
mutex_unlock(&apply_lock);
return 0;
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 58bd9c27369..b2af72dc20b 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
+#include <linux/slab.h>
#include <video/omapdss.h>
@@ -57,6 +58,11 @@ bool dss_debug;
module_param_named(debug, dss_debug, bool, 0644);
#endif
+const char *dss_get_default_display_name(void)
+{
+ return core.default_display_name;
+}
+
/* REGULATORS */
struct regulator *dss_get_vdds_dsi(void)
@@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev)
int r;
struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
struct omap_dss_device *dssdev = to_dss_device(dev);
- bool force;
DSSDBG("driver_probe: dev %s/%s, drv %s\n",
dev_name(dev), dssdev->driver_name,
dssdrv->driver.name);
- dss_init_device(core.pdev, dssdev);
-
- force = core.default_display_name &&
- strcmp(core.default_display_name, dssdev->name) == 0;
- dss_recheck_connections(dssdev, force);
+ r = dss_init_device(core.pdev, dssdev);
+ if (r)
+ return r;
r = dssdrv->probe(dssdev);
@@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
EXPORT_SYMBOL(omap_dss_unregister_driver);
/* DEVICE */
-static void reset_device(struct device *dev, int check)
-{
- u8 *dev_p = (u8 *)dev;
- u8 *dev_end = dev_p + sizeof(*dev);
- void *saved_pdata;
-
- saved_pdata = dev->platform_data;
- if (check) {
- /*
- * Check if there is any other setting than platform_data
- * in struct device; warn that these will be reset by our
- * init.
- */
- dev->platform_data = NULL;
- while (dev_p < dev_end) {
- if (*dev_p) {
- WARN("%s: struct device fields will be "
- "discarded\n",
- __func__);
- break;
- }
- dev_p++;
- }
- }
- memset(dev, 0, sizeof(*dev));
- dev->platform_data = saved_pdata;
-}
-
static void omap_dss_dev_release(struct device *dev)
{
- reset_device(dev, 0);
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ kfree(dssdev);
}
-int omap_dss_register_device(struct omap_dss_device *dssdev,
- struct device *parent, int disp_num)
+static int disp_num_counter;
+
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent)
{
- WARN_ON(!dssdev->driver_name);
+ struct omap_dss_device *dssdev;
+
+ dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL);
+ if (!dssdev)
+ return NULL;
- reset_device(&dssdev->dev, 1);
dssdev->dev.bus = &dss_bus_type;
dssdev->dev.parent = parent;
dssdev->dev.release = omap_dss_dev_release;
- dev_set_name(&dssdev->dev, "display%d", disp_num);
- return device_register(&dssdev->dev);
+ dev_set_name(&dssdev->dev, "display%d", disp_num_counter++);
+
+ device_initialize(&dssdev->dev);
+
+ return dssdev;
+}
+
+int dss_add_device(struct omap_dss_device *dssdev)
+{
+ return device_add(&dssdev->dev);
+}
+
+void dss_put_device(struct omap_dss_device *dssdev)
+{
+ put_device(&dssdev->dev);
}
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+void dss_unregister_device(struct omap_dss_device *dssdev)
{
device_unregister(&dssdev->dev);
}
@@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev)
static int dss_unregister_dss_dev(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- omap_dss_unregister_device(dssdev);
+ dss_unregister_device(dssdev);
return 0;
}
-void omap_dss_unregister_child_devices(struct device *parent)
+void dss_unregister_child_devices(struct device *parent)
{
device_for_each_child(parent, NULL, dss_unregister_dss_dev);
}
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+ const struct omap_dss_device *src)
+{
+ u8 *d = (u8 *)dst;
+ u8 *s = (u8 *)src;
+ size_t dsize = sizeof(struct device);
+
+ memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize);
+}
+
/* BUS */
static int __init omap_dss_bus_register(void)
{
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index ee9e29639dc..b43477a5fae 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -38,7 +38,6 @@
#include <linux/pm_runtime.h>
#include <plat/cpu.h>
-#include <plat/clock.h>
#include <video/omapdss.h>
@@ -82,6 +81,30 @@ struct dispc_irq_stats {
unsigned irqs[32];
};
+struct dispc_features {
+ u8 sw_start;
+ u8 fp_start;
+ u8 bp_start;
+ u16 sw_max;
+ u16 vp_max;
+ u16 hp_max;
+ int (*calc_scaling) (enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
+ unsigned long (*calc_core_clk) (enum omap_plane plane,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ bool mem_to_mem);
+ u8 num_fifos;
+
+ /* swap GFX & WB fifos */
+ bool gfx_fifo_workaround:1;
+};
+
+#define DISPC_MAX_NR_FIFOS 5
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -91,7 +114,9 @@ static struct {
int irq;
struct clk *dss_clk;
- u32 fifo_size[MAX_DSS_OVERLAYS];
+ 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];
spinlock_t irq_lock;
u32 irq_error_mask;
@@ -102,6 +127,8 @@ static struct {
bool ctx_valid;
u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
+ const struct dispc_features *feat;
+
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock;
struct dispc_irq_stats irq_stats;
@@ -211,7 +238,14 @@ static const struct {
},
};
+struct color_conv_coef {
+ int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
+ int full_range;
+};
+
static void _omap_dispc_set_irqs(void);
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
static inline void dispc_write_reg(const u16 idx, u32 val)
{
@@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
return mgr_desc[channel].framedone_irq;
}
+u32 dispc_wb_get_framedone_irq(void)
+{
+ return DISPC_IRQ_FRAMEDONEWB;
+}
+
bool dispc_mgr_go_busy(enum omap_channel channel)
{
return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
@@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel)
mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
}
+bool dispc_wb_go_busy(void)
+{
+ return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+}
+
+void dispc_wb_go(void)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+ bool enable, go;
+
+ enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
+
+ if (!enable)
+ return;
+
+ go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
+ if (go) {
+ DSSERR("GO bit not down for WB\n");
+ return;
+ }
+
+ REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
+}
+
static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
{
dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
@@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
}
}
-static void _dispc_setup_color_conv_coef(void)
-{
- int i;
- const struct color_conv_coef {
- int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
- int full_range;
- } ctbl_bt601_5 = {
- 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
- };
-
- const struct color_conv_coef *ct;
+static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
+ const struct color_conv_coef *ct)
+{
#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
- ct = &ctbl_bt601_5;
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
+ dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
- for (i = 1; i < dss_feat_get_num_ovls(); i++) {
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0),
- CVAL(ct->rcr, ct->ry));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1),
- CVAL(ct->gy, ct->rcb));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2),
- CVAL(ct->gcb, ct->gcr));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3),
- CVAL(ct->bcr, ct->by));
- dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4),
- CVAL(0, ct->bcb));
-
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range,
- 11, 11);
- }
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
#undef CVAL
}
+static void dispc_setup_color_conv_coef(void)
+{
+ int i;
+ int num_ovl = dss_feat_get_num_ovls();
+ int num_wb = dss_feat_get_num_wbs();
+ const struct color_conv_coef ctbl_bt601_5_ovl = {
+ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
+ };
+ const struct color_conv_coef ctbl_bt601_5_wb = {
+ 66, 112, -38, 129, -94, -74, 25, -18, 112, 0,
+ };
+
+ for (i = 1; i < num_ovl; i++)
+ dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
+
+ for (; i < num_wb; i++)
+ dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb);
+}
static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
{
@@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
}
-static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y)
+static void dispc_ovl_set_pos(enum omap_plane plane,
+ enum omap_overlay_caps caps, int x, int y)
{
- u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
+ u32 val;
+
+ if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
+ return;
+
+ val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
dispc_write_reg(DISPC_OVL_POSITION(plane), val);
}
-static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
+ int height)
{
u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
- if (plane == OMAP_DSS_GFX)
+ if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
dispc_write_reg(DISPC_OVL_SIZE(plane), val);
else
dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
}
-static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
+static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
+ int height)
{
u32 val;
@@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
- dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+ if (plane == OMAP_DSS_WB)
+ dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
+ else
+ dispc_write_reg(DISPC_OVL_SIZE(plane), val);
}
-static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
+static void dispc_ovl_set_zorder(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 zorder)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
return;
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
@@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void)
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
}
-static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
+static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
return;
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
}
-static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
+static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
+ enum omap_overlay_caps caps, u8 global_alpha)
{
static const unsigned shifts[] = { 0, 8, 16, 24, };
int shift;
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
return;
shift = shifts[plane];
@@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
return channel;
}
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
+}
+
static void dispc_ovl_set_burst_size(enum omap_plane plane,
enum omap_burst_size burst_size)
{
- static const unsigned shifts[] = { 6, 14, 14, 14, };
+ static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
int shift;
shift = shifts[plane];
@@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
}
-static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
+static void dispc_ovl_enable_replication(enum omap_plane plane,
+ enum omap_overlay_caps caps, bool enable)
{
static const unsigned shifts[] = { 5, 10, 10, 10 };
int shift;
+ if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
+ return;
+
shift = shifts[plane];
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
}
@@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
dispc_write_reg(DISPC_SIZE_MGR(channel), val);
}
-static void dispc_read_plane_fifo_sizes(void)
+static void dispc_init_fifos(void)
{
u32 size;
- int plane;
+ int fifo;
u8 start, end;
u32 unit;
@@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void)
dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
- for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) {
- size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
size *= unit;
- dispc.fifo_size[plane] = size;
+ dispc.fifo_size[fifo] = size;
+
+ /*
+ * By default fifos are mapped directly to overlays, fifo 0 to
+ * ovl 0, fifo 1 to ovl 1, etc.
+ */
+ dispc.fifo_assignment[fifo] = fifo;
+ }
+
+ /*
+ * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
+ * causes problems with certain use cases, like using the tiler in 2D
+ * mode. The below hack swaps the fifos of GFX and WB planes, thus
+ * giving GFX plane a larger fifo. WB but should work fine with a
+ * smaller fifo.
+ */
+ if (dispc.feat->gfx_fifo_workaround) {
+ u32 v;
+
+ v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
+
+ v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
+ v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
+ v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
+ v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
+
+ dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
+
+ dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
+ dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
}
}
static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
{
- return dispc.fifo_size[plane];
+ int fifo;
+ u32 size = 0;
+
+ for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
+ if (dispc.fifo_assignment[fifo] == plane)
+ size += dispc.fifo_size[fifo];
+ }
+
+ return size;
}
void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
@@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
*fifo_low = ovl_fifo_size - burst_size * 2;
*fifo_high = total_fifo_size - burst_size;
+ } else if (plane == OMAP_DSS_WB) {
+ /*
+ * Most optimal configuration for writeback is to push out data
+ * to the interconnect the moment writeback pushes enough pixels
+ * in the FIFO to form a burst
+ */
+ *fifo_low = 0;
+ *fifo_high = burst_size;
} else {
*fifo_low = ovl_fifo_size - burst_size;
*fifo_high = total_fifo_size - buf_unit;
@@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
{
int scale_x = out_width != orig_width;
int scale_y = out_height != orig_height;
+ bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
return;
@@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
color_mode != OMAP_DSS_COLOR_UYVY &&
color_mode != OMAP_DSS_COLOR_NV12)) {
/* reset chroma resampling for RGB formats */
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
+ if (plane != OMAP_DSS_WB)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
return;
}
@@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
switch (color_mode) {
case OMAP_DSS_COLOR_NV12:
- /* UV is subsampled by 2 vertically*/
- orig_height >>= 1;
- /* UV is subsampled by 2 horz.*/
- orig_width >>= 1;
+ if (chroma_upscale) {
+ /* UV is subsampled by 2 horizontally and vertically */
+ orig_height >>= 1;
+ orig_width >>= 1;
+ } else {
+ /* UV is downsampled by 2 horizontally and vertically */
+ orig_height <<= 1;
+ orig_width <<= 1;
+ }
+
break;
case OMAP_DSS_COLOR_YUV2:
case OMAP_DSS_COLOR_UYVY:
- /*For YUV422 with 90/270 rotation,
- *we don't upsample chroma
- */
+ /* For YUV422 with 90/270 rotation, we don't upsample chroma */
if (rotation == OMAP_DSS_ROT_0 ||
- rotation == OMAP_DSS_ROT_180)
- /* UV is subsampled by 2 hrz*/
- orig_width >>= 1;
+ rotation == OMAP_DSS_ROT_180) {
+ if (chroma_upscale)
+ /* UV is subsampled by 2 horizontally */
+ orig_width >>= 1;
+ else
+ /* UV is downsampled by 2 horizontally */
+ orig_width <<= 1;
+ }
+
/* must use FIR for YUV422 if rotated */
if (rotation != OMAP_DSS_ROT_0)
scale_x = scale_y = true;
+
break;
default:
BUG();
@@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
out_width, out_height, five_taps,
rotation, DISPC_COLOR_COMPONENT_UV);
- REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
- (scale_x || scale_y) ? 1 : 0, 8, 8);
+ if (plane != OMAP_DSS_WB)
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
+ (scale_x || scale_y) ? 1 : 0, 8, 8);
+
/* set H scaling */
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
/* set V scaling */
@@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
* This function is used to avoid synclosts in OMAP3, because of some
* undocumented horizontal position and timing related limitations.
*/
-static int check_horiz_timing_omap3(enum omap_channel channel,
+static int check_horiz_timing_omap3(enum omap_plane plane,
const struct omap_video_timings *t, u16 pos_x,
u16 width, u16 height, u16 out_width, u16 out_height)
{
int DS = DIV_ROUND_UP(height, out_height);
- unsigned long nonactive, lclk, pclk;
+ unsigned long nonactive;
static const u8 limits[3] = { 8, 10, 20 };
u64 val, blank;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ unsigned long lclk = dispc_plane_lclk_rate(plane);
int i;
nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
- pclk = dispc_mgr_pclk_rate(channel);
- if (dss_mgr_is_lcd(channel))
- lclk = dispc_mgr_lclk_rate(channel);
- else
- lclk = dispc_fclk_rate();
i = 0;
if (out_height < height)
@@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel,
return 0;
}
-static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
+static unsigned long calc_core_clk_five_taps(enum omap_plane plane,
const struct omap_video_timings *mgr_timings, u16 width,
u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode)
{
u32 core_clk = 0;
- u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
+ u64 tmp;
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
if (height <= out_height && width <= out_width)
return (unsigned long) pclk;
@@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
return core_clk;
}
-static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
- u16 height, u16 out_width, u16 out_height)
+static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+
+ if (height > out_height && width > out_width)
+ return pclk * 4;
+ else
+ return pclk * 2;
+}
+
+static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
{
unsigned int hf, vf;
- unsigned long pclk = dispc_mgr_pclk_rate(channel);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
/*
* FIXME how to determine the 'A' factor
@@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width,
hf = 2;
else
hf = 1;
-
if (height > out_height)
vf = 2;
else
vf = 1;
- if (cpu_is_omap24xx()) {
- if (vf > 1 && hf > 1)
- return pclk * 4;
- else
- return pclk * 2;
- } else if (cpu_is_omap34xx()) {
- return pclk * vf * hf;
- } else {
- if (hf > 1)
- return DIV_ROUND_UP(pclk, out_width) * width;
- else
- return pclk;
+ return pclk * vf * hf;
+}
+
+static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width,
+ u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
+{
+ unsigned long pclk;
+
+ /*
+ * If the overlay/writeback is in mem to mem mode, there are no
+ * downscaling limitations with respect to pixel clock, return 1 as
+ * required core clock to represent that we have sufficient enough
+ * core clock to do maximum downscaling
+ */
+ if (mem_to_mem)
+ return 1;
+
+ pclk = dispc_plane_pclk_rate(plane);
+
+ if (width > out_width)
+ return DIV_ROUND_UP(pclk, out_width) * width;
+ else
+ return pclk;
+}
+
+static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ *five_taps = false;
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ in_height, out_width, out_height, mem_to_mem);
+ error = (in_width > maxsinglelinewidth || !*core_clk ||
+ *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x == *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale max input width exceeded");
+ return -EINVAL;
}
+ return 0;
}
-static int dispc_ovl_calc_scaling(enum omap_plane plane,
- enum omap_channel channel,
+static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane,
const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height,
enum omap_color_mode color_mode, bool *five_taps,
- int *x_predecim, int *y_predecim, u16 pos_x)
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
- const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+ int error;
+ u16 in_width, in_height;
+ int min_factor = min(*decim_x, *decim_y);
+ const int maxsinglelinewidth =
+ dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+
+ do {
+ in_height = DIV_ROUND_UP(height, *decim_y);
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ *core_clk = calc_core_clk_five_taps(plane, mgr_timings,
+ in_width, in_height, out_width, out_height, color_mode);
+
+ error = check_horiz_timing_omap3(plane, mgr_timings,
+ pos_x, in_width, in_height, out_width,
+ out_height);
+
+ if (in_width > maxsinglelinewidth)
+ if (in_height > out_height &&
+ in_height < out_height * 2)
+ *five_taps = false;
+ if (!*five_taps)
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width,
+ in_height, out_width, out_height,
+ mem_to_mem);
+
+ error = (error || in_width > maxsinglelinewidth * 2 ||
+ (in_width > maxsinglelinewidth && *five_taps) ||
+ !*core_clk || *core_clk > dispc_core_clk_rate());
+ if (error) {
+ if (*decim_x == *decim_y) {
+ *decim_x = min_factor;
+ ++*decim_y;
+ } else {
+ swap(*decim_x, *decim_y);
+ if (*decim_x < *decim_y)
+ ++*decim_x;
+ }
+ }
+ } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
+
+ if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height,
+ out_width, out_height)){
+ DSSERR("horizontal timing too tight\n");
+ return -EINVAL;
+ }
+
+ if (in_width > (maxsinglelinewidth * 2)) {
+ DSSERR("Cannot setup scaling");
+ DSSERR("width exceeds maximum width possible");
+ return -EINVAL;
+ }
+
+ if (in_width > maxsinglelinewidth && *five_taps) {
+ DSSERR("cannot setup scaling with five taps");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
+ u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
+{
+ u16 in_width, in_width_max;
+ int decim_x_min = *decim_x;
+ u16 in_height = DIV_ROUND_UP(height, *decim_y);
const int maxsinglelinewidth =
dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
+ unsigned long pclk = dispc_plane_pclk_rate(plane);
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
+
+ if (mem_to_mem)
+ in_width_max = DIV_ROUND_UP(out_width, maxdownscale);
+ else
+ in_width_max = dispc_core_clk_rate() /
+ DIV_ROUND_UP(pclk, out_width);
+
+ *decim_x = DIV_ROUND_UP(width, in_width_max);
+
+ *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
+ if (*decim_x > *x_predecim)
+ return -EINVAL;
+
+ do {
+ in_width = DIV_ROUND_UP(width, *decim_x);
+ } while (*decim_x <= *x_predecim &&
+ in_width > maxsinglelinewidth && ++*decim_x);
+
+ if (in_width > maxsinglelinewidth) {
+ DSSERR("Cannot scale width exceeds max line width");
+ return -EINVAL;
+ }
+
+ *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height,
+ out_width, out_height, mem_to_mem);
+ return 0;
+}
+
+static int dispc_ovl_calc_scaling(enum omap_plane plane,
+ enum omap_overlay_caps caps,
+ const struct omap_video_timings *mgr_timings,
+ u16 width, u16 height, u16 out_width, u16 out_height,
+ enum omap_color_mode color_mode, bool *five_taps,
+ int *x_predecim, int *y_predecim, u16 pos_x,
+ enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
+{
+ const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
const int max_decim_limit = 16;
unsigned long core_clk = 0;
- int decim_x, decim_y, error, min_factor;
- u16 in_width, in_height, in_width_max = 0;
+ int decim_x, decim_y, ret;
if (width == out_width && height == out_height)
return 0;
- if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
+ if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
return -EINVAL;
*x_predecim = max_decim_limit;
- *y_predecim = max_decim_limit;
+ *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
+ dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit;
if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
color_mode == OMAP_DSS_COLOR_CLUT2 ||
@@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
- min_factor = min(decim_x, decim_y);
-
if (decim_x > *x_predecim || out_width > width * 8)
return -EINVAL;
if (decim_y > *y_predecim || out_height > height * 8)
return -EINVAL;
- if (cpu_is_omap24xx()) {
- *five_taps = false;
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- error = (in_width > maxsinglelinewidth || !core_clk ||
- core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x == decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim &&
- error);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale max input width exceeded");
- return -EINVAL;
- }
- } else if (cpu_is_omap34xx()) {
-
- do {
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width = DIV_ROUND_UP(width, decim_x);
- core_clk = calc_core_clk_five_taps(channel, mgr_timings,
- in_width, in_height, out_width, out_height,
- color_mode);
-
- error = check_horiz_timing_omap3(channel, mgr_timings,
- pos_x, in_width, in_height, out_width,
- out_height);
-
- if (in_width > maxsinglelinewidth)
- if (in_height > out_height &&
- in_height < out_height * 2)
- *five_taps = false;
- if (!*five_taps)
- core_clk = calc_core_clk(channel, in_width,
- in_height, out_width, out_height);
- error = (error || in_width > maxsinglelinewidth * 2 ||
- (in_width > maxsinglelinewidth && *five_taps) ||
- !core_clk || core_clk > dispc_core_clk_rate());
- if (error) {
- if (decim_x == decim_y) {
- decim_x = min_factor;
- decim_y++;
- } else {
- swap(decim_x, decim_y);
- if (decim_x < decim_y)
- decim_x++;
- }
- }
- } while (decim_x <= *x_predecim && decim_y <= *y_predecim
- && error);
-
- if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width,
- height, out_width, out_height)){
- DSSERR("horizontal timing too tight\n");
- return -EINVAL;
- }
-
- if (in_width > (maxsinglelinewidth * 2)) {
- DSSERR("Cannot setup scaling");
- DSSERR("width exceeds maximum width possible");
- return -EINVAL;
- }
-
- if (in_width > maxsinglelinewidth && *five_taps) {
- DSSERR("cannot setup scaling with five taps");
- return -EINVAL;
- }
- } else {
- int decim_x_min = decim_x;
- in_height = DIV_ROUND_UP(height, decim_y);
- in_width_max = dispc_core_clk_rate() /
- DIV_ROUND_UP(dispc_mgr_pclk_rate(channel),
- out_width);
- decim_x = DIV_ROUND_UP(width, in_width_max);
-
- decim_x = decim_x > decim_x_min ? decim_x : decim_x_min;
- if (decim_x > *x_predecim)
- return -EINVAL;
-
- do {
- in_width = DIV_ROUND_UP(width, decim_x);
- } while (decim_x <= *x_predecim &&
- in_width > maxsinglelinewidth && decim_x++);
-
- if (in_width > maxsinglelinewidth) {
- DSSERR("Cannot scale width exceeds max line width");
- return -EINVAL;
- }
-
- core_clk = calc_core_clk(channel, in_width, in_height,
- out_width, out_height);
- }
+ ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height,
+ out_width, out_height, color_mode, five_taps,
+ x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
+ mem_to_mem);
+ if (ret)
+ return ret;
DSSDBG("required core clk rate = %lu Hz\n", core_clk);
DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
@@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane,
return 0;
}
-int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
- bool replication, const struct omap_video_timings *mgr_timings)
+static int dispc_ovl_setup_common(enum omap_plane plane,
+ enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
+ u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
+ u16 out_width, u16 out_height, enum omap_color_mode color_mode,
+ u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
+ u8 global_alpha, enum omap_dss_rotation_type rotation_type,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
{
- struct omap_overlay *ovl = omap_dss_get_overlay(plane);
bool five_taps = true;
bool fieldmode = 0;
int r, cconv = 0;
unsigned offset0, offset1;
s32 row_inc;
s32 pix_inc;
- u16 frame_height = oi->height;
+ u16 frame_height = height;
unsigned int field_offset = 0;
- u16 in_height = oi->height;
- u16 in_width = oi->width;
- u16 out_width, out_height;
- enum omap_channel channel;
+ u16 in_height = height;
+ u16 in_width = width;
int x_predecim = 1, y_predecim = 1;
bool ilace = mgr_timings->interlace;
- channel = dispc_ovl_get_channel_out(plane);
-
- DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
- "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
- plane, oi->paddr, oi->p_uv_addr,
- oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
- oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
- oi->mirror, ilace, channel, replication);
-
- if (oi->paddr == 0)
+ if (paddr == 0)
return -EINVAL;
- out_width = oi->out_width == 0 ? oi->width : oi->out_width;
- out_height = oi->out_height == 0 ? oi->height : oi->out_height;
+ out_width = out_width == 0 ? width : out_width;
+ out_height = out_height == 0 ? height : out_height;
- if (ilace && oi->height == out_height)
+ if (ilace && height == out_height)
fieldmode = 1;
if (ilace) {
if (fieldmode)
in_height /= 2;
- oi->pos_y /= 2;
+ pos_y /= 2;
out_height /= 2;
DSSDBG("adjusting for ilace: height %d, pos_y %d, "
- "out_height %d\n",
- in_height, oi->pos_y, out_height);
+ "out_height %d\n", in_height, pos_y,
+ out_height);
}
- if (!dss_feat_color_mode_supported(plane, oi->color_mode))
+ if (!dss_feat_color_mode_supported(plane, color_mode))
return -EINVAL;
- r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width,
- in_height, out_width, out_height, oi->color_mode,
- &five_taps, &x_predecim, &y_predecim, oi->pos_x);
+ r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width,
+ in_height, out_width, out_height, color_mode,
+ &five_taps, &x_predecim, &y_predecim, pos_x,
+ rotation_type, mem_to_mem);
if (r)
return r;
in_width = DIV_ROUND_UP(in_width, x_predecim);
in_height = DIV_ROUND_UP(in_height, y_predecim);
- if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
- oi->color_mode == OMAP_DSS_COLOR_UYVY ||
- oi->color_mode == OMAP_DSS_COLOR_NV12)
+ if (color_mode == OMAP_DSS_COLOR_YUV2 ||
+ color_mode == OMAP_DSS_COLOR_UYVY ||
+ color_mode == OMAP_DSS_COLOR_NV12)
cconv = 1;
if (ilace && !fieldmode) {
@@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
row_inc = 0;
pix_inc = 0;
- if (oi->rotation_type == OMAP_DSS_ROT_TILER)
- calc_tiler_rotation_offset(oi->screen_width, in_width,
- oi->color_mode, fieldmode, field_offset,
+ if (rotation_type == OMAP_DSS_ROT_TILER)
+ calc_tiler_rotation_offset(screen_width, in_width,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
- else if (oi->rotation_type == OMAP_DSS_ROT_DMA)
- calc_dma_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, in_width, frame_height,
- oi->color_mode, fieldmode, field_offset,
+ else if (rotation_type == OMAP_DSS_ROT_DMA)
+ calc_dma_rotation_offset(rotation, mirror,
+ screen_width, in_width, frame_height,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
else
- calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
- oi->screen_width, in_width, frame_height,
- oi->color_mode, fieldmode, field_offset,
+ calc_vrfb_rotation_offset(rotation, mirror,
+ screen_width, in_width, frame_height,
+ color_mode, fieldmode, field_offset,
&offset0, &offset1, &row_inc, &pix_inc,
x_predecim, y_predecim);
DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
offset0, offset1, row_inc, pix_inc);
- dispc_ovl_set_color_mode(plane, oi->color_mode);
+ dispc_ovl_set_color_mode(plane, color_mode);
- dispc_ovl_configure_burst_type(plane, oi->rotation_type);
+ dispc_ovl_configure_burst_type(plane, rotation_type);
- dispc_ovl_set_ba0(plane, oi->paddr + offset0);
- dispc_ovl_set_ba1(plane, oi->paddr + offset1);
+ dispc_ovl_set_ba0(plane, paddr + offset0);
+ dispc_ovl_set_ba1(plane, paddr + offset1);
- if (OMAP_DSS_COLOR_NV12 == oi->color_mode) {
- dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0);
- dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1);
+ if (OMAP_DSS_COLOR_NV12 == color_mode) {
+ dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
+ dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
}
-
dispc_ovl_set_row_inc(plane, row_inc);
dispc_ovl_set_pix_inc(plane, pix_inc);
- DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width,
+ DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
in_height, out_width, out_height);
- dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
+ dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
- dispc_ovl_set_pic_size(plane, in_width, in_height);
+ dispc_ovl_set_input_size(plane, in_width, in_height);
- if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
+ if (caps & OMAP_DSS_OVL_CAP_SCALE) {
dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
out_height, ilace, five_taps, fieldmode,
- oi->color_mode, oi->rotation);
- dispc_ovl_set_vid_size(plane, out_width, out_height);
+ color_mode, rotation);
+ dispc_ovl_set_output_size(plane, out_width, out_height);
dispc_ovl_set_vid_color_conv(plane, cconv);
}
- dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
- oi->color_mode);
+ dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode);
- dispc_ovl_set_zorder(plane, oi->zorder);
- dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
- dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
+ dispc_ovl_set_zorder(plane, caps, zorder);
+ dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
+ dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
- dispc_ovl_enable_replication(plane, replication);
+ dispc_ovl_enable_replication(plane, caps, replication);
return 0;
}
+int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem)
+{
+ int r;
+ struct omap_overlay *ovl = omap_dss_get_overlay(plane);
+ enum omap_channel channel;
+
+ channel = dispc_ovl_get_channel_out(plane);
+
+ DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
+ "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
+ plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x,
+ oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
+ oi->color_mode, oi->rotation, oi->mirror, channel, replication);
+
+ r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr,
+ oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
+ oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
+ oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
+ oi->rotation_type, replication, mgr_timings, mem_to_mem);
+
+ return r;
+}
+
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *mgr_timings)
+{
+ int r;
+ u32 l;
+ enum omap_plane plane = OMAP_DSS_WB;
+ const int pos_x = 0, pos_y = 0;
+ const u8 zorder = 0, global_alpha = 0;
+ const bool replication = false;
+ bool truncation;
+ int in_width = mgr_timings->x_res;
+ int in_height = mgr_timings->y_res;
+ enum omap_overlay_caps caps =
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
+
+ DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
+ "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
+ in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
+ wi->mirror);
+
+ r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
+ wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
+ wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
+ wi->pre_mult_alpha, global_alpha, wi->rotation_type,
+ replication, mgr_timings, mem_to_mem);
+
+ switch (wi->color_mode) {
+ case OMAP_DSS_COLOR_RGB16:
+ case OMAP_DSS_COLOR_RGB24P:
+ case OMAP_DSS_COLOR_ARGB16:
+ case OMAP_DSS_COLOR_RGBA16:
+ case OMAP_DSS_COLOR_RGB12U:
+ case OMAP_DSS_COLOR_ARGB16_1555:
+ case OMAP_DSS_COLOR_XRGB16_1555:
+ case OMAP_DSS_COLOR_RGBX16:
+ truncation = true;
+ break;
+ default:
+ truncation = false;
+ break;
+ }
+
+ /* setup extra DISPC_WB_ATTRIBUTES */
+ l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
+ l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
+ l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
+ dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
+
+ return r;
+}
+
int dispc_ovl_enable(enum omap_plane plane, bool enable)
{
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
@@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable)
BUG();
}
+void dispc_wb_enable(bool enable)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+ struct completion frame_done_completion;
+ bool is_on;
+ int r;
+ u32 irq;
+
+ is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+ irq = DISPC_IRQ_FRAMEDONEWB;
+
+ if (!enable && is_on) {
+ init_completion(&frame_done_completion);
+
+ r = omap_dispc_register_isr(dispc_disable_isr,
+ &frame_done_completion, irq);
+ if (r)
+ DSSERR("failed to register FRAMEDONEWB isr\n");
+ }
+
+ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
+
+ if (!enable && is_on) {
+ if (!wait_for_completion_timeout(&frame_done_completion,
+ msecs_to_jiffies(100)))
+ DSSERR("timeout waiting for FRAMEDONEWB\n");
+
+ r = omap_dispc_unregister_isr(dispc_disable_isr,
+ &frame_done_completion, irq);
+ if (r)
+ DSSERR("failed to unregister FRAMEDONEWB isr\n");
+ }
+}
+
+bool dispc_wb_is_enabled(void)
+{
+ enum omap_plane plane = OMAP_DSS_WB;
+
+ return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
+}
+
void dispc_lcd_enable_signal_polarity(bool act_high)
{
if (!dss_has_feature(FEAT_LCDENABLEPOL))
@@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height)
static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
int vsw, int vfp, int vbp)
{
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- if (hsw < 1 || hsw > 64 ||
- hfp < 1 || hfp > 256 ||
- hbp < 1 || hbp > 256 ||
- vsw < 1 || vsw > 64 ||
- vfp < 0 || vfp > 255 ||
- vbp < 0 || vbp > 255)
- return false;
- } else {
- if (hsw < 1 || hsw > 256 ||
- hfp < 1 || hfp > 4096 ||
- hbp < 1 || hbp > 4096 ||
- vsw < 1 || vsw > 256 ||
- vfp < 0 || vfp > 4095 ||
- vbp < 0 || vbp > 4095)
- return false;
- }
-
+ if (hsw < 1 || hsw > dispc.feat->sw_max ||
+ hfp < 1 || hfp > dispc.feat->hp_max ||
+ hbp < 1 || hbp > dispc.feat->hp_max ||
+ vsw < 1 || vsw > dispc.feat->sw_max ||
+ vfp < 0 || vfp > dispc.feat->vp_max ||
+ vbp < 0 || vbp > dispc.feat->vp_max)
+ return false;
return true;
}
@@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
u32 timing_h, timing_v, l;
bool onoff, rf, ipc;
- if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
- timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
- FLD_VAL(hbp-1, 27, 20);
-
- timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
- FLD_VAL(vbp, 27, 20);
- } else {
- timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
- FLD_VAL(hbp-1, 31, 20);
-
- timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
- FLD_VAL(vbp, 31, 20);
- }
+ timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
+ FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
+ timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
+ FLD_VAL(vfp, dispc.feat->fp_start, 8) |
+ FLD_VAL(vbp, dispc.feat->bp_start, 20);
dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
@@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void)
return fclk / lcd;
}
+static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+
+ return dispc_mgr_pclk_rate(channel);
+}
+
+static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
+{
+ enum omap_channel channel = dispc_ovl_get_channel_out(plane);
+
+ if (dss_mgr_is_lcd(channel))
+ return dispc_mgr_lclk_rate(channel);
+ else
+ return dispc_fclk_rate();
+
+}
static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
{
int lcd, pcd;
@@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work)
ovl->name);
dispc_ovl_enable(ovl->id, false);
dispc_mgr_go(ovl->manager->id);
- mdelay(50);
+ msleep(50);
}
}
@@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work)
bit = mgr_desc[i].sync_lost_irq;
if (bit & errors) {
- struct omap_dss_device *dssdev = mgr->device;
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
bool enable;
DSSERR("SYNC_LOST on channel %s, restarting the output "
@@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work)
}
dispc_mgr_go(mgr->id);
- mdelay(50);
+ msleep(50);
if (enable)
dssdev->driver->enable(dssdev);
@@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work)
DSSERR("OCP_ERR\n");
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
struct omap_overlay_manager *mgr;
+ struct omap_dss_device *dssdev;
+
mgr = omap_dss_get_overlay_manager(i);
- if (mgr->device && mgr->device->driver)
- mgr->device->driver->disable(mgr->device);
+ dssdev = mgr->get_device(mgr);
+
+ if (dssdev && dssdev->driver)
+ dssdev->driver->disable(dssdev);
}
}
@@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void)
if (dss_has_feature(FEAT_FUNCGATED))
REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
- _dispc_setup_color_conv_coef();
+ dispc_setup_color_conv_coef();
dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
- dispc_read_plane_fifo_sizes();
+ dispc_init_fifos();
dispc_configure_burst_sizes();
dispc_ovl_enable_zorder_planes();
}
+static const struct dispc_features omap24xx_dispc_feats __initconst = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .calc_scaling = dispc_ovl_calc_scaling_24xx,
+ .calc_core_clk = calc_core_clk_24xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
+ .sw_start = 5,
+ .fp_start = 15,
+ .bp_start = 27,
+ .sw_max = 64,
+ .vp_max = 255,
+ .hp_max = 256,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .calc_scaling = dispc_ovl_calc_scaling_34xx,
+ .calc_core_clk = calc_core_clk_34xx,
+ .num_fifos = 3,
+};
+
+static const struct dispc_features omap44xx_dispc_feats __initconst = {
+ .sw_start = 7,
+ .fp_start = 19,
+ .bp_start = 31,
+ .sw_max = 256,
+ .vp_max = 4095,
+ .hp_max = 4096,
+ .calc_scaling = dispc_ovl_calc_scaling_44xx,
+ .calc_core_clk = calc_core_clk_44xx,
+ .num_fifos = 5,
+ .gfx_fifo_workaround = true,
+};
+
+static int __init dispc_init_features(struct device *dev)
+{
+ const struct dispc_features *src;
+ struct dispc_features *dst;
+
+ dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(dev, "Failed to allocate DISPC Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx()) {
+ src = &omap24xx_dispc_feats;
+ } else if (cpu_is_omap34xx()) {
+ if (omap_rev() < OMAP3430_REV_ES3_0)
+ src = &omap34xx_rev1_0_dispc_feats;
+ else
+ src = &omap34xx_rev3_0_dispc_feats;
+ } else if (cpu_is_omap44xx()) {
+ src = &omap44xx_dispc_feats;
+ } else if (soc_is_omap54xx()) {
+ src = &omap44xx_dispc_feats;
+ } else {
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ dispc.feat = dst;
+
+ return 0;
+}
+
/* DISPC HW IP initialisation */
static int __init omap_dispchw_probe(struct platform_device *pdev)
{
@@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
dispc.pdev = pdev;
+ r = dispc_init_features(&dispc.pdev->dev);
+ if (r)
+ return r;
+
spin_lock_init(&dispc.irq_lock);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
index 92d8a9be86f..222363c6e62 100644
--- a/drivers/video/omap2/dss/dispc.h
+++ b/drivers/video/omap2/dss/dispc.h
@@ -36,6 +36,7 @@
#define DISPC_CONTROL2 0x0238
#define DISPC_CONFIG2 0x0620
#define DISPC_DIVISOR 0x0804
+#define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C
@@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
return 0x014C;
case OMAP_DSS_VIDEO3:
return 0x0300;
+ case OMAP_DSS_WB:
+ return 0x0500;
default:
BUG();
return 0;
@@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0000;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0008;
default:
BUG();
@@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0004;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x000C;
default:
BUG();
@@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
return 0x04BC;
case OMAP_DSS_VIDEO3:
return 0x0310;
+ case OMAP_DSS_WB:
+ return 0x0118;
default:
BUG();
return 0;
@@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
return 0x04C0;
case OMAP_DSS_VIDEO3:
return 0x0314;
+ case OMAP_DSS_WB:
+ return 0x011C;
default:
BUG();
return 0;
@@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x000C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x00A8;
default:
BUG();
@@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0010;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0070;
default:
BUG();
@@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
return 0x04DC;
case OMAP_DSS_VIDEO3:
return 0x032C;
+ case OMAP_DSS_WB:
+ return 0x0310;
default:
BUG();
return 0;
@@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0014;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x008C;
default:
BUG();
@@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0018;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0088;
default:
BUG();
@@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x001C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x00A4;
default:
BUG();
@@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0020;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0098;
default:
BUG();
@@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0024;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0090;
default:
BUG();
@@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
return 0x055C;
case OMAP_DSS_VIDEO3:
return 0x0424;
+ case OMAP_DSS_WB:
+ return 0x290;
default:
BUG();
return 0;
@@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0028;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0094;
default:
BUG();
@@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x002C;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0000;
default:
BUG();
@@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
return 0x0560;
case OMAP_DSS_VIDEO3:
return 0x0428;
+ case OMAP_DSS_WB:
+ return 0x0294;
default:
BUG();
return 0;
@@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
case OMAP_DSS_VIDEO2:
return 0x0030;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0004;
default:
BUG();
@@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
return 0x0564;
case OMAP_DSS_VIDEO3:
return 0x042C;
+ case OMAP_DSS_WB:
+ return 0x0298;
default:
BUG();
return 0;
@@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0034 + i * 0x8;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0010 + i * 0x8;
default:
BUG();
@@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
return 0x0568 + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0430 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A0 + i * 0x8;
default:
BUG();
return 0;
@@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x0038 + i * 0x8;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0014 + i * 0x8;
default:
BUG();
@@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
return 0x056C + i * 0x8;
case OMAP_DSS_VIDEO3:
return 0x0434 + i * 0x8;
+ case OMAP_DSS_WB:
+ return 0x02A4 + i * 0x8;
default:
BUG();
return 0;
@@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO1:
case OMAP_DSS_VIDEO2:
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0074 + i * 0x4;
default:
BUG();
@@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
case OMAP_DSS_VIDEO2:
return 0x00B4 + i * 0x4;
case OMAP_DSS_VIDEO3:
+ case OMAP_DSS_WB:
return 0x0050 + i * 0x4;
default:
BUG();
@@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
return 0x05A8 + i * 0x4;
case OMAP_DSS_VIDEO3:
return 0x0470 + i * 0x4;
+ case OMAP_DSS_WB:
+ return 0x02E0 + i * 0x4;
default:
BUG();
return 0;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 5bd957e8550..ccf8550fafd 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev,
if (r)
return r;
+ dssdev->driver->disable(dssdev);
dssdev->driver->set_timings(dssdev, &t);
+ r = dssdev->driver->enable(dssdev);
+ if (r)
+ return r;
return size;
}
@@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_default_get_timings);
-void dss_init_device(struct platform_device *pdev,
+/*
+ * Connect dssdev to a manager if the manager is free or if force is specified.
+ * Connect all overlays to that manager if they are free or if force is
+ * specified.
+ */
+static int dss_init_connections(struct omap_dss_device *dssdev, bool force)
+{
+ struct omap_dss_output *out;
+ struct omap_overlay_manager *mgr;
+ int i, r;
+
+ out = omapdss_get_output_from_dssdev(dssdev);
+
+ WARN_ON(dssdev->output);
+ WARN_ON(out->device);
+
+ r = omapdss_output_set_device(out, dssdev);
+ if (r) {
+ DSSERR("failed to connect output to new device\n");
+ return r;
+ }
+
+ mgr = omap_dss_get_overlay_manager(dssdev->channel);
+
+ if (mgr->output && !force)
+ return 0;
+
+ if (mgr->output)
+ mgr->unset_output(mgr);
+
+ r = mgr->set_output(mgr, out);
+ if (r) {
+ DSSERR("failed to connect manager to output of new device\n");
+
+ /* remove the output-device connection we just made */
+ omapdss_output_unset_device(out);
+ return r;
+ }
+
+ for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
+ struct omap_overlay *ovl = omap_dss_get_overlay(i);
+
+ if (!ovl->manager || force) {
+ if (ovl->manager)
+ ovl->unset_manager(ovl);
+
+ r = ovl->set_manager(ovl, mgr);
+ if (r) {
+ DSSERR("failed to set initial overlay\n");
+ return r;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void dss_uninit_connections(struct omap_dss_device *dssdev)
+{
+ if (dssdev->output) {
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ if (mgr)
+ mgr->unset_output(mgr);
+
+ omapdss_output_unset_device(dssdev->output);
+ }
+}
+
+int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev)
{
struct device_attribute *attr;
- int i;
- int r;
+ int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ bool force;
+
+ force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0;
+ dss_init_connections(dssdev, force);
/* create device sysfs files */
i = 0;
while ((attr = display_sysfs_attrs[i++]) != NULL) {
r = device_create_file(&dssdev->dev, attr);
- if (r)
+ if (r) {
+ for (i = i - 2; i >= 0; i--) {
+ attr = display_sysfs_attrs[i];
+ device_remove_file(&dssdev->dev, attr);
+ }
+
+ dss_uninit_connections(dssdev);
+
DSSERR("failed to create sysfs file\n");
+ return r;
+ }
}
/* create display? sysfs links */
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
dev_name(&dssdev->dev));
- if (r)
+ if (r) {
+ while ((attr = display_sysfs_attrs[i++]) != NULL)
+ device_remove_file(&dssdev->dev, attr);
+
+ dss_uninit_connections(dssdev);
+
DSSERR("failed to create sysfs display link\n");
+ return r;
+ }
+
+ return 0;
}
void dss_uninit_device(struct platform_device *pdev,
@@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev,
while ((attr = display_sysfs_attrs[i++]) != NULL)
device_remove_file(&dssdev->dev, attr);
- if (dssdev->manager)
- dssdev->manager->unset_device(dssdev->manager);
+ dss_uninit_connections(dssdev);
}
static int dss_suspend_device(struct device *dev, void *data)
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index 3266be23fc0..56748cf8760 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -29,17 +29,24 @@
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/string.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
+#include "dss_features.h"
static struct {
struct regulator *vdds_dsi_reg;
struct platform_device *dsidev;
+ struct mutex lock;
+
+ struct omap_video_timings timings;
struct dss_lcd_mgr_config mgr_config;
+ int data_lines;
+
+ struct omap_dss_output output;
} dpi;
static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
@@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
static int dpi_set_mode(struct omap_dss_device *dssdev)
{
- struct omap_video_timings *t = &dssdev->panel.timings;
+ 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;
@@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
t->pixel_clock = pck;
}
- dss_mgr_set_timings(dssdev->manager, t);
+ dss_mgr_set_timings(mgr, t);
return 0;
}
static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.stallmode = false;
dpi.mgr_config.fifohandcheck = false;
- dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines;
+ dpi.mgr_config.video_port_width = dpi.data_lines;
dpi.mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);
+ dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
}
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
{
+ struct omap_dss_output *out = dssdev->output;
int r;
- if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
+ mutex_lock(&dpi.lock);
+
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
- return -ENODEV;
+ r = -ENODEV;
+ goto err_no_reg;
}
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
- return -ENODEV;
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err_no_out_mgr;
}
r = omap_dss_start_device(dssdev);
@@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
goto err_start_dev;
}
- if (cpu_is_omap34xx()) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
r = regulator_enable(dpi.vdds_dsi_reg);
if (r)
goto err_reg_enable;
@@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
+ r = dss_dpi_select_source(dssdev->channel);
+ if (r)
+ goto err_src_sel;
+
if (dpi_use_dsi_pll(dssdev)) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
@@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
mdelay(2);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
+ mutex_unlock(&dpi.lock);
+
return 0;
err_mgr_enable:
@@ -227,20 +248,28 @@ err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
+err_src_sel:
dispc_runtime_put();
err_get_dispc:
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
err_reg_enable:
omap_dss_stop_device(dssdev);
err_start_dev:
+err_no_out_mgr:
+err_no_reg:
+ mutex_unlock(&dpi.lock);
return r;
}
EXPORT_SYMBOL(omapdss_dpi_display_enable);
void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ mutex_lock(&dpi.lock);
+
+ dss_mgr_disable(mgr);
if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
@@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put();
- if (cpu_is_omap34xx())
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg);
omap_dss_stop_device(dssdev);
+
+ mutex_unlock(&dpi.lock);
}
EXPORT_SYMBOL(omapdss_dpi_display_disable);
-void dpi_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
- int r;
-
DSSDBG("dpi_set_timings\n");
- dssdev->panel.timings = *timings;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- r = dispc_runtime_get();
- if (r)
- return;
- dpi_set_mode(dssdev);
+ mutex_lock(&dpi.lock);
- dispc_runtime_put();
- } else {
- dss_mgr_set_timings(dssdev->manager, timings);
- }
+ dpi.timings = *timings;
+
+ mutex_unlock(&dpi.lock);
}
-EXPORT_SYMBOL(dpi_set_timings);
+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;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
struct dispc_clock_info dispc_cinfo;
- if (dss_mgr_check_timings(dssdev->manager, timings))
+ if (dss_mgr_check_timings(mgr, timings))
return -EINVAL;
if (timings->pixel_clock == 0)
@@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(dpi_check_timings);
+void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ mutex_lock(&dpi.lock);
+
+ dpi.data_lines = data_lines;
+
+ mutex_unlock(&dpi.lock);
+}
+EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
+
static int __init dpi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
- if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
+ dpi.vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
vdds_dsi = dss_get_vdds_dsi();
@@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static void __init dpi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
continue;
- r = dpi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init dpi_probe_pdata(struct platform_device *dpidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = dpi_find_dssdev(dpidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&dpidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = dpi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
}
+static void __init 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;
+
+ dss_register_output(out);
+}
+
+static void __exit dpi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &dpi.output;
+
+ dss_unregister_output(out);
+}
+
static int __init omap_dpi_probe(struct platform_device *pdev)
{
+ mutex_init(&dpi.lock);
+
+ dpi_init_output(pdev);
+
dpi_probe_pdata(pdev);
return 0;
@@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev)
static int __exit omap_dpi_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ dpi_uninit_output(pdev);
return 0;
}
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 05ee04667af..d64ac384288 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -41,7 +41,6 @@
#include <video/omapdss.h>
#include <video/mipi_display.h>
-#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
@@ -333,6 +332,12 @@ struct dsi_data {
unsigned scp_clk_refcount;
struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ enum omap_dss_dsi_pixel_format pix_fmt;
+ enum omap_dss_dsi_mode mode;
+ struct omap_dss_dsi_videomode_timings vm_timings;
+
+ struct omap_dss_output output;
};
struct dsi_packet_sent_handler_data {
@@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data {
struct completion *completion;
};
-static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
-
#ifdef DEBUG
static bool dsi_perf;
module_param(dsi_perf, bool, 0644);
@@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside
static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
{
- return dsi_pdev_map[dssdev->phy.dsi.module];
+ return dssdev->output->pdev;
}
struct platform_device *dsi_get_dsidev_from_id(int module)
{
- return dsi_pdev_map[module];
+ struct omap_dss_output *out;
+ enum omap_dss_output_id id;
+
+ id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+ out = omap_dss_get_output(id);
+
+ return out->pdev;
}
static inline void dsi_write_reg(struct platform_device *dsidev,
@@ -1450,6 +1460,148 @@ found:
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)
+{
+ unsigned long max_dsi_fck;
+
+ max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
+
+ cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
+ 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)
{
@@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev,
BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
+ l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
+
if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
f = cinfo->fint < 1000000 ? 0x3 :
cinfo->fint < 1250000 ? 0x4 :
cinfo->fint < 1500000 ? 0x5 :
cinfo->fint < 1750000 ? 0x6 :
0x7;
- }
- l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
-
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
+ } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
+ f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
+
+ l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
+ }
+
l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
+ if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
+ l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
@@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
return 1194 * 3; /* 1194x24 bits */
case 6:
return 1365 * 3; /* 1365x24 bits */
+ case 7:
+ return 1920 * 3; /* 1920x24 bits */
default:
BUG();
return 0;
}
}
-static int dsi_set_lane_config(struct omap_dss_device *dssdev)
+static int dsi_set_lane_config(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
static const u8 offsets[] = { 0, 4, 8, 12, 16 };
static const enum dsi_lane_function functions[] = {
@@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev)
dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
- r = FLD_MOD(r, tlpx_half, 22, 16);
+ r = FLD_MOD(r, tlpx_half, 20, 16);
r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0);
+
+ if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
+ r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
+ r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
+ r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
+ }
+
dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
@@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev)
}
/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
-static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
+static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
unsigned mask_p, unsigned mask_n)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int i;
u32 l;
@@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
}
-static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
+static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int t, i;
bool in_use[DSI_MAX_NR_LANES];
@@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
}
/* return bitmask of enabled lanes, lane0 being the lsb */
-static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
+static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
unsigned mask = 0;
int i;
@@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev)
return mask;
}
-static int dsi_cio_init(struct omap_dss_device *dssdev)
+static int dsi_cio_init(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
u32 l;
DSSDBGF();
- r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
if (r)
return r;
@@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
goto err_scp_clk_dom;
}
- r = dsi_set_lane_config(dssdev);
+ r = dsi_set_lane_config(dsidev);
if (r)
goto err_scp_clk_dom;
@@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
mask_p |= 1 << i;
}
- dsi_cio_enable_lane_override(dssdev, mask_p, 0);
+ dsi_cio_enable_lane_override(dsidev, mask_p, 0);
}
r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
dsi_if_enable(dsidev, false);
REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
- r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
+ r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
if (r)
goto err_tx_clk_esc_rst;
@@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
dsi_cio_timings(dsidev);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
/* DDR_CLK_ALWAYS_ON */
REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
- dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13);
+ dsi->vm_timings.ddr_clk_always_on, 13, 13);
}
dsi->ulps_enabled = false;
@@ -2381,13 +2543,12 @@ err_cio_pwr:
dsi_cio_disable_lane_override(dsidev);
err_scp_clk_dom:
dsi_disable_scp_clk(dsidev);
- dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
return r;
}
-static void dsi_cio_uninit(struct omap_dss_device *dssdev)
+static void dsi_cio_uninit(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
/* DDR_CLK_ALWAYS_ON */
@@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev)
dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
dsi_disable_scp_clk(dsidev);
- dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev));
+ dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
}
static void dsi_config_tx_fifo(struct platform_device *dsidev,
@@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
bool enable)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
@@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
dsi_force_tx_stop_mode_io(dsidev);
/* start the DDR clock by sending a NULL packet */
- if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable)
+ if (dsi->vm_timings.ddr_clk_always_on && enable)
dsi_vc_send_null(dssdev, channel);
}
EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
@@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
}
EXPORT_SYMBOL(dsi_vc_send_null);
-static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
+static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
int channel, u8 *data, int len, enum dss_dsi_content_type type)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
if (len == 0) {
@@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev,
int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
u8 *data, int len)
{
- return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
DSS_DSI_CONTENT_DCS);
}
EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
@@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
u8 *data, int len)
{
- return dsi_vc_write_nosync_common(dssdev, channel, data, len,
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+ return dsi_vc_write_nosync_common(dsidev, channel, data, len,
DSS_DSI_CONTENT_GENERIC);
}
EXPORT_SYMBOL(dsi_vc_generic_write_nosync);
@@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type);
+ r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
if (r)
goto err;
@@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel,
}
EXPORT_SYMBOL(dsi_vc_generic_write_2);
-static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
int channel, u8 dcs_cmd)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
@@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev,
return 0;
}
-static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev,
+static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
int channel, u8 *reqdata, int reqlen)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u16 data;
u8 data_type;
@@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd);
+ r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
if (r)
goto err;
@@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
int r;
- r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen);
+ r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
if (r)
return r;
@@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
(total_ticks * 1000) / (fck / 1000 / 1000));
}
-static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
+static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int num_line_buffers;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ 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 = &dssdev->panel.timings;
+ struct omap_video_timings *timings = &dsi->timings;
/*
* Don't use line buffers if width is greater than the video
* port's line buffer size
@@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev)
REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
}
-static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
+static void dsi_config_vp_sync_events(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end;
- bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
+ 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;
u32 r;
r = dsi_read_reg(dsidev, DSI_CTRL);
@@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_CTRL, r);
}
-static void dsi_config_blanking_modes(struct omap_dss_device *dssdev)
+static void dsi_config_blanking_modes(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode;
- int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode;
- int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode;
- int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int blanking_mode = dsi->vm_timings.blanking_mode;
+ int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
+ int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
+ int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
u32 r;
/*
@@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
int tclk_trail, ths_exit, exiths_clk;
bool ddr_alwon;
- struct omap_video_timings *timings = &dssdev->panel.timings;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ 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 hsa_interleave_hs = 0, hsa_interleave_lp = 0;
@@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
static int dsi_proto_config(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 r;
int buswidth = 0;
@@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
- switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) {
+ switch (dsi_get_pixel_size(dsi->pix_fmt)) {
case 16:
buswidth = 0;
break;
@@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_CTRL, r);
- dsi_config_vp_num_line_buffers(dssdev);
+ dsi_config_vp_num_line_buffers(dsidev);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- dsi_config_vp_sync_events(dssdev);
- dsi_config_blanking_modes(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);
}
@@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
return 0;
}
-static void dsi_proto_timings(struct omap_dss_device *dssdev)
+static void dsi_proto_timings(struct platform_device *dsidev)
{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
unsigned tclk_pre, tclk_post;
@@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
ths_exit = FLD_GET(r, 7, 0);
r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
- tlpx = FLD_GET(r, 22, 16) * 2;
+ tlpx = FLD_GET(r, 20, 16) * 2;
tclk_trail = FLD_GET(r, 15, 8);
tclk_zero = FLD_GET(r, 7, 0);
@@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
enter_hs_mode_lat, exit_hs_mode_lat);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
/* TODO: Implement a video mode check_timings function */
- int hsa = dssdev->panel.dsi_vm_data.hsa;
- int hfp = dssdev->panel.dsi_vm_data.hfp;
- int hbp = dssdev->panel.dsi_vm_data.hbp;
- int vsa = dssdev->panel.dsi_vm_data.vsa;
- int vfp = dssdev->panel.dsi_vm_data.vfp;
- int vbp = dssdev->panel.dsi_vm_data.vbp;
- int window_sync = dssdev->panel.dsi_vm_data.window_sync;
- bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end;
- struct omap_video_timings *timings = &dssdev->panel.timings;
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ int hsa = dsi->vm_timings.hsa;
+ int hfp = dsi->vm_timings.hfp;
+ int hbp = dsi->vm_timings.hbp;
+ int vsa = dsi->vm_timings.vsa;
+ 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;
+ struct omap_video_timings *timings = &dsi->timings;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int tl, t_he, width_bytes;
t_he = hsync_end ?
@@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
}
EXPORT_SYMBOL(omapdss_dsi_configure_pins);
-int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
+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;
+
+ DSSDBGF("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;
+ int bpp = dsi_get_pixel_size(dsi->pix_fmt);
u8 data_type;
u16 word_count;
int r;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
- switch (dssdev->panel.dsi_pix_fmt) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ switch (dsi->pix_fmt) {
case OMAP_DSS_DSI_FMT_RGB888:
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
break;
@@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
/* MODE, 1 = video mode */
REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
- word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8);
+ word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
dsi_vc_write_long_header(dsidev, channel, data_type,
word_count, 0);
@@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
dsi_if_enable(dsidev, true);
}
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r) {
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_if_enable(dsidev, false);
dsi_vc_enable(dsidev, channel, false);
}
@@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output);
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;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) {
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
dsi_if_enable(dsidev, false);
dsi_vc_enable(dsidev, channel, false);
@@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
dsi_if_enable(dsidev, true);
}
- dss_mgr_disable(dssdev->manager);
+ dss_mgr_disable(mgr);
}
EXPORT_SYMBOL(dsi_disable_video_output);
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
- u16 w, u16 h)
+static void dsi_update_screen_dispc(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_overlay_manager *mgr = dssdev->output->manager;
unsigned bytespp;
unsigned bytespl;
unsigned bytespf;
@@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
int r;
const unsigned channel = dsi->update_channel;
const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
+ u16 w = dsi->timings.x_res;
+ u16 h = dsi->timings.y_res;
DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
- bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+ bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
bytespl = w * bytespp;
bytespf = bytespl * h;
@@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
msecs_to_jiffies(250));
BUG_ON(r == 0);
- dss_mgr_start_update(dssdev->manager);
+ dss_mgr_set_timings(mgr, &dsi->timings);
+
+ dss_mgr_start_update(mgr);
if (dsi->te_enabled) {
/* disable LP_RX_TO, so that we can receive TE. Time to wait
@@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
static void dsi_framedone_irq_callback(void *data, u32 mask)
{
- struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct platform_device *dsidev = (struct platform_device *) data;
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
@@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
dsi->framedone_callback = callback;
dsi->framedone_data = data;
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
+ dw = dsi->timings.x_res;
+ dh = dsi->timings.y_res;
#ifdef DEBUG
dsi->update_bytes = dw * dh *
- dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8;
+ dsi_get_pixel_size(dsi->pix_fmt) / 8;
#endif
- dsi_update_screen_dispc(dssdev, dw, dh);
+ dsi_update_screen_dispc(dssdev);
return 0;
}
@@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(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_video_timings timings;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
int r;
u32 irq = 0;
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
- u16 dw, dh;
-
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
- timings.x_res = dw;
- timings.y_res = dh;
- timings.hsw = 1;
- timings.hfp = 1;
- timings.hbp = 1;
- timings.vsw = 1;
- timings.vfp = 0;
- timings.vbp = 0;
+ 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;
- irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+ irq = dispc_mgr_get_framedone_irq(mgr->id);
r = omap_dispc_register_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
if (r) {
DSSERR("can't get FRAMEDONE irq\n");
goto err;
@@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dsi->mgr_config.stallmode = true;
dsi->mgr_config.fifohandcheck = true;
} else {
- timings = dssdev->panel.timings;
-
dsi->mgr_config.stallmode = false;
dsi->mgr_config.fifohandcheck = false;
}
@@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
* override interlace, logic level and edge related parameters in
* omap_video_timings with default values
*/
- timings.interlace = false;
- timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
- timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+ dsi->timings.interlace = false;
+ dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
- dss_mgr_set_timings(dssdev->manager, &timings);
+ dss_mgr_set_timings(mgr, &dsi->timings);
r = dsi_configure_dispc_clocks(dssdev);
if (r)
@@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dsi->mgr_config.video_port_width =
- dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
+ dsi_get_pixel_size(dsi->pix_fmt);
dsi->mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config);
+ dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
return 0;
err1:
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE)
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
err:
return r;
}
static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
{
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
+ 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) {
u32 irq;
- irq = dispc_mgr_get_framedone_irq(dssdev->manager->id);
+ irq = dispc_mgr_get_framedone_irq(mgr->id);
omap_dispc_unregister_isr(dsi_framedone_irq_callback,
- (void *) dssdev, irq);
+ (void *) dsidev, irq);
}
}
@@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(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_overlay_manager *mgr = dssdev->output->manager;
int r;
r = dsi_pll_init(dsidev, true, true);
@@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
- dss_select_lcd_clk_source(dssdev->manager->id,
+ dss_select_lcd_clk_source(mgr->id,
dssdev->clocks.dispc.channel.lcd_clk_src);
DSSDBG("PLL OK\n");
- r = dsi_cio_init(dssdev);
+ r = dsi_cio_init(dsidev);
if (r)
goto err2;
_dsi_print_reset_status(dsidev);
- dsi_proto_timings(dssdev);
+ dsi_proto_timings(dsidev);
dsi_set_lp_clk_divisor(dssdev);
if (1)
@@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
return 0;
err3:
- dsi_cio_uninit(dssdev);
+ dsi_cio_uninit(dsidev);
err2:
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
err1:
dsi_pll_uninit(dsidev, true);
@@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(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_overlay_manager *mgr = dssdev->output->manager;
if (enter_ulps && !dsi->ulps_enabled)
dsi_enter_ulps(dsidev);
@@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
- dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK);
- dsi_cio_uninit(dssdev);
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
+ dsi_cio_uninit(dsidev);
dsi_pll_uninit(dsidev, disconnect_lanes);
}
@@ -4559,6 +4794,7 @@ 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");
@@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&dsi->lock);
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err_start_dev;
}
@@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
}
EXPORT_SYMBOL(omapdss_dsi_enable_te);
-static int __init dsi_init_display(struct omap_dss_device *dssdev)
+void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- DSSDBG("DSI init\n");
+ mutex_lock(&dsi->lock);
- if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) {
- dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
- OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
- }
+ dsi->timings = *timings;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_timings);
+
+void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->timings.x_res = w;
+ dsi->timings.y_res = h;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_size);
+
+void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_pixel_format fmt)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->pix_fmt = fmt;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
+
+void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
+ enum omap_dss_dsi_mode mode)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->mode = mode;
+
+ mutex_unlock(&dsi->lock);
+}
+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)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ mutex_lock(&dsi->lock);
+
+ dsi->vm_timings = *timings;
+
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
+
+static int __init dsi_init_display(struct omap_dss_device *dssdev)
+{
+ struct platform_device *dsidev =
+ dsi_get_dsidev_from_id(dssdev->phy.dsi.module);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+ DSSDBG("DSI init\n");
if (dsi->vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi;
@@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev)
clk_put(dsi->sys_clk);
}
-static void __init dsi_probe_pdata(struct platform_device *dsidev)
+static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct omap_dss_board_info *pdata = dsidev->dev.platform_data;
- int i, r;
+ struct omap_dss_board_info *pdata = pdev->dev.platform_data;
+ struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev)
if (dssdev->phy.dsi.module != dsi->module_id)
continue;
- r = dsi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &dsidev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init dsi_probe_pdata(struct platform_device *dsidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = dsi_find_dssdev(dsidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&dsidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = dsi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
}
+static void __init dsi_init_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_output *out = &dsi->output;
+
+ out->pdev = dsidev;
+ out->id = dsi->module_id == 0 ?
+ OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+
+ out->type = OMAP_DISPLAY_TYPE_DSI;
+
+ dss_register_output(out);
+}
+
+static void __exit dsi_uninit_output(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct omap_dss_output *out = &dsi->output;
+
+ dss_unregister_output(out);
+}
+
/* DSI1 HW IP initialisation */
static int __init omap_dsihw_probe(struct platform_device *dsidev)
{
@@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
dsi->module_id = dsidev->id;
dsi->pdev = dsidev;
- dsi_pdev_map[dsi->module_id] = dsidev;
dev_set_drvdata(&dsidev->dev, dsi);
spin_lock_init(&dsi->irq_lock);
@@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
else
dsi->num_lanes_supported = 3;
+ dsi_init_output(dsidev);
+
dsi_probe_pdata(dsidev);
dsi_runtime_put(dsidev);
@@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
WARN_ON(dsi->scp_clk_refcount > 0);
- omap_dss_unregister_child_devices(&dsidev->dev);
+ dss_unregister_child_devices(&dsidev->dev);
+
+ dsi_uninit_output(dsidev);
pm_runtime_disable(&dsidev->dev);
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 04b4586113e..2ab1c3e9655 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -31,11 +31,11 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/gfp.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
-#include <plat/clock.h>
#include "dss.h"
#include "dss_features.h"
@@ -65,6 +65,13 @@ struct dss_reg {
static int dss_runtime_get(void);
static void dss_runtime_put(void);
+struct dss_features {
+ u8 fck_div_max;
+ u8 dss_fck_multiplier;
+ const char *clk_name;
+ int (*dpi_select_source)(enum omap_channel channel);
+};
+
static struct {
struct platform_device *pdev;
void __iomem *base;
@@ -83,6 +90,8 @@ static struct {
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
+
+ const struct dss_features *feat;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@@ -144,7 +153,7 @@ static void dss_restore_context(void)
#undef SR
#undef RR
-void dss_sdi_init(u8 datapairs)
+void dss_sdi_init(int datapairs)
{
u32 l;
@@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
return dss_generic_clk_source_names[clk_src];
}
-
void dss_dump_clocks(struct seq_file *s)
{
unsigned long dpll4_ck_rate;
@@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- seq_printf(s, "%s (%s) = %lu / %lu = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
- else
- seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n",
- fclk_name, fclk_real_name,
- dpll4_ck_rate,
- dpll4_ck_rate / dpll4_m4_ck_rate,
- fclk_rate);
+ seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n",
+ fclk_name, fclk_real_name, dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss.feat->dss_fck_multiplier, fclk_rate);
} else {
seq_printf(s, "%s (%s) = %lu\n",
fclk_name, fclk_real_name,
@@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
}
}
-/* calculate clock rates using dividers in cinfo */
-int dss_calc_clock_rates(struct dss_clock_info *cinfo)
-{
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
- u16 fck_div_max = 16;
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0)
- return -EINVAL;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- cinfo->fck = prate / cinfo->fck_div;
- } else {
- if (cinfo->fck_div != 0)
- return -EINVAL;
- cinfo->fck = clk_get_rate(dss.dss_clk);
- }
-
- return 0;
-}
-
int dss_set_clock_div(struct dss_clock_info *cinfo)
{
if (dss.dpll4_m4_ck) {
@@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
return 0;
}
-int dss_get_clock_div(struct dss_clock_info *cinfo)
-{
- cinfo->fck = clk_get_rate(dss.dss_clk);
-
- if (dss.dpll4_m4_ck) {
- unsigned long prate;
-
- prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
-
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- cinfo->fck_div = prate / (cinfo->fck);
- else
- cinfo->fck_div = prate / (cinfo->fck / 2);
- } else {
- cinfo->fck_div = 0;
- }
-
- return 0;
-}
-
unsigned long dss_get_dpll4_rate(void)
{
if (dss.dpll4_m4_ck)
@@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
unsigned long fck, max_dss_fck;
- u16 fck_div, fck_div_max = 16;
+ u16 fck_div;
int match = 0;
int min_fck_per_pck;
@@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
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 &&
- ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
- dss.cache_dss_cinfo.fck == fck)) {
+ 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;
@@ -564,16 +518,10 @@ retry:
goto found;
} else {
- if (cpu_is_omap3630() || cpu_is_omap44xx())
- fck_div_max = 32;
-
- for (fck_div = fck_div_max; fck_div > 0; --fck_div) {
+ for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- if (fck_div_max == 32)
- fck = prate / fck_div;
- else
- fck = prate / fck_div * 2;
+ fck = prate / fck_div * dss.feat->dss_fck_multiplier;
if (fck > max_dss_fck)
continue;
@@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable)
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
}
-void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
+void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
{
- REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
+ enum omap_display_type dp;
+ dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
+
+ /* Complain about invalid selections */
+ WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
+ WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
+
+ /* Select only if we have options */
+ if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
+ REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
}
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
@@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
return DSS_VENC_TV_CLK;
+ if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
+ return DSS_HDMI_M_PCLK;
+
return REG_GET(DSS_CONTROL, 15, 15);
}
+static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
+{
+ if (channel != OMAP_DSS_CHANNEL_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap4(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 0;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
+
+ return 0;
+}
+
+static int dss_dpi_select_source_omap5(enum omap_channel channel)
+{
+ int val;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ val = 1;
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ val = 2;
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ val = 3;
+ break;
+ case OMAP_DSS_CHANNEL_DIGIT:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
+
+ return 0;
+}
+
+int dss_dpi_select_source(enum omap_channel channel)
+{
+ return dss.feat->dpi_select_source(channel);
+}
+
static int dss_get_clocks(void)
{
struct clk *clk;
@@ -678,22 +697,11 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
- if (cpu_is_omap34xx()) {
- clk = clk_get(NULL, "dpll4_m4_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll4_m4_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else if (cpu_is_omap44xx()) {
- clk = clk_get(NULL, "dpll_per_m5x2_ck");
- if (IS_ERR(clk)) {
- DSSERR("Failed to get dpll_per_m5x2_ck\n");
- r = PTR_ERR(clk);
- goto err;
- }
- } else { /* omap24xx */
- clk = NULL;
+ 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;
}
dss.dpll4_m4_ck = clk;
@@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+static const struct dss_features omap24xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = NULL,
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap34xx_dss_feats __initconst = {
+ .fck_div_max = 16,
+ .dss_fck_multiplier = 2,
+ .clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap3630_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll4_m4_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
+static const struct dss_features omap44xx_dss_feats __initconst = {
+ .fck_div_max = 32,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_m5x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap4,
+};
+
+static const struct dss_features omap54xx_dss_feats __initconst = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .clk_name = "dpll_per_h12x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_omap5,
+};
+
+static int __init dss_init_features(struct device *dev)
+{
+ const struct dss_features *src;
+ struct dss_features *dst;
+
+ dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(dev, "Failed to allocate local DSS Features\n");
+ return -ENOMEM;
+ }
+
+ if (cpu_is_omap24xx())
+ src = &omap24xx_dss_feats;
+ else if (cpu_is_omap34xx())
+ src = &omap34xx_dss_feats;
+ else if (cpu_is_omap3630())
+ src = &omap3630_dss_feats;
+ else if (cpu_is_omap44xx())
+ src = &omap44xx_dss_feats;
+ else if (soc_is_omap54xx())
+ src = &omap54xx_dss_feats;
+ else
+ return -ENODEV;
+
+ memcpy(dst, src, sizeof(*dst));
+ dss.feat = dst;
+
+ return 0;
+}
+
/* DSS HW IP initialisation */
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
@@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss.pdev = pdev;
+ r = dss_init_features(&dss.pdev->dev);
+ if (r)
+ return r;
+
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
if (!dss_mem) {
DSSERR("can't get IORESOURCE_MEM DSS\n");
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index f67afe76f21..6728892f9da 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -113,6 +113,17 @@ enum dss_dsi_content_type {
DSS_DSI_CONTENT_GENERIC,
};
+enum dss_writeback_channel {
+ DSS_WB_LCD1_MGR = 0,
+ DSS_WB_LCD2_MGR = 1,
+ DSS_WB_TV_MGR = 2,
+ DSS_WB_OVL0 = 3,
+ DSS_WB_OVL1 = 4,
+ DSS_WB_OVL2 = 5,
+ DSS_WB_OVL3 = 6,
+ DSS_WB_LCD3_MGR = 7,
+};
+
struct dss_clock_info {
/* rates that we get with dividers below */
unsigned long fck;
@@ -175,6 +186,7 @@ struct seq_file;
struct platform_device;
/* core */
+const char *dss_get_default_display_name(void);
struct bus_type *dss_get_bus(void);
struct regulator *dss_get_vdds_dsi(void);
struct regulator *dss_get_vdds_sdi(void);
@@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
-int omap_dss_register_device(struct omap_dss_device *dssdev,
- struct device *parent, int disp_num);
-void omap_dss_unregister_device(struct omap_dss_device *dssdev);
-void omap_dss_unregister_child_devices(struct device *parent);
+struct omap_dss_device *dss_alloc_and_init_device(struct device *parent);
+int dss_add_device(struct omap_dss_device *dssdev);
+void dss_unregister_device(struct omap_dss_device *dssdev);
+void dss_unregister_child_devices(struct device *parent);
+void dss_put_device(struct omap_dss_device *dssdev);
+void dss_copy_device_pdata(struct omap_dss_device *dst,
+ const struct omap_dss_device *src);
/* apply */
void dss_apply_init(void);
@@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr,
int dss_mgr_set_device(struct omap_overlay_manager *mgr,
struct omap_dss_device *dssdev);
int dss_mgr_unset_device(struct omap_overlay_manager *mgr);
+int dss_mgr_set_output(struct omap_overlay_manager *mgr,
+ struct omap_dss_output *output);
+int dss_mgr_unset_output(struct omap_overlay_manager *mgr);
void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
- struct omap_video_timings *timings);
+ const struct omap_video_timings *timings);
void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config);
const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr);
@@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl,
struct omap_overlay_manager *mgr);
int dss_ovl_unset_manager(struct omap_overlay *ovl);
+/* output */
+void dss_register_output(struct omap_dss_output *out);
+void dss_unregister_output(struct omap_dss_output *out);
+struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev);
+
/* display */
int dss_suspend_all_devices(void);
int dss_resume_all_devices(void);
void dss_disable_all_devices(void);
-void dss_init_device(struct platform_device *pdev,
+int dss_init_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
void dss_uninit_device(struct platform_device *pdev,
struct omap_dss_device *dssdev);
@@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id)
return false;
}
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev);
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
+
/* overlay */
void dss_init_overlays(struct platform_device *pdev);
void dss_uninit_overlays(struct platform_device *pdev);
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
int dss_ovl_simple_check(struct omap_overlay *ovl,
const struct omap_overlay_info *info);
int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
const struct omap_video_timings *mgr_timings);
bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
enum omap_color_mode mode);
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev);
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
/* DSS */
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
+int dss_dpi_select_source(enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
@@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s);
void dss_debug_dump_clocks(struct seq_file *s);
#endif
-void dss_sdi_init(u8 datapairs);
+void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
@@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
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_get_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);
@@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
bool manual_update);
-int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
- bool replication, const struct omap_video_timings *mgr_timings);
+int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
+ bool replication, const struct omap_video_timings *mgr_timings,
+ bool mem_to_mem);
int dispc_ovl_enable(enum omap_plane plane, bool enable);
void dispc_ovl_set_channel_out(enum omap_plane plane,
enum omap_channel channel);
@@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel,
void dispc_mgr_setup(enum omap_channel channel,
struct omap_overlay_manager_info *info);
+u32 dispc_wb_get_framedone_irq(void);
+bool dispc_wb_go_busy(void);
+void dispc_wb_go(void);
+void dispc_wb_enable(bool enable);
+bool dispc_wb_is_enabled(void);
+void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
+int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
+ bool mem_to_mem, const struct omap_video_timings *timings);
+
/* VENC */
#ifdef CONFIG_OMAP2_DSS_VENC
int venc_init_platform_driver(void) __init;
@@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void)
return 0;
}
#endif
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev);
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev);
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev);
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss);
+void omapdss_venc_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type);
+void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity);
+int venc_panel_init(void);
+void venc_panel_exit(void);
/* HDMI */
#ifdef CONFIG_OMAP4_DSS_HDMI
@@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void)
#endif
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev);
void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev);
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev);
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings);
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
struct omap_video_timings *timings);
int omapdss_hdmi_read_edid(u8 *buf, int len);
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 938709724f0..acbc1e1efba 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -46,7 +46,9 @@ struct omap_dss_features {
const int num_mgrs;
const int num_ovls;
+ const int num_wbs;
const enum omap_display_type *supported_displays;
+ const enum omap_dss_output_id *supported_outputs;
const enum omap_color_mode *supported_color_modes;
const enum omap_overlay_caps *overlay_caps;
const char * const *clksrc_names;
@@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
+static const struct dss_reg_field omap5_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
+ [FEAT_REG_FIFOSIZE] = { 15, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
+ [FEAT_REG_VERTICALACCU] = { 26, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
+ [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
+ [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
+ [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
+ [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
+};
+
static const enum omap_display_type omap2_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
@@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_DSI,
};
+static const enum omap_display_type omap5_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
+ OMAP_DISPLAY_TYPE_DSI,
+};
+
+static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC,
+};
+
+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_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
+ OMAP_DSS_OUTPUT_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
+static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
+
+ /* OMAP_DSS_CHANNEL_DIGIT */
+ OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
+
+ /* OMAP_DSS_CHANNEL_LCD2 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI1,
+
+ /* OMAP_DSS_CHANNEL_LCD3 */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
+ OMAP_DSS_OUTPUT_DSI2,
+};
+
static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
@@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
OMAP_DSS_COLOR_RGBX32,
+
+ /* OMAP_DSS_WB */
+ OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+ OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+ OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+ OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+ OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+ OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+ OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+ OMAP_DSS_COLOR_RGBX32,
};
static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- 0,
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
- OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
- OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
- OMAP_DSS_OVL_CAP_SCALE,
+ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
};
static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
/* OMAP_DSS_GFX */
OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
- OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
+ OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO1 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO2 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
/* OMAP_DSS_VIDEO3 */
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
- OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER,
+ OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
+ OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
};
static const char * const omap2_dss_clk_source_names[] = {
@@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
};
+static const char * const omap5_dss_clk_source_names[] = {
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
+ [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
+ [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
+};
+
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
@@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
+ [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
+ [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 },
+};
+
+static const struct dss_param_range omap5_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [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_LPDIV] = { 0, (1 << 13) - 1 },
+ [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
[FEAT_PARAM_MGR_WIDTH] = { 1, 2048 },
@@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
+ FEAT_DPI_USES_VDDS_DSI,
+};
+
+static const enum dss_feat_id am35xx_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_DSI_PLL_FREQSEL,
+ FEAT_DSI_REVERSE_TXCLKESC,
+ FEAT_VENC_REQUIRES_TV_DAC_CLK,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_OMAP3_DSI_FIFO_BUG,
};
static const enum dss_feat_id omap3630_dss_feat_list[] = {
@@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
FEAT_BURST_2D,
};
+static const enum dss_feat_id omap5_dss_feat_list[] = {
+ FEAT_MGR_LCD2,
+ FEAT_CORE_CLK_DIV,
+ FEAT_LCD_CLK_SRC,
+ FEAT_DSI_DCS_CMD_CONFIG_VC,
+ FEAT_DSI_VC_OCP_WIDTH,
+ FEAT_DSI_GNQ,
+ FEAT_HDMI_CTS_SWMODE,
+ FEAT_HDMI_AUDIO_USE_MCLK,
+ FEAT_HANDLE_UV_SEPARATE,
+ FEAT_ATTR2,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FREE_ZORDER,
+ FEAT_FIFO_MERGE,
+ FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
+};
+
/* OMAP2 DSS Features */
static const struct omap_dss_features omap2_dss_features = {
.reg_fields = omap2_dss_reg_fields,
@@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap2_dss_supported_displays,
+ .supported_outputs = omap2_dss_supported_outputs,
.supported_color_modes = omap2_dss_supported_color_modes,
.overlay_caps = omap2_dss_overlay_caps,
.clksrc_names = omap2_dss_clk_source_names,
@@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap3_dss_clk_source_names,
+ .dss_params = omap3_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
+/*
+ * AM35xx DSS Features. This is basically OMAP3 DSS Features without the
+ * vdds_dsi regulator.
+ */
+static const struct omap_dss_features am35xx_dss_features = {
+ .reg_fields = omap3_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
+
+ .features = am35xx_dss_feat_list,
+ .num_features = ARRAY_SIZE(am35xx_dss_feat_list),
+
+ .num_mgrs = 2,
+ .num_ovls = 3,
+ .supported_displays = omap3430_dss_supported_displays,
+ .supported_outputs = omap3430_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3430_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = {
.num_mgrs = 2,
.num_ovls = 3,
.supported_displays = omap3630_dss_supported_displays,
+ .supported_outputs = omap3630_dss_supported_outputs,
.supported_color_modes = omap3_dss_supported_color_modes,
.overlay_caps = omap3630_dss_overlay_caps,
.clksrc_names = omap3_dss_clk_source_names,
@@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = {
.num_mgrs = 3,
.num_ovls = 4,
+ .num_wbs = 1,
.supported_displays = omap4_dss_supported_displays,
+ .supported_outputs = omap4_dss_supported_outputs,
.supported_color_modes = omap4_dss_supported_color_modes,
.overlay_caps = omap4_dss_overlay_caps,
.clksrc_names = omap4_dss_clk_source_names,
@@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = {
.burst_size_unit = 16,
};
+/* OMAP5 DSS Features */
+static const struct omap_dss_features omap5_dss_features = {
+ .reg_fields = omap5_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
+
+ .features = omap5_dss_feat_list,
+ .num_features = ARRAY_SIZE(omap5_dss_feat_list),
+
+ .num_mgrs = 3,
+ .num_ovls = 4,
+ .supported_displays = omap5_dss_supported_displays,
+ .supported_outputs = omap5_dss_supported_outputs,
+ .supported_color_modes = omap4_dss_supported_color_modes,
+ .overlay_caps = omap4_dss_overlay_caps,
+ .clksrc_names = omap5_dss_clk_source_names,
+ .dss_params = omap5_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
+ .buffer_size_unit = 16,
+ .burst_size_unit = 16,
+};
+
#if defined(CONFIG_OMAP4_DSS_HDMI)
/* HDMI OMAP4 Functions*/
static const struct ti_hdmi_ip_ops omap4_hdmi_functions = {
@@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void)
return omap_current_dss_features->num_ovls;
}
+int dss_feat_get_num_wbs(void)
+{
+ return omap_current_dss_features->num_wbs;
+}
+
unsigned long dss_feat_get_param_min(enum dss_range_param param)
{
return omap_current_dss_features->dss_params[param].min;
@@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
return omap_current_dss_features->supported_displays[channel];
}
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
+{
+ return omap_current_dss_features->supported_outputs[channel];
+}
+
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
{
return omap_current_dss_features->supported_color_modes[plane];
@@ -694,8 +935,13 @@ void dss_features_init(void)
omap_current_dss_features = &omap2_dss_features;
else if (cpu_is_omap3630())
omap_current_dss_features = &omap3630_dss_features;
- else if (cpu_is_omap34xx())
- omap_current_dss_features = &omap3430_dss_features;
+ else if (cpu_is_omap34xx()) {
+ if (soc_is_am35xx()) {
+ omap_current_dss_features = &am35xx_dss_features;
+ } else {
+ omap_current_dss_features = &omap3430_dss_features;
+ }
+ }
else if (omap_rev() == OMAP4430_REV_ES1_0)
omap_current_dss_features = &omap4430_es1_0_dss_features;
else if (omap_rev() == OMAP4430_REV_ES2_0 ||
@@ -704,6 +950,8 @@ void dss_features_init(void)
omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
else if (cpu_is_omap44xx())
omap_current_dss_features = &omap4_dss_features;
+ else if (soc_is_omap54xx())
+ omap_current_dss_features = &omap5_dss_features;
else
DSSWARN("Unsupported OMAP version");
}
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 996ffcbfed5..9218113b5e8 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -50,6 +50,7 @@ enum dss_feat_id {
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_DSI_GNQ,
+ FEAT_DPI_USES_VDDS_DSI,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
@@ -64,6 +65,9 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
+ FEAT_DSI_PLL_SELFREQDCO,
+ FEAT_DSI_PLL_REFSEL,
+ FEAT_DSI_PHY_DCC,
};
/* DSS register field id */
@@ -91,6 +95,7 @@ enum dss_range_param {
FEAT_PARAM_DSIPLL_REGM_DSI,
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
+ FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
FEAT_PARAM_LINEWIDTH,
FEAT_PARAM_MGR_WIDTH,
@@ -100,9 +105,11 @@ enum dss_range_param {
/* DSS Feature Functions */
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
+int dss_feat_get_num_wbs(void);
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
+enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
bool dss_feat_color_mode_supported(enum omap_plane plane,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 060216fdc57..a48a7dd75b3 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -32,6 +32,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include "ti_hdmi.h"
@@ -61,6 +63,13 @@ static struct {
struct hdmi_ip_data ip_data;
struct clk *sys_clk;
+ struct regulator *vdda_hdmi_dac_reg;
+
+ int ct_cp_hpd_gpio;
+ int ls_oe_gpio;
+ int hpd_gpio;
+
+ struct omap_dss_output output;
} hdmi;
/*
@@ -314,12 +323,47 @@ static void hdmi_runtime_put(void)
static int __init hdmi_init_display(struct omap_dss_device *dssdev)
{
+ int r;
+
+ struct gpio gpios[] = {
+ { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" },
+ { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" },
+ { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" },
+ };
+
DSSDBG("init_display\n");
dss_init_hdmi_ip_ops(&hdmi.ip_data);
+
+ if (hdmi.vdda_hdmi_dac_reg == NULL) {
+ struct regulator *reg;
+
+ reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
+
+ if (IS_ERR(reg)) {
+ DSSERR("can't get VDDA_HDMI_DAC regulator\n");
+ return PTR_ERR(reg);
+ }
+
+ hdmi.vdda_hdmi_dac_reg = reg;
+ }
+
+ r = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+ if (r)
+ return r;
+
return 0;
}
+static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev)
+{
+ DSSDBG("uninit_display\n");
+
+ gpio_free(hdmi.ct_cp_hpd_gpio);
+ gpio_free(hdmi.ls_oe_gpio);
+ gpio_free(hdmi.hpd_gpio);
+}
+
static const struct hdmi_config *hdmi_find_timing(
const struct hdmi_config *timings_arr,
int len)
@@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r;
- const struct hdmi_config *timing;
struct omap_video_timings *p;
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
unsigned long phy;
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 1);
+ gpio_set_value(hdmi.ls_oe_gpio, 1);
+
+ /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */
+ udelay(300);
+
+ r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
+ if (r)
+ goto err_vdac_enable;
+
r = hdmi_runtime_get();
if (r)
- return r;
+ goto err_runtime_get;
- dss_mgr_disable(dssdev->manager);
+ dss_mgr_disable(mgr);
- p = &dssdev->panel.timings;
+ p = &hdmi.ip_data.cfg.timings;
- DSSDBG("hdmi_power_on x_res= %d y_res = %d\n",
- dssdev->panel.timings.x_res,
- dssdev->panel.timings.y_res);
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
- timing = hdmi_get_timings();
- if (timing == NULL) {
- /* HDMI code 4 corresponds to 640 * 480 VGA */
- hdmi.ip_data.cfg.cm.code = 4;
- /* DVI mode 1 corresponds to HDMI 0 to DVI */
- hdmi.ip_data.cfg.cm.mode = HDMI_DVI;
- hdmi.ip_data.cfg = vesa_timings[0];
- } else {
- hdmi.ip_data.cfg = *timing;
- }
phy = p->pixel_clock;
hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data);
@@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to lock PLL\n");
- goto err;
+ goto err_pll_enable;
}
r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data);
if (r) {
DSSDBG("Failed to start PHY\n");
- goto err;
+ goto err_phy_enable;
}
hdmi.ip_data.ops->video_configure(&hdmi.ip_data);
@@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
dispc_enable_gamma_table(0);
/* tv size */
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+ dss_mgr_set_timings(mgr, p);
r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data);
if (r)
goto err_vid_enable;
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
goto err_mgr_enable;
@@ -537,20 +579,33 @@ err_mgr_enable:
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
err_vid_enable:
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
+err_phy_enable:
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
-err:
+err_pll_enable:
hdmi_runtime_put();
+err_runtime_get:
+ regulator_disable(hdmi.vdda_hdmi_dac_reg);
+err_vdac_enable:
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
return -EIO;
}
static void hdmi_power_off(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ dss_mgr_disable(mgr);
hdmi.ip_data.ops->video_disable(&hdmi.ip_data);
hdmi.ip_data.ops->phy_disable(&hdmi.ip_data);
hdmi.ip_data.ops->pll_disable(&hdmi.ip_data);
hdmi_runtime_put();
+
+ regulator_disable(hdmi.vdda_hdmi_dac_reg);
+
+ gpio_set_value(hdmi.ct_cp_hpd_gpio, 0);
+ gpio_set_value(hdmi.ls_oe_gpio, 0);
}
int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
@@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev,
}
-void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev)
+void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
struct hdmi_cm cm;
+ const struct hdmi_config *t;
- cm = hdmi_get_code(&dssdev->panel.timings);
- hdmi.ip_data.cfg.cm.code = cm.code;
- hdmi.ip_data.cfg.cm.mode = cm.mode;
+ mutex_lock(&hdmi.lock);
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- int r;
+ cm = hdmi_get_code(timings);
+ hdmi.ip_data.cfg.cm = cm;
- hdmi_power_off(dssdev);
+ t = hdmi_get_timings();
+ if (t != NULL)
+ hdmi.ip_data.cfg = *t;
- r = hdmi_power_on(dssdev);
- if (r)
- DSSERR("failed to power on device\n");
- } else {
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
- }
+ mutex_unlock(&hdmi.lock);
}
static void hdmi_dump_regs(struct seq_file *s)
@@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void)
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_hdmi_data *priv = dssdev->data;
+ struct omap_dss_output *out = dssdev->output;
int r = 0;
DSSDBG("ENTER hdmi_display_enable\n");
mutex_lock(&hdmi.lock);
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV;
goto err0;
}
- hdmi.ip_data.hpd_gpio = priv->hpd_gpio;
+ hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio;
r = omap_dss_start_device(dssdev);
if (r) {
@@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r) {
- DSSERR("failed to enable GPIO's\n");
- goto err1;
- }
- }
-
r = hdmi_power_on(dssdev);
if (r) {
DSSERR("failed to power on device\n");
- goto err2;
+ goto err1;
}
mutex_unlock(&hdmi.lock);
return 0;
-err2:
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
err1:
omap_dss_stop_device(dssdev);
err0:
@@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
hdmi_power_off(dssdev);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
omap_dss_stop_device(dssdev);
mutex_unlock(&hdmi.lock);
@@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio)
#endif
-static void __init hdmi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int r, i;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI)
continue;
- r = hdmi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ return def_dssdev;
+}
+
+static void __init hdmi_probe_pdata(struct platform_device *pdev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ struct omap_dss_hdmi_data *priv;
+ int r;
+
+ plat_dssdev = hdmi_find_dssdev(pdev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&pdev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ priv = dssdev->data;
+
+ hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio;
+ 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;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init 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;
+
+ dss_register_output(out);
+}
+
+static void __exit hdmi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &hdmi.output;
+
+ dss_unregister_output(out);
}
/* HDMI HW IP initialisation */
@@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.core_av_offset = HDMI_CORE_AV;
hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY;
+
mutex_init(&hdmi.ip_data.lock);
hdmi_panel_init();
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+ hdmi_init_output(pdev);
+
hdmi_probe_pdata(pdev);
return 0;
}
+static int __exit hdmi_remove_child(struct device *dev, void *data)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ hdmi_uninit_display(dssdev);
+ return 0;
+}
+
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ device_for_each_child(&pdev->dev, NULL, hdmi_remove_child);
+
+ dss_unregister_child_devices(&pdev->dev);
hdmi_panel_exit();
+ hdmi_uninit_output(pdev);
+
pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c
index e10844faadf..69fb115bab3 100644
--- a/drivers/video/omap2/dss/hdmi_panel.c
+++ b/drivers/video/omap2/dss/hdmi_panel.c
@@ -41,17 +41,34 @@ static struct {
static int hdmi_panel_probe(struct omap_dss_device *dssdev)
{
+ /* Initialize default timings to VGA in DVI mode */
+ const struct omap_video_timings default_timings = {
+ .x_res = 640,
+ .y_res = 480,
+ .pixel_clock = 25175,
+ .hsw = 96,
+ .hfp = 16,
+ .hbp = 48,
+ .vsw = 2,
+ .vfp = 11,
+ .vbp = 31,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+
+ .interlace = false,
+ };
+
DSSDBG("ENTER hdmi_panel_probe\n");
- dssdev->panel.timings = (struct omap_video_timings)
- { 640, 480, 25175, 96, 16, 48, 2, 11, 31,
- OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
- false,
- };
+ dssdev->panel.timings = default_timings;
DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
dssdev->panel.timings.x_res,
dssdev->panel.timings.y_res);
+
+ omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
+
return 0;
}
@@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev)
goto err;
}
+ omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings);
+
r = omapdss_hdmi_display_enable(dssdev);
if (r) {
DSSERR("failed to power on\n");
@@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev,
*/
hdmi_panel_audio_disable(dssdev);
+ omapdss_hdmi_display_set_timing(dssdev, timings);
dssdev->panel.timings = *timings;
- omapdss_hdmi_display_set_timing(dssdev);
mutex_unlock(&hdmi.lock);
}
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c
new file mode 100644
index 00000000000..9a2fb59b6f8
--- /dev/null
+++ b/drivers/video/omap2/dss/manager-sysfs.c
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "MANAGER"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
+}
+
+static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_dss_device *dssdev = mgr->get_device(mgr);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
+ dssdev->name : "<none>");
+}
+
+static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ int r = 0;
+ size_t len = size;
+ struct omap_dss_device *dssdev = NULL;
+
+ int match(struct omap_dss_device *dssdev, void *data)
+ {
+ const char *str = data;
+ return sysfs_streq(dssdev->name, str);
+ }
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0)
+ dssdev = omap_dss_find_device((void *)buf, match);
+
+ if (len > 0 && dssdev == NULL)
+ return -EINVAL;
+
+ if (dssdev)
+ DSSDBG("display %s found\n", dssdev->name);
+
+ if (mgr->output) {
+ r = mgr->unset_output(mgr);
+ if (r) {
+ DSSERR("failed to unset current output\n");
+ goto put_device;
+ }
+ }
+
+ if (dssdev) {
+ struct omap_dss_output *out = dssdev->output;
+
+ /*
+ * a registered device should have an output connected to it
+ * already
+ */
+ if (!out) {
+ DSSERR("device has no output connected to it\n");
+ goto put_device;
+ }
+
+ r = mgr->set_output(mgr, out);
+ if (r) {
+ DSSERR("failed to set manager output\n");
+ goto put_device;
+ }
+
+ r = mgr->apply(mgr);
+ if (r) {
+ DSSERR("failed to apply dispc config\n");
+ goto put_device;
+ }
+ }
+
+put_device:
+ if (dssdev)
+ omap_dss_put_device(dssdev);
+
+ return r ? r : size;
+}
+
+static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
+}
+
+static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 color;
+ int r;
+
+ r = kstrtouint(buf, 0, &color);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.default_color = color;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static const char *trans_key_type_str[] = {
+ "gfx-destination",
+ "video-source",
+};
+
+static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ key_type = info.trans_key_type;
+ BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
+}
+
+static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ enum omap_dss_trans_key_type key_type;
+ struct omap_overlay_manager_info info;
+ int r;
+
+ for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+ key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
+ if (sysfs_streq(buf, trans_key_type_str[key_type]))
+ break;
+ }
+
+ if (key_type == ARRAY_SIZE(trans_key_type_str))
+ return -EINVAL;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key_type = key_type;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
+}
+
+static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ u32 key_value;
+ int r;
+
+ r = kstrtouint(buf, 0, &key_value);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_key = key_value;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
+}
+
+static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.trans_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_alpha_blending_enabled_show(
+ struct omap_overlay_manager *mgr, char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.partial_alpha_enabled);
+}
+
+static ssize_t manager_alpha_blending_enabled_store(
+ struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ bool enable;
+ int r;
+
+ WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.partial_alpha_enabled = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
+}
+
+static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ int r;
+ bool enable;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ mgr->get_manager_info(mgr, &info);
+
+ if (info.cpr_enable == enable)
+ return size;
+
+ info.cpr_enable = enable;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
+ char *buf)
+{
+ struct omap_overlay_manager_info info;
+
+ mgr->get_manager_info(mgr, &info);
+
+ return snprintf(buf, PAGE_SIZE,
+ "%d %d %d %d %d %d %d %d %d\n",
+ info.cpr_coefs.rr,
+ info.cpr_coefs.rg,
+ info.cpr_coefs.rb,
+ info.cpr_coefs.gr,
+ info.cpr_coefs.gg,
+ info.cpr_coefs.gb,
+ info.cpr_coefs.br,
+ info.cpr_coefs.bg,
+ info.cpr_coefs.bb);
+}
+
+static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager_info info;
+ struct omap_dss_cpr_coefs coefs;
+ int r, i;
+ s16 *arr;
+
+ if (!dss_has_feature(FEAT_CPR))
+ return -ENODEV;
+
+ if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
+ &coefs.rr, &coefs.rg, &coefs.rb,
+ &coefs.gr, &coefs.gg, &coefs.gb,
+ &coefs.br, &coefs.bg, &coefs.bb) != 9)
+ return -EINVAL;
+
+ arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
+ coefs.gr, coefs.gg, coefs.gb,
+ coefs.br, coefs.bg, coefs.bb };
+
+ for (i = 0; i < 9; ++i) {
+ if (arr[i] < -512 || arr[i] > 511)
+ return -EINVAL;
+ }
+
+ mgr->get_manager_info(mgr, &info);
+
+ info.cpr_coefs = coefs;
+
+ r = mgr->set_manager_info(mgr, &info);
+ if (r)
+ return r;
+
+ r = mgr->apply(mgr);
+ if (r)
+ return r;
+
+ return size;
+}
+
+struct manager_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay_manager *, char *);
+ ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
+};
+
+#define MANAGER_ATTR(_name, _mode, _show, _store) \
+ struct manager_attribute manager_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
+static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
+ manager_display_show, manager_display_store);
+static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
+ manager_default_color_show, manager_default_color_store);
+static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
+ manager_trans_key_type_show, manager_trans_key_type_store);
+static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
+ manager_trans_key_value_show, manager_trans_key_value_store);
+static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
+ manager_trans_key_enabled_show,
+ manager_trans_key_enabled_store);
+static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
+ manager_alpha_blending_enabled_show,
+ manager_alpha_blending_enabled_store);
+static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
+ manager_cpr_enable_show,
+ manager_cpr_enable_store);
+static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
+ manager_cpr_coef_show,
+ manager_cpr_coef_store);
+
+
+static struct attribute *manager_sysfs_attrs[] = {
+ &manager_attr_name.attr,
+ &manager_attr_display.attr,
+ &manager_attr_default_color.attr,
+ &manager_attr_trans_key_type.attr,
+ &manager_attr_trans_key_value.attr,
+ &manager_attr_trans_key_enabled.attr,
+ &manager_attr_alpha_blending_enabled.attr,
+ &manager_attr_cpr_enable.attr,
+ &manager_attr_cpr_coef.attr,
+ NULL
+};
+
+static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->show)
+ return -ENOENT;
+
+ return manager_attr->show(manager, buf);
+}
+
+static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay_manager *manager;
+ struct manager_attribute *manager_attr;
+
+ manager = container_of(kobj, struct omap_overlay_manager, kobj);
+ manager_attr = container_of(attr, struct manager_attribute, attr);
+
+ if (!manager_attr->store)
+ return -ENOENT;
+
+ return manager_attr->store(manager, buf, size);
+}
+
+static const struct sysfs_ops manager_sysfs_ops = {
+ .show = manager_attr_show,
+ .store = manager_attr_store,
+};
+
+static struct kobj_type manager_ktype = {
+ .sysfs_ops = &manager_sysfs_ops,
+ .default_attrs = manager_sysfs_attrs,
+};
+
+int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&mgr->kobj, &manager_ktype,
+ &pdev->dev.kobj, "manager%d", mgr->id);
+}
+
+void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
+{
+ kobject_del(&mgr->kobj);
+ kobject_put(&mgr->kobj);
+}
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 53710fadc82..c54d2f620ce 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -36,463 +36,15 @@
static int num_managers;
static struct omap_overlay_manager *managers;
-static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
+static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
+ return mgr->output ? mgr->output->device : NULL;
}
-static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n",
- mgr->device ? mgr->device->name : "<none>");
-}
-
-static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- int r = 0;
- size_t len = size;
- struct omap_dss_device *dssdev = NULL;
-
- int match(struct omap_dss_device *dssdev, void *data)
- {
- const char *str = data;
- return sysfs_streq(dssdev->name, str);
- }
-
- if (buf[size-1] == '\n')
- --len;
-
- if (len > 0)
- dssdev = omap_dss_find_device((void *)buf, match);
-
- if (len > 0 && dssdev == NULL)
- return -EINVAL;
-
- if (dssdev)
- DSSDBG("display %s found\n", dssdev->name);
-
- if (mgr->device) {
- r = mgr->unset_device(mgr);
- if (r) {
- DSSERR("failed to unset display\n");
- goto put_device;
- }
- }
-
- if (dssdev) {
- r = mgr->set_device(mgr, dssdev);
- if (r) {
- DSSERR("failed to set manager\n");
- goto put_device;
- }
-
- r = mgr->apply(mgr);
- if (r) {
- DSSERR("failed to apply dispc config\n");
- goto put_device;
- }
- }
-
-put_device:
- if (dssdev)
- omap_dss_put_device(dssdev);
-
- return r ? r : size;
-}
-
-static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
-}
-
-static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- u32 color;
- int r;
-
- r = kstrtouint(buf, 0, &color);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.default_color = color;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static const char *trans_key_type_str[] = {
- "gfx-destination",
- "video-source",
-};
-
-static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- enum omap_dss_trans_key_type key_type;
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- key_type = info.trans_key_type;
- BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
-
- return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
-}
-
-static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- enum omap_dss_trans_key_type key_type;
- struct omap_overlay_manager_info info;
- int r;
-
- for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
- key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
- if (sysfs_streq(buf, trans_key_type_str[key_type]))
- break;
- }
-
- if (key_type == ARRAY_SIZE(trans_key_type_str))
- return -EINVAL;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_key_type = key_type;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
-}
-
-static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- u32 key_value;
- int r;
-
- r = kstrtouint(buf, 0, &key_value);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_key = key_value;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
-}
-
-static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- bool enable;
- int r;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.trans_enabled = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_alpha_blending_enabled_show(
- struct omap_overlay_manager *mgr, char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.partial_alpha_enabled);
-}
-
-static ssize_t manager_alpha_blending_enabled_store(
- struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- bool enable;
- int r;
-
- WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER));
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- info.partial_alpha_enabled = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
-}
-
-static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- int r;
- bool enable;
-
- if (!dss_has_feature(FEAT_CPR))
- return -ENODEV;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- mgr->get_manager_info(mgr, &info);
-
- if (info.cpr_enable == enable)
- return size;
-
- info.cpr_enable = enable;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
- char *buf)
-{
- struct omap_overlay_manager_info info;
-
- mgr->get_manager_info(mgr, &info);
-
- return snprintf(buf, PAGE_SIZE,
- "%d %d %d %d %d %d %d %d %d\n",
- info.cpr_coefs.rr,
- info.cpr_coefs.rg,
- info.cpr_coefs.rb,
- info.cpr_coefs.gr,
- info.cpr_coefs.gg,
- info.cpr_coefs.gb,
- info.cpr_coefs.br,
- info.cpr_coefs.bg,
- info.cpr_coefs.bb);
-}
-
-static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager_info info;
- struct omap_dss_cpr_coefs coefs;
- int r, i;
- s16 *arr;
-
- if (!dss_has_feature(FEAT_CPR))
- return -ENODEV;
-
- if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
- &coefs.rr, &coefs.rg, &coefs.rb,
- &coefs.gr, &coefs.gg, &coefs.gb,
- &coefs.br, &coefs.bg, &coefs.bb) != 9)
- return -EINVAL;
-
- arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
- coefs.gr, coefs.gg, coefs.gb,
- coefs.br, coefs.bg, coefs.bb };
-
- for (i = 0; i < 9; ++i) {
- if (arr[i] < -512 || arr[i] > 511)
- return -EINVAL;
- }
-
- mgr->get_manager_info(mgr, &info);
-
- info.cpr_coefs = coefs;
-
- r = mgr->set_manager_info(mgr, &info);
- if (r)
- return r;
-
- r = mgr->apply(mgr);
- if (r)
- return r;
-
- return size;
-}
-
-struct manager_attribute {
- struct attribute attr;
- ssize_t (*show)(struct omap_overlay_manager *, char *);
- ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
-};
-
-#define MANAGER_ATTR(_name, _mode, _show, _store) \
- struct manager_attribute manager_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
-static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
- manager_display_show, manager_display_store);
-static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
- manager_default_color_show, manager_default_color_store);
-static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
- manager_trans_key_type_show, manager_trans_key_type_store);
-static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
- manager_trans_key_value_show, manager_trans_key_value_store);
-static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
- manager_trans_key_enabled_show,
- manager_trans_key_enabled_store);
-static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
- manager_alpha_blending_enabled_show,
- manager_alpha_blending_enabled_store);
-static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
- manager_cpr_enable_show,
- manager_cpr_enable_store);
-static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
- manager_cpr_coef_show,
- manager_cpr_coef_store);
-
-
-static struct attribute *manager_sysfs_attrs[] = {
- &manager_attr_name.attr,
- &manager_attr_display.attr,
- &manager_attr_default_color.attr,
- &manager_attr_trans_key_type.attr,
- &manager_attr_trans_key_value.attr,
- &manager_attr_trans_key_enabled.attr,
- &manager_attr_alpha_blending_enabled.attr,
- &manager_attr_cpr_enable.attr,
- &manager_attr_cpr_coef.attr,
- NULL
-};
-
-static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct omap_overlay_manager *manager;
- struct manager_attribute *manager_attr;
-
- manager = container_of(kobj, struct omap_overlay_manager, kobj);
- manager_attr = container_of(attr, struct manager_attribute, attr);
-
- if (!manager_attr->show)
- return -ENOENT;
-
- return manager_attr->show(manager, buf);
-}
-
-static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_overlay_manager *manager;
- struct manager_attribute *manager_attr;
-
- manager = container_of(kobj, struct omap_overlay_manager, kobj);
- manager_attr = container_of(attr, struct manager_attribute, attr);
-
- if (!manager_attr->store)
- return -ENOENT;
-
- return manager_attr->store(manager, buf, size);
-}
-
-static const struct sysfs_ops manager_sysfs_ops = {
- .show = manager_attr_show,
- .store = manager_attr_store,
-};
-
-static struct kobj_type manager_ktype = {
- .sysfs_ops = &manager_sysfs_ops,
- .default_attrs = manager_sysfs_attrs,
-};
-
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;
@@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
if (r)
return r;
- if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
+ if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
irq = DISPC_IRQ_EVSYNC_ODD;
- else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI)
+ else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI)
irq = DISPC_IRQ_EVSYNC_EVEN;
else
irq = dispc_mgr_get_vsync_irq(mgr->id);
@@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev)
break;
}
- mgr->set_device = &dss_mgr_set_device;
- mgr->unset_device = &dss_mgr_unset_device;
+ mgr->set_output = &dss_mgr_set_output;
+ mgr->unset_output = &dss_mgr_unset_output;
mgr->apply = &omap_dss_mgr_apply;
mgr->set_manager_info = &dss_mgr_set_info;
mgr->get_manager_info = &dss_mgr_get_info;
mgr->wait_for_go = &dss_mgr_wait_for_go;
mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
+ mgr->get_device = &dss_mgr_get_device;
mgr->caps = 0;
mgr->supported_displays =
dss_feat_get_supported_displays(mgr->id);
+ mgr->supported_outputs =
+ dss_feat_get_supported_outputs(mgr->id);
INIT_LIST_HEAD(&mgr->overlays);
- r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
- &pdev->dev.kobj, "manager%d", i);
-
+ r = dss_manager_kobj_init(mgr, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
@@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev)
for (i = 0; i < num_managers; ++i) {
struct omap_overlay_manager *mgr = &managers[i];
-
- kobject_del(&mgr->kobj);
- kobject_put(&mgr->kobj);
+ dss_manager_kobj_uninit(mgr);
}
kfree(managers);
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c
new file mode 100644
index 00000000000..813f26682b7
--- /dev/null
+++ b/drivers/video/omap2/dss/output.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Ltd
+ * Author: Archit Taneja <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static LIST_HEAD(output_list);
+static DEFINE_MUTEX(output_lock);
+
+int omapdss_output_set_device(struct omap_dss_output *out,
+ struct omap_dss_device *dssdev)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (out->device) {
+ DSSERR("output already has device %s connected to it\n",
+ out->device->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->type != dssdev->type) {
+ DSSERR("output type and display type don't match\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->device = dssdev;
+ dssdev->output = out;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_set_device);
+
+int omapdss_output_unset_device(struct omap_dss_output *out)
+{
+ int r;
+
+ mutex_lock(&output_lock);
+
+ if (!out->device) {
+ DSSERR("output doesn't have a device connected to it\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) {
+ DSSERR("device %s is not disabled, cannot unset device\n",
+ out->device->name);
+ r = -EINVAL;
+ goto err;
+ }
+
+ out->device->output = NULL;
+ out->device = NULL;
+
+ mutex_unlock(&output_lock);
+
+ return 0;
+err:
+ mutex_unlock(&output_lock);
+
+ return r;
+}
+EXPORT_SYMBOL(omapdss_output_unset_device);
+
+void dss_register_output(struct omap_dss_output *out)
+{
+ list_add_tail(&out->list, &output_list);
+}
+
+void dss_unregister_output(struct omap_dss_output *out)
+{
+ list_del(&out->list);
+}
+
+struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
+{
+ struct omap_dss_output *out;
+
+ list_for_each_entry(out, &output_list, list) {
+ if (out->id == id)
+ return out;
+ }
+
+ return NULL;
+}
+
+struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_output *out = NULL;
+ enum omap_dss_output_id id;
+
+ switch (dssdev->type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI);
+ break;
+ case OMAP_DISPLAY_TYPE_DBI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI);
+ break;
+ case OMAP_DISPLAY_TYPE_VENC:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC);
+ break;
+ case OMAP_DISPLAY_TYPE_HDMI:
+ out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI);
+ break;
+ case OMAP_DISPLAY_TYPE_DSI:
+ id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 :
+ OMAP_DSS_OUTPUT_DSI2;
+ out = omap_dss_get_output(id);
+ break;
+ default:
+ break;
+ }
+
+ return out;
+}
diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c
new file mode 100644
index 00000000000..4cc5ddebfb3
--- /dev/null
+++ b/drivers/video/omap2/dss/overlay-sysfs.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * Some code and ideas taken from drivers/video/omap/ driver
+ * by Imre Deak.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "OVERLAY"
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
+}
+
+static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ovl->manager ? ovl->manager->name : "<none>");
+}
+
+static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int i, r;
+ struct omap_overlay_manager *mgr = NULL;
+ struct omap_overlay_manager *old_mgr;
+ int len = size;
+
+ if (buf[size-1] == '\n')
+ --len;
+
+ if (len > 0) {
+ for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
+ mgr = omap_dss_get_overlay_manager(i);
+
+ if (sysfs_streq(buf, mgr->name))
+ break;
+
+ mgr = NULL;
+ }
+ }
+
+ if (len > 0 && mgr == NULL)
+ return -EINVAL;
+
+ if (mgr)
+ DSSDBG("manager %s found\n", mgr->name);
+
+ if (mgr == ovl->manager)
+ return size;
+
+ old_mgr = ovl->manager;
+
+ r = dispc_runtime_get();
+ if (r)
+ return r;
+
+ /* detach old manager */
+ if (old_mgr) {
+ r = ovl->unset_manager(ovl);
+ if (r) {
+ DSSERR("detach failed\n");
+ goto err;
+ }
+
+ r = old_mgr->apply(old_mgr);
+ if (r)
+ goto err;
+ }
+
+ if (mgr) {
+ r = ovl->set_manager(ovl, mgr);
+ if (r) {
+ DSSERR("Failed to attach overlay\n");
+ goto err;
+ }
+
+ r = mgr->apply(mgr);
+ if (r)
+ goto err;
+ }
+
+ dispc_runtime_put();
+
+ return size;
+
+err:
+ dispc_runtime_put();
+ return r;
+}
+
+static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.width, info.height);
+}
+
+static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
+}
+
+static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.pos_x, info.pos_y);
+}
+
+static ssize_t overlay_position_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pos_x = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.pos_y = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d,%d\n",
+ info.out_width, info.out_height);
+}
+
+static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ char *last;
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.out_width = simple_strtoul(buf, &last, 10);
+ ++last;
+ if (last - buf >= size)
+ return -EINVAL;
+
+ info.out_height = simple_strtoul(last, &last, 10);
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
+}
+
+static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
+ size_t size)
+{
+ int r;
+ bool enable;
+
+ r = strtobool(buf, &enable);
+ if (r)
+ return r;
+
+ if (enable)
+ r = ovl->enable(ovl);
+ else
+ r = ovl->disable(ovl);
+
+ if (r)
+ return r;
+
+ return size;
+}
+
+static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.global_alpha);
+}
+
+static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 alpha;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.global_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
+ char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ info.pre_mult_alpha);
+}
+
+static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 alpha;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &alpha);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.pre_mult_alpha = alpha;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
+{
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
+}
+
+static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
+ const char *buf, size_t size)
+{
+ int r;
+ u8 zorder;
+ struct omap_overlay_info info;
+
+ if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
+ return -ENODEV;
+
+ r = kstrtou8(buf, 0, &zorder);
+ if (r)
+ return r;
+
+ ovl->get_overlay_info(ovl, &info);
+
+ info.zorder = zorder;
+
+ r = ovl->set_overlay_info(ovl, &info);
+ if (r)
+ return r;
+
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ return r;
+ }
+
+ return size;
+}
+
+struct overlay_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct omap_overlay *, char *);
+ ssize_t (*store)(struct omap_overlay *, const char *, size_t);
+};
+
+#define OVERLAY_ATTR(_name, _mode, _show, _store) \
+ struct overlay_attribute overlay_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
+static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
+ overlay_manager_show, overlay_manager_store);
+static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
+static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
+static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
+ overlay_position_show, overlay_position_store);
+static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
+ overlay_output_size_show, overlay_output_size_store);
+static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
+ overlay_enabled_show, overlay_enabled_store);
+static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
+ overlay_global_alpha_show, overlay_global_alpha_store);
+static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
+ overlay_pre_mult_alpha_show,
+ overlay_pre_mult_alpha_store);
+static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
+ overlay_zorder_show, overlay_zorder_store);
+
+static struct attribute *overlay_sysfs_attrs[] = {
+ &overlay_attr_name.attr,
+ &overlay_attr_manager.attr,
+ &overlay_attr_input_size.attr,
+ &overlay_attr_screen_width.attr,
+ &overlay_attr_position.attr,
+ &overlay_attr_output_size.attr,
+ &overlay_attr_enabled.attr,
+ &overlay_attr_global_alpha.attr,
+ &overlay_attr_pre_mult_alpha.attr,
+ &overlay_attr_zorder.attr,
+ NULL
+};
+
+static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->show)
+ return -ENOENT;
+
+ return overlay_attr->show(overlay, buf);
+}
+
+static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap_overlay *overlay;
+ struct overlay_attribute *overlay_attr;
+
+ overlay = container_of(kobj, struct omap_overlay, kobj);
+ overlay_attr = container_of(attr, struct overlay_attribute, attr);
+
+ if (!overlay_attr->store)
+ return -ENOENT;
+
+ return overlay_attr->store(overlay, buf, size);
+}
+
+static const struct sysfs_ops overlay_sysfs_ops = {
+ .show = overlay_attr_show,
+ .store = overlay_attr_store,
+};
+
+static struct kobj_type overlay_ktype = {
+ .sysfs_ops = &overlay_sysfs_ops,
+ .default_attrs = overlay_sysfs_attrs,
+};
+
+int dss_overlay_kobj_init(struct omap_overlay *ovl,
+ struct platform_device *pdev)
+{
+ return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
+ &pdev->dev.kobj, "overlay%d", ovl->id);
+}
+
+void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
+{
+ kobject_del(&ovl->kobj);
+ kobject_put(&ovl->kobj);
+}
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
index 952c6fad9a8..45f4994bc6b 100644
--- a/drivers/video/omap2/dss/overlay.c
+++ b/drivers/video/omap2/dss/overlay.c
@@ -26,13 +26,11 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/sysfs.h>
-#include <linux/kobject.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@@ -40,417 +38,13 @@
static int num_overlays;
static struct omap_overlay *overlays;
-static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
+static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
+ return ovl->manager ?
+ (ovl->manager->output ? ovl->manager->output->device : NULL) :
+ NULL;
}
-static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%s\n",
- ovl->manager ? ovl->manager->name : "<none>");
-}
-
-static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
- size_t size)
-{
- int i, r;
- struct omap_overlay_manager *mgr = NULL;
- struct omap_overlay_manager *old_mgr;
- int len = size;
-
- if (buf[size-1] == '\n')
- --len;
-
- if (len > 0) {
- for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
- mgr = omap_dss_get_overlay_manager(i);
-
- if (sysfs_streq(buf, mgr->name))
- break;
-
- mgr = NULL;
- }
- }
-
- if (len > 0 && mgr == NULL)
- return -EINVAL;
-
- if (mgr)
- DSSDBG("manager %s found\n", mgr->name);
-
- if (mgr == ovl->manager)
- return size;
-
- old_mgr = ovl->manager;
-
- r = dispc_runtime_get();
- if (r)
- return r;
-
- /* detach old manager */
- if (old_mgr) {
- r = ovl->unset_manager(ovl);
- if (r) {
- DSSERR("detach failed\n");
- goto err;
- }
-
- r = old_mgr->apply(old_mgr);
- if (r)
- goto err;
- }
-
- if (mgr) {
- r = ovl->set_manager(ovl, mgr);
- if (r) {
- DSSERR("Failed to attach overlay\n");
- goto err;
- }
-
- r = mgr->apply(mgr);
- if (r)
- goto err;
- }
-
- dispc_runtime_put();
-
- return size;
-
-err:
- dispc_runtime_put();
- return r;
-}
-
-static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.width, info.height);
-}
-
-static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
-}
-
-static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.pos_x, info.pos_y);
-}
-
-static ssize_t overlay_position_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- char *last;
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.pos_x = simple_strtoul(buf, &last, 10);
- ++last;
- if (last - buf >= size)
- return -EINVAL;
-
- info.pos_y = simple_strtoul(last, &last, 10);
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d,%d\n",
- info.out_width, info.out_height);
-}
-
-static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- char *last;
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.out_width = simple_strtoul(buf, &last, 10);
- ++last;
- if (last - buf >= size)
- return -EINVAL;
-
- info.out_height = simple_strtoul(last, &last, 10);
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
-}
-
-static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
- size_t size)
-{
- int r;
- bool enable;
-
- r = strtobool(buf, &enable);
- if (r)
- return r;
-
- if (enable)
- r = ovl->enable(ovl);
- else
- r = ovl->disable(ovl);
-
- if (r)
- return r;
-
- return size;
-}
-
-static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.global_alpha);
-}
-
-static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- u8 alpha;
- struct omap_overlay_info info;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &alpha);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.global_alpha = alpha;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
- char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- info.pre_mult_alpha);
-}
-
-static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- u8 alpha;
- struct omap_overlay_info info;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &alpha);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.pre_mult_alpha = alpha;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
-{
- struct omap_overlay_info info;
-
- ovl->get_overlay_info(ovl, &info);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
-}
-
-static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
- const char *buf, size_t size)
-{
- int r;
- u8 zorder;
- struct omap_overlay_info info;
-
- if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
- return -ENODEV;
-
- r = kstrtou8(buf, 0, &zorder);
- if (r)
- return r;
-
- ovl->get_overlay_info(ovl, &info);
-
- info.zorder = zorder;
-
- r = ovl->set_overlay_info(ovl, &info);
- if (r)
- return r;
-
- if (ovl->manager) {
- r = ovl->manager->apply(ovl->manager);
- if (r)
- return r;
- }
-
- return size;
-}
-
-struct overlay_attribute {
- struct attribute attr;
- ssize_t (*show)(struct omap_overlay *, char *);
- ssize_t (*store)(struct omap_overlay *, const char *, size_t);
-};
-
-#define OVERLAY_ATTR(_name, _mode, _show, _store) \
- struct overlay_attribute overlay_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
-static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
- overlay_manager_show, overlay_manager_store);
-static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
-static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
-static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
- overlay_position_show, overlay_position_store);
-static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
- overlay_output_size_show, overlay_output_size_store);
-static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
- overlay_enabled_show, overlay_enabled_store);
-static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
- overlay_global_alpha_show, overlay_global_alpha_store);
-static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
- overlay_pre_mult_alpha_show,
- overlay_pre_mult_alpha_store);
-static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
- overlay_zorder_show, overlay_zorder_store);
-
-static struct attribute *overlay_sysfs_attrs[] = {
- &overlay_attr_name.attr,
- &overlay_attr_manager.attr,
- &overlay_attr_input_size.attr,
- &overlay_attr_screen_width.attr,
- &overlay_attr_position.attr,
- &overlay_attr_output_size.attr,
- &overlay_attr_enabled.attr,
- &overlay_attr_global_alpha.attr,
- &overlay_attr_pre_mult_alpha.attr,
- &overlay_attr_zorder.attr,
- NULL
-};
-
-static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct omap_overlay *overlay;
- struct overlay_attribute *overlay_attr;
-
- overlay = container_of(kobj, struct omap_overlay, kobj);
- overlay_attr = container_of(attr, struct overlay_attribute, attr);
-
- if (!overlay_attr->show)
- return -ENOENT;
-
- return overlay_attr->show(overlay, buf);
-}
-
-static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t size)
-{
- struct omap_overlay *overlay;
- struct overlay_attribute *overlay_attr;
-
- overlay = container_of(kobj, struct omap_overlay, kobj);
- overlay_attr = container_of(attr, struct overlay_attribute, attr);
-
- if (!overlay_attr->store)
- return -ENOENT;
-
- return overlay_attr->store(overlay, buf, size);
-}
-
-static const struct sysfs_ops overlay_sysfs_ops = {
- .show = overlay_attr_show,
- .store = overlay_attr_store,
-};
-
-static struct kobj_type overlay_ktype = {
- .sysfs_ops = &overlay_sysfs_ops,
- .default_attrs = overlay_sysfs_attrs,
-};
-
int omap_dss_get_num_overlays(void)
{
return num_overlays;
@@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev)
ovl->set_overlay_info = &dss_ovl_set_info;
ovl->get_overlay_info = &dss_ovl_get_info;
ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
+ ovl->get_device = &dss_ovl_get_device;
ovl->caps = dss_feat_get_overlay_caps(ovl->id);
ovl->supported_modes =
dss_feat_get_supported_color_modes(ovl->id);
- r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
- &pdev->dev.kobj, "overlay%d", i);
-
+ r = dss_overlay_kobj_init(ovl, pdev);
if (r)
DSSERR("failed to create sysfs file\n");
}
}
-/* connect overlays to the new device, if not already connected. if force
- * selected, connect always. */
-void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
-{
- int i;
- struct omap_overlay_manager *lcd_mgr;
- struct omap_overlay_manager *tv_mgr;
- struct omap_overlay_manager *lcd2_mgr = NULL;
- struct omap_overlay_manager *lcd3_mgr = NULL;
- struct omap_overlay_manager *mgr = NULL;
-
- lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD);
- tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT);
- if (dss_has_feature(FEAT_MGR_LCD3))
- lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3);
- if (dss_has_feature(FEAT_MGR_LCD2))
- lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2);
-
- if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) {
- if (!lcd3_mgr->device || force) {
- if (lcd3_mgr->device)
- lcd3_mgr->unset_device(lcd3_mgr);
- lcd3_mgr->set_device(lcd3_mgr, dssdev);
- mgr = lcd3_mgr;
- }
- } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) {
- if (!lcd2_mgr->device || force) {
- if (lcd2_mgr->device)
- lcd2_mgr->unset_device(lcd2_mgr);
- lcd2_mgr->set_device(lcd2_mgr, dssdev);
- mgr = lcd2_mgr;
- }
- } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC
- && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) {
- if (!lcd_mgr->device || force) {
- if (lcd_mgr->device)
- lcd_mgr->unset_device(lcd_mgr);
- lcd_mgr->set_device(lcd_mgr, dssdev);
- mgr = lcd_mgr;
- }
- }
-
- if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
- || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
- if (!tv_mgr->device || force) {
- if (tv_mgr->device)
- tv_mgr->unset_device(tv_mgr);
- tv_mgr->set_device(tv_mgr, dssdev);
- mgr = tv_mgr;
- }
- }
-
- if (mgr) {
- dispc_runtime_get();
-
- for (i = 0; i < dss_feat_get_num_ovls(); i++) {
- struct omap_overlay *ovl;
- ovl = omap_dss_get_overlay(i);
- if (!ovl->manager || force) {
- if (ovl->manager)
- ovl->unset_manager(ovl);
- ovl->set_manager(ovl, mgr);
- }
- }
-
- dispc_runtime_put();
- }
-}
-
void dss_uninit_overlays(struct platform_device *pdev)
{
int i;
for (i = 0; i < num_overlays; ++i) {
struct omap_overlay *ovl = &overlays[i];
-
- kobject_del(&ovl->kobj);
- kobject_put(&ovl->kobj);
+ dss_overlay_kobj_uninit(ovl);
}
kfree(overlays);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 7c087424b63..7282e5af3e1 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -111,6 +111,13 @@ static struct {
struct omap_dss_device *dssdev[2];
struct semaphore bus_lock;
+
+ struct omap_video_timings timings;
+ int pixel_size;
+ int data_lines;
+ struct rfbi_timings intf_timings;
+
+ struct omap_dss_output output;
} rfbi;
static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
@@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
}
EXPORT_SYMBOL(omap_rfbi_write_pixels);
-static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
- u16 height, void (*callback)(void *data), void *data)
+static int rfbi_transfer_area(struct omap_dss_device *dssdev,
+ void (*callback)(void *data), void *data)
{
u32 l;
int r;
- struct omap_video_timings timings = {
- .hsw = 1,
- .hfp = 1,
- .hbp = 1,
- .vsw = 1,
- .vfp = 0,
- .vbp = 0,
- .x_res = width,
- .y_res = height,
- };
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+ u16 width = rfbi.timings.x_res;
+ u16 height = rfbi.timings.y_res;
/*BUG_ON(callback == 0);*/
BUG_ON(rfbi.framedone_callback != NULL);
DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
- dss_mgr_set_timings(dssdev->manager, &timings);
+ dss_mgr_set_timings(mgr, &rfbi.timings);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
return r;
@@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines)
return 0;
}
-int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
- int data_lines)
+int omap_rfbi_configure(struct omap_dss_device *dssdev)
{
- return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
+ return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.data_lines);
}
EXPORT_SYMBOL(omap_rfbi_configure);
-int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
- u16 *x, u16 *y, u16 *w, u16 *h)
+int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
+ void *data)
{
- u16 dw, dh;
- struct omap_video_timings timings = {
- .hsw = 1,
- .hfp = 1,
- .hbp = 1,
- .vsw = 1,
- .vfp = 0,
- .vbp = 0,
- .x_res = *w,
- .y_res = *h,
- };
-
- dssdev->driver->get_resolution(dssdev, &dw, &dh);
-
- if (*x > dw || *y > dh)
- return -EINVAL;
-
- if (*x + *w > dw)
- return -EINVAL;
-
- if (*y + *h > dh)
- return -EINVAL;
-
- if (*w == 1)
- return -EINVAL;
-
- if (*w == 0 || *h == 0)
- return -EINVAL;
-
- dss_mgr_set_timings(dssdev->manager, &timings);
+ return rfbi_transfer_area(dssdev, callback, data);
+}
+EXPORT_SYMBOL(omap_rfbi_update);
- return 0;
+void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
+{
+ rfbi.timings.x_res = w;
+ rfbi.timings.y_res = h;
}
-EXPORT_SYMBOL(omap_rfbi_prepare_update);
+EXPORT_SYMBOL(omapdss_rfbi_set_size);
-int omap_rfbi_update(struct omap_dss_device *dssdev,
- u16 x, u16 y, u16 w, u16 h,
- void (*callback)(void *), void *data)
+void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
{
- int r;
+ rfbi.pixel_size = pixel_size;
+}
+EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size);
- r = rfbi_transfer_area(dssdev, w, h, callback, data);
+void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
+{
+ rfbi.data_lines = data_lines;
+}
+EXPORT_SYMBOL(omapdss_rfbi_set_data_lines);
- return r;
+void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev,
+ struct rfbi_timings *timings)
+{
+ rfbi.intf_timings = *timings;
}
-EXPORT_SYMBOL(omap_rfbi_update);
+EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings);
static void rfbi_dump_regs(struct seq_file *s)
{
@@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s)
static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
struct dss_lcd_mgr_config mgr_config;
mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
@@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
/* Do we need fifohandcheck for RFBI? */
mgr_config.fifohandcheck = false;
- mgr_config.video_port_width = dssdev->ctrl.pixel_size;
+ mgr_config.video_port_width = rfbi.pixel_size;
mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(dssdev->manager, &mgr_config);
+ dss_mgr_set_lcd_config(mgr, &mgr_config);
+
+ /*
+ * Set rfbi.timings with default values, the x_res and y_res fields
+ * are expected to be already configured by the panel driver via
+ * omapdss_rfbi_set_size()
+ */
+ rfbi.timings.hsw = 1;
+ rfbi.timings.hfp = 1;
+ rfbi.timings.hbp = 1;
+ rfbi.timings.vsw = 1;
+ rfbi.timings.vfp = 0;
+ rfbi.timings.vbp = 0;
+
+ rfbi.timings.interlace = false;
+ rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
+ rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
+
+ dss_mgr_set_timings(mgr, &rfbi.timings);
}
int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
+ struct omap_dss_output *out = dssdev->output;
int r;
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
rfbi_config_lcd_manager(dssdev);
- rfbi_configure(dssdev->phy.rfbi.channel,
- dssdev->ctrl.pixel_size,
- dssdev->phy.rfbi.data_lines);
-
- rfbi_set_timings(dssdev->phy.rfbi.channel,
- &dssdev->ctrl.rfbi_timings);
+ rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size,
+ rfbi.data_lines);
+ rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
return 0;
err1:
@@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable);
static int __init rfbi_init_display(struct omap_dss_device *dssdev)
{
rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
- dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
return 0;
}
-static void __init rfbi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_DBI)
continue;
- r = rfbi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init rfbi_probe_pdata(struct platform_device *rfbidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = rfbi_find_dssdev(rfbidev);
+
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&rfbidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ r = rfbi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init 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;
+
+ dss_register_output(out);
+}
+
+static void __exit rfbi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &rfbi.output;
+
+ dss_unregister_output(out);
}
/* RFBI HW IP initialisation */
@@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev)
dss_debugfs_create_file("rfbi", rfbi_dump_regs);
+ rfbi_init_output(pdev);
+
rfbi_probe_pdata(pdev);
return 0;
@@ -1031,8 +1089,12 @@ err_runtime_get:
static int __exit omap_rfbihw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ rfbi_uninit_output(pdev);
+
pm_runtime_disable(&pdev->dev);
+
return 0;
}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index f43bfe17b3b..7760851f6e5 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -25,6 +25,7 @@
#include <linux/regulator/consumer.h>
#include <linux/export.h>
#include <linux/platform_device.h>
+#include <linux/string.h>
#include <video/omapdss.h>
#include "dss.h"
@@ -34,10 +35,16 @@ static struct {
struct regulator *vdds_sdi_reg;
struct dss_lcd_mgr_config mgr_config;
+ struct omap_video_timings timings;
+ int datapairs;
+
+ struct omap_dss_output output;
} sdi;
static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
sdi.mgr_config.stallmode = false;
@@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
sdi.mgr_config.video_port_width = 24;
sdi.mgr_config.lcden_sig_polarity = 1;
- dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config);
+ dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
}
int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_video_timings *t = &dssdev->panel.timings;
+ struct omap_dss_output *out = dssdev->output;
+ struct omap_video_timings *t = &sdi.timings;
struct dss_clock_info dss_cinfo;
struct dispc_clock_info dispc_cinfo;
unsigned long pck;
int r;
- if (dssdev->manager == NULL) {
- DSSERR("failed to enable display: no manager\n");
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
return -ENODEV;
}
@@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
goto err_get_dispc;
/* 15.5.9.1.2 */
- dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
- dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
+ 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);
if (r)
@@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
}
- dss_mgr_set_timings(dssdev->manager, t);
+ dss_mgr_set_timings(out->manager, t);
r = dss_set_clock_div(&dss_cinfo);
if (r)
@@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
* need to care about the shadow register mechanism for pck-free. The
* exact reason for this is unknown.
*/
- dispc_mgr_set_clock_div(dssdev->manager->id,
- &sdi.mgr_config.clock_info);
+ dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
- dss_sdi_init(dssdev->phy.sdi.datapairs);
+ dss_sdi_init(sdi.datapairs);
r = dss_sdi_enable();
if (r)
goto err_sdi_enable;
mdelay(2);
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(out->manager);
if (r)
goto err_mgr_enable;
@@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- dss_mgr_disable(dssdev->manager);
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
+ dss_mgr_disable(mgr);
dss_sdi_disable();
@@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
+void omapdss_sdi_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ sdi.timings = *timings;
+}
+EXPORT_SYMBOL(omapdss_sdi_set_timings);
+
+void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
+{
+ sdi.datapairs = datapairs;
+}
+EXPORT_SYMBOL(omapdss_sdi_set_datapairs);
+
static int __init sdi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("SDI init\n");
@@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev)
return 0;
}
-static void __init sdi_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int i, r;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_SDI)
continue;
- r = sdi_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init sdi_probe_pdata(struct platform_device *sdidev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = sdi_find_dssdev(sdidev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&sdidev->dev);
+ if (!dssdev)
+ return;
+
+ dss_copy_device_pdata(dssdev, plat_dssdev);
+
+ r = sdi_init_display(dssdev);
+ if (r) {
+ DSSERR("device %s init failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init 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;
+
+ dss_register_output(out);
+}
+
+static void __exit sdi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &sdi.output;
+
+ dss_unregister_output(out);
}
static int __init omap_sdi_probe(struct platform_device *pdev)
{
+ sdi_init_output(pdev);
+
sdi_probe_pdata(pdev);
return 0;
@@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev)
static int __exit omap_sdi_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
+
+ sdi_uninit_output(pdev);
return 0;
}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 3a220877461..56efa3bb465 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -36,7 +36,6 @@
#include <linux/pm_runtime.h>
#include <video/omapdss.h>
-#include <plat/cpu.h>
#include "dss.h"
#include "dss_features.h"
@@ -300,6 +299,12 @@ static struct {
struct regulator *vdda_dac_reg;
struct clk *tv_dac_clk;
+
+ struct omap_video_timings timings;
+ enum omap_dss_venc_type type;
+ bool invert_polarity;
+
+ struct omap_dss_output output;
} venc;
static inline void venc_write_reg(int idx, u32 val)
@@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config(
static int venc_power_on(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
u32 l;
int r;
+ r = venc_runtime_get();
+ if (r)
+ goto err0;
+
venc_reset();
- venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
+ venc_write_config(venc_timings_to_config(&venc.timings));
- dss_set_venc_output(dssdev->phy.venc.type);
+ dss_set_venc_output(venc.type);
dss_set_dac_pwrdn_bgz(1);
l = 0;
- if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
+ if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
l |= 1 << 1;
else /* S-Video */
l |= (1 << 0) | (1 << 2);
- if (dssdev->phy.venc.invert_polarity == false)
+ if (venc.invert_polarity == false)
l |= 1 << 3;
venc_write_reg(VENC_OUTPUT_CONTROL, l);
- dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings);
+ dss_mgr_set_timings(mgr, &venc.timings);
r = regulator_enable(venc.vdda_dac_reg);
if (r)
- goto err;
-
- if (dssdev->platform_enable)
- dssdev->platform_enable(dssdev);
+ goto err1;
- r = dss_mgr_enable(dssdev->manager);
+ r = dss_mgr_enable(mgr);
if (r)
- goto err;
+ goto err2;
return 0;
-err:
+err2:
+ regulator_disable(venc.vdda_dac_reg);
+err1:
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
- regulator_disable(venc.vdda_dac_reg);
-
+ venc_runtime_put();
+err0:
return r;
}
static void venc_power_off(struct omap_dss_device *dssdev)
{
+ struct omap_overlay_manager *mgr = dssdev->output->manager;
+
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);
- dss_mgr_disable(dssdev->manager);
-
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
+ dss_mgr_disable(mgr);
regulator_disable(venc.vdda_dac_reg);
+
+ venc_runtime_put();
}
unsigned long venc_get_pixel_clock(void)
@@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void)
return 13500000;
}
-static ssize_t display_output_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+int omapdss_venc_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- const char *ret;
-
- switch (dssdev->phy.venc.type) {
- case OMAP_DSS_VENC_TYPE_COMPOSITE:
- ret = "composite";
- break;
- case OMAP_DSS_VENC_TYPE_SVIDEO:
- ret = "svideo";
- break;
- default:
- return -EINVAL;
- }
-
- return snprintf(buf, PAGE_SIZE, "%s\n", ret);
-}
+ struct omap_dss_output *out = dssdev->output;
+ int r;
-static ssize_t display_output_type_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- enum omap_dss_venc_type new_type;
-
- if (sysfs_streq("composite", buf))
- new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
- else if (sysfs_streq("svideo", buf))
- new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
- else
- return -EINVAL;
+ DSSDBG("venc_display_enable\n");
mutex_lock(&venc.venc_lock);
- if (dssdev->phy.venc.type != new_type) {
- dssdev->phy.venc.type = new_type;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- venc_power_off(dssdev);
- venc_power_on(dssdev);
- }
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("Failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
}
- mutex_unlock(&venc.venc_lock);
-
- return size;
-}
-
-static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
- display_output_type_show, display_output_type_store);
-
-/* driver */
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
- dssdev->panel.timings = omap_dss_pal_timings;
-
- return device_create_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
- device_remove_file(&dssdev->dev, &dev_attr_output_type);
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
- int r = 0;
-
- DSSDBG("venc_enable_display\n");
-
- mutex_lock(&venc.venc_lock);
-
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
goto err0;
}
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- r = -EINVAL;
- goto err1;
- }
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
- r = venc_runtime_get();
- if (r)
- goto err1;
r = venc_power_on(dssdev);
if (r)
- goto err2;
+ goto err1;
venc.wss_data = 0;
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
mutex_unlock(&venc.venc_lock);
+
return 0;
-err2:
- venc_runtime_put();
err1:
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
omap_dss_stop_device(dssdev);
err0:
mutex_unlock(&venc.venc_lock);
-
return r;
}
-static void venc_panel_disable(struct omap_dss_device *dssdev)
+void omapdss_venc_display_disable(struct omap_dss_device *dssdev)
{
- DSSDBG("venc_disable_display\n");
+ DSSDBG("venc_display_disable\n");
mutex_lock(&venc.venc_lock);
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- goto end;
-
- if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
- /* suspended is the same as disabled with venc */
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
- goto end;
- }
-
venc_power_off(dssdev);
- venc_runtime_put();
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-
omap_dss_stop_device(dssdev);
-end:
- mutex_unlock(&venc.venc_lock);
-}
-static int venc_panel_suspend(struct omap_dss_device *dssdev)
-{
- venc_panel_disable(dssdev);
- return 0;
-}
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
-static int venc_panel_resume(struct omap_dss_device *dssdev)
-{
- return venc_panel_enable(dssdev);
+ mutex_unlock(&venc.venc_lock);
}
-static void venc_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+void omapdss_venc_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
DSSDBG("venc_set_timings\n");
+ mutex_lock(&venc.venc_lock);
+
/* Reset WSS data when the TV standard changes. */
- if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
+ if (memcmp(&venc.timings, timings, sizeof(*timings)))
venc.wss_data = 0;
- dssdev->panel.timings = *timings;
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- /* turn the venc off and on to get new timings to use */
- venc_panel_disable(dssdev);
- venc_panel_enable(dssdev);
- } else {
- dss_mgr_set_timings(dssdev->manager, timings);
- }
+ venc.timings = *timings;
+
+ mutex_unlock(&venc.venc_lock);
}
-static int venc_check_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
+int omapdss_venc_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
{
DSSDBG("venc_check_timings\n");
@@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev,
return -EINVAL;
}
-static u32 venc_get_wss(struct omap_dss_device *dssdev)
+u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev)
{
/* Invert due to VENC_L21_WC_CTL:INV=1 */
return (venc.wss_data >> 8) ^ 0xfffff;
}
-static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
+int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
const struct venc_config *config;
int r;
@@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
mutex_lock(&venc.venc_lock);
- config = venc_timings_to_config(&dssdev->panel.timings);
+ config = venc_timings_to_config(&venc.timings);
/* Invert due to VENC_L21_WC_CTL:INV=1 */
venc.wss_data = (wss ^ 0xfffff) << 8;
@@ -703,30 +622,25 @@ err:
return r;
}
-static struct omap_dss_driver venc_driver = {
- .probe = venc_panel_probe,
- .remove = venc_panel_remove,
+void omapdss_venc_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ mutex_lock(&venc.venc_lock);
- .enable = venc_panel_enable,
- .disable = venc_panel_disable,
- .suspend = venc_panel_suspend,
- .resume = venc_panel_resume,
+ venc.type = type;
- .get_resolution = omapdss_default_get_resolution,
- .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+ mutex_unlock(&venc.venc_lock);
+}
- .set_timings = venc_set_timings,
- .check_timings = venc_check_timings,
+void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity)
+{
+ mutex_lock(&venc.venc_lock);
- .get_wss = venc_get_wss,
- .set_wss = venc_set_wss,
+ venc.invert_polarity = invert_polarity;
- .driver = {
- .name = "venc",
- .owner = THIS_MODULE,
- },
-};
-/* driver end */
+ mutex_unlock(&venc.venc_lock);
+}
static int __init venc_init_display(struct omap_dss_device *dssdev)
{
@@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
- if (cpu_is_omap44xx()) {
- seq_printf(s, "VENC currently disabled on OMAP44xx\n");
- return;
- }
-
if (venc_runtime_get())
return;
@@ -832,10 +741,14 @@ static void venc_put_clocks(void)
clk_put(venc.tv_dac_clk);
}
-static void __init venc_probe_pdata(struct platform_device *pdev)
+static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
{
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
- int r, i;
+ const char *def_disp_name = dss_get_default_display_name();
+ struct omap_dss_device *def_dssdev;
+ int i;
+
+ def_dssdev = NULL;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
@@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev)
if (dssdev->type != OMAP_DISPLAY_TYPE_VENC)
continue;
- r = venc_init_display(dssdev);
- if (r) {
- DSSERR("device %s init failed: %d\n", dssdev->name, r);
- continue;
+ if (def_dssdev == NULL)
+ def_dssdev = dssdev;
+
+ if (def_disp_name != NULL &&
+ strcmp(dssdev->name, def_disp_name) == 0) {
+ def_dssdev = dssdev;
+ break;
}
+ }
+
+ return def_dssdev;
+}
+
+static void __init venc_probe_pdata(struct platform_device *vencdev)
+{
+ struct omap_dss_device *plat_dssdev;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ plat_dssdev = venc_find_dssdev(vencdev);
- r = omap_dss_register_device(dssdev, &pdev->dev, i);
- if (r)
- DSSERR("device %s register failed: %d\n",
- dssdev->name, r);
+ if (!plat_dssdev)
+ return;
+
+ dssdev = dss_alloc_and_init_device(&vencdev->dev);
+ if (!dssdev)
+ return;
+
+ 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;
}
+
+ r = dss_add_device(dssdev);
+ if (r) {
+ DSSERR("device %s register failed: %d\n", dssdev->name, r);
+ dss_put_device(dssdev);
+ return;
+ }
+}
+
+static void __init 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;
+
+ dss_register_output(out);
+}
+
+static void __exit venc_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_output *out = &venc.output;
+
+ dss_unregister_output(out);
}
/* VENC HW IP initialisation */
@@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
venc_runtime_put();
- r = omap_dss_register_driver(&venc_driver);
+ r = venc_panel_init();
if (r)
- goto err_reg_panel_driver;
+ goto err_panel_init;
dss_debugfs_create_file("venc", venc_dump_regs);
+ venc_init_output(pdev);
+
venc_probe_pdata(pdev);
return 0;
-err_reg_panel_driver:
+err_panel_init:
err_runtime_get:
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@@ -916,14 +883,16 @@ err_runtime_get:
static int __exit omap_venchw_remove(struct platform_device *pdev)
{
- omap_dss_unregister_child_devices(&pdev->dev);
+ dss_unregister_child_devices(&pdev->dev);
if (venc.vdda_dac_reg != NULL) {
regulator_put(venc.vdda_dac_reg);
venc.vdda_dac_reg = NULL;
}
- omap_dss_unregister_driver(&venc_driver);
+ venc_panel_exit();
+
+ venc_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
@@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = {
int __init venc_init_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return 0;
-
return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe);
}
void __exit venc_uninit_platform_driver(void)
{
- if (cpu_is_omap44xx())
- return;
-
platform_driver_unregister(&omap_venchw_driver);
}
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c
new file mode 100644
index 00000000000..d55b8784ecf
--- /dev/null
+++ b/drivers/video/omap2/dss/venc_panel.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ *
+ * VENC panel driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+static struct {
+ struct mutex lock;
+} venc_panel;
+
+static ssize_t display_output_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ const char *ret;
+
+ switch (dssdev->phy.venc.type) {
+ case OMAP_DSS_VENC_TYPE_COMPOSITE:
+ ret = "composite";
+ break;
+ case OMAP_DSS_VENC_TYPE_SVIDEO:
+ ret = "svideo";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ret);
+}
+
+static ssize_t display_output_type_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ enum omap_dss_venc_type new_type;
+
+ if (sysfs_streq("composite", buf))
+ new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+ else if (sysfs_streq("svideo", buf))
+ new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
+ else
+ return -EINVAL;
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->phy.venc.type != new_type) {
+ dssdev->phy.venc.type = new_type;
+ omapdss_venc_set_type(dssdev, new_type);
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ omapdss_venc_display_disable(dssdev);
+ omapdss_venc_display_enable(dssdev);
+ }
+ }
+
+ mutex_unlock(&venc_panel.lock);
+
+ return size;
+}
+
+static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
+ display_output_type_show, display_output_type_store);
+
+static int venc_panel_probe(struct omap_dss_device *dssdev)
+{
+ /* set default timings to PAL */
+ const struct omap_video_timings default_timings = {
+ .x_res = 720,
+ .y_res = 574,
+ .pixel_clock = 13500,
+ .hsw = 64,
+ .hfp = 12,
+ .hbp = 68,
+ .vsw = 5,
+ .vfp = 5,
+ .vbp = 41,
+
+ .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
+
+ .interlace = true,
+ };
+
+ mutex_init(&venc_panel.lock);
+
+ dssdev->panel.timings = default_timings;
+
+ return device_create_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static void venc_panel_remove(struct omap_dss_device *dssdev)
+{
+ device_remove_file(&dssdev->dev, &dev_attr_output_type);
+}
+
+static int venc_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "venc_panel_enable\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
+
+ omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
+ omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
+ omapdss_venc_invert_vid_out_polarity(dssdev,
+ dssdev->phy.venc.invert_polarity);
+
+ r = omapdss_venc_display_enable(dssdev);
+ if (r)
+ goto err;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ mutex_unlock(&venc_panel.lock);
+
+ return 0;
+err:
+ mutex_unlock(&venc_panel.lock);
+
+ return r;
+}
+
+static void venc_panel_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_disable\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
+ goto end;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
+ /* suspended is the same as disabled with venc */
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+ goto end;
+ }
+
+ omapdss_venc_display_disable(dssdev);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+end:
+ mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_suspend(struct omap_dss_device *dssdev)
+{
+ venc_panel_disable(dssdev);
+ return 0;
+}
+
+static int venc_panel_resume(struct omap_dss_device *dssdev)
+{
+ return venc_panel_enable(dssdev);
+}
+
+static void venc_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
+
+ mutex_lock(&venc_panel.lock);
+
+ omapdss_venc_set_timings(dssdev, timings);
+ dssdev->panel.timings = *timings;
+
+ mutex_unlock(&venc_panel.lock);
+}
+
+static int venc_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
+
+ return omapdss_venc_check_timings(dssdev, timings);
+}
+
+static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
+
+ return omapdss_venc_get_wss(dssdev);
+}
+
+static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
+{
+ dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
+
+ return omapdss_venc_set_wss(dssdev, wss);
+}
+
+static struct omap_dss_driver venc_driver = {
+ .probe = venc_panel_probe,
+ .remove = venc_panel_remove,
+
+ .enable = venc_panel_enable,
+ .disable = venc_panel_disable,
+ .suspend = venc_panel_suspend,
+ .resume = venc_panel_resume,
+
+ .get_resolution = omapdss_default_get_resolution,
+ .get_recommended_bpp = omapdss_default_get_recommended_bpp,
+
+ .set_timings = venc_panel_set_timings,
+ .check_timings = venc_panel_check_timings,
+
+ .get_wss = venc_panel_get_wss,
+ .set_wss = venc_panel_set_wss,
+
+ .driver = {
+ .name = "venc",
+ .owner = THIS_MODULE,
+ },
+};
+
+int venc_panel_init(void)
+{
+ return omap_dss_register_driver(&venc_driver);
+}
+
+void venc_panel_exit(void)
+{
+ omap_dss_unregister_driver(&venc_driver);
+}