mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
Merge branch 'for-3.1-rc1' of git://gitorious.org/linux-omap-dss2/linux
* 'for-3.1-rc1' of git://gitorious.org/linux-omap-dss2/linux: (31 commits) OMAP: DSS2: HDMI: fix hdmi clock name HACK: OMAP: DSS2: clk hack for OMAP2/3 OMAP: DSS2: DSS: Fix context save/restore OMAP: DSS2: DISPC: Fix context save/restore OMAP: DSS2: Remove ctx loss count from dss.c OMAP: DSS2: Remove unused code from display.c OMAP: DSS2: DISPC: remove finegrained clk enables/disables OMAP: DSS2: Remove unused opt_clock_available OMAP: DSS2: Use PM runtime & HWMOD support OMAP: DSS2: Remove CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET OMAP: DSS2: Remove core_dump_clocks OMAP: DSS2: DPI: remove unneeded SYSCK enable/disable OMAP: DSS2: Use omap_pm_get_dev_context_loss_count to get ctx loss count OMAP: DSS2: rewrite use of context_loss_count OMAP: DSS2: Remove clk optimization at dss init OMAP: DSS2: Fix init and unit sequence OMAP: DSS2: Clean up probe for DSS & DSI OMAP: DSS2: Handle dpll4_m4_ck in dss_get/put_clocks OMAP: DSS2: Fix FIFO threshold and burst size for OMAP4 OMAP: DSS2: DSI: sync when disabling a display ...
This commit is contained in:
commit
965e32b18d
23 changed files with 1689 additions and 1405 deletions
|
@ -25,6 +25,7 @@
|
|||
#include <video/omapdss.h>
|
||||
#include <plat/omap_hwmod.h>
|
||||
#include <plat/omap_device.h>
|
||||
#include <plat/omap-pm.h>
|
||||
|
||||
static struct platform_device omap_display_device = {
|
||||
.name = "omapdss",
|
||||
|
@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* oh_core is used for getting opt-clocks */
|
||||
static struct omap_hwmod *oh_core;
|
||||
|
||||
static bool opt_clock_available(const char *clk_role)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oh_core->opt_clks_cnt; i++) {
|
||||
if (!strcmp(oh_core->opt_clks[i].role, clk_role))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct omap_dss_hwmod_data {
|
||||
const char *oh_name;
|
||||
const char *dev_name;
|
||||
|
@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
|
|||
oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
|
||||
}
|
||||
|
||||
/* opt_clks are always associated with dss hwmod */
|
||||
oh_core = omap_hwmod_lookup("dss_core");
|
||||
if (!oh_core) {
|
||||
pr_err("Could not look up dss_core.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata.board_data = board_data;
|
||||
pdata.board_data->get_last_off_on_transaction_id = NULL;
|
||||
pdata.opt_clock_available = opt_clock_available;
|
||||
pdata.board_data->get_context_loss_count =
|
||||
omap_pm_get_dev_context_loss_count;
|
||||
|
||||
for (i = 0; i < oh_count; i++) {
|
||||
oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
|
||||
|
|
|
@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
|||
return 0;
|
||||
|
||||
r = omapdss_dsi_display_enable(dssdev);
|
||||
if (r)
|
||||
goto err;
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to enable DSI\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
|
||||
|
||||
r = _taal_enable_te(dssdev, true);
|
||||
if (r)
|
||||
goto err;
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev, "failed to re-enable TE");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
|
||||
|
||||
|
@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dev_err(&dssdev->dev, "exit ULPS failed");
|
||||
err2:
|
||||
dev_err(&dssdev->dev, "failed to exit ULPS");
|
||||
|
||||
r = taal_panel_reset(dssdev);
|
||||
|
||||
enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
|
||||
td->ulps_enabled = false;
|
||||
|
||||
if (!r) {
|
||||
enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
|
||||
td->ulps_enabled = false;
|
||||
}
|
||||
err1:
|
||||
taal_queue_ulps_work(dssdev);
|
||||
|
||||
return r;
|
||||
|
@ -1241,11 +1247,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
|
|||
int r;
|
||||
|
||||
r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
|
||||
if (!r) {
|
||||
if (!r)
|
||||
r = taal_sleep_in(td);
|
||||
/* HACK: wait a bit so that the message goes through */
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
if (r) {
|
||||
dev_err(&dssdev->dev,
|
||||
|
@ -1317,8 +1320,11 @@ static void taal_disable(struct omap_dss_device *dssdev)
|
|||
dsi_bus_lock(dssdev);
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
taal_wake_up(dssdev);
|
||||
taal_power_off(dssdev);
|
||||
int r;
|
||||
|
||||
r = taal_wake_up(dssdev);
|
||||
if (!r)
|
||||
taal_power_off(dssdev);
|
||||
}
|
||||
|
||||
dsi_bus_unlock(dssdev);
|
||||
|
@ -1897,20 +1903,6 @@ static void taal_esd_work(struct work_struct *work)
|
|||
mutex_unlock(&td->lock);
|
||||
}
|
||||
|
||||
static int taal_set_update_mode(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode mode)
|
||||
{
|
||||
if (mode != OMAP_DSS_UPDATE_MANUAL)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum omap_dss_update_mode taal_get_update_mode(
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
return OMAP_DSS_UPDATE_MANUAL;
|
||||
}
|
||||
|
||||
static struct omap_dss_driver taal_driver = {
|
||||
.probe = taal_probe,
|
||||
.remove = __exit_p(taal_remove),
|
||||
|
@ -1920,9 +1912,6 @@ static struct omap_dss_driver taal_driver = {
|
|||
.suspend = taal_suspend,
|
||||
.resume = taal_resume,
|
||||
|
||||
.set_update_mode = taal_set_update_mode,
|
||||
.get_update_mode = taal_get_update_mode,
|
||||
|
||||
.update = taal_update,
|
||||
.sync = taal_sync,
|
||||
|
||||
|
|
|
@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
|
|||
Max FCK is 173MHz, so this doesn't work if your PCK
|
||||
is very high.
|
||||
|
||||
config OMAP2_DSS_SLEEP_BEFORE_RESET
|
||||
bool "Sleep 50ms before DSS reset"
|
||||
default y
|
||||
help
|
||||
For some unknown reason we may get SYNC_LOST errors from the display
|
||||
subsystem at initialization time if we don't sleep before resetting
|
||||
the DSS. See the source (dss.c) for more comments.
|
||||
|
||||
However, 50ms is quite long time to sleep, and with some
|
||||
configurations the SYNC_LOST may never happen, so the sleep can
|
||||
be disabled here.
|
||||
|
||||
config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
|
||||
bool "Sleep 20ms after VENC reset"
|
||||
default y
|
||||
|
|
|
@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev)
|
|||
goto err_dss;
|
||||
}
|
||||
|
||||
/* keep clocks enabled to prevent context saves/restores during init */
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
r = dispc_init_platform_driver();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize dispc platform driver\n");
|
||||
goto err_dispc;
|
||||
}
|
||||
|
||||
r = rfbi_init_platform_driver();
|
||||
if (r) {
|
||||
|
@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev)
|
|||
goto err_rfbi;
|
||||
}
|
||||
|
||||
r = dispc_init_platform_driver();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize dispc platform driver\n");
|
||||
goto err_dispc;
|
||||
}
|
||||
|
||||
r = venc_init_platform_driver();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize venc platform driver\n");
|
||||
|
@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev)
|
|||
pdata->default_device = dssdev;
|
||||
}
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
|
@ -268,11 +263,11 @@ static int omap_dss_remove(struct platform_device *pdev)
|
|||
|
||||
dss_uninitialize_debugfs();
|
||||
|
||||
venc_uninit_platform_driver();
|
||||
dispc_uninit_platform_driver();
|
||||
rfbi_uninit_platform_driver();
|
||||
dsi_uninit_platform_driver();
|
||||
hdmi_uninit_platform_driver();
|
||||
dsi_uninit_platform_driver();
|
||||
venc_uninit_platform_driver();
|
||||
rfbi_uninit_platform_driver();
|
||||
dispc_uninit_platform_driver();
|
||||
dss_uninit_platform_driver();
|
||||
|
||||
dss_uninit_overlays(pdev);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static ssize_t display_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -65,48 +66,6 @@ static ssize_t display_enabled_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_upd_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
|
||||
if (dssdev->driver->get_update_mode)
|
||||
mode = dssdev->driver->get_update_mode(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
|
||||
}
|
||||
|
||||
static ssize_t display_upd_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
int val, r;
|
||||
enum omap_dss_update_mode mode;
|
||||
|
||||
if (!dssdev->driver->set_update_mode)
|
||||
return -EINVAL;
|
||||
|
||||
r = kstrtoint(buf, 0, &val);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
switch (val) {
|
||||
case OMAP_DSS_UPDATE_DISABLED:
|
||||
case OMAP_DSS_UPDATE_AUTO:
|
||||
case OMAP_DSS_UPDATE_MANUAL:
|
||||
mode = (enum omap_dss_update_mode)val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = dssdev->driver->set_update_mode(dssdev, mode);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_tear_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -294,8 +253,6 @@ static ssize_t display_wss_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
display_enabled_show, display_enabled_store);
|
||||
static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
|
||||
display_upd_mode_show, display_upd_mode_store);
|
||||
static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
|
||||
display_tear_show, display_tear_store);
|
||||
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
|
||||
|
@ -309,7 +266,6 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
|
|||
|
||||
static struct device_attribute *display_sysfs_attrs[] = {
|
||||
&dev_attr_enabled,
|
||||
&dev_attr_update_mode,
|
||||
&dev_attr_tear_elim,
|
||||
&dev_attr_timings,
|
||||
&dev_attr_rotate,
|
||||
|
@ -327,16 +283,13 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
|
|||
EXPORT_SYMBOL(omapdss_default_get_resolution);
|
||||
|
||||
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 fifo_size, u32 burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high)
|
||||
{
|
||||
unsigned burst_size_bytes;
|
||||
unsigned buf_unit = dss_feat_get_buffer_size_unit();
|
||||
|
||||
*burst_size = OMAP_DSS_BURST_16x32;
|
||||
burst_size_bytes = 16 * 32 / 8;
|
||||
|
||||
*fifo_high = fifo_size - 1;
|
||||
*fifo_low = fifo_size - burst_size_bytes;
|
||||
*fifo_high = fifo_size - buf_unit;
|
||||
*fifo_low = fifo_size - burst_size;
|
||||
}
|
||||
|
||||
int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#define DSS_SUBSYS_NAME "DPI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
|
@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
|
|||
bool is_tft;
|
||||
int r = 0;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
|
||||
dssdev->panel.acbi, dssdev->panel.acb);
|
||||
|
||||
|
@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
|
|||
r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
|
||||
&fck, &lck_div, &pck_div);
|
||||
if (r)
|
||||
goto err0;
|
||||
return r;
|
||||
|
||||
pck = fck / lck_div / pck_div / 1000;
|
||||
|
||||
|
@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
|
|||
|
||||
dispc_set_lcd_timings(dssdev->manager->id, t);
|
||||
|
||||
err0:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_basic_init(struct omap_dss_device *dssdev)
|
||||
static void dpi_basic_init(struct omap_dss_device *dssdev)
|
||||
{
|
||||
bool is_tft;
|
||||
|
||||
|
@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
|
|||
OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
|
||||
dispc_set_tft_data_lines(dssdev->manager->id,
|
||||
dssdev->phy.dpi.data_lines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
|
@ -186,31 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
r = regulator_enable(dpi.vdds_dsi_reg);
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err_reg_enable;
|
||||
}
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
r = dpi_basic_init(dssdev);
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
goto err2;
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
dpi_basic_init(dssdev);
|
||||
|
||||
if (dpi_use_dsi_pll(dssdev)) {
|
||||
dss_clk_enable(DSS_CLK_SYSCK);
|
||||
r = dsi_runtime_get(dpi.dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
||||
r = dsi_pll_init(dpi.dsidev, 0, 1);
|
||||
if (r)
|
||||
goto err3;
|
||||
goto err_dsi_pll_init;
|
||||
}
|
||||
|
||||
r = dpi_set_mode(dssdev);
|
||||
if (r)
|
||||
goto err4;
|
||||
goto err_set_mode;
|
||||
|
||||
mdelay(2);
|
||||
|
||||
|
@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
err_set_mode:
|
||||
if (dpi_use_dsi_pll(dssdev))
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
err3:
|
||||
err_dsi_pll_init:
|
||||
if (dpi_use_dsi_pll(dssdev))
|
||||
dss_clk_disable(DSS_CLK_SYSCK);
|
||||
err2:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
err_get_dsi:
|
||||
dispc_runtime_put();
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
if (cpu_is_omap34xx())
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
err1:
|
||||
err_reg_enable:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
err_start_dev:
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_dpi_display_enable);
|
||||
|
@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
|
|||
if (dpi_use_dsi_pll(dssdev)) {
|
||||
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
dss_clk_disable(DSS_CLK_SYSCK);
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
}
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
if (cpu_is_omap34xx())
|
||||
regulator_disable(dpi.vdds_dsi_reg);
|
||||
|
@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable);
|
|||
void 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 = dss_runtime_get();
|
||||
if (r)
|
||||
return;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r) {
|
||||
dss_runtime_put();
|
||||
return;
|
||||
}
|
||||
|
||||
dpi_set_mode(dssdev);
|
||||
dispc_go(dssdev->manager->id);
|
||||
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dpi_set_timings);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <plat/clock.h>
|
||||
|
@ -267,8 +268,12 @@ struct dsi_isr_tables {
|
|||
struct dsi_data {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
|
||||
int irq;
|
||||
|
||||
struct clk *dss_clk;
|
||||
struct clk *sys_clk;
|
||||
|
||||
void (*dsi_mux_pads)(bool enable);
|
||||
|
||||
struct dsi_clock_info current_cinfo;
|
||||
|
@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev,
|
|||
return __raw_readl(dsi->base + idx.idx);
|
||||
}
|
||||
|
||||
|
||||
void dsi_save_context(void)
|
||||
{
|
||||
}
|
||||
|
||||
void dsi_restore_context(void)
|
||||
{
|
||||
}
|
||||
|
||||
void dsi_bus_lock(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
|
@ -493,9 +489,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
|
|||
total_bytes * 1000 / total_us);
|
||||
}
|
||||
#else
|
||||
#define dsi_perf_mark_setup(x)
|
||||
#define dsi_perf_mark_start(x)
|
||||
#define dsi_perf_show(x, y)
|
||||
static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dsi_perf_mark_start(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dsi_perf_show(struct platform_device *dsidev,
|
||||
const char *name)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void print_irq_status(u32 status)
|
||||
|
@ -1039,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
|
|||
return e;
|
||||
}
|
||||
|
||||
/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
|
||||
static inline void enable_clocks(bool enable)
|
||||
int dsi_runtime_get(struct platform_device *dsidev)
|
||||
{
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
int r;
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
DSSDBG("dsi_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&dsi->pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
void dsi_runtime_put(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
int r;
|
||||
|
||||
DSSDBG("dsi_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put(&dsi->pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
|
||||
/* source clock for DSI PLL. this could also be PCLKFREE */
|
||||
|
@ -1055,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
|
|||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_SYSCK);
|
||||
clk_enable(dsi->sys_clk);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_SYSCK);
|
||||
clk_disable(dsi->sys_clk);
|
||||
|
||||
if (enable && dsi->pll_locked) {
|
||||
if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
|
||||
|
@ -1150,10 +1169,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
|
|||
{
|
||||
unsigned long r;
|
||||
int dsi_module = dsi_get_dsidev_id(dsidev);
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
|
||||
/* DSI FCLK source is DSS_CLK_FCK */
|
||||
r = dss_clk_get_rate(DSS_CLK_FCK);
|
||||
r = clk_get_rate(dsi->dss_clk);
|
||||
} else {
|
||||
/* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
|
||||
r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
|
||||
|
@ -1262,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
|
|||
return -EINVAL;
|
||||
|
||||
if (cinfo->use_sys_clk) {
|
||||
cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
|
||||
cinfo->clkin = clk_get_rate(dsi->sys_clk);
|
||||
/* XXX it is unclear if highfreq should be used
|
||||
* with DSS_SYS_CLK source also */
|
||||
cinfo->highfreq = 0;
|
||||
|
@ -1311,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
|
|||
int match = 0;
|
||||
unsigned long dss_sys_clk, max_dss_fck;
|
||||
|
||||
dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
|
||||
dss_sys_clk = clk_get_rate(dsi->sys_clk);
|
||||
|
||||
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
||||
|
||||
|
@ -1601,7 +1621,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
|
|||
dsi->vdds_dsi_reg = vdds_dsi;
|
||||
}
|
||||
|
||||
enable_clocks(1);
|
||||
dsi_enable_pll_clock(dsidev, 1);
|
||||
/*
|
||||
* Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
|
||||
|
@ -1653,7 +1672,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
|
|||
}
|
||||
err0:
|
||||
dsi_disable_scp_clk(dsidev);
|
||||
enable_clocks(0);
|
||||
dsi_enable_pll_clock(dsidev, 0);
|
||||
return r;
|
||||
}
|
||||
|
@ -1671,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
|
|||
}
|
||||
|
||||
dsi_disable_scp_clk(dsidev);
|
||||
enable_clocks(0);
|
||||
dsi_enable_pll_clock(dsidev, 0);
|
||||
|
||||
DSSDBG("PLL uninit done\n");
|
||||
|
@ -1688,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
|
|||
dispc_clk_src = dss_get_dispc_clk_source();
|
||||
dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
|
||||
|
||||
enable_clocks(1);
|
||||
if (dsi_runtime_get(dsidev))
|
||||
return;
|
||||
|
||||
seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
|
||||
|
||||
|
@ -1731,7 +1749,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
|
|||
|
||||
seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
|
||||
|
||||
enable_clocks(0);
|
||||
dsi_runtime_put(dsidev);
|
||||
}
|
||||
|
||||
void dsi_dump_clocks(struct seq_file *s)
|
||||
|
@ -1873,7 +1891,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
|
|||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
if (dsi_runtime_get(dsidev))
|
||||
return;
|
||||
dsi_enable_scp_clk(dsidev);
|
||||
|
||||
DUMPREG(DSI_REVISION);
|
||||
|
@ -1947,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
|
|||
DUMPREG(DSI_PLL_CONFIGURATION2);
|
||||
|
||||
dsi_disable_scp_clk(dsidev);
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dsi_runtime_put(dsidev);
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
|
@ -2463,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev)
|
|||
dsi->dsi_mux_pads(false);
|
||||
}
|
||||
|
||||
static int _dsi_wait_reset(struct platform_device *dsidev)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
|
||||
if (++t > 5) {
|
||||
DSSERR("soft reset failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dsi_reset(struct platform_device *dsidev)
|
||||
{
|
||||
/* Soft reset */
|
||||
REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
|
||||
return _dsi_wait_reset(dsidev);
|
||||
}
|
||||
|
||||
static void dsi_config_tx_fifo(struct platform_device *dsidev,
|
||||
enum fifo_size size1, enum fifo_size size2,
|
||||
enum fifo_size size3, enum fifo_size size4)
|
||||
|
@ -3386,6 +3383,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
|
|||
dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
|
||||
DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
|
||||
|
||||
/* Reset LANEx_ULPS_SIG2 */
|
||||
REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2),
|
||||
7, 5);
|
||||
|
||||
dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
|
||||
|
||||
dsi_if_enable(dsidev, false);
|
||||
|
@ -4198,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
|
|||
dsi_pll_uninit(dsidev, disconnect_lanes);
|
||||
}
|
||||
|
||||
static int dsi_core_init(struct platform_device *dsidev)
|
||||
{
|
||||
/* Autoidle */
|
||||
REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
|
||||
|
||||
/* ENWAKEUP */
|
||||
REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
|
||||
|
||||
/* SIDLEMODE smart-idle */
|
||||
REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
|
||||
|
||||
_dsi_initialize_irq(dsidev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
||||
|
@ -4229,37 +4214,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
enable_clocks(1);
|
||||
r = dsi_runtime_get(dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
||||
dsi_enable_pll_clock(dsidev, 1);
|
||||
|
||||
r = _dsi_reset(dsidev);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
dsi_core_init(dsidev);
|
||||
_dsi_initialize_irq(dsidev);
|
||||
|
||||
r = dsi_display_init_dispc(dssdev);
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err_init_dispc;
|
||||
|
||||
r = dsi_display_init_dsi(dssdev);
|
||||
if (r)
|
||||
goto err2;
|
||||
goto err_init_dsi;
|
||||
|
||||
mutex_unlock(&dsi->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
err_init_dsi:
|
||||
dsi_display_uninit_dispc(dssdev);
|
||||
err1:
|
||||
enable_clocks(0);
|
||||
err_init_dispc:
|
||||
dsi_enable_pll_clock(dsidev, 0);
|
||||
dsi_runtime_put(dsidev);
|
||||
err_get_dsi:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
err_start_dev:
|
||||
mutex_unlock(&dsi->lock);
|
||||
DSSDBG("dsi_display_enable FAILED\n");
|
||||
return r;
|
||||
|
@ -4278,11 +4263,16 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
|
|||
|
||||
mutex_lock(&dsi->lock);
|
||||
|
||||
dsi_sync_vc(dsidev, 0);
|
||||
dsi_sync_vc(dsidev, 1);
|
||||
dsi_sync_vc(dsidev, 2);
|
||||
dsi_sync_vc(dsidev, 3);
|
||||
|
||||
dsi_display_uninit_dispc(dssdev);
|
||||
|
||||
dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
|
||||
|
||||
enable_clocks(0);
|
||||
dsi_runtime_put(dsidev);
|
||||
dsi_enable_pll_clock(dsidev, 0);
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
@ -4302,16 +4292,11 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
|
|||
EXPORT_SYMBOL(omapdss_dsi_enable_te);
|
||||
|
||||
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 fifo_size, u32 burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high)
|
||||
{
|
||||
unsigned burst_size_bytes;
|
||||
|
||||
*burst_size = OMAP_DSS_BURST_16x32;
|
||||
burst_size_bytes = 16 * 32 / 8;
|
||||
|
||||
*fifo_high = fifo_size - burst_size_bytes;
|
||||
*fifo_low = fifo_size - burst_size_bytes * 2;
|
||||
*fifo_high = fifo_size - burst_size;
|
||||
*fifo_low = fifo_size - burst_size * 2;
|
||||
}
|
||||
|
||||
int dsi_init_display(struct omap_dss_device *dssdev)
|
||||
|
@ -4437,7 +4422,47 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
|
|||
dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
|
||||
}
|
||||
|
||||
static int dsi_init(struct platform_device *dsidev)
|
||||
static int dsi_get_clocks(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(&dsidev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get fck\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
dsi->dss_clk = clk;
|
||||
|
||||
if (cpu_is_omap34xx() || cpu_is_omap3630())
|
||||
clk = clk_get(&dsidev->dev, "dss2_alwon_fck");
|
||||
else
|
||||
clk = clk_get(&dsidev->dev, "sys_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get sys_clk\n");
|
||||
clk_put(dsi->dss_clk);
|
||||
dsi->dss_clk = NULL;
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
dsi->sys_clk = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsi_put_clocks(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
if (dsi->dss_clk)
|
||||
clk_put(dsi->dss_clk);
|
||||
if (dsi->sys_clk)
|
||||
clk_put(dsi->sys_clk);
|
||||
}
|
||||
|
||||
/* DSI1 HW IP initialisation */
|
||||
static int omap_dsi1hw_probe(struct platform_device *dsidev)
|
||||
{
|
||||
struct omap_display_platform_data *dss_plat_data;
|
||||
struct omap_dss_board_info *board_info;
|
||||
|
@ -4449,7 +4474,7 @@ static int dsi_init(struct platform_device *dsidev)
|
|||
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
|
||||
if (!dsi) {
|
||||
r = -ENOMEM;
|
||||
goto err0;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
dsi->pdev = dsidev;
|
||||
|
@ -4472,6 +4497,12 @@ static int dsi_init(struct platform_device *dsidev)
|
|||
mutex_init(&dsi->lock);
|
||||
sema_init(&dsi->bus_lock, 1);
|
||||
|
||||
r = dsi_get_clocks(dsidev);
|
||||
if (r)
|
||||
goto err_get_clk;
|
||||
|
||||
pm_runtime_enable(&dsidev->dev);
|
||||
|
||||
INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
|
||||
dsi_framedone_timeout_work_callback);
|
||||
|
||||
|
@ -4484,26 +4515,26 @@ static int dsi_init(struct platform_device *dsidev)
|
|||
if (!dsi_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM DSI\n");
|
||||
r = -EINVAL;
|
||||
goto err1;
|
||||
goto err_ioremap;
|
||||
}
|
||||
dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
|
||||
if (!dsi->base) {
|
||||
DSSERR("can't ioremap DSI\n");
|
||||
r = -ENOMEM;
|
||||
goto err1;
|
||||
goto err_ioremap;
|
||||
}
|
||||
dsi->irq = platform_get_irq(dsi->pdev, 0);
|
||||
if (dsi->irq < 0) {
|
||||
DSSERR("platform_get_irq failed\n");
|
||||
r = -ENODEV;
|
||||
goto err2;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
|
||||
dev_name(&dsidev->dev), dsi->pdev);
|
||||
if (r < 0) {
|
||||
DSSERR("request_irq failed\n");
|
||||
goto err2;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
/* DSI VCs initialization */
|
||||
|
@ -4515,7 +4546,9 @@ static int dsi_init(struct platform_device *dsidev)
|
|||
|
||||
dsi_calc_clock_param_ranges(dsidev);
|
||||
|
||||
enable_clocks(1);
|
||||
r = dsi_runtime_get(dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
||||
rev = dsi_read_reg(dsidev, DSI_REVISION);
|
||||
dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
|
||||
|
@ -4523,21 +4556,32 @@ static int dsi_init(struct platform_device *dsidev)
|
|||
|
||||
dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
|
||||
|
||||
enable_clocks(0);
|
||||
dsi_runtime_put(dsidev);
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
|
||||
err_get_dsi:
|
||||
free_irq(dsi->irq, dsi->pdev);
|
||||
err_get_irq:
|
||||
iounmap(dsi->base);
|
||||
err1:
|
||||
err_ioremap:
|
||||
pm_runtime_disable(&dsidev->dev);
|
||||
err_get_clk:
|
||||
kfree(dsi);
|
||||
err0:
|
||||
err_alloc:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dsi_exit(struct platform_device *dsidev)
|
||||
static int omap_dsi1hw_remove(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
WARN_ON(dsi->scp_clk_refcount > 0);
|
||||
|
||||
pm_runtime_disable(&dsidev->dev);
|
||||
|
||||
dsi_put_clocks(dsidev);
|
||||
|
||||
if (dsi->vdds_dsi_reg != NULL) {
|
||||
if (dsi->vdds_dsi_enabled) {
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
|
@ -4553,31 +4597,48 @@ static void dsi_exit(struct platform_device *dsidev)
|
|||
|
||||
kfree(dsi);
|
||||
|
||||
DSSDBG("omap_dsi_exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DSI1 HW IP initialisation */
|
||||
static int omap_dsi1hw_probe(struct platform_device *dsidev)
|
||||
static int dsi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
|
||||
|
||||
clk_disable(dsi->dss_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
|
||||
int r;
|
||||
|
||||
r = dsi_init(dsidev);
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DSI\n");
|
||||
goto err_dsi;
|
||||
}
|
||||
err_dsi:
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
clk_enable(dsi->dss_clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_dsi1hw_remove(struct platform_device *dsidev)
|
||||
{
|
||||
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
||||
|
||||
dsi_exit(dsidev);
|
||||
WARN_ON(dsi->scp_clk_refcount > 0);
|
||||
return 0;
|
||||
}
|
||||
static const struct dev_pm_ops dsi_pm_ops = {
|
||||
.runtime_suspend = dsi_runtime_suspend,
|
||||
.runtime_resume = dsi_runtime_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver omap_dsi1hw_driver = {
|
||||
.probe = omap_dsi1hw_probe,
|
||||
|
@ -4585,6 +4646,7 @@ static struct platform_driver omap_dsi1hw_driver = {
|
|||
.driver = {
|
||||
.name = "omapdss_dsi1",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dsi_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <plat/clock.h>
|
||||
|
@ -59,15 +61,9 @@ struct dss_reg {
|
|||
static struct {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
int ctx_id;
|
||||
|
||||
struct clk *dpll4_m4_ck;
|
||||
struct clk *dss_ick;
|
||||
struct clk *dss_fck;
|
||||
struct clk *dss_sys_clk;
|
||||
struct clk *dss_tv_fck;
|
||||
struct clk *dss_video_fck;
|
||||
unsigned num_clks_enabled;
|
||||
struct clk *dss_clk;
|
||||
|
||||
unsigned long cache_req_pck;
|
||||
unsigned long cache_prate;
|
||||
|
@ -78,6 +74,7 @@ static struct {
|
|||
enum omap_dss_clk_source dispc_clk_source;
|
||||
enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
|
||||
|
||||
bool ctx_valid;
|
||||
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
|
||||
} dss;
|
||||
|
||||
|
@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = {
|
|||
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
|
||||
};
|
||||
|
||||
static void dss_clk_enable_all_no_ctx(void);
|
||||
static void dss_clk_disable_all_no_ctx(void);
|
||||
static void dss_clk_enable_no_ctx(enum dss_clock clks);
|
||||
static void dss_clk_disable_no_ctx(enum dss_clock clks);
|
||||
|
||||
static int _omap_dss_wait_reset(void);
|
||||
|
||||
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
|
||||
{
|
||||
__raw_writel(val, dss.base + idx.idx);
|
||||
|
@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx)
|
|||
#define RR(reg) \
|
||||
dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
|
||||
|
||||
void dss_save_context(void)
|
||||
static void dss_save_context(void)
|
||||
{
|
||||
if (cpu_is_omap24xx())
|
||||
return;
|
||||
DSSDBG("dss_save_context\n");
|
||||
|
||||
SR(SYSCONFIG);
|
||||
SR(CONTROL);
|
||||
|
||||
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
||||
|
@ -122,14 +110,19 @@ void dss_save_context(void)
|
|||
SR(SDI_CONTROL);
|
||||
SR(PLL_CONTROL);
|
||||
}
|
||||
|
||||
dss.ctx_valid = true;
|
||||
|
||||
DSSDBG("context saved\n");
|
||||
}
|
||||
|
||||
void dss_restore_context(void)
|
||||
static void dss_restore_context(void)
|
||||
{
|
||||
if (_omap_dss_wait_reset())
|
||||
DSSERR("DSS not coming out of reset after sleep\n");
|
||||
DSSDBG("dss_restore_context\n");
|
||||
|
||||
if (!dss.ctx_valid)
|
||||
return;
|
||||
|
||||
RR(SYSCONFIG);
|
||||
RR(CONTROL);
|
||||
|
||||
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
||||
|
@ -137,6 +130,8 @@ void dss_restore_context(void)
|
|||
RR(SDI_CONTROL);
|
||||
RR(PLL_CONTROL);
|
||||
}
|
||||
|
||||
DSSDBG("context restored\n");
|
||||
}
|
||||
|
||||
#undef SR
|
||||
|
@ -234,6 +229,7 @@ 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;
|
||||
|
@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s)
|
|||
const char *fclk_name, *fclk_real_name;
|
||||
unsigned long fclk_rate;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
if (dss_runtime_get())
|
||||
return;
|
||||
|
||||
seq_printf(s, "- DSS -\n");
|
||||
|
||||
fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
||||
fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
||||
fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
|
||||
fclk_rate = clk_get_rate(dss.dss_clk);
|
||||
|
||||
if (dss.dpll4_m4_ck) {
|
||||
dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
|
@ -273,14 +270,15 @@ void dss_dump_clocks(struct seq_file *s)
|
|||
fclk_rate);
|
||||
}
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dss_runtime_put();
|
||||
}
|
||||
|
||||
void dss_dump_regs(struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
if (dss_runtime_get())
|
||||
return;
|
||||
|
||||
DUMPREG(DSS_REVISION);
|
||||
DUMPREG(DSS_SYSCONFIG);
|
||||
|
@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s)
|
|||
DUMPREG(DSS_SDI_STATUS);
|
||||
}
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dss_runtime_put();
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
|
@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
|
|||
} else {
|
||||
if (cinfo->fck_div != 0)
|
||||
return -EINVAL;
|
||||
cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
|
||||
cinfo->fck = clk_get_rate(dss.dss_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
|
|||
|
||||
int dss_get_clock_div(struct dss_clock_info *cinfo)
|
||||
{
|
||||
cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
|
||||
cinfo->fck = clk_get_rate(dss.dss_clk);
|
||||
|
||||
if (dss.dpll4_m4_ck) {
|
||||
unsigned long prate;
|
||||
|
@ -512,7 +510,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
|||
|
||||
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
||||
|
||||
fck = dss_clk_get_rate(DSS_CLK_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)) {
|
||||
|
@ -539,7 +537,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
|||
if (dss.dpll4_m4_ck == NULL) {
|
||||
struct dispc_clock_info cur_dispc;
|
||||
/* XXX can we change the clock on omap2? */
|
||||
fck = dss_clk_get_rate(DSS_CLK_FCK);
|
||||
fck = clk_get_rate(dss.dss_clk);
|
||||
fck_div = 1;
|
||||
|
||||
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
|
||||
|
@ -616,28 +614,6 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _omap_dss_wait_reset(void)
|
||||
{
|
||||
int t = 0;
|
||||
|
||||
while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
|
||||
if (++t > 1000) {
|
||||
DSSERR("soft reset failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _omap_dss_reset(void)
|
||||
{
|
||||
/* Soft reset */
|
||||
REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
|
||||
return _omap_dss_wait_reset();
|
||||
}
|
||||
|
||||
void dss_set_venc_output(enum omap_dss_venc_type type)
|
||||
{
|
||||
int l = 0;
|
||||
|
@ -663,48 +639,127 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
|
|||
REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
|
||||
}
|
||||
|
||||
static int dss_init(void)
|
||||
static int dss_get_clocks(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
int r;
|
||||
|
||||
clk = clk_get(&dss.pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get clock fck\n");
|
||||
r = PTR_ERR(clk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
dss.dpll4_m4_ck = clk;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (dss.dss_clk)
|
||||
clk_put(dss.dss_clk);
|
||||
if (dss.dpll4_m4_ck)
|
||||
clk_put(dss.dpll4_m4_ck);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dss_put_clocks(void)
|
||||
{
|
||||
if (dss.dpll4_m4_ck)
|
||||
clk_put(dss.dpll4_m4_ck);
|
||||
clk_put(dss.dss_clk);
|
||||
}
|
||||
|
||||
struct clk *dss_get_ick(void)
|
||||
{
|
||||
return clk_get(&dss.pdev->dev, "ick");
|
||||
}
|
||||
|
||||
int dss_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
u32 rev;
|
||||
|
||||
DSSDBG("dss_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&dss.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
void dss_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("dss_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put(&dss.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
|
||||
/* DEBUGFS */
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
void dss_debug_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
dss_dump_clocks(s);
|
||||
dispc_dump_clocks(s);
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_dump_clocks(s);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* DSS HW IP initialisation */
|
||||
static int omap_dsshw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *dss_mem;
|
||||
struct clk *dpll4_m4_ck;
|
||||
u32 rev;
|
||||
int r;
|
||||
|
||||
dss.pdev = pdev;
|
||||
|
||||
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
|
||||
if (!dss_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM DSS\n");
|
||||
r = -EINVAL;
|
||||
goto fail0;
|
||||
goto err_ioremap;
|
||||
}
|
||||
dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
|
||||
if (!dss.base) {
|
||||
DSSERR("can't ioremap DSS\n");
|
||||
r = -ENOMEM;
|
||||
goto fail0;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
/* disable LCD and DIGIT output. This seems to fix the synclost
|
||||
* problem that we get, if the bootloader starts the DSS and
|
||||
* the kernel resets it */
|
||||
omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
|
||||
r = dss_get_clocks();
|
||||
if (r)
|
||||
goto err_clocks;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
|
||||
/* We need to wait here a bit, otherwise we sometimes start to
|
||||
* get synclost errors, and after that only power cycle will
|
||||
* restore DSS functionality. I have no idea why this happens.
|
||||
* And we have to wait _before_ resetting the DSS, but after
|
||||
* enabling clocks.
|
||||
*
|
||||
* This bug was at least present on OMAP3430. It's unknown
|
||||
* if it happens on OMAP2 or OMAP3630.
|
||||
*/
|
||||
msleep(50);
|
||||
#endif
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
_omap_dss_reset();
|
||||
|
||||
/* autoidle */
|
||||
REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
goto err_runtime_get;
|
||||
|
||||
/* Select DPLL */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
|
||||
|
@ -714,404 +769,12 @@ static int dss_init(void)
|
|||
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
|
||||
#endif
|
||||
if (cpu_is_omap34xx()) {
|
||||
dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
|
||||
if (IS_ERR(dpll4_m4_ck)) {
|
||||
DSSERR("Failed to get dpll4_m4_ck\n");
|
||||
r = PTR_ERR(dpll4_m4_ck);
|
||||
goto fail1;
|
||||
}
|
||||
} else if (cpu_is_omap44xx()) {
|
||||
dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
|
||||
if (IS_ERR(dpll4_m4_ck)) {
|
||||
DSSERR("Failed to get dpll4_m4_ck\n");
|
||||
r = PTR_ERR(dpll4_m4_ck);
|
||||
goto fail1;
|
||||
}
|
||||
} else { /* omap24xx */
|
||||
dpll4_m4_ck = NULL;
|
||||
}
|
||||
|
||||
dss.dpll4_m4_ck = dpll4_m4_ck;
|
||||
|
||||
dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
|
||||
dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
|
||||
|
||||
dss_save_context();
|
||||
|
||||
rev = dss_read_reg(DSS_REVISION);
|
||||
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
|
||||
return 0;
|
||||
|
||||
fail1:
|
||||
iounmap(dss.base);
|
||||
fail0:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dss_exit(void)
|
||||
{
|
||||
if (dss.dpll4_m4_ck)
|
||||
clk_put(dss.dpll4_m4_ck);
|
||||
|
||||
iounmap(dss.base);
|
||||
}
|
||||
|
||||
/* CONTEXT */
|
||||
static int dss_get_ctx_id(void)
|
||||
{
|
||||
struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
|
||||
int r;
|
||||
|
||||
if (!pdata->board_data->get_last_off_on_transaction_id)
|
||||
return 0;
|
||||
r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
|
||||
if (r < 0) {
|
||||
dev_err(&dss.pdev->dev, "getting transaction ID failed, "
|
||||
"will force context restore\n");
|
||||
r = -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int dss_need_ctx_restore(void)
|
||||
{
|
||||
int id = dss_get_ctx_id();
|
||||
|
||||
if (id < 0 || id != dss.ctx_id) {
|
||||
DSSDBG("ctx id %d -> id %d\n",
|
||||
dss.ctx_id, id);
|
||||
dss.ctx_id = id;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void save_all_ctx(void)
|
||||
{
|
||||
DSSDBG("save context\n");
|
||||
|
||||
dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
dss_save_context();
|
||||
dispc_save_context();
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_save_context();
|
||||
#endif
|
||||
|
||||
dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
}
|
||||
|
||||
static void restore_all_ctx(void)
|
||||
{
|
||||
DSSDBG("restore context\n");
|
||||
|
||||
dss_clk_enable_all_no_ctx();
|
||||
|
||||
dss_restore_context();
|
||||
dispc_restore_context();
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_restore_context();
|
||||
#endif
|
||||
|
||||
dss_clk_disable_all_no_ctx();
|
||||
}
|
||||
|
||||
static int dss_get_clock(struct clk **clock, const char *clk_name)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(&dss.pdev->dev, clk_name);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get clock %s", clk_name);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
*clock = clk;
|
||||
|
||||
DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_get_clocks(void)
|
||||
{
|
||||
int r;
|
||||
struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
|
||||
|
||||
dss.dss_ick = NULL;
|
||||
dss.dss_fck = NULL;
|
||||
dss.dss_sys_clk = NULL;
|
||||
dss.dss_tv_fck = NULL;
|
||||
dss.dss_video_fck = NULL;
|
||||
|
||||
r = dss_get_clock(&dss.dss_ick, "ick");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = dss_get_clock(&dss.dss_fck, "fck");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
if (!pdata->opt_clock_available) {
|
||||
r = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pdata->opt_clock_available("sys_clk")) {
|
||||
r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pdata->opt_clock_available("tv_clk")) {
|
||||
r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pdata->opt_clock_available("video_clk")) {
|
||||
r = dss_get_clock(&dss.dss_video_fck, "video_clk");
|
||||
if (r)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (dss.dss_ick)
|
||||
clk_put(dss.dss_ick);
|
||||
if (dss.dss_fck)
|
||||
clk_put(dss.dss_fck);
|
||||
if (dss.dss_sys_clk)
|
||||
clk_put(dss.dss_sys_clk);
|
||||
if (dss.dss_tv_fck)
|
||||
clk_put(dss.dss_tv_fck);
|
||||
if (dss.dss_video_fck)
|
||||
clk_put(dss.dss_video_fck);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dss_put_clocks(void)
|
||||
{
|
||||
if (dss.dss_video_fck)
|
||||
clk_put(dss.dss_video_fck);
|
||||
if (dss.dss_tv_fck)
|
||||
clk_put(dss.dss_tv_fck);
|
||||
if (dss.dss_sys_clk)
|
||||
clk_put(dss.dss_sys_clk);
|
||||
clk_put(dss.dss_fck);
|
||||
clk_put(dss.dss_ick);
|
||||
}
|
||||
|
||||
unsigned long dss_clk_get_rate(enum dss_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case DSS_CLK_ICK:
|
||||
return clk_get_rate(dss.dss_ick);
|
||||
case DSS_CLK_FCK:
|
||||
return clk_get_rate(dss.dss_fck);
|
||||
case DSS_CLK_SYSCK:
|
||||
return clk_get_rate(dss.dss_sys_clk);
|
||||
case DSS_CLK_TVFCK:
|
||||
return clk_get_rate(dss.dss_tv_fck);
|
||||
case DSS_CLK_VIDFCK:
|
||||
return clk_get_rate(dss.dss_video_fck);
|
||||
}
|
||||
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned count_clk_bits(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = 0;
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_FCK)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_SYSCK)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_TVFCK)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_VIDFCK)
|
||||
++num_clks;
|
||||
|
||||
return num_clks;
|
||||
}
|
||||
|
||||
static void dss_clk_enable_no_ctx(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
clk_enable(dss.dss_ick);
|
||||
if (clks & DSS_CLK_FCK)
|
||||
clk_enable(dss.dss_fck);
|
||||
if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
|
||||
clk_enable(dss.dss_sys_clk);
|
||||
if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
|
||||
clk_enable(dss.dss_tv_fck);
|
||||
if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
|
||||
clk_enable(dss.dss_video_fck);
|
||||
|
||||
dss.num_clks_enabled += num_clks;
|
||||
}
|
||||
|
||||
void dss_clk_enable(enum dss_clock clks)
|
||||
{
|
||||
bool check_ctx = dss.num_clks_enabled == 0;
|
||||
|
||||
dss_clk_enable_no_ctx(clks);
|
||||
|
||||
/*
|
||||
* HACK: On omap4 the registers may not be accessible right after
|
||||
* enabling the clocks. At some point this will be handled by
|
||||
* pm_runtime, but for the time begin this should make things work.
|
||||
*/
|
||||
if (cpu_is_omap44xx() && check_ctx)
|
||||
udelay(10);
|
||||
|
||||
if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
|
||||
restore_all_ctx();
|
||||
}
|
||||
|
||||
static void dss_clk_disable_no_ctx(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
clk_disable(dss.dss_ick);
|
||||
if (clks & DSS_CLK_FCK)
|
||||
clk_disable(dss.dss_fck);
|
||||
if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
|
||||
clk_disable(dss.dss_sys_clk);
|
||||
if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
|
||||
clk_disable(dss.dss_tv_fck);
|
||||
if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
|
||||
clk_disable(dss.dss_video_fck);
|
||||
|
||||
dss.num_clks_enabled -= num_clks;
|
||||
}
|
||||
|
||||
void dss_clk_disable(enum dss_clock clks)
|
||||
{
|
||||
if (cpu_is_omap34xx()) {
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
BUG_ON(dss.num_clks_enabled < num_clks);
|
||||
|
||||
if (dss.num_clks_enabled == num_clks)
|
||||
save_all_ctx();
|
||||
}
|
||||
|
||||
dss_clk_disable_no_ctx(clks);
|
||||
}
|
||||
|
||||
static void dss_clk_enable_all_no_ctx(void)
|
||||
{
|
||||
enum dss_clock clks;
|
||||
|
||||
clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
|
||||
if (cpu_is_omap34xx())
|
||||
clks |= DSS_CLK_VIDFCK;
|
||||
dss_clk_enable_no_ctx(clks);
|
||||
}
|
||||
|
||||
static void dss_clk_disable_all_no_ctx(void)
|
||||
{
|
||||
enum dss_clock clks;
|
||||
|
||||
clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
|
||||
if (cpu_is_omap34xx())
|
||||
clks |= DSS_CLK_VIDFCK;
|
||||
dss_clk_disable_no_ctx(clks);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
/* CLOCKS */
|
||||
static void core_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
int i;
|
||||
struct clk *clocks[5] = {
|
||||
dss.dss_ick,
|
||||
dss.dss_fck,
|
||||
dss.dss_sys_clk,
|
||||
dss.dss_tv_fck,
|
||||
dss.dss_video_fck
|
||||
};
|
||||
|
||||
const char *names[5] = {
|
||||
"ick",
|
||||
"fck",
|
||||
"sys_clk",
|
||||
"tv_fck",
|
||||
"video_fck"
|
||||
};
|
||||
|
||||
seq_printf(s, "- CORE -\n");
|
||||
|
||||
seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!clocks[i])
|
||||
continue;
|
||||
seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
|
||||
names[i],
|
||||
clocks[i]->name,
|
||||
24 - strlen(names[i]) - strlen(clocks[i]->name),
|
||||
"",
|
||||
clk_get_rate(clocks[i]),
|
||||
clocks[i]->usecount);
|
||||
}
|
||||
}
|
||||
#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
|
||||
|
||||
/* DEBUGFS */
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
void dss_debug_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
core_dump_clocks(s);
|
||||
dss_dump_clocks(s);
|
||||
dispc_dump_clocks(s);
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_dump_clocks(s);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* DSS HW IP initialisation */
|
||||
static int omap_dsshw_probe(struct platform_device *pdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
dss.pdev = pdev;
|
||||
|
||||
r = dss_get_clocks();
|
||||
if (r)
|
||||
goto err_clocks;
|
||||
|
||||
dss_clk_enable_all_no_ctx();
|
||||
|
||||
dss.ctx_id = dss_get_ctx_id();
|
||||
DSSDBG("initial ctx id %u\n", dss.ctx_id);
|
||||
|
||||
r = dss_init();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DSS\n");
|
||||
goto err_dss;
|
||||
}
|
||||
|
||||
r = dpi_init();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DPI\n");
|
||||
|
@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev)
|
|||
goto err_sdi;
|
||||
}
|
||||
|
||||
dss_clk_disable_all_no_ctx();
|
||||
rev = dss_read_reg(DSS_REVISION);
|
||||
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
|
||||
dss_runtime_put();
|
||||
|
||||
return 0;
|
||||
err_sdi:
|
||||
dpi_exit();
|
||||
err_dpi:
|
||||
dss_exit();
|
||||
err_dss:
|
||||
dss_clk_disable_all_no_ctx();
|
||||
dss_runtime_put();
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
dss_put_clocks();
|
||||
err_clocks:
|
||||
iounmap(dss.base);
|
||||
err_ioremap:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_dsshw_remove(struct platform_device *pdev)
|
||||
{
|
||||
dpi_exit();
|
||||
sdi_exit();
|
||||
|
||||
dss_exit();
|
||||
iounmap(dss.base);
|
||||
|
||||
/*
|
||||
* As part of hwmod changes, DSS is not the only controller of dss
|
||||
* clocks; hwmod framework itself will also enable clocks during hwmod
|
||||
* init for dss, and autoidle is set in h/w for DSS. Hence, there's no
|
||||
* need to disable clocks if their usecounts > 1.
|
||||
*/
|
||||
WARN_ON(dss.num_clks_enabled > 0);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
dss_put_clocks();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_runtime_suspend(struct device *dev)
|
||||
{
|
||||
dss_save_context();
|
||||
clk_disable(dss.dss_clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_runtime_resume(struct device *dev)
|
||||
{
|
||||
clk_enable(dss.dss_clk);
|
||||
dss_restore_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dss_pm_ops = {
|
||||
.runtime_suspend = dss_runtime_suspend,
|
||||
.runtime_resume = dss_runtime_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver omap_dsshw_driver = {
|
||||
.probe = omap_dsshw_probe,
|
||||
.remove = omap_dsshw_remove,
|
||||
.driver = {
|
||||
.name = "omapdss_dss",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dss_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -97,26 +97,12 @@ extern unsigned int dss_debug;
|
|||
#define FLD_MOD(orig, val, start, end) \
|
||||
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
|
||||
|
||||
enum omap_burst_size {
|
||||
OMAP_DSS_BURST_4x32 = 0,
|
||||
OMAP_DSS_BURST_8x32 = 1,
|
||||
OMAP_DSS_BURST_16x32 = 2,
|
||||
};
|
||||
|
||||
enum omap_parallel_interface_mode {
|
||||
OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
|
||||
OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
|
||||
OMAP_DSS_PARALLELMODE_DSI,
|
||||
};
|
||||
|
||||
enum dss_clock {
|
||||
DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */
|
||||
DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */
|
||||
DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */
|
||||
DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */
|
||||
DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/
|
||||
};
|
||||
|
||||
enum dss_hdmi_venc_clk_source_select {
|
||||
DSS_VENC_TV_CLK = 0,
|
||||
DSS_HDMI_M_PCLK = 1,
|
||||
|
@ -194,7 +180,7 @@ void dss_uninit_device(struct platform_device *pdev,
|
|||
bool dss_use_replication(struct omap_dss_device *dssdev,
|
||||
enum omap_color_mode mode);
|
||||
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 fifo_size, u32 burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high);
|
||||
|
||||
/* manager */
|
||||
|
@ -220,13 +206,12 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
|
|||
int dss_init_platform_driver(void);
|
||||
void dss_uninit_platform_driver(void);
|
||||
|
||||
int dss_runtime_get(void);
|
||||
void dss_runtime_put(void);
|
||||
|
||||
struct clk *dss_get_ick(void);
|
||||
|
||||
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
|
||||
void dss_save_context(void);
|
||||
void dss_restore_context(void);
|
||||
void dss_clk_enable(enum dss_clock clks);
|
||||
void dss_clk_disable(enum dss_clock clks);
|
||||
unsigned long dss_clk_get_rate(enum dss_clock clk);
|
||||
int dss_need_ctx_restore(void);
|
||||
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
|
||||
void dss_dump_clocks(struct seq_file *s);
|
||||
|
||||
|
@ -283,15 +268,15 @@ struct file_operations;
|
|||
int dsi_init_platform_driver(void);
|
||||
void dsi_uninit_platform_driver(void);
|
||||
|
||||
int dsi_runtime_get(struct platform_device *dsidev);
|
||||
void dsi_runtime_put(struct platform_device *dsidev);
|
||||
|
||||
void dsi_dump_clocks(struct seq_file *s);
|
||||
void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
|
||||
const struct file_operations *debug_fops);
|
||||
void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
|
||||
const struct file_operations *debug_fops);
|
||||
|
||||
void dsi_save_context(void);
|
||||
void dsi_restore_context(void);
|
||||
|
||||
int dsi_init_display(struct omap_dss_device *display);
|
||||
void dsi_irq_handler(void);
|
||||
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
|
||||
|
@ -304,7 +289,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
|
|||
bool enable_hsdiv);
|
||||
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
|
||||
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 fifo_size, u32 burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high);
|
||||
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
|
||||
void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
|
||||
|
@ -317,6 +302,13 @@ static inline int dsi_init_platform_driver(void)
|
|||
static inline void dsi_uninit_platform_driver(void)
|
||||
{
|
||||
}
|
||||
static inline int dsi_runtime_get(struct platform_device *dsidev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void dsi_runtime_put(struct platform_device *dsidev)
|
||||
{
|
||||
}
|
||||
static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
|
||||
{
|
||||
WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
|
||||
|
@ -384,8 +376,8 @@ void dispc_dump_regs(struct seq_file *s);
|
|||
void dispc_irq_handler(void);
|
||||
void dispc_fake_vsync_irq(void);
|
||||
|
||||
void dispc_save_context(void);
|
||||
void dispc_restore_context(void);
|
||||
int dispc_runtime_get(void);
|
||||
void dispc_runtime_put(void);
|
||||
|
||||
void dispc_enable_sidle(void);
|
||||
void dispc_disable_sidle(void);
|
||||
|
@ -398,10 +390,12 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
|
|||
void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
|
||||
void dispc_set_digit_size(u16 width, u16 height);
|
||||
u32 dispc_get_plane_fifo_size(enum omap_plane plane);
|
||||
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
|
||||
void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
|
||||
void dispc_enable_fifomerge(bool enable);
|
||||
void dispc_set_burst_size(enum omap_plane plane,
|
||||
enum omap_burst_size burst_size);
|
||||
u32 dispc_get_burst_size(enum omap_plane plane);
|
||||
void dispc_enable_cpr(enum omap_channel channel, bool enable);
|
||||
void dispc_set_cpr_coef(enum omap_channel channel,
|
||||
struct omap_dss_cpr_coefs *coefs);
|
||||
|
||||
void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
|
||||
void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
|
||||
|
|
|
@ -49,6 +49,9 @@ struct omap_dss_features {
|
|||
const enum omap_color_mode *supported_color_modes;
|
||||
const char * const *clksrc_names;
|
||||
const struct dss_param_range *dss_params;
|
||||
|
||||
const u32 buffer_size_unit;
|
||||
const u32 burst_size_unit;
|
||||
};
|
||||
|
||||
/* This struct is assigned to one of the below during initialization */
|
||||
|
@ -274,6 +277,8 @@ static const struct omap_dss_features omap2_dss_features = {
|
|||
.supported_color_modes = omap2_dss_supported_color_modes,
|
||||
.clksrc_names = omap2_dss_clk_source_names,
|
||||
.dss_params = omap2_dss_param_range,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
/* OMAP3 DSS Features */
|
||||
|
@ -286,7 +291,9 @@ static const struct omap_dss_features omap3430_dss_features = {
|
|||
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
|
||||
FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
|
||||
FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
|
||||
FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
|
||||
FEAT_FIR_COEF_V,
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
|
@ -294,6 +301,8 @@ static const struct omap_dss_features omap3430_dss_features = {
|
|||
.supported_color_modes = omap3_dss_supported_color_modes,
|
||||
.clksrc_names = omap3_dss_clk_source_names,
|
||||
.dss_params = omap3_dss_param_range,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
static const struct omap_dss_features omap3630_dss_features = {
|
||||
|
@ -306,7 +315,8 @@ static const struct omap_dss_features omap3630_dss_features = {
|
|||
FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
|
||||
FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
|
||||
FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
|
||||
FEAT_FIR_COEF_V,
|
||||
|
||||
.num_mgrs = 2,
|
||||
.num_ovls = 3,
|
||||
|
@ -314,6 +324,8 @@ static const struct omap_dss_features omap3630_dss_features = {
|
|||
.supported_color_modes = omap3_dss_supported_color_modes,
|
||||
.clksrc_names = omap3_dss_clk_source_names,
|
||||
.dss_params = omap3_dss_param_range,
|
||||
.buffer_size_unit = 1,
|
||||
.burst_size_unit = 8,
|
||||
};
|
||||
|
||||
/* OMAP4 DSS Features */
|
||||
|
@ -327,7 +339,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
|
|||
FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
|
||||
FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
|
||||
FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
|
||||
FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
|
||||
FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V,
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 3,
|
||||
|
@ -335,6 +348,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
|
|||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.clksrc_names = omap4_dss_clk_source_names,
|
||||
.dss_params = omap4_dss_param_range,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* For all the other OMAP4 versions */
|
||||
|
@ -348,7 +363,8 @@ static const struct omap_dss_features omap4_dss_features = {
|
|||
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_HANDLE_UV_SEPARATE | FEAT_ATTR2,
|
||||
FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
|
||||
FEAT_PRELOAD | FEAT_FIR_COEF_V,
|
||||
|
||||
.num_mgrs = 3,
|
||||
.num_ovls = 3,
|
||||
|
@ -356,6 +372,8 @@ static const struct omap_dss_features omap4_dss_features = {
|
|||
.supported_color_modes = omap4_dss_supported_color_modes,
|
||||
.clksrc_names = omap4_dss_clk_source_names,
|
||||
.dss_params = omap4_dss_param_range,
|
||||
.buffer_size_unit = 16,
|
||||
.burst_size_unit = 16,
|
||||
};
|
||||
|
||||
/* Functions returning values related to a DSS feature */
|
||||
|
@ -401,6 +419,16 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
|
|||
return omap_current_dss_features->clksrc_names[id];
|
||||
}
|
||||
|
||||
u32 dss_feat_get_buffer_size_unit(void)
|
||||
{
|
||||
return omap_current_dss_features->buffer_size_unit;
|
||||
}
|
||||
|
||||
u32 dss_feat_get_burst_size_unit(void)
|
||||
{
|
||||
return omap_current_dss_features->burst_size_unit;
|
||||
}
|
||||
|
||||
/* DSS has_feature check */
|
||||
bool dss_has_feature(enum dss_feat_id id)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,10 @@ enum dss_feat_id {
|
|||
FEAT_HDMI_CTS_SWMODE = 1 << 19,
|
||||
FEAT_HANDLE_UV_SEPARATE = 1 << 20,
|
||||
FEAT_ATTR2 = 1 << 21,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK = 1 << 22,
|
||||
FEAT_CPR = 1 << 23,
|
||||
FEAT_PRELOAD = 1 << 24,
|
||||
FEAT_FIR_COEF_V = 1 << 25,
|
||||
};
|
||||
|
||||
/* DSS register field id */
|
||||
|
@ -90,6 +94,9 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
|
|||
enum omap_color_mode color_mode);
|
||||
const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
|
||||
|
||||
u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
|
||||
u32 dss_feat_get_burst_size_unit(void); /* in bytes */
|
||||
|
||||
bool dss_has_feature(enum dss_feat_id id);
|
||||
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
|
||||
void dss_features_init(void);
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#include <video/omapdss.h>
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
|
@ -51,6 +54,9 @@ static struct {
|
|||
u8 edid_set;
|
||||
bool custom_set;
|
||||
struct hdmi_config cfg;
|
||||
|
||||
struct clk *sys_clk;
|
||||
struct clk *hdmi_clk;
|
||||
} hdmi;
|
||||
|
||||
/*
|
||||
|
@ -162,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
|
|||
return val;
|
||||
}
|
||||
|
||||
static int hdmi_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("hdmi_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&hdmi.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void hdmi_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("hdmi_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put(&hdmi.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
|
||||
int hdmi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("init_display\n");
|
||||
|
@ -311,30 +338,11 @@ static int hdmi_phy_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_wait_softreset(void)
|
||||
{
|
||||
/* reset W1 */
|
||||
REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
|
||||
|
||||
/* wait till SOFTRESET == 0 */
|
||||
if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
|
||||
DSSERR("sysconfig reset failed\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_pll_program(struct hdmi_pll_info *fmt)
|
||||
{
|
||||
u16 r = 0;
|
||||
enum hdmi_clk_refsel refsel;
|
||||
|
||||
/* wait for wrapper reset */
|
||||
r = hdmi_wait_softreset();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -1064,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
|
|||
unsigned long clkin, refclk;
|
||||
u32 mf;
|
||||
|
||||
clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
|
||||
clkin = clk_get_rate(hdmi.sys_clk) / 10000;
|
||||
/*
|
||||
* Input clock is predivided by N + 1
|
||||
* out put of which is reference clk
|
||||
|
@ -1098,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
|
|||
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
|
||||
}
|
||||
|
||||
static void hdmi_enable_clocks(int enable)
|
||||
{
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
|
||||
DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
|
||||
DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
|
||||
}
|
||||
|
||||
static int hdmi_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r, code = 0;
|
||||
|
@ -1115,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
|
|||
struct omap_video_timings *p;
|
||||
unsigned long phy;
|
||||
|
||||
hdmi_enable_clocks(1);
|
||||
r = hdmi_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
|
||||
|
||||
|
@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
|
|||
|
||||
return 0;
|
||||
err:
|
||||
hdmi_enable_clocks(0);
|
||||
hdmi_runtime_put();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
|
|||
hdmi_wp_video_start(0);
|
||||
hdmi_phy_off();
|
||||
hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
|
||||
hdmi_enable_clocks(0);
|
||||
hdmi_runtime_put();
|
||||
|
||||
hdmi.edid_set = 0;
|
||||
}
|
||||
|
@ -1686,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static int hdmi_get_clocks(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(&pdev->dev, "sys_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get sys_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
hdmi.sys_clk = clk;
|
||||
|
||||
clk = clk_get(&pdev->dev, "dss_48mhz_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get hdmi_clk\n");
|
||||
clk_put(hdmi.sys_clk);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
hdmi.hdmi_clk = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_put_clocks(void)
|
||||
{
|
||||
if (hdmi.sys_clk)
|
||||
clk_put(hdmi.sys_clk);
|
||||
if (hdmi.hdmi_clk)
|
||||
clk_put(hdmi.hdmi_clk);
|
||||
}
|
||||
|
||||
/* HDMI HW IP initialisation */
|
||||
static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *hdmi_mem;
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
int ret;
|
||||
#endif
|
||||
int r;
|
||||
|
||||
hdmi.pdata = pdev->dev.platform_data;
|
||||
hdmi.pdev = pdev;
|
||||
|
@ -1713,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = hdmi_get_clocks(pdev);
|
||||
if (r) {
|
||||
iounmap(hdmi.base_wp);
|
||||
return r;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
hdmi_panel_init();
|
||||
|
||||
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
|
||||
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
|
||||
|
||||
/* Register ASoC codec DAI */
|
||||
ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
|
||||
r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
|
||||
&hdmi_codec_dai_drv, 1);
|
||||
if (ret) {
|
||||
if (r) {
|
||||
DSSERR("can't register ASoC HDMI audio codec\n");
|
||||
return ret;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -1738,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
|
|||
snd_soc_unregister_codec(&pdev->dev);
|
||||
#endif
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
hdmi_put_clocks();
|
||||
|
||||
iounmap(hdmi.base_wp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable(hdmi.hdmi_clk);
|
||||
clk_disable(hdmi.sys_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dss_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dispc;
|
||||
|
||||
|
||||
clk_enable(hdmi.sys_clk);
|
||||
clk_enable(hdmi.hdmi_clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops hdmi_pm_ops = {
|
||||
.runtime_suspend = hdmi_runtime_suspend,
|
||||
.runtime_resume = hdmi_runtime_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver omapdss_hdmihw_driver = {
|
||||
.probe = omapdss_hdmihw_probe,
|
||||
.remove = omapdss_hdmihw_remove,
|
||||
.driver = {
|
||||
.name = "omapdss_hdmi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &hdmi_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -275,6 +275,108 @@ static ssize_t manager_alpha_blending_enabled_store(
|
|||
return size;
|
||||
}
|
||||
|
||||
static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", mgr->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 v;
|
||||
int r;
|
||||
bool enable;
|
||||
|
||||
if (!dss_has_feature(FEAT_CPR))
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtoint(buf, 0, &v);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
enable = !!v;
|
||||
|
||||
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 *);
|
||||
|
@ -300,6 +402,12 @@ static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
|
|||
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[] = {
|
||||
|
@ -310,6 +418,8 @@ static struct attribute *manager_sysfs_attrs[] = {
|
|||
&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
|
||||
};
|
||||
|
||||
|
@ -391,33 +501,14 @@ struct overlay_cache_data {
|
|||
|
||||
bool enabled;
|
||||
|
||||
u32 paddr;
|
||||
void __iomem *vaddr;
|
||||
u32 p_uv_addr; /* relevant for NV12 format only */
|
||||
u16 screen_width;
|
||||
u16 width;
|
||||
u16 height;
|
||||
enum omap_color_mode color_mode;
|
||||
u8 rotation;
|
||||
enum omap_dss_rotation_type rotation_type;
|
||||
bool mirror;
|
||||
|
||||
u16 pos_x;
|
||||
u16 pos_y;
|
||||
u16 out_width; /* if 0, out_width == width */
|
||||
u16 out_height; /* if 0, out_height == height */
|
||||
u8 global_alpha;
|
||||
u8 pre_mult_alpha;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
enum omap_channel channel;
|
||||
bool replication;
|
||||
bool ilace;
|
||||
|
||||
enum omap_burst_size burst_size;
|
||||
u32 fifo_low;
|
||||
u32 fifo_high;
|
||||
|
||||
bool manual_update;
|
||||
};
|
||||
|
||||
struct manager_cache_data {
|
||||
|
@ -429,15 +520,8 @@ struct manager_cache_data {
|
|||
* VSYNC/EVSYNC */
|
||||
bool shadow_dirty;
|
||||
|
||||
u32 default_color;
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
enum omap_dss_trans_key_type trans_key_type;
|
||||
u32 trans_key;
|
||||
bool trans_enabled;
|
||||
|
||||
bool alpha_enabled;
|
||||
|
||||
bool manual_upd_display;
|
||||
bool manual_update;
|
||||
bool do_manual_update;
|
||||
|
||||
|
@ -539,24 +623,15 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
|
|||
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return 0;
|
||||
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
|
||||
return 0;
|
||||
|
||||
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
|
||||
|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
|
||||
} else {
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
|
||||
enum omap_dss_update_mode mode;
|
||||
mode = dssdev->driver->get_update_mode(dssdev);
|
||||
if (mode != OMAP_DSS_UPDATE_AUTO)
|
||||
return 0;
|
||||
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_FRAMEDONE
|
||||
: DISPC_IRQ_FRAMEDONE2;
|
||||
} else {
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_VSYNC
|
||||
: DISPC_IRQ_VSYNC2;
|
||||
}
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
|
||||
}
|
||||
|
||||
mc = &dss_cache.manager_cache[mgr->id];
|
||||
|
@ -617,24 +692,15 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
|
|||
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return 0;
|
||||
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
|
||||
return 0;
|
||||
|
||||
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
|
||||
|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
|
||||
} else {
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
|
||||
enum omap_dss_update_mode mode;
|
||||
mode = dssdev->driver->get_update_mode(dssdev);
|
||||
if (mode != OMAP_DSS_UPDATE_AUTO)
|
||||
return 0;
|
||||
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_FRAMEDONE
|
||||
: DISPC_IRQ_FRAMEDONE2;
|
||||
} else {
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_VSYNC
|
||||
: DISPC_IRQ_VSYNC2;
|
||||
}
|
||||
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
|
||||
DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
|
||||
}
|
||||
|
||||
oc = &dss_cache.overlay_cache[ovl->id];
|
||||
|
@ -720,10 +786,12 @@ static bool rectangle_intersects(int x1, int y1, int w1, int h1,
|
|||
|
||||
static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
|
||||
{
|
||||
if (oc->out_width != 0 && oc->width != oc->out_width)
|
||||
struct omap_overlay_info *oi = &oc->info;
|
||||
|
||||
if (oi->out_width != 0 && oi->width != oi->out_width)
|
||||
return true;
|
||||
|
||||
if (oc->out_height != 0 && oc->height != oc->out_height)
|
||||
if (oi->out_height != 0 && oi->height != oi->out_height)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -733,6 +801,8 @@ static int configure_overlay(enum omap_plane plane)
|
|||
{
|
||||
struct overlay_cache_data *c;
|
||||
struct manager_cache_data *mc;
|
||||
struct omap_overlay_info *oi;
|
||||
struct omap_overlay_manager_info *mi;
|
||||
u16 outw, outh;
|
||||
u16 x, y, w, h;
|
||||
u32 paddr;
|
||||
|
@ -742,6 +812,7 @@ static int configure_overlay(enum omap_plane plane)
|
|||
DSSDBGF("%d", plane);
|
||||
|
||||
c = &dss_cache.overlay_cache[plane];
|
||||
oi = &c->info;
|
||||
|
||||
if (!c->enabled) {
|
||||
dispc_enable_plane(plane, 0);
|
||||
|
@ -749,21 +820,22 @@ static int configure_overlay(enum omap_plane plane)
|
|||
}
|
||||
|
||||
mc = &dss_cache.manager_cache[c->channel];
|
||||
mi = &mc->info;
|
||||
|
||||
x = c->pos_x;
|
||||
y = c->pos_y;
|
||||
w = c->width;
|
||||
h = c->height;
|
||||
outw = c->out_width == 0 ? c->width : c->out_width;
|
||||
outh = c->out_height == 0 ? c->height : c->out_height;
|
||||
paddr = c->paddr;
|
||||
x = oi->pos_x;
|
||||
y = oi->pos_y;
|
||||
w = oi->width;
|
||||
h = oi->height;
|
||||
outw = oi->out_width == 0 ? oi->width : oi->out_width;
|
||||
outh = oi->out_height == 0 ? oi->height : oi->out_height;
|
||||
paddr = oi->paddr;
|
||||
|
||||
orig_w = w;
|
||||
orig_h = h;
|
||||
orig_outw = outw;
|
||||
orig_outh = outh;
|
||||
|
||||
if (c->manual_update && mc->do_manual_update) {
|
||||
if (mc->manual_update && mc->do_manual_update) {
|
||||
unsigned bpp;
|
||||
unsigned scale_x_m = w, scale_x_d = outw;
|
||||
unsigned scale_y_m = h, scale_y_d = outh;
|
||||
|
@ -775,7 +847,7 @@ static int configure_overlay(enum omap_plane plane)
|
|||
return 0;
|
||||
}
|
||||
|
||||
switch (c->color_mode) {
|
||||
switch (oi->color_mode) {
|
||||
case OMAP_DSS_COLOR_NV12:
|
||||
bpp = 8;
|
||||
break;
|
||||
|
@ -805,23 +877,23 @@ static int configure_overlay(enum omap_plane plane)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (mc->x > c->pos_x) {
|
||||
if (mc->x > oi->pos_x) {
|
||||
x = 0;
|
||||
outw -= (mc->x - c->pos_x);
|
||||
paddr += (mc->x - c->pos_x) *
|
||||
outw -= (mc->x - oi->pos_x);
|
||||
paddr += (mc->x - oi->pos_x) *
|
||||
scale_x_m / scale_x_d * bpp / 8;
|
||||
} else {
|
||||
x = c->pos_x - mc->x;
|
||||
x = oi->pos_x - mc->x;
|
||||
}
|
||||
|
||||
if (mc->y > c->pos_y) {
|
||||
if (mc->y > oi->pos_y) {
|
||||
y = 0;
|
||||
outh -= (mc->y - c->pos_y);
|
||||
paddr += (mc->y - c->pos_y) *
|
||||
outh -= (mc->y - oi->pos_y);
|
||||
paddr += (mc->y - oi->pos_y) *
|
||||
scale_y_m / scale_y_d *
|
||||
c->screen_width * bpp / 8;
|
||||
oi->screen_width * bpp / 8;
|
||||
} else {
|
||||
y = c->pos_y - mc->y;
|
||||
y = oi->pos_y - mc->y;
|
||||
}
|
||||
|
||||
if (mc->w < (x + outw))
|
||||
|
@ -840,8 +912,8 @@ static int configure_overlay(enum omap_plane plane)
|
|||
* the width if the original width was bigger.
|
||||
*/
|
||||
if ((w & 1) &&
|
||||
(c->color_mode == OMAP_DSS_COLOR_YUV2 ||
|
||||
c->color_mode == OMAP_DSS_COLOR_UYVY)) {
|
||||
(oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
|
||||
oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
|
||||
if (orig_w > w)
|
||||
w += 1;
|
||||
else
|
||||
|
@ -851,19 +923,19 @@ static int configure_overlay(enum omap_plane plane)
|
|||
|
||||
r = dispc_setup_plane(plane,
|
||||
paddr,
|
||||
c->screen_width,
|
||||
oi->screen_width,
|
||||
x, y,
|
||||
w, h,
|
||||
outw, outh,
|
||||
c->color_mode,
|
||||
oi->color_mode,
|
||||
c->ilace,
|
||||
c->rotation_type,
|
||||
c->rotation,
|
||||
c->mirror,
|
||||
c->global_alpha,
|
||||
c->pre_mult_alpha,
|
||||
oi->rotation_type,
|
||||
oi->rotation,
|
||||
oi->mirror,
|
||||
oi->global_alpha,
|
||||
oi->pre_mult_alpha,
|
||||
c->channel,
|
||||
c->p_uv_addr);
|
||||
oi->p_uv_addr);
|
||||
|
||||
if (r) {
|
||||
/* this shouldn't happen */
|
||||
|
@ -874,8 +946,7 @@ static int configure_overlay(enum omap_plane plane)
|
|||
|
||||
dispc_enable_replication(plane, c->replication);
|
||||
|
||||
dispc_set_burst_size(plane, c->burst_size);
|
||||
dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
|
||||
dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
|
||||
|
||||
dispc_enable_plane(plane, 1);
|
||||
|
||||
|
@ -884,16 +955,21 @@ static int configure_overlay(enum omap_plane plane)
|
|||
|
||||
static void configure_manager(enum omap_channel channel)
|
||||
{
|
||||
struct manager_cache_data *c;
|
||||
struct omap_overlay_manager_info *mi;
|
||||
|
||||
DSSDBGF("%d", channel);
|
||||
|
||||
c = &dss_cache.manager_cache[channel];
|
||||
/* picking info from the cache */
|
||||
mi = &dss_cache.manager_cache[channel].info;
|
||||
|
||||
dispc_set_default_color(channel, c->default_color);
|
||||
dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
|
||||
dispc_enable_trans_key(channel, c->trans_enabled);
|
||||
dispc_enable_alpha_blending(channel, c->alpha_enabled);
|
||||
dispc_set_default_color(channel, mi->default_color);
|
||||
dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
|
||||
dispc_enable_trans_key(channel, mi->trans_enabled);
|
||||
dispc_enable_alpha_blending(channel, mi->alpha_enabled);
|
||||
if (dss_has_feature(FEAT_CPR)) {
|
||||
dispc_enable_cpr(channel, mi->cpr_enable);
|
||||
dispc_set_cpr_coef(channel, &mi->cpr_coefs);
|
||||
}
|
||||
}
|
||||
|
||||
/* configure_dispc() tries to write values from cache to shadow registers.
|
||||
|
@ -928,7 +1004,7 @@ static int configure_dispc(void)
|
|||
if (!oc->dirty)
|
||||
continue;
|
||||
|
||||
if (oc->manual_update && !mc->do_manual_update)
|
||||
if (mc->manual_update && !mc->do_manual_update)
|
||||
continue;
|
||||
|
||||
if (mgr_busy[oc->channel]) {
|
||||
|
@ -976,7 +1052,7 @@ static int configure_dispc(void)
|
|||
/* We don't need GO with manual update display. LCD iface will
|
||||
* always be turned off after frame, and new settings will be
|
||||
* taken in to use at next update */
|
||||
if (!mc->manual_upd_display)
|
||||
if (!mc->manual_update)
|
||||
dispc_go(i);
|
||||
}
|
||||
|
||||
|
@ -1011,6 +1087,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
|
|||
{
|
||||
struct overlay_cache_data *oc;
|
||||
struct manager_cache_data *mc;
|
||||
struct omap_overlay_info *oi;
|
||||
const int num_ovls = dss_feat_get_num_ovls();
|
||||
struct omap_overlay_manager *mgr;
|
||||
int i;
|
||||
|
@ -1053,6 +1130,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
|
|||
unsigned outw, outh;
|
||||
|
||||
oc = &dss_cache.overlay_cache[i];
|
||||
oi = &oc->info;
|
||||
|
||||
if (oc->channel != mgr->id)
|
||||
continue;
|
||||
|
@ -1068,39 +1146,39 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
|
|||
if (!dispc_is_overlay_scaled(oc))
|
||||
continue;
|
||||
|
||||
outw = oc->out_width == 0 ?
|
||||
oc->width : oc->out_width;
|
||||
outh = oc->out_height == 0 ?
|
||||
oc->height : oc->out_height;
|
||||
outw = oi->out_width == 0 ?
|
||||
oi->width : oi->out_width;
|
||||
outh = oi->out_height == 0 ?
|
||||
oi->height : oi->out_height;
|
||||
|
||||
/* is the overlay outside the update region? */
|
||||
if (!rectangle_intersects(x, y, w, h,
|
||||
oc->pos_x, oc->pos_y,
|
||||
oi->pos_x, oi->pos_y,
|
||||
outw, outh))
|
||||
continue;
|
||||
|
||||
/* if the overlay totally inside the update region? */
|
||||
if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
|
||||
if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
|
||||
x, y, w, h))
|
||||
continue;
|
||||
|
||||
if (x > oc->pos_x)
|
||||
x1 = oc->pos_x;
|
||||
if (x > oi->pos_x)
|
||||
x1 = oi->pos_x;
|
||||
else
|
||||
x1 = x;
|
||||
|
||||
if (y > oc->pos_y)
|
||||
y1 = oc->pos_y;
|
||||
if (y > oi->pos_y)
|
||||
y1 = oi->pos_y;
|
||||
else
|
||||
y1 = y;
|
||||
|
||||
if ((x + w) < (oc->pos_x + outw))
|
||||
x2 = oc->pos_x + outw;
|
||||
if ((x + w) < (oi->pos_x + outw))
|
||||
x2 = oi->pos_x + outw;
|
||||
else
|
||||
x2 = x + w;
|
||||
|
||||
if ((y + h) < (oc->pos_y + outh))
|
||||
y2 = oc->pos_y + outh;
|
||||
if ((y + h) < (oi->pos_y + outh))
|
||||
y2 = oi->pos_y + outh;
|
||||
else
|
||||
y2 = y + h;
|
||||
|
||||
|
@ -1236,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
|
||||
DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
spin_lock_irqsave(&dss_cache.lock, flags);
|
||||
|
||||
/* Configure overlays */
|
||||
|
@ -1275,23 +1357,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
|
||||
ovl->info_dirty = false;
|
||||
oc->dirty = true;
|
||||
|
||||
oc->paddr = ovl->info.paddr;
|
||||
oc->vaddr = ovl->info.vaddr;
|
||||
oc->p_uv_addr = ovl->info.p_uv_addr;
|
||||
oc->screen_width = ovl->info.screen_width;
|
||||
oc->width = ovl->info.width;
|
||||
oc->height = ovl->info.height;
|
||||
oc->color_mode = ovl->info.color_mode;
|
||||
oc->rotation = ovl->info.rotation;
|
||||
oc->rotation_type = ovl->info.rotation_type;
|
||||
oc->mirror = ovl->info.mirror;
|
||||
oc->pos_x = ovl->info.pos_x;
|
||||
oc->pos_y = ovl->info.pos_y;
|
||||
oc->out_width = ovl->info.out_width;
|
||||
oc->out_height = ovl->info.out_height;
|
||||
oc->global_alpha = ovl->info.global_alpha;
|
||||
oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
|
||||
oc->info = ovl->info;
|
||||
|
||||
oc->replication =
|
||||
dss_use_replication(dssdev, ovl->info.color_mode);
|
||||
|
@ -1302,11 +1368,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
|
||||
oc->enabled = true;
|
||||
|
||||
oc->manual_update =
|
||||
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
|
||||
dssdev->driver->get_update_mode(dssdev) !=
|
||||
OMAP_DSS_UPDATE_AUTO;
|
||||
|
||||
++num_planes_enabled;
|
||||
}
|
||||
|
||||
|
@ -1334,20 +1395,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
|
||||
mgr->info_dirty = false;
|
||||
mc->dirty = true;
|
||||
|
||||
mc->default_color = mgr->info.default_color;
|
||||
mc->trans_key_type = mgr->info.trans_key_type;
|
||||
mc->trans_key = mgr->info.trans_key;
|
||||
mc->trans_enabled = mgr->info.trans_enabled;
|
||||
mc->alpha_enabled = mgr->info.alpha_enabled;
|
||||
|
||||
mc->manual_upd_display =
|
||||
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
|
||||
mc->info = mgr->info;
|
||||
|
||||
mc->manual_update =
|
||||
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
|
||||
dssdev->driver->get_update_mode(dssdev) !=
|
||||
OMAP_DSS_UPDATE_AUTO;
|
||||
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
|
||||
}
|
||||
|
||||
/* XXX TODO: Try to get fifomerge working. The problem is that it
|
||||
|
@ -1368,7 +1419,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
/* Configure overlay fifos */
|
||||
for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
|
||||
struct omap_dss_device *dssdev;
|
||||
u32 size;
|
||||
u32 size, burst_size;
|
||||
|
||||
ovl = omap_dss_get_overlay(i);
|
||||
|
||||
|
@ -1386,6 +1437,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
if (use_fifomerge)
|
||||
size *= 3;
|
||||
|
||||
burst_size = dispc_get_burst_size(ovl->id);
|
||||
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
|
@ -1393,13 +1446,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
case OMAP_DISPLAY_TYPE_HDMI:
|
||||
default_get_overlay_fifo_thresholds(ovl->id, size,
|
||||
&oc->burst_size, &oc->fifo_low,
|
||||
burst_size, &oc->fifo_low,
|
||||
&oc->fifo_high);
|
||||
break;
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
dsi_get_overlay_fifo_thresholds(ovl->id, size,
|
||||
&oc->burst_size, &oc->fifo_low,
|
||||
burst_size, &oc->fifo_low,
|
||||
&oc->fifo_high);
|
||||
break;
|
||||
#endif
|
||||
|
@ -1409,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
}
|
||||
|
||||
r = 0;
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
if (!dss_cache.irq_enabled) {
|
||||
u32 mask;
|
||||
|
||||
|
@ -1422,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
|
|||
dss_cache.irq_enabled = true;
|
||||
}
|
||||
configure_dispc();
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
spin_unlock_irqrestore(&dss_cache.lock, flags);
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
|
|||
|
||||
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");
|
||||
return r;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = old_mgr->apply(old_mgr);
|
||||
if (r)
|
||||
return r;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mgr) {
|
||||
r = ovl->set_manager(ovl, mgr);
|
||||
if (r) {
|
||||
DSSERR("Failed to attach overlay\n");
|
||||
return r;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return 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)
|
||||
|
@ -238,6 +248,9 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
|
|||
u8 alpha;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
|
||||
return -ENODEV;
|
||||
|
||||
r = kstrtou8(buf, 0, &alpha);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
|
|||
|
||||
ovl->manager = mgr;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
/* XXX: When there is an overlay on a DSI manual update display, and
|
||||
* the overlay is first disabled, then moved to tv, and enabled, we
|
||||
* seem to get SYNC_LOST_DIGIT error.
|
||||
|
@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
|
|||
* the overlay, but before moving the overlay to TV.
|
||||
*/
|
||||
dispc_set_channel_out(ovl->id, mgr->id);
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
|
|||
omap_dss_set_manager(ovl, mgr);
|
||||
}
|
||||
}
|
||||
|
||||
dispc_runtime_put();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <linux/hrtimer.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include "dss.h"
|
||||
|
@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
|
|||
return __raw_readl(rfbi.base + idx.idx);
|
||||
}
|
||||
|
||||
static void rfbi_enable_clocks(bool enable)
|
||||
static int rfbi_runtime_get(void)
|
||||
{
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
int r;
|
||||
|
||||
DSSDBG("rfbi_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&rfbi.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void rfbi_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("rfbi_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put(&rfbi.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
|
||||
void rfbi_bus_lock(void)
|
||||
|
@ -805,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s)
|
|||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
if (rfbi_runtime_get())
|
||||
return;
|
||||
|
||||
DUMPREG(RFBI_REVISION);
|
||||
DUMPREG(RFBI_SYSCONFIG);
|
||||
|
@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
|
|||
DUMPREG(RFBI_VSYNC_WIDTH);
|
||||
DUMPREG(RFBI_HSYNC_WIDTH);
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
rfbi_runtime_put();
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
|
@ -844,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
|
|||
{
|
||||
int r;
|
||||
|
||||
rfbi_enable_clocks(1);
|
||||
r = rfbi_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
|
@ -879,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
|
|||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
rfbi_runtime_put();
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_rfbi_display_enable);
|
||||
|
@ -889,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
|
|||
DISPC_IRQ_FRAMEDONE);
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
||||
rfbi_enable_clocks(0);
|
||||
rfbi_runtime_put();
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_rfbi_display_disable);
|
||||
|
||||
|
@ -904,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
|
|||
static int omap_rfbihw_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 rev;
|
||||
u32 l;
|
||||
struct resource *rfbi_mem;
|
||||
struct clk *clk;
|
||||
int r;
|
||||
|
||||
rfbi.pdev = pdev;
|
||||
|
||||
|
@ -914,46 +934,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
|
|||
rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
|
||||
if (!rfbi_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM RFBI\n");
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
goto err_ioremap;
|
||||
}
|
||||
rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
|
||||
if (!rfbi.base) {
|
||||
DSSERR("can't ioremap RFBI\n");
|
||||
return -ENOMEM;
|
||||
r = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
rfbi_enable_clocks(1);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
r = rfbi_runtime_get();
|
||||
if (r)
|
||||
goto err_get_rfbi;
|
||||
|
||||
msleep(10);
|
||||
|
||||
rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
|
||||
if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630())
|
||||
clk = dss_get_ick();
|
||||
else
|
||||
clk = clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get ick\n");
|
||||
r = PTR_ERR(clk);
|
||||
goto err_get_ick;
|
||||
}
|
||||
|
||||
/* Enable autoidle and smart-idle */
|
||||
l = rfbi_read_reg(RFBI_SYSCONFIG);
|
||||
l |= (1 << 0) | (2 << 3);
|
||||
rfbi_write_reg(RFBI_SYSCONFIG, l);
|
||||
rfbi.l4_khz = clk_get_rate(clk) / 1000;
|
||||
|
||||
clk_put(clk);
|
||||
|
||||
rev = rfbi_read_reg(RFBI_REVISION);
|
||||
dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
|
||||
rfbi_enable_clocks(0);
|
||||
rfbi_runtime_put();
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_ick:
|
||||
rfbi_runtime_put();
|
||||
err_get_rfbi:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
iounmap(rfbi.base);
|
||||
err_ioremap:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_rfbihw_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
iounmap(rfbi.base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rfbi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rfbi_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dss_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dispc;
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rfbi_pm_ops = {
|
||||
.runtime_suspend = rfbi_runtime_suspend,
|
||||
.runtime_resume = rfbi_runtime_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver omap_rfbihw_driver = {
|
||||
.probe = omap_rfbihw_probe,
|
||||
.remove = omap_rfbihw_remove,
|
||||
.driver = {
|
||||
.name = "omapdss_rfbi",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &rfbi_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -20,13 +20,11 @@
|
|||
#define DSS_SUBSYS_NAME "SDI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <plat/cpu.h>
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
|
@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
goto err_start_dev;
|
||||
}
|
||||
|
||||
r = regulator_enable(sdi.vdds_sdi_reg);
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err_reg_enable;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
sdi_basic_init(dssdev);
|
||||
|
||||
|
@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
|
||||
&dss_cinfo, &dispc_cinfo);
|
||||
if (r)
|
||||
goto err2;
|
||||
goto err_calc_clock_div;
|
||||
|
||||
fck = dss_cinfo.fck;
|
||||
lck_div = dispc_cinfo.lck_div;
|
||||
|
@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
r = dss_set_clock_div(&dss_cinfo);
|
||||
if (r)
|
||||
goto err2;
|
||||
goto err_set_dss_clock_div;
|
||||
|
||||
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
|
||||
if (r)
|
||||
goto err2;
|
||||
goto err_set_dispc_clock_div;
|
||||
|
||||
dss_sdi_init(dssdev->phy.sdi.datapairs);
|
||||
r = dss_sdi_enable();
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err_sdi_enable;
|
||||
mdelay(2);
|
||||
|
||||
dssdev->manager->enable(dssdev->manager);
|
||||
|
||||
return 0;
|
||||
err2:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
|
||||
err_sdi_enable:
|
||||
err_set_dispc_clock_div:
|
||||
err_set_dss_clock_div:
|
||||
err_calc_clock_div:
|
||||
dispc_runtime_put();
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
err1:
|
||||
err_reg_enable:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
err_start_dev:
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_sdi_display_enable);
|
||||
|
@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
|
|||
|
||||
dss_sdi_disable();
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
regulator_disable(sdi.vdds_sdi_reg);
|
||||
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
/* Venc registers */
|
||||
#define VENC_REV_ID 0x00
|
||||
|
@ -292,6 +294,9 @@ static struct {
|
|||
struct mutex venc_lock;
|
||||
u32 wss_data;
|
||||
struct regulator *vdda_dac_reg;
|
||||
|
||||
struct clk *tv_clk;
|
||||
struct clk *tv_dac_clk;
|
||||
} venc;
|
||||
|
||||
static inline void venc_write_reg(int idx, u32 val)
|
||||
|
@ -380,14 +385,25 @@ static void venc_reset(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void venc_enable_clocks(int enable)
|
||||
static int venc_runtime_get(void)
|
||||
{
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
|
||||
DSS_CLK_VIDFCK);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
|
||||
DSS_CLK_VIDFCK);
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_runtime_get\n");
|
||||
|
||||
r = pm_runtime_get_sync(&venc.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void venc_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_runtime_put\n");
|
||||
|
||||
r = pm_runtime_put(&venc.pdev->dev);
|
||||
WARN_ON(r < 0);
|
||||
}
|
||||
|
||||
static const struct venc_config *venc_timings_to_config(
|
||||
|
@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
|
|||
{
|
||||
u32 l;
|
||||
|
||||
venc_enable_clocks(1);
|
||||
|
||||
venc_reset();
|
||||
venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
|
||||
|
||||
|
@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
|
|||
dssdev->platform_disable(dssdev);
|
||||
|
||||
regulator_disable(venc.vdda_dac_reg);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
venc_power_on(dssdev);
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
|
|||
|
||||
venc_power_off(dssdev);
|
||||
|
||||
venc_runtime_put();
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
|
@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
|
|||
return venc_panel_enable(dssdev);
|
||||
}
|
||||
|
||||
static enum omap_dss_update_mode venc_get_update_mode(
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
return OMAP_DSS_UPDATE_AUTO;
|
||||
}
|
||||
|
||||
static int venc_set_update_mode(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode mode)
|
||||
{
|
||||
if (mode != OMAP_DSS_UPDATE_AUTO)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void venc_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
|
@ -598,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev)
|
|||
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
||||
{
|
||||
const struct venc_config *config;
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_set_wss\n");
|
||||
|
||||
|
@ -608,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
|||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
venc.wss_data = (wss ^ 0xfffff) << 8;
|
||||
|
||||
venc_enable_clocks(1);
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc.wss_data);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
venc_runtime_put();
|
||||
|
||||
err:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct omap_dss_driver venc_driver = {
|
||||
|
@ -632,9 +640,6 @@ static struct omap_dss_driver venc_driver = {
|
|||
.get_resolution = omapdss_default_get_resolution,
|
||||
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
|
||||
|
||||
.set_update_mode = venc_set_update_mode,
|
||||
.get_update_mode = venc_get_update_mode,
|
||||
|
||||
.get_timings = venc_get_timings,
|
||||
.set_timings = venc_set_timings,
|
||||
.check_timings = venc_check_timings,
|
||||
|
@ -673,7 +678,8 @@ void venc_dump_regs(struct seq_file *s)
|
|||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
|
||||
|
||||
venc_enable_clocks(1);
|
||||
if (venc_runtime_get())
|
||||
return;
|
||||
|
||||
DUMPREG(VENC_F_CONTROL);
|
||||
DUMPREG(VENC_VIDOUT_CTRL);
|
||||
|
@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s)
|
|||
DUMPREG(VENC_OUTPUT_CONTROL);
|
||||
DUMPREG(VENC_OUTPUT_TEST);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
venc_runtime_put();
|
||||
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
static int venc_get_clocks(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get fck\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
venc.tv_clk = clk;
|
||||
|
||||
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
|
||||
if (cpu_is_omap34xx() || cpu_is_omap3630())
|
||||
clk = clk_get(&pdev->dev, "dss_96m_fck");
|
||||
else
|
||||
clk = clk_get(&pdev->dev, "tv_dac_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get tv_dac_clk\n");
|
||||
clk_put(venc.tv_clk);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
} else {
|
||||
clk = NULL;
|
||||
}
|
||||
|
||||
venc.tv_dac_clk = clk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void venc_put_clocks(void)
|
||||
{
|
||||
if (venc.tv_clk)
|
||||
clk_put(venc.tv_clk);
|
||||
if (venc.tv_dac_clk)
|
||||
clk_put(venc.tv_dac_clk);
|
||||
}
|
||||
|
||||
/* VENC HW IP initialisation */
|
||||
static int omap_venchw_probe(struct platform_device *pdev)
|
||||
{
|
||||
u8 rev_id;
|
||||
struct resource *venc_mem;
|
||||
int r;
|
||||
|
||||
venc.pdev = pdev;
|
||||
|
||||
|
@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
|
|||
venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
|
||||
if (!venc_mem) {
|
||||
DSSERR("can't get IORESOURCE_MEM VENC\n");
|
||||
return -EINVAL;
|
||||
r = -EINVAL;
|
||||
goto err_ioremap;
|
||||
}
|
||||
venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
|
||||
if (!venc.base) {
|
||||
DSSERR("can't ioremap VENC\n");
|
||||
return -ENOMEM;
|
||||
r = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
venc_enable_clocks(1);
|
||||
r = venc_get_clocks(pdev);
|
||||
if (r)
|
||||
goto err_get_clk;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
r = venc_runtime_get();
|
||||
if (r)
|
||||
goto err_get_venc;
|
||||
|
||||
rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
|
||||
dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
venc_runtime_put();
|
||||
|
||||
return omap_dss_register_driver(&venc_driver);
|
||||
|
||||
err_get_venc:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
venc_put_clocks();
|
||||
err_get_clk:
|
||||
iounmap(venc.base);
|
||||
err_ioremap:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_venchw_remove(struct platform_device *pdev)
|
||||
|
@ -763,16 +827,61 @@ static int omap_venchw_remove(struct platform_device *pdev)
|
|||
}
|
||||
omap_dss_unregister_driver(&venc_driver);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
venc_put_clocks();
|
||||
|
||||
iounmap(venc.base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_runtime_suspend(struct device *dev)
|
||||
{
|
||||
if (venc.tv_dac_clk)
|
||||
clk_disable(venc.tv_dac_clk);
|
||||
clk_disable(venc.tv_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
dss_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_runtime_resume(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dss_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dss;
|
||||
|
||||
r = dispc_runtime_get();
|
||||
if (r < 0)
|
||||
goto err_get_dispc;
|
||||
|
||||
clk_enable(venc.tv_clk);
|
||||
if (venc.tv_dac_clk)
|
||||
clk_enable(venc.tv_dac_clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_get_dispc:
|
||||
dss_runtime_put();
|
||||
err_get_dss:
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops venc_pm_ops = {
|
||||
.runtime_suspend = venc_runtime_suspend,
|
||||
.runtime_resume = venc_runtime_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver omap_venchw_driver = {
|
||||
.probe = omap_venchw_probe,
|
||||
.remove = omap_venchw_remove,
|
||||
.driver = {
|
||||
.name = "omapdss_venc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &venc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -316,68 +316,68 @@ int omapfb_update_window(struct fb_info *fbi,
|
|||
}
|
||||
EXPORT_SYMBOL(omapfb_update_window);
|
||||
|
||||
static int omapfb_set_update_mode(struct fb_info *fbi,
|
||||
int omapfb_set_update_mode(struct fb_info *fbi,
|
||||
enum omapfb_update_mode mode)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
enum omap_dss_update_mode um;
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omapfb_display_data *d;
|
||||
int r;
|
||||
|
||||
if (!display || !display->driver->set_update_mode)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mode) {
|
||||
case OMAPFB_UPDATE_DISABLED:
|
||||
um = OMAP_DSS_UPDATE_DISABLED;
|
||||
break;
|
||||
|
||||
case OMAPFB_AUTO_UPDATE:
|
||||
um = OMAP_DSS_UPDATE_AUTO;
|
||||
break;
|
||||
|
||||
case OMAPFB_MANUAL_UPDATE:
|
||||
um = OMAP_DSS_UPDATE_MANUAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = display->driver->set_update_mode(display, um);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_get_update_mode(struct fb_info *fbi,
|
||||
enum omapfb_update_mode *mode)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
enum omap_dss_update_mode m;
|
||||
|
||||
if (!display)
|
||||
return -EINVAL;
|
||||
|
||||
if (!display->driver->get_update_mode) {
|
||||
*mode = OMAPFB_AUTO_UPDATE;
|
||||
if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
|
||||
return -EINVAL;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
d = get_display_data(fbdev, display);
|
||||
|
||||
if (d->update_mode == mode) {
|
||||
omapfb_unlock(fbdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m = display->driver->get_update_mode(display);
|
||||
r = 0;
|
||||
|
||||
switch (m) {
|
||||
case OMAP_DSS_UPDATE_DISABLED:
|
||||
*mode = OMAPFB_UPDATE_DISABLED;
|
||||
break;
|
||||
case OMAP_DSS_UPDATE_AUTO:
|
||||
*mode = OMAPFB_AUTO_UPDATE;
|
||||
break;
|
||||
case OMAP_DSS_UPDATE_MANUAL:
|
||||
*mode = OMAPFB_MANUAL_UPDATE;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
|
||||
if (mode == OMAPFB_AUTO_UPDATE)
|
||||
omapfb_start_auto_update(fbdev, display);
|
||||
else /* MANUAL_UPDATE */
|
||||
omapfb_stop_auto_update(fbdev, display);
|
||||
|
||||
d->update_mode = mode;
|
||||
} else { /* AUTO_UPDATE */
|
||||
if (mode == OMAPFB_MANUAL_UPDATE)
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int omapfb_get_update_mode(struct fb_info *fbi,
|
||||
enum omapfb_update_mode *mode)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
if (!display)
|
||||
return -EINVAL;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
d = get_display_data(fbdev, display);
|
||||
|
||||
*mode = d->update_mode;
|
||||
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ static char *def_vram;
|
|||
static int def_vrfb;
|
||||
static int def_rotate;
|
||||
static int def_mirror;
|
||||
static bool auto_update;
|
||||
static unsigned int auto_update_freq;
|
||||
module_param(auto_update, bool, 0);
|
||||
module_param(auto_update_freq, uint, 0644);
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned int omapfb_debug;
|
||||
|
@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
|
|||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
struct omapfb_display_data *d;
|
||||
int r = 0;
|
||||
|
||||
if (!display)
|
||||
|
@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
|
|||
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
d = get_display_data(fbdev, display);
|
||||
|
||||
switch (blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
|
@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
|
|||
if (display->driver->resume)
|
||||
r = display->driver->resume(display);
|
||||
|
||||
if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
|
||||
d->update_mode == OMAPFB_AUTO_UPDATE &&
|
||||
!d->auto_update_work_enabled)
|
||||
omapfb_start_auto_update(fbdev, display);
|
||||
|
||||
break;
|
||||
|
||||
case FB_BLANK_NORMAL:
|
||||
|
@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
|
|||
if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
goto exit;
|
||||
|
||||
if (d->auto_update_work_enabled)
|
||||
omapfb_stop_auto_update(fbdev, display);
|
||||
|
||||
if (display->driver->suspend)
|
||||
r = display->driver->suspend(display);
|
||||
|
||||
|
@ -1724,6 +1739,78 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
|
|||
return r;
|
||||
}
|
||||
|
||||
static void omapfb_auto_update_work(struct work_struct *work)
|
||||
{
|
||||
struct omap_dss_device *dssdev;
|
||||
struct omap_dss_driver *dssdrv;
|
||||
struct omapfb_display_data *d;
|
||||
u16 w, h;
|
||||
unsigned int freq;
|
||||
struct omapfb2_device *fbdev;
|
||||
|
||||
d = container_of(work, struct omapfb_display_data,
|
||||
auto_update_work.work);
|
||||
|
||||
dssdev = d->dssdev;
|
||||
dssdrv = dssdev->driver;
|
||||
fbdev = d->fbdev;
|
||||
|
||||
if (!dssdrv || !dssdrv->update)
|
||||
return;
|
||||
|
||||
if (dssdrv->sync)
|
||||
dssdrv->sync(dssdev);
|
||||
|
||||
dssdrv->get_resolution(dssdev, &w, &h);
|
||||
dssdrv->update(dssdev, 0, 0, w, h);
|
||||
|
||||
freq = auto_update_freq;
|
||||
if (freq == 0)
|
||||
freq = 20;
|
||||
queue_delayed_work(fbdev->auto_update_wq,
|
||||
&d->auto_update_work, HZ / freq);
|
||||
}
|
||||
|
||||
void omapfb_start_auto_update(struct omapfb2_device *fbdev,
|
||||
struct omap_dss_device *display)
|
||||
{
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
if (fbdev->auto_update_wq == NULL) {
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
wq = create_singlethread_workqueue("omapfb_auto_update");
|
||||
|
||||
if (wq == NULL) {
|
||||
dev_err(fbdev->dev, "Failed to create workqueue for "
|
||||
"auto-update\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fbdev->auto_update_wq = wq;
|
||||
}
|
||||
|
||||
d = get_display_data(fbdev, display);
|
||||
|
||||
INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
|
||||
|
||||
d->auto_update_work_enabled = true;
|
||||
|
||||
omapfb_auto_update_work(&d->auto_update_work.work);
|
||||
}
|
||||
|
||||
void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
|
||||
struct omap_dss_device *display)
|
||||
{
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
d = get_display_data(fbdev, display);
|
||||
|
||||
cancel_delayed_work_sync(&d->auto_update_work);
|
||||
|
||||
d->auto_update_work_enabled = false;
|
||||
}
|
||||
|
||||
/* initialize fb_info, var, fix to something sane based on the display */
|
||||
static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
|
||||
{
|
||||
|
@ -1858,10 +1945,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
|
|||
}
|
||||
|
||||
for (i = 0; i < fbdev->num_displays; i++) {
|
||||
if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
|
||||
fbdev->displays[i]->driver->disable(fbdev->displays[i]);
|
||||
struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
|
||||
|
||||
omap_dss_put_device(fbdev->displays[i]);
|
||||
if (fbdev->displays[i].auto_update_work_enabled)
|
||||
omapfb_stop_auto_update(fbdev, dssdev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
|
||||
dssdev->driver->disable(dssdev);
|
||||
|
||||
omap_dss_put_device(dssdev);
|
||||
}
|
||||
|
||||
if (fbdev->auto_update_wq != NULL) {
|
||||
flush_workqueue(fbdev->auto_update_wq);
|
||||
destroy_workqueue(fbdev->auto_update_wq);
|
||||
fbdev->auto_update_wq = NULL;
|
||||
}
|
||||
|
||||
dev_set_drvdata(fbdev->dev, NULL);
|
||||
|
@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
|
|||
int r;
|
||||
u8 bpp;
|
||||
struct omap_video_timings timings, temp_timings;
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
|
||||
fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
|
||||
++fbdev->num_bpp_overrides;
|
||||
d = get_display_data(fbdev, display);
|
||||
d->bpp_override = bpp;
|
||||
|
||||
if (display->driver->check_timings) {
|
||||
r = display->driver->check_timings(display, &timings);
|
||||
|
@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
|
|||
static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
int i;
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
|
||||
|
||||
for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
|
||||
if (dssdev == fbdev->bpp_overrides[i].dssdev)
|
||||
return fbdev->bpp_overrides[i].bpp;
|
||||
}
|
||||
d = get_display_data(fbdev, dssdev);
|
||||
|
||||
if (d->bpp_override != 0)
|
||||
return d->bpp_override;
|
||||
|
||||
return dssdev->driver->get_recommended_bpp(dssdev);
|
||||
}
|
||||
|
@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
|
|||
|
||||
display = NULL;
|
||||
for (i = 0; i < fbdev->num_displays; ++i) {
|
||||
if (strcmp(fbdev->displays[i]->name,
|
||||
if (strcmp(fbdev->displays[i].dssdev->name,
|
||||
display_str) == 0) {
|
||||
display = fbdev->displays[i];
|
||||
display = fbdev->displays[i].dssdev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
|
|||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_driver *dssdrv = dssdev->driver;
|
||||
struct omapfb_display_data *d;
|
||||
int r;
|
||||
|
||||
r = dssdrv->enable(dssdev);
|
||||
|
@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
|
|||
return r;
|
||||
}
|
||||
|
||||
d = get_display_data(fbdev, dssdev);
|
||||
|
||||
d->fbdev = fbdev;
|
||||
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
|
||||
u16 w, h;
|
||||
|
||||
if (auto_update) {
|
||||
omapfb_start_auto_update(fbdev, dssdev);
|
||||
d->update_mode = OMAPFB_AUTO_UPDATE;
|
||||
} else {
|
||||
d->update_mode = OMAPFB_MANUAL_UPDATE;
|
||||
}
|
||||
|
||||
if (dssdrv->enable_te) {
|
||||
r = dssdrv->enable_te(dssdev, 1);
|
||||
if (r) {
|
||||
|
@ -2201,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
|
|||
}
|
||||
}
|
||||
|
||||
if (dssdrv->set_update_mode) {
|
||||
r = dssdrv->set_update_mode(dssdev,
|
||||
OMAP_DSS_UPDATE_MANUAL);
|
||||
if (r) {
|
||||
dev_err(fbdev->dev,
|
||||
"Failed to set update mode\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
dssdrv->get_resolution(dssdev, &w, &h);
|
||||
r = dssdrv->update(dssdev, 0, 0, w, h);
|
||||
if (r) {
|
||||
|
@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
|
|||
return r;
|
||||
}
|
||||
} else {
|
||||
if (dssdrv->set_update_mode) {
|
||||
r = dssdrv->set_update_mode(dssdev,
|
||||
OMAP_DSS_UPDATE_AUTO);
|
||||
if (r) {
|
||||
dev_err(fbdev->dev,
|
||||
"Failed to set update mode\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
d->update_mode = OMAPFB_AUTO_UPDATE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev)
|
|||
fbdev->num_displays = 0;
|
||||
dssdev = NULL;
|
||||
for_each_dss_dev(dssdev) {
|
||||
struct omapfb_display_data *d;
|
||||
|
||||
omap_dss_get_device(dssdev);
|
||||
|
||||
if (!dssdev->driver) {
|
||||
|
@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev)
|
|||
r = -ENODEV;
|
||||
}
|
||||
|
||||
fbdev->displays[fbdev->num_displays++] = dssdev;
|
||||
d = &fbdev->displays[fbdev->num_displays++];
|
||||
d->dssdev = dssdev;
|
||||
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
|
||||
d->update_mode = OMAPFB_MANUAL_UPDATE;
|
||||
else
|
||||
d->update_mode = OMAPFB_AUTO_UPDATE;
|
||||
}
|
||||
|
||||
if (r)
|
||||
|
|
|
@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
|
|||
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
|
||||
}
|
||||
|
||||
static ssize_t show_upd_mode(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
enum omapfb_update_mode mode;
|
||||
int r;
|
||||
|
||||
r = omapfb_get_update_mode(fbi, &mode);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
|
||||
}
|
||||
|
||||
static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
unsigned mode;
|
||||
int r;
|
||||
|
||||
r = kstrtouint(buf, 0, &mode);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = omapfb_set_update_mode(fbi, mode);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute omapfb_attrs[] = {
|
||||
__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
|
||||
store_rotate_type),
|
||||
|
@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
|
|||
store_overlays_rotate),
|
||||
__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
|
||||
__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
|
||||
__ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
|
||||
};
|
||||
|
||||
int omapfb_create_sysfs(struct omapfb2_device *fbdev)
|
||||
|
|
|
@ -73,6 +73,15 @@ struct omapfb_info {
|
|||
bool mirror;
|
||||
};
|
||||
|
||||
struct omapfb_display_data {
|
||||
struct omapfb2_device *fbdev;
|
||||
struct omap_dss_device *dssdev;
|
||||
u8 bpp_override;
|
||||
enum omapfb_update_mode update_mode;
|
||||
bool auto_update_work_enabled;
|
||||
struct delayed_work auto_update_work;
|
||||
};
|
||||
|
||||
struct omapfb2_device {
|
||||
struct device *dev;
|
||||
struct mutex mtx;
|
||||
|
@ -86,17 +95,13 @@ struct omapfb2_device {
|
|||
struct omapfb2_mem_region regions[10];
|
||||
|
||||
unsigned num_displays;
|
||||
struct omap_dss_device *displays[10];
|
||||
struct omapfb_display_data displays[10];
|
||||
unsigned num_overlays;
|
||||
struct omap_overlay *overlays[10];
|
||||
unsigned num_managers;
|
||||
struct omap_overlay_manager *managers[10];
|
||||
|
||||
unsigned num_bpp_overrides;
|
||||
struct {
|
||||
struct omap_dss_device *dssdev;
|
||||
u8 bpp;
|
||||
} bpp_overrides[10];
|
||||
struct workqueue_struct *auto_update_wq;
|
||||
};
|
||||
|
||||
struct omapfb_colormode {
|
||||
|
@ -128,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
|
|||
int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
|
||||
u16 posx, u16 posy, u16 outw, u16 outh);
|
||||
|
||||
void omapfb_start_auto_update(struct omapfb2_device *fbdev,
|
||||
struct omap_dss_device *display);
|
||||
void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
|
||||
struct omap_dss_device *display);
|
||||
int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode);
|
||||
int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode);
|
||||
|
||||
/* find the display connected to this fb, if any */
|
||||
static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
|
||||
{
|
||||
|
@ -143,6 +155,19 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct omapfb_display_data *get_display_data(
|
||||
struct omapfb2_device *fbdev, struct omap_dss_device *dssdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fbdev->num_displays; ++i)
|
||||
if (fbdev->displays[i].dssdev == dssdev)
|
||||
return &fbdev->displays[i];
|
||||
|
||||
/* This should never happen */
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline void omapfb_lock(struct omapfb2_device *fbdev)
|
||||
{
|
||||
mutex_lock(&fbdev->mtx);
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define DISPC_IRQ_FRAMEDONE (1 << 0)
|
||||
#define DISPC_IRQ_VSYNC (1 << 1)
|
||||
|
@ -136,12 +134,6 @@ enum omap_display_caps {
|
|||
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1,
|
||||
};
|
||||
|
||||
enum omap_dss_update_mode {
|
||||
OMAP_DSS_UPDATE_DISABLED = 0,
|
||||
OMAP_DSS_UPDATE_AUTO,
|
||||
OMAP_DSS_UPDATE_MANUAL,
|
||||
};
|
||||
|
||||
enum omap_dss_display_state {
|
||||
OMAP_DSS_DISPLAY_DISABLED = 0,
|
||||
OMAP_DSS_DISPLAY_ACTIVE,
|
||||
|
@ -246,7 +238,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
|
|||
|
||||
/* Board specific data */
|
||||
struct omap_dss_board_info {
|
||||
int (*get_last_off_on_transaction_id)(struct device *dev);
|
||||
int (*get_context_loss_count)(struct device *dev);
|
||||
int num_devices;
|
||||
struct omap_dss_device **devices;
|
||||
struct omap_dss_device *default_device;
|
||||
|
@ -266,8 +258,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data)
|
|||
struct omap_display_platform_data {
|
||||
struct omap_dss_board_info *board_data;
|
||||
/* TODO: Additional members to be added when PM is considered */
|
||||
|
||||
bool (*opt_clock_available)(const char *clk_role);
|
||||
};
|
||||
|
||||
struct omap_video_timings {
|
||||
|
@ -300,6 +290,12 @@ extern const struct omap_video_timings omap_dss_pal_timings;
|
|||
extern const struct omap_video_timings omap_dss_ntsc_timings;
|
||||
#endif
|
||||
|
||||
struct omap_dss_cpr_coefs {
|
||||
s16 rr, rg, rb;
|
||||
s16 gr, gg, gb;
|
||||
s16 br, bg, bb;
|
||||
};
|
||||
|
||||
struct omap_overlay_info {
|
||||
bool enabled;
|
||||
|
||||
|
@ -359,6 +355,9 @@ struct omap_overlay_manager_info {
|
|||
bool trans_enabled;
|
||||
|
||||
bool alpha_enabled;
|
||||
|
||||
bool cpr_enable;
|
||||
struct omap_dss_cpr_coefs cpr_coefs;
|
||||
};
|
||||
|
||||
struct omap_overlay_manager {
|
||||
|
@ -526,11 +525,6 @@ struct omap_dss_driver {
|
|||
int (*resume)(struct omap_dss_device *display);
|
||||
int (*run_test)(struct omap_dss_device *display, int test);
|
||||
|
||||
int (*set_update_mode)(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode);
|
||||
enum omap_dss_update_mode (*get_update_mode)(
|
||||
struct omap_dss_device *dssdev);
|
||||
|
||||
int (*update)(struct omap_dss_device *dssdev,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
int (*sync)(struct omap_dss_device *dssdev);
|
||||
|
|
Loading…
Reference in a new issue