dect
/
linux-2.6
Archived
13
0
Fork 0

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:
Linus Torvalds 2011-08-01 06:13:05 -10:00
commit 965e32b18d
23 changed files with 1689 additions and 1405 deletions

View File

@ -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);

View File

@ -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 @@ err:
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,

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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 @@ err1:
}
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,
},
};

View File

@ -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 @@ retry:
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 @@ found:
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,
},
};

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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,
},
};

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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,
},
};

View File

@ -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);

View File

@ -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,
},
};

View File

@ -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;
}

View File

@ -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 @@ err:
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)

View File

@ -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)

View File

@ -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);

View File

@ -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);