Commit 965e32b1 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents e10b87d2 df5d3ed2
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <video/omapdss.h> #include <video/omapdss.h>
#include <plat/omap_hwmod.h> #include <plat/omap_hwmod.h>
#include <plat/omap_device.h> #include <plat/omap_device.h>
#include <plat/omap-pm.h>
static struct platform_device omap_display_device = { static struct platform_device omap_display_device = {
.name = "omapdss", .name = "omapdss",
...@@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = { ...@@ -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 { struct omap_dss_hwmod_data {
const char *oh_name; const char *oh_name;
const char *dev_name; const char *dev_name;
...@@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) ...@@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
oh_count = ARRAY_SIZE(omap4_dss_hwmod_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 = board_data;
pdata.board_data->get_last_off_on_transaction_id = NULL; pdata.board_data->get_context_loss_count =
pdata.opt_clock_available = opt_clock_available; omap_pm_get_dev_context_loss_count;
for (i = 0; i < oh_count; i++) { for (i = 0; i < oh_count; i++) {
oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name); oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
......
...@@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) ...@@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
return 0; return 0;
r = omapdss_dsi_display_enable(dssdev); r = omapdss_dsi_display_enable(dssdev);
if (r) if (r) {
goto err; dev_err(&dssdev->dev, "failed to enable DSI\n");
goto err1;
}
omapdss_dsi_vc_enable_hs(dssdev, td->channel, true); omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
r = _taal_enable_te(dssdev, true); r = _taal_enable_te(dssdev, true);
if (r) if (r) {
goto err; dev_err(&dssdev->dev, "failed to re-enable TE");
goto err2;
}
enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
...@@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) ...@@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
return 0; return 0;
err: err2:
dev_err(&dssdev->dev, "exit ULPS failed"); dev_err(&dssdev->dev, "failed to exit ULPS");
r = taal_panel_reset(dssdev);
r = taal_panel_reset(dssdev);
if (!r) {
enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
td->ulps_enabled = false; td->ulps_enabled = false;
}
err1:
taal_queue_ulps_work(dssdev); taal_queue_ulps_work(dssdev);
return r; return r;
...@@ -1241,11 +1247,8 @@ static void taal_power_off(struct omap_dss_device *dssdev) ...@@ -1241,11 +1247,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
int r; int r;
r = taal_dcs_write_0(td, DCS_DISPLAY_OFF); r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
if (!r) { if (!r)
r = taal_sleep_in(td); r = taal_sleep_in(td);
/* HACK: wait a bit so that the message goes through */
msleep(10);
}
if (r) { if (r) {
dev_err(&dssdev->dev, dev_err(&dssdev->dev,
...@@ -1317,7 +1320,10 @@ static void taal_disable(struct omap_dss_device *dssdev) ...@@ -1317,7 +1320,10 @@ static void taal_disable(struct omap_dss_device *dssdev)
dsi_bus_lock(dssdev); dsi_bus_lock(dssdev);
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
taal_wake_up(dssdev); int r;
r = taal_wake_up(dssdev);
if (!r)
taal_power_off(dssdev); taal_power_off(dssdev);
} }
...@@ -1897,20 +1903,6 @@ static void taal_esd_work(struct work_struct *work) ...@@ -1897,20 +1903,6 @@ static void taal_esd_work(struct work_struct *work)
mutex_unlock(&td->lock); 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 = { static struct omap_dss_driver taal_driver = {
.probe = taal_probe, .probe = taal_probe,
.remove = __exit_p(taal_remove), .remove = __exit_p(taal_remove),
...@@ -1920,9 +1912,6 @@ static struct omap_dss_driver taal_driver = { ...@@ -1920,9 +1912,6 @@ static struct omap_dss_driver taal_driver = {
.suspend = taal_suspend, .suspend = taal_suspend,
.resume = taal_resume, .resume = taal_resume,
.set_update_mode = taal_set_update_mode,
.get_update_mode = taal_get_update_mode,
.update = taal_update, .update = taal_update,
.sync = taal_sync, .sync = taal_sync,
......
...@@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK ...@@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
Max FCK is 173MHz, so this doesn't work if your PCK Max FCK is 173MHz, so this doesn't work if your PCK
is very high. 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 config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
bool "Sleep 20ms after VENC reset" bool "Sleep 20ms after VENC reset"
default y default y
......
...@@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev) ...@@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev)
goto err_dss; goto err_dss;
} }
/* keep clocks enabled to prevent context saves/restores during init */ r = dispc_init_platform_driver();
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (r) {
DSSERR("Failed to initialize dispc platform driver\n");
goto err_dispc;
}
r = rfbi_init_platform_driver(); r = rfbi_init_platform_driver();
if (r) { if (r) {
...@@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev) ...@@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev)
goto err_rfbi; 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(); r = venc_init_platform_driver();
if (r) { if (r) {
DSSERR("Failed to initialize venc platform driver\n"); DSSERR("Failed to initialize venc platform driver\n");
...@@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev) ...@@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev)
pdata->default_device = dssdev; pdata->default_device = dssdev;
} }
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return 0; return 0;
err_register: err_register:
...@@ -268,11 +263,11 @@ static int omap_dss_remove(struct platform_device *pdev) ...@@ -268,11 +263,11 @@ static int omap_dss_remove(struct platform_device *pdev)
dss_uninitialize_debugfs(); dss_uninitialize_debugfs();
hdmi_uninit_platform_driver();
dsi_uninit_platform_driver();
venc_uninit_platform_driver(); venc_uninit_platform_driver();
dispc_uninit_platform_driver();
rfbi_uninit_platform_driver(); rfbi_uninit_platform_driver();
dsi_uninit_platform_driver(); dispc_uninit_platform_driver();
hdmi_uninit_platform_driver();
dss_uninit_platform_driver(); dss_uninit_platform_driver();
dss_uninit_overlays(pdev); dss_uninit_overlays(pdev);
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <plat/sram.h> #include <plat/sram.h>
#include <plat/clock.h> #include <plat/clock.h>
...@@ -77,6 +79,12 @@ struct dispc_v_coef { ...@@ -77,6 +79,12 @@ struct dispc_v_coef {
s8 vc00; s8 vc00;
}; };
enum omap_burst_size {
BURST_SIZE_X2 = 0,
BURST_SIZE_X4 = 1,
BURST_SIZE_X8 = 2,
};
#define REG_GET(idx, start, end) \ #define REG_GET(idx, start, end) \
FLD_GET(dispc_read_reg(idx), start, end) FLD_GET(dispc_read_reg(idx), start, end)
...@@ -92,7 +100,11 @@ struct dispc_irq_stats { ...@@ -92,7 +100,11 @@ struct dispc_irq_stats {
static struct { static struct {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *base; void __iomem *base;
int ctx_loss_cnt;
int irq; int irq;
struct clk *dss_clk;
u32 fifo_size[3]; u32 fifo_size[3];
...@@ -102,6 +114,7 @@ static struct { ...@@ -102,6 +114,7 @@ static struct {
u32 error_irqs; u32 error_irqs;
struct work_struct error_work; struct work_struct error_work;
bool ctx_valid;
u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
...@@ -134,18 +147,34 @@ static inline u32 dispc_read_reg(const u16 idx) ...@@ -134,18 +147,34 @@ static inline u32 dispc_read_reg(const u16 idx)
return __raw_readl(dispc.base + idx); return __raw_readl(dispc.base + idx);
} }
static int dispc_get_ctx_loss_count(void)
{
struct device *dev = &dispc.pdev->dev;
struct omap_display_platform_data *pdata = dev->platform_data;
struct omap_dss_board_info *board_data = pdata->board_data;
int cnt;
if (!board_data->get_context_loss_count)
return -ENOENT;
cnt = board_data->get_context_loss_count(dev);
WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
return cnt;
}
#define SR(reg) \ #define SR(reg) \
dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
#define RR(reg) \ #define RR(reg) \
dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)]) dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
void dispc_save_context(void) static void dispc_save_context(void)
{ {
int i; int i;
if (cpu_is_omap24xx())
return;
SR(SYSCONFIG); DSSDBG("dispc_save_context\n");
SR(IRQENABLE); SR(IRQENABLE);
SR(CONTROL); SR(CONTROL);
SR(CONFIG); SR(CONFIG);
...@@ -158,6 +187,7 @@ void dispc_save_context(void) ...@@ -158,6 +187,7 @@ void dispc_save_context(void)
SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_GLOBAL_ALPHA))
SR(GLOBAL_ALPHA); SR(GLOBAL_ALPHA);
SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
...@@ -188,19 +218,24 @@ void dispc_save_context(void) ...@@ -188,19 +218,24 @@ void dispc_save_context(void)
SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_CPR)) {
SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
}
if (dss_has_feature(FEAT_MGR_LCD2)) { if (dss_has_feature(FEAT_MGR_LCD2)) {
if (dss_has_feature(FEAT_CPR)) {
SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
}
SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
} }
if (dss_has_feature(FEAT_PRELOAD))
SR(OVL_PRELOAD(OMAP_DSS_GFX)); SR(OVL_PRELOAD(OMAP_DSS_GFX));
/* VID1 */ /* VID1 */
...@@ -226,8 +261,10 @@ void dispc_save_context(void) ...@@ -226,8 +261,10 @@ void dispc_save_context(void)
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
...@@ -248,6 +285,7 @@ void dispc_save_context(void) ...@@ -248,6 +285,7 @@ void dispc_save_context(void)
if (dss_has_feature(FEAT_ATTR2)) if (dss_has_feature(FEAT_ATTR2))
SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
if (dss_has_feature(FEAT_PRELOAD))
SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
/* VID2 */ /* VID2 */
...@@ -273,8 +311,10 @@ void dispc_save_context(void) ...@@ -273,8 +311,10 @@ void dispc_save_context(void)
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
...@@ -295,16 +335,35 @@ void dispc_save_context(void) ...@@ -295,16 +335,35 @@ void dispc_save_context(void)
if (dss_has_feature(FEAT_ATTR2)) if (dss_has_feature(FEAT_ATTR2))
SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
if (dss_has_feature(FEAT_PRELOAD))
SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
if (dss_has_feature(FEAT_CORE_CLK_DIV)) if (dss_has_feature(FEAT_CORE_CLK_DIV))
SR(DIVISOR); SR(DIVISOR);
dispc.ctx_loss_cnt = dispc_get_ctx_loss_count();
dispc.ctx_valid = true;
DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
} }
void dispc_restore_context(void) static void dispc_restore_context(void)
{ {
int i; int i, ctx;
RR(SYSCONFIG);
DSSDBG("dispc_restore_context\n");
if (!dispc.ctx_valid)
return;
ctx = dispc_get_ctx_loss_count();
if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
return;
DSSDBG("ctx_loss_count: saved %d, current %d\n",
dispc.ctx_loss_cnt, ctx);
/*RR(IRQENABLE);*/ /*RR(IRQENABLE);*/
/*RR(CONTROL);*/ /*RR(CONTROL);*/
RR(CONFIG); RR(CONFIG);
...@@ -317,6 +376,7 @@ void dispc_restore_context(void) ...@@ -317,6 +376,7 @@ void dispc_restore_context(void)
RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_GLOBAL_ALPHA))
RR(GLOBAL_ALPHA); RR(GLOBAL_ALPHA);
RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
...@@ -347,19 +407,24 @@ void dispc_restore_context(void) ...@@ -347,19 +407,24 @@ void dispc_restore_context(void)
RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_CPR)) {
RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
}
if (dss_has_feature(FEAT_MGR_LCD2)) { if (dss_has_feature(FEAT_MGR_LCD2)) {
RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
if (dss_has_feature(FEAT_CPR)) {
RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
} }
}
if (dss_has_feature(FEAT_PRELOAD))
RR(OVL_PRELOAD(OMAP_DSS_GFX)); RR(OVL_PRELOAD(OMAP_DSS_GFX));
/* VID1 */ /* VID1 */
...@@ -385,8 +450,10 @@ void dispc_restore_context(void) ...@@ -385,8 +450,10 @@ void dispc_restore_context(void)
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
...@@ -407,6 +474,7 @@ void dispc_restore_context(void) ...@@ -407,6 +474,7 @@ void dispc_restore_context(void)
if (dss_has_feature(FEAT_ATTR2)) if (dss_has_feature(FEAT_ATTR2))
RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
if (dss_has_feature(FEAT_PRELOAD))
RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
/* VID2 */ /* VID2 */
...@@ -432,8 +500,10 @@ void dispc_restore_context(void) ...@@ -432,8 +500,10 @@ void dispc_restore_context(void)
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
...@@ -454,6 +524,7 @@ void dispc_restore_context(void) ...@@ -454,6 +524,7 @@ void dispc_restore_context(void)
if (dss_has_feature(FEAT_ATTR2)) if (dss_has_feature(FEAT_ATTR2))
RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
if (dss_has_feature(FEAT_PRELOAD))
RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
if (dss_has_feature(FEAT_CORE_CLK_DIV)) if (dss_has_feature(FEAT_CORE_CLK_DIV))
...@@ -471,19 +542,35 @@ void dispc_restore_context(void) ...@@ -471,19 +542,35 @@ void dispc_restore_context(void)
* the context is fully restored * the context is fully restored
*/ */
RR(IRQENABLE); RR(IRQENABLE);
DSSDBG("context restored\n");
} }
#undef SR #undef SR
#undef RR #undef RR
static inline void enable_clocks(bool enable) int dispc_runtime_get(void)
{ {
if (enable) int r;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else DSSDBG("dispc_runtime_get\n");
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
r = pm_runtime_get_sync(&dispc.pdev->dev);
WARN_ON(r < 0);
return r < 0 ? r : 0;
}
void dispc_runtime_put(void)
{
int r;
DSSDBG("dispc_runtime_put\n");
r = pm_runtime_put(&dispc.pdev->dev);
WARN_ON(r < 0);
} }
bool dispc_go_busy(enum omap_channel channel) bool dispc_go_busy(enum omap_channel channel)
{ {
int bit; int bit;
...@@ -505,8 +592,6 @@ void dispc_go(enum omap_channel channel) ...@@ -505,8 +592,6 @@ void dispc_go(enum omap_channel channel)
int bit; int bit;
bool enable_bit, go_bit; bool enable_bit, go_bit;
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD || if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2) channel == OMAP_DSS_CHANNEL_LCD2)
bit = 0; /* LCDENABLE */ bit = 0; /* LCDENABLE */
...@@ -520,7 +605,7 @@ void dispc_go(enum omap_channel channel) ...@@ -520,7 +605,7 @@ void dispc_go(enum omap_channel channel)
enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
if (!enable_bit) if (!enable_bit)
goto end; return;
if (channel == OMAP_DSS_CHANNEL_LCD || if (channel == OMAP_DSS_CHANNEL_LCD ||
channel == OMAP_DSS_CHANNEL_LCD2) channel == OMAP_DSS_CHANNEL_LCD2)
...@@ -535,7 +620,7 @@ void dispc_go(enum omap_channel channel) ...@@ -535,7 +620,7 @@ void dispc_go(enum omap_channel channel)
if (go_bit) { if (go_bit) {
DSSERR("GO bit not down for channel %d\n", channel); DSSERR("GO bit not down for channel %d\n", channel);
goto end; return;
} }
DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
...@@ -545,8 +630,6 @@ void dispc_go(enum omap_channel channel) ...@@ -545,8 +630,6 @@ void dispc_go(enum omap_channel channel)
REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
else else
REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
end:
enable_clocks(0);
} }
static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
...@@ -920,7 +1003,7 @@ static void _dispc_set_color_mode(enum omap_plane plane, ...@@ -920,7 +1003,7 @@ static void _dispc_set_color_mode(enum omap_plane plane,
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
} }
static void _dispc_set_channel_out(enum omap_plane plane, void dispc_set_channel_out(enum omap_plane plane,
enum omap_channel channel) enum omap_channel channel)
{ {
int shift; int shift;
...@@ -967,13 +1050,10 @@ static void _dispc_set_channel_out(enum omap_plane plane, ...@@ -967,13 +1050,10 @@ static void _dispc_set_channel_out(enum omap_plane plane,
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
} }
void dispc_set_burst_size(enum omap_plane plane, static void dispc_set_burst_size(enum omap_plane plane,
enum omap_burst_size burst_size) enum omap_burst_size burst_size)
{ {
int shift; int shift;
u32 val;
enable_clocks(1);
switch (plane) { switch (plane) {
case OMAP_DSS_GFX: case OMAP_DSS_GFX:
...@@ -988,11 +1068,24 @@ void dispc_set_burst_size(enum omap_plane plane, ...@@ -988,11 +1068,24 @@ void dispc_set_burst_size(enum omap_plane plane,
return; return;
} }
val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
val = FLD_MOD(val, burst_size, shift+1, shift); }
dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
static void dispc_configure_burst_sizes(void)
{
int i;
const int burst_size = BURST_SIZE_X8;
enable_clocks(0); /* Configure burst size always to maximum size */
for (i = 0; i < omap_dss_get_num_overlays(); ++i)
dispc_set_burst_size(i, burst_size);
}
u32 dispc_get_burst_size(enum omap_plane plane)
{
unsigned unit = dss_feat_get_burst_size_unit();
/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
return unit * 8;
} }
void dispc_enable_gamma_table(bool enable) void dispc_enable_gamma_table(bool enable)
...@@ -1009,6 +1102,40 @@ void dispc_enable_gamma_table(bool enable) ...@@ -1009,6 +1102,40 @@ void dispc_enable_gamma_table(bool enable)
REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
} }
void dispc_enable_cpr(enum omap_channel channel, bool enable)
{
u16 reg;
if (channel == OMAP_DSS_CHANNEL_LCD)
reg = DISPC_CONFIG;
else if (channel == OMAP_DSS_CHANNEL_LCD2)
reg = DISPC_CONFIG2;
else
return;
REG_FLD_MOD(reg, enable, 15, 15);
}
void dispc_set_cpr_coef(enum omap_channel channel,
struct omap_dss_cpr_coefs *coefs)
{
u32 coef_r, coef_g, coef_b;
if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2)
return;
coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
FLD_VAL(coefs->rb, 9, 0);
coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
FLD_VAL(coefs->gb, 9, 0);
coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
FLD_VAL(coefs->bb, 9, 0);
dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
}
static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
{ {
u32 val; u32 val;
...@@ -1029,9 +1156,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) ...@@ -1029,9 +1156,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
else else
bit = 10; bit = 10;
enable_clocks(1);
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
enable_clocks(0);
} }
void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
...@@ -1039,9 +1164,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) ...@@ -1039,9 +1164,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
u32 val; u32 val;
BUG_ON((width > (1 << 11)) || (height > (1 << 11))); BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
enable_clocks(1);
dispc_write_reg(DISPC_SIZE_MGR(channel), val); dispc_write_reg(DISPC_SIZE_MGR(channel), val);
enable_clocks(0);
} }
void dispc_set_digit_size(u16 width, u16 height) void dispc_set_digit_size(u16 width, u16 height)
...@@ -1049,9 +1172,7 @@ void dispc_set_digit_size(u16 width, u16 height) ...@@ -1049,9 +1172,7 @@ void dispc_set_digit_size(u16 width, u16 height)
u32 val; u32 val;
BUG_ON((width > (1 << 11)) || (height > (1 << 11))); BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
enable_clocks(1);
dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
enable_clocks(0);
} }
static void dispc_read_plane_fifo_sizes(void) static void dispc_read_plane_fifo_sizes(void)
...@@ -1059,18 +1180,17 @@ static void dispc_read_plane_fifo_sizes(void) ...@@ -1059,18 +1180,17 @@ static void dispc_read_plane_fifo_sizes(void)
u32 size; u32 size;
int plane; int plane;
u8 start, end; u8 start, end;
u32 unit;
enable_clocks(1); unit = dss_feat_get_buffer_size_unit();
dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)), size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
start, end); size *= unit;
dispc.fifo_size[plane] = size; dispc.fifo_size[plane] = size;
} }
enable_clocks(0);
} }
u32 dispc_get_plane_fifo_size(enum omap_plane plane) u32 dispc_get_plane_fifo_size(enum omap_plane plane)
...@@ -1078,15 +1198,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane) ...@@ -1078,15 +1198,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
return dispc.fifo_size[plane]; return dispc.fifo_size[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)
{ {
u8 hi_start, hi_end, lo_start, lo_end; u8 hi_start, hi_end, lo_start, lo_end;
u32 unit;
unit = dss_feat_get_buffer_size_unit();
WARN_ON(low % unit != 0);
WARN_ON(high % unit != 0);
low /= unit;
high /= unit;
dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
enable_clocks(1);
DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
plane, plane,
REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
...@@ -1098,18 +1225,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) ...@@ -1098,18 +1225,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
FLD_VAL(high, hi_start, hi_end) | FLD_VAL(high, hi_start, hi_end) |
FLD_VAL(low, lo_start, lo_end)); FLD_VAL(low, lo_start, lo_end));
enable_clocks(0);
} }
void dispc_enable_fifomerge(bool enable) void dispc_enable_fifomerge(bool enable)
{ {
enable_clocks(1);
DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
enable_clocks(0);
} }
static void _dispc_set_fir(enum omap_plane plane, static void _dispc_set_fir(enum omap_plane plane,
...@@ -1729,14 +1850,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, ...@@ -1729,14 +1850,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
return dispc_pclk_rate(channel) * vf * hf; return dispc_pclk_rate(channel) * vf * hf;
} }
void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) int dispc_setup_plane(enum omap_plane plane,
{
enable_clocks(1);
_dispc_set_channel_out(plane, channel_out);
enable_clocks(0);
}
static int _dispc_setup_plane(enum omap_plane plane,
u32 paddr, u16 screen_width, u32 paddr, u16 screen_width,
u16 pos_x, u16 pos_y, u16 pos_x, u16 pos_y,
u16 width, u16 height, u16 width, u16 height,
...@@ -1744,7 +1858,7 @@ static int _dispc_setup_plane(enum omap_plane plane, ...@@ -1744,7 +1858,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
enum omap_color_mode color_mode, enum omap_color_mode color_mode,
bool ilace, bool ilace,
enum omap_dss_rotation_type rotation_type, enum omap_dss_rotation_type rotation_type,
u8 rotation, int mirror, u8 rotation, bool mirror,
u8 global_alpha, u8 pre_mult_alpha, u8 global_alpha, u8 pre_mult_alpha,
enum omap_channel channel, u32 puv_addr) enum omap_channel channel, u32 puv_addr)
{ {
...@@ -1758,6 +1872,14 @@ static int _dispc_setup_plane(enum omap_plane plane, ...@@ -1758,6 +1872,14 @@ static int _dispc_setup_plane(enum omap_plane plane,
u16 frame_height = height; u16 frame_height = height;
unsigned int field_offset = 0; unsigned int field_offset = 0;
DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
"%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
plane, paddr, screen_width, pos_x, pos_y,
width, height,
out_width, out_height,
ilace, color_mode,
rotation, mirror, channel);
if (paddr == 0) if (paddr == 0)
return -EINVAL; return -EINVAL;
...@@ -1903,9 +2025,13 @@ static int _dispc_setup_plane(enum omap_plane plane, ...@@ -1903,9 +2025,13 @@ static int _dispc_setup_plane(enum omap_plane plane,
return 0; return 0;
} }
static void _dispc_enable_plane(enum omap_plane plane, bool enable) int dispc_enable_plane(enum omap_plane plane, bool enable)
{ {
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
return 0;
} }
static void dispc_disable_isr(void *data, u32 mask) static void dispc_disable_isr(void *data, u32 mask)
...@@ -1929,8 +2055,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) ...@@ -1929,8 +2055,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
int r; int r;
u32 irq; u32 irq;
enable_clocks(1);
/* When we disable LCD output, we need to wait until frame is done. /* When we disable LCD output, we need to wait until frame is done.
* Otherwise the DSS is still working, and turning off the clocks * Otherwise the DSS is still working, and turning off the clocks
* prevents DSS from going to OFF mode */ * prevents DSS from going to OFF mode */
...@@ -1964,8 +2088,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) ...@@ -1964,8 +2088,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
if (r) if (r)
DSSERR("failed to unregister FRAMEDONE isr\n"); DSSERR("failed to unregister FRAMEDONE isr\n");
} }
enable_clocks(0);
} }
static void _enable_digit_out(bool enable) static void _enable_digit_out(bool enable)
...@@ -1978,12 +2100,8 @@ static void dispc_enable_digit_out(bool enable) ...@@ -1978,12 +2100,8 @@ static void dispc_enable_digit_out(bool enable)
struct completion frame_done_completion; struct completion frame_done_completion;
int r; int r;
enable_clocks(1); if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
enable_clocks(0);
return; return;
}
if (enable) { if (enable) {
unsigned long flags; unsigned long flags;
...@@ -2035,8 +2153,6 @@ static void dispc_enable_digit_out(bool enable) ...@@ -2035,8 +2153,6 @@ static void dispc_enable_digit_out(bool enable)
_omap_dispc_set_irqs(); _omap_dispc_set_irqs();
spin_unlock_irqrestore(&dispc.irq_lock, flags); spin_unlock_irqrestore(&dispc.irq_lock, flags);
} }
enable_clocks(0);
} }
bool dispc_is_channel_enabled(enum omap_channel channel) bool dispc_is_channel_enabled(enum omap_channel channel)
...@@ -2067,9 +2183,7 @@ void dispc_lcd_enable_signal_polarity(bool act_high) ...@@ -2067,9 +2183,7 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
if (!dss_has_feature(FEAT_LCDENABLEPOL)) if (!dss_has_feature(FEAT_LCDENABLEPOL))
return; return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
enable_clocks(0);
} }
void dispc_lcd_enable_signal(bool enable) void dispc_lcd_enable_signal(bool enable)
...@@ -2077,9 +2191,7 @@ void dispc_lcd_enable_signal(bool enable) ...@@ -2077,9 +2191,7 @@ void dispc_lcd_enable_signal(bool enable)
if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
return; return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
enable_clocks(0);
} }
void dispc_pck_free_enable(bool enable) void dispc_pck_free_enable(bool enable)
...@@ -2087,19 +2199,15 @@ void dispc_pck_free_enable(bool enable) ...@@ -2087,19 +2199,15 @@ void dispc_pck_free_enable(bool enable)
if (!dss_has_feature(FEAT_PCKFREEENABLE)) if (!dss_has_feature(FEAT_PCKFREEENABLE))
return; return;
enable_clocks(1);
REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
enable_clocks(0);
} }
void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
{ {
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD2) if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
else else
REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
enable_clocks(0);
} }
...@@ -2122,27 +2230,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel, ...@@ -2122,27 +2230,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel,
return; return;
} }
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD2) if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
else else
REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
enable_clocks(0);
} }
void dispc_set_loadmode(enum omap_dss_load_mode mode) void dispc_set_loadmode(enum omap_dss_load_mode mode)
{ {
enable_clocks(1);
REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
enable_clocks(0);
} }
void dispc_set_default_color(enum omap_channel channel, u32 color) void dispc_set_default_color(enum omap_channel channel, u32 color)
{ {
enable_clocks(1);
dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
enable_clocks(0);
} }
u32 dispc_get_default_color(enum omap_channel channel) u32 dispc_get_default_color(enum omap_channel channel)
...@@ -2153,9 +2255,7 @@ u32 dispc_get_default_color(enum omap_channel channel) ...@@ -2153,9 +2255,7 @@ u32 dispc_get_default_color(enum omap_channel channel)
channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD &&
channel != OMAP_DSS_CHANNEL_LCD2); channel != OMAP_DSS_CHANNEL_LCD2);
enable_clocks(1);
l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
enable_clocks(0);
return l; return l;
} }
...@@ -2164,7 +2264,6 @@ void dispc_set_trans_key(enum omap_channel ch, ...@@ -2164,7 +2264,6 @@ void dispc_set_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type type, enum omap_dss_trans_key_type type,
u32 trans_key) u32 trans_key)
{ {
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
else if (ch == OMAP_DSS_CHANNEL_DIGIT) else if (ch == OMAP_DSS_CHANNEL_DIGIT)
...@@ -2173,14 +2272,12 @@ void dispc_set_trans_key(enum omap_channel ch, ...@@ -2173,14 +2272,12 @@ void dispc_set_trans_key(enum omap_channel ch,
REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
enable_clocks(0);
} }
void dispc_get_trans_key(enum omap_channel ch, void dispc_get_trans_key(enum omap_channel ch,
enum omap_dss_trans_key_type *type, enum omap_dss_trans_key_type *type,
u32 *trans_key) u32 *trans_key)
{ {
enable_clocks(1);
if (type) { if (type) {
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
*type = REG_GET(DISPC_CONFIG, 11, 11); *type = REG_GET(DISPC_CONFIG, 11, 11);
...@@ -2194,33 +2291,28 @@ void dispc_get_trans_key(enum omap_channel ch, ...@@ -2194,33 +2291,28 @@ void dispc_get_trans_key(enum omap_channel ch,
if (trans_key) if (trans_key)
*trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
enable_clocks(0);
} }
void dispc_enable_trans_key(enum omap_channel ch, bool enable) void dispc_enable_trans_key(enum omap_channel ch, bool enable)
{ {
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
else if (ch == OMAP_DSS_CHANNEL_DIGIT) else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
else /* OMAP_DSS_CHANNEL_LCD2 */ else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
enable_clocks(0);
} }
void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
{ {
if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return; return;
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
else if (ch == OMAP_DSS_CHANNEL_DIGIT) else if (ch == OMAP_DSS_CHANNEL_DIGIT)
REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
else /* OMAP_DSS_CHANNEL_LCD2 */ else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
enable_clocks(0);
} }
bool dispc_alpha_blending_enabled(enum omap_channel ch) bool dispc_alpha_blending_enabled(enum omap_channel ch)
{ {
...@@ -2229,7 +2321,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) ...@@ -2229,7 +2321,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return false; return false;
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
enabled = REG_GET(DISPC_CONFIG, 18, 18); enabled = REG_GET(DISPC_CONFIG, 18, 18);
else if (ch == OMAP_DSS_CHANNEL_DIGIT) else if (ch == OMAP_DSS_CHANNEL_DIGIT)
...@@ -2238,7 +2329,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) ...@@ -2238,7 +2329,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
enabled = REG_GET(DISPC_CONFIG2, 18, 18); enabled = REG_GET(DISPC_CONFIG2, 18, 18);
else else
BUG(); BUG();
enable_clocks(0);
return enabled; return enabled;
} }
...@@ -2248,7 +2338,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) ...@@ -2248,7 +2338,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
{ {
bool enabled; bool enabled;
enable_clocks(1);
if (ch == OMAP_DSS_CHANNEL_LCD) if (ch == OMAP_DSS_CHANNEL_LCD)
enabled = REG_GET(DISPC_CONFIG, 10, 10); enabled = REG_GET(DISPC_CONFIG, 10, 10);
else if (ch == OMAP_DSS_CHANNEL_DIGIT) else if (ch == OMAP_DSS_CHANNEL_DIGIT)
...@@ -2257,7 +2346,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch) ...@@ -2257,7 +2346,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
enabled = REG_GET(DISPC_CONFIG2, 10, 10); enabled = REG_GET(DISPC_CONFIG2, 10, 10);
else else
BUG(); BUG();
enable_clocks(0);
return enabled; return enabled;
} }
...@@ -2285,12 +2373,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) ...@@ -2285,12 +2373,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
return; return;
} }
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD2) if (channel == OMAP_DSS_CHANNEL_LCD2)
REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
else else
REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
enable_clocks(0);
} }
void dispc_set_parallel_interface_mode(enum omap_channel channel, void dispc_set_parallel_interface_mode(enum omap_channel channel,
...@@ -2322,8 +2408,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, ...@@ -2322,8 +2408,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
return; return;
} }
enable_clocks(1);
if (channel == OMAP_DSS_CHANNEL_LCD2) { if (channel == OMAP_DSS_CHANNEL_LCD2) {
l = dispc_read_reg(DISPC_CONTROL2); l = dispc_read_reg(DISPC_CONTROL2);
l = FLD_MOD(l, stallmode, 11, 11); l = FLD_MOD(l, stallmode, 11, 11);
...@@ -2335,8 +2419,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel, ...@@ -2335,8 +2419,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
l = FLD_MOD(l, gpout1, 16, 16); l = FLD_MOD(l, gpout1, 16, 16);
dispc_write_reg(DISPC_CONTROL, l); dispc_write_reg(DISPC_CONTROL, l);
} }
enable_clocks(0);
} }
static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
...@@ -2389,10 +2471,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, ...@@ -2389,10 +2471,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
FLD_VAL(vbp, 31, 20); FLD_VAL(vbp, 31, 20);
} }
enable_clocks(1);
dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
dispc_write_reg(DISPC_TIMING_V(channel), timing_v); dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
enable_clocks(0);
} }
/* change name to mode? */ /* change name to mode? */
...@@ -2435,10 +2515,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, ...@@ -2435,10 +2515,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
BUG_ON(lck_div < 1); BUG_ON(lck_div < 1);
BUG_ON(pck_div < 2); BUG_ON(pck_div < 2);
enable_clocks(1);
dispc_write_reg(DISPC_DIVISORo(channel), dispc_write_reg(DISPC_DIVISORo(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
enable_clocks(0);
} }
static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
...@@ -2457,7 +2535,7 @@ unsigned long dispc_fclk_rate(void) ...@@ -2457,7 +2535,7 @@ unsigned long dispc_fclk_rate(void)
switch (dss_get_dispc_clk_source()) { switch (dss_get_dispc_clk_source()) {
case OMAP_DSS_CLK_SRC_FCK: case OMAP_DSS_CLK_SRC_FCK:
r = dss_clk_get_rate(DSS_CLK_FCK); r = clk_get_rate(dispc.dss_clk);
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0); dsidev = dsi_get_dsidev_from_id(0);
...@@ -2487,7 +2565,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) ...@@ -2487,7 +2565,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
switch (dss_get_lcd_clk_source(channel)) { switch (dss_get_lcd_clk_source(channel)) {
case OMAP_DSS_CLK_SRC_FCK: case OMAP_DSS_CLK_SRC_FCK:
r = dss_clk_get_rate(DSS_CLK_FCK); r = clk_get_rate(dispc.dss_clk);
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0); dsidev = dsi_get_dsidev_from_id(0);
...@@ -2526,7 +2604,8 @@ void dispc_dump_clocks(struct seq_file *s) ...@@ -2526,7 +2604,8 @@ void dispc_dump_clocks(struct seq_file *s)
enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
enum omap_dss_clk_source lcd_clk_src; enum omap_dss_clk_source lcd_clk_src;
enable_clocks(1); if (dispc_runtime_get())
return;
seq_printf(s, "- DISPC -\n"); seq_printf(s, "- DISPC -\n");
...@@ -2574,7 +2653,8 @@ void dispc_dump_clocks(struct seq_file *s) ...@@ -2574,7 +2653,8 @@ void dispc_dump_clocks(struct seq_file *s)
seq_printf(s, "pck\t\t%-16lupck div\t%u\n", seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
} }
enable_clocks(0);
dispc_runtime_put();
} }
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
...@@ -2629,7 +2709,8 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2629,7 +2709,8 @@ void dispc_dump_regs(struct seq_file *s)
{ {
#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (dispc_runtime_get())
return;
DUMPREG(DISPC_REVISION); DUMPREG(DISPC_REVISION);
DUMPREG(DISPC_SYSCONFIG); DUMPREG(DISPC_SYSCONFIG);
...@@ -2649,6 +2730,7 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2649,6 +2730,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_GLOBAL_ALPHA))
DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_GLOBAL_ALPHA);
DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
...@@ -2680,19 +2762,24 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2680,19 +2762,24 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
if (dss_has_feature(FEAT_CPR)) {
DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
}
if (dss_has_feature(FEAT_MGR_LCD2)) { if (dss_has_feature(FEAT_MGR_LCD2)) {
DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
if (dss_has_feature(FEAT_CPR)) {
DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
} }
}
if (dss_has_feature(FEAT_PRELOAD))
DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
...@@ -2744,6 +2831,7 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2744,6 +2831,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
...@@ -2752,6 +2840,7 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2752,6 +2840,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
...@@ -2812,6 +2901,8 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2812,6 +2901,8 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
if (dss_has_feature(FEAT_FIR_COEF_V)) {
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
...@@ -2820,6 +2911,7 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2820,6 +2911,7 @@ void dispc_dump_regs(struct seq_file *s)
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
}
if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
...@@ -2858,10 +2950,12 @@ void dispc_dump_regs(struct seq_file *s) ...@@ -2858,10 +2950,12 @@ void dispc_dump_regs(struct seq_file *s)
if (dss_has_feature(FEAT_ATTR2)) if (dss_has_feature(FEAT_ATTR2))
DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
if (dss_has_feature(FEAT_PRELOAD)) {
DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
}
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dispc_runtime_put();
#undef DUMPREG #undef DUMPREG
} }
...@@ -2882,9 +2976,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, ...@@ -2882,9 +2976,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
l |= FLD_VAL(acbi, 11, 8); l |= FLD_VAL(acbi, 11, 8);
l |= FLD_VAL(acb, 7, 0); l |= FLD_VAL(acb, 7, 0);
enable_clocks(1);
dispc_write_reg(DISPC_POL_FREQ(channel), l); dispc_write_reg(DISPC_POL_FREQ(channel), l);
enable_clocks(0);
} }
void dispc_set_pol_freq(enum omap_channel channel, void dispc_set_pol_freq(enum omap_channel channel,
...@@ -3005,15 +3097,11 @@ static void _omap_dispc_set_irqs(void) ...@@ -3005,15 +3097,11 @@ static void _omap_dispc_set_irqs(void)
mask |= isr_data->mask; mask |= isr_data->mask;
} }
enable_clocks(1);
old_mask = dispc_read_reg(DISPC_IRQENABLE); old_mask = dispc_read_reg(DISPC_IRQENABLE);
/* clear the irqstatus for newly enabled irqs */ /* clear the irqstatus for newly enabled irqs */
dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
dispc_write_reg(DISPC_IRQENABLE, mask); dispc_write_reg(DISPC_IRQENABLE, mask);
enable_clocks(0);
} }
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
...@@ -3522,13 +3610,6 @@ static void _omap_dispc_initial_config(void) ...@@ -3522,13 +3610,6 @@ static void _omap_dispc_initial_config(void)
{ {
u32 l; u32 l;
l = dispc_read_reg(DISPC_SYSCONFIG);
l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
dispc_write_reg(DISPC_SYSCONFIG, l);
/* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
if (dss_has_feature(FEAT_CORE_CLK_DIV)) { if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
l = dispc_read_reg(DISPC_DIVISOR); l = dispc_read_reg(DISPC_DIVISOR);
...@@ -3552,58 +3633,8 @@ static void _omap_dispc_initial_config(void) ...@@ -3552,58 +3633,8 @@ static void _omap_dispc_initial_config(void)
dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
dispc_read_plane_fifo_sizes(); dispc_read_plane_fifo_sizes();
}
int dispc_enable_plane(enum omap_plane plane, bool enable)
{
DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
enable_clocks(1);
_dispc_enable_plane(plane, enable);
enable_clocks(0);
return 0;
}
int dispc_setup_plane(enum omap_plane plane,
u32 paddr, u16 screen_width,
u16 pos_x, u16 pos_y,
u16 width, u16 height,
u16 out_width, u16 out_height,
enum omap_color_mode color_mode,
bool ilace,
enum omap_dss_rotation_type rotation_type,
u8 rotation, bool mirror, u8 global_alpha,
u8 pre_mult_alpha, enum omap_channel channel,
u32 puv_addr)
{
int r = 0;
DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
"%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
plane, paddr, screen_width, pos_x, pos_y,
width, height,
out_width, out_height,
ilace, color_mode,
rotation, mirror, channel);
enable_clocks(1);
r = _dispc_setup_plane(plane, dispc_configure_burst_sizes();
paddr, screen_width,
pos_x, pos_y,
width, height,
out_width, out_height,
color_mode, ilace,
rotation_type,
rotation, mirror,
global_alpha,
pre_mult_alpha,
channel, puv_addr);
enable_clocks(0);
return r;
} }
/* DISPC HW IP initialisation */ /* DISPC HW IP initialisation */
...@@ -3612,9 +3643,19 @@ static int omap_dispchw_probe(struct platform_device *pdev) ...@@ -3612,9 +3643,19 @@ static int omap_dispchw_probe(struct platform_device *pdev)
u32 rev; u32 rev;
int r = 0; int r = 0;
struct resource *dispc_mem; struct resource *dispc_mem;
struct clk *clk;
dispc.pdev = pdev; dispc.pdev = pdev;
clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(clk)) {
DSSERR("can't get fck\n");
r = PTR_ERR(clk);
goto err_get_clk;
}
dispc.dss_clk = clk;
spin_lock_init(&dispc.irq_lock); spin_lock_init(&dispc.irq_lock);
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
...@@ -3628,62 +3669,103 @@ static int omap_dispchw_probe(struct platform_device *pdev) ...@@ -3628,62 +3669,103 @@ static int omap_dispchw_probe(struct platform_device *pdev)
if (!dispc_mem) { if (!dispc_mem) {
DSSERR("can't get IORESOURCE_MEM DISPC\n"); DSSERR("can't get IORESOURCE_MEM DISPC\n");
r = -EINVAL; r = -EINVAL;
goto fail0; goto err_ioremap;
} }
dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
if (!dispc.base) { if (!dispc.base) {
DSSERR("can't ioremap DISPC\n"); DSSERR("can't ioremap DISPC\n");
r = -ENOMEM; r = -ENOMEM;
goto fail0; goto err_ioremap;
} }
dispc.irq = platform_get_irq(dispc.pdev, 0); dispc.irq = platform_get_irq(dispc.pdev, 0);
if (dispc.irq < 0) { if (dispc.irq < 0) {
DSSERR("platform_get_irq failed\n"); DSSERR("platform_get_irq failed\n");
r = -ENODEV; r = -ENODEV;
goto fail1; goto err_irq;
} }
r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
"OMAP DISPC", dispc.pdev); "OMAP DISPC", dispc.pdev);
if (r < 0) { if (r < 0) {
DSSERR("request_irq failed\n"); DSSERR("request_irq failed\n");
goto fail1; goto err_irq;
} }
enable_clocks(1); pm_runtime_enable(&pdev->dev);
r = dispc_runtime_get();
if (r)
goto err_runtime_get;
_omap_dispc_initial_config(); _omap_dispc_initial_config();
_omap_dispc_initialize_irq(); _omap_dispc_initialize_irq();
dispc_save_context();
rev = dispc_read_reg(DISPC_REVISION); rev = dispc_read_reg(DISPC_REVISION);
dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
enable_clocks(0); dispc_runtime_put();
return 0; return 0;
fail1:
err_runtime_get:
pm_runtime_disable(&pdev->dev);
free_irq(dispc.irq, dispc.pdev);
err_irq:
iounmap(dispc.base); iounmap(dispc.base);
fail0: err_ioremap:
clk_put(dispc.dss_clk);
err_get_clk:
return r; return r;
} }
static int omap_dispchw_remove(struct platform_device *pdev) static int omap_dispchw_remove(struct platform_device *pdev)
{ {
pm_runtime_disable(&pdev->dev);
clk_put(dispc.dss_clk);
free_irq(dispc.irq, dispc.pdev); free_irq(dispc.irq, dispc.pdev);
iounmap(dispc.base); iounmap(dispc.base);
return 0; return 0;
} }
static int dispc_runtime_suspend(struct device *dev)
{
dispc_save_context();
clk_disable(dispc.dss_clk);
dss_runtime_put();
return 0;
}
static int dispc_runtime_resume(struct device *dev)
{
int r;
r = dss_runtime_get();
if (r < 0)
return r;
clk_enable(dispc.dss_clk);
dispc_restore_context();
return 0;
}
static const struct dev_pm_ops dispc_pm_ops = {
.runtime_suspend = dispc_runtime_suspend,
.runtime_resume = dispc_runtime_resume,
};
static struct platform_driver omap_dispchw_driver = { static struct platform_driver omap_dispchw_driver = {
.probe = omap_dispchw_probe, .probe = omap_dispchw_probe,
.remove = omap_dispchw_remove, .remove = omap_dispchw_remove,
.driver = { .driver = {
.name = "omapdss_dispc", .name = "omapdss_dispc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &dispc_pm_ops,
}, },
}; };
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <video/omapdss.h> #include <video/omapdss.h>
#include "dss.h" #include "dss.h"
#include "dss_features.h"
static ssize_t display_enabled_show(struct device *dev, static ssize_t display_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
...@@ -65,48 +66,6 @@ static ssize_t display_enabled_store(struct device *dev, ...@@ -65,48 +66,6 @@ static ssize_t display_enabled_store(struct device *dev,
return size; 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, static ssize_t display_tear_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -294,8 +253,6 @@ static ssize_t display_wss_store(struct device *dev, ...@@ -294,8 +253,6 @@ static ssize_t display_wss_store(struct device *dev,
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
display_enabled_show, display_enabled_store); 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, static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
display_tear_show, display_tear_store); display_tear_show, display_tear_store);
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
...@@ -309,7 +266,6 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, ...@@ -309,7 +266,6 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
static struct device_attribute *display_sysfs_attrs[] = { static struct device_attribute *display_sysfs_attrs[] = {
&dev_attr_enabled, &dev_attr_enabled,
&dev_attr_update_mode,
&dev_attr_tear_elim, &dev_attr_tear_elim,
&dev_attr_timings, &dev_attr_timings,
&dev_attr_rotate, &dev_attr_rotate,
...@@ -327,16 +283,13 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev, ...@@ -327,16 +283,13 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
EXPORT_SYMBOL(omapdss_default_get_resolution); EXPORT_SYMBOL(omapdss_default_get_resolution);
void default_get_overlay_fifo_thresholds(enum omap_plane plane, 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) 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_high = fifo_size - buf_unit;
*fifo_low = fifo_size - burst_size_bytes; *fifo_low = fifo_size - burst_size;
} }
int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#define DSS_SUBSYS_NAME "DPI" #define DSS_SUBSYS_NAME "DPI"
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) ...@@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
bool is_tft; bool is_tft;
int r = 0; int r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb); dssdev->panel.acbi, dssdev->panel.acb);
...@@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) ...@@ -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, r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div); &fck, &lck_div, &pck_div);
if (r) if (r)
goto err0; return r;
pck = fck / lck_div / pck_div / 1000; pck = fck / lck_div / pck_div / 1000;
...@@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) ...@@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
dispc_set_lcd_timings(dssdev->manager->id, t); dispc_set_lcd_timings(dssdev->manager->id, t);
err0: return 0;
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return r;
} }
static int dpi_basic_init(struct omap_dss_device *dssdev) static void dpi_basic_init(struct omap_dss_device *dssdev)
{ {
bool is_tft; bool is_tft;
...@@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) ...@@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
dispc_set_tft_data_lines(dssdev->manager->id, dispc_set_tft_data_lines(dssdev->manager->id,
dssdev->phy.dpi.data_lines); dssdev->phy.dpi.data_lines);
return 0;
} }
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
...@@ -186,31 +179,38 @@ 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); r = omap_dss_start_device(dssdev);
if (r) { if (r) {
DSSERR("failed to start device\n"); DSSERR("failed to start device\n");
goto err0; goto err_start_dev;
} }
if (cpu_is_omap34xx()) { if (cpu_is_omap34xx()) {
r = regulator_enable(dpi.vdds_dsi_reg); r = regulator_enable(dpi.vdds_dsi_reg);
if (r) 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 = dpi_basic_init(dssdev); r = dispc_runtime_get();
if (r) if (r)
goto err2; goto err_get_dispc;
dpi_basic_init(dssdev);
if (dpi_use_dsi_pll(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); r = dsi_pll_init(dpi.dsidev, 0, 1);
if (r) if (r)
goto err3; goto err_dsi_pll_init;
} }
r = dpi_set_mode(dssdev); r = dpi_set_mode(dssdev);
if (r) if (r)
goto err4; goto err_set_mode;
mdelay(2); mdelay(2);
...@@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
return 0; return 0;
err4: err_set_mode:
if (dpi_use_dsi_pll(dssdev)) if (dpi_use_dsi_pll(dssdev))
dsi_pll_uninit(dpi.dsidev, true); dsi_pll_uninit(dpi.dsidev, true);
err3: err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev)) if (dpi_use_dsi_pll(dssdev))
dss_clk_disable(DSS_CLK_SYSCK); dsi_runtime_put(dpi.dsidev);
err2: err_get_dsi:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dispc_runtime_put();
err_get_dispc:
dss_runtime_put();
err_get_dss:
if (cpu_is_omap34xx()) if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg); regulator_disable(dpi.vdds_dsi_reg);
err1: err_reg_enable:
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
err0: err_start_dev:
return r; return r;
} }
EXPORT_SYMBOL(omapdss_dpi_display_enable); EXPORT_SYMBOL(omapdss_dpi_display_enable);
...@@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) ...@@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
if (dpi_use_dsi_pll(dssdev)) { if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true); 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()) if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg); regulator_disable(dpi.vdds_dsi_reg);
...@@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable); ...@@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable);
void dpi_set_timings(struct omap_dss_device *dssdev, void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings) struct omap_video_timings *timings)
{ {
int r;
DSSDBG("dpi_set_timings\n"); DSSDBG("dpi_set_timings\n");
dssdev->panel.timings = *timings; dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { 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); dpi_set_mode(dssdev);
dispc_go(dssdev->manager->id); dispc_go(dssdev->manager->id);
dispc_runtime_put();
dss_runtime_put();
} }
} }
EXPORT_SYMBOL(dpi_set_timings); EXPORT_SYMBOL(dpi_set_timings);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <plat/clock.h> #include <plat/clock.h>
...@@ -267,8 +268,12 @@ struct dsi_isr_tables { ...@@ -267,8 +268,12 @@ struct dsi_isr_tables {
struct dsi_data { struct dsi_data {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *base; void __iomem *base;
int irq; int irq;
struct clk *dss_clk;
struct clk *sys_clk;
void (*dsi_mux_pads)(bool enable); void (*dsi_mux_pads)(bool enable);
struct dsi_clock_info current_cinfo; struct dsi_clock_info current_cinfo;
...@@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev, ...@@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev,
return __raw_readl(dsi->base + idx.idx); 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) void dsi_bus_lock(struct omap_dss_device *dssdev)
{ {
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(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) ...@@ -493,9 +489,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
total_bytes * 1000 / total_us); total_bytes * 1000 / total_us);
} }
#else #else
#define dsi_perf_mark_setup(x) static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
#define dsi_perf_mark_start(x) {
#define dsi_perf_show(x, y) }
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 #endif
static void print_irq_status(u32 status) static void print_irq_status(u32 status)
...@@ -1039,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev) ...@@ -1039,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
return e; return e;
} }
/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ int dsi_runtime_get(struct platform_device *dsidev)
static inline void enable_clocks(bool enable)
{ {
if (enable) int r;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
else
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); 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 */ /* 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, ...@@ -1055,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
if (enable) if (enable)
dss_clk_enable(DSS_CLK_SYSCK); clk_enable(dsi->sys_clk);
else else
dss_clk_disable(DSS_CLK_SYSCK); clk_disable(dsi->sys_clk);
if (enable && dsi->pll_locked) { if (enable && dsi->pll_locked) {
if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) 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) ...@@ -1150,10 +1169,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
{ {
unsigned long r; unsigned long r;
int dsi_module = dsi_get_dsidev_id(dsidev); 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) { if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
/* DSI FCLK source is DSS_CLK_FCK */ /* DSI FCLK source is DSS_CLK_FCK */
r = dss_clk_get_rate(DSS_CLK_FCK); r = clk_get_rate(dsi->dss_clk);
} else { } else {
/* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
r = dsi_get_pll_hsdiv_dsi_rate(dsidev); r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
...@@ -1262,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, ...@@ -1262,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
return -EINVAL; return -EINVAL;
if (cinfo->use_sys_clk) { 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 /* XXX it is unclear if highfreq should be used
* with DSS_SYS_CLK source also */ * with DSS_SYS_CLK source also */
cinfo->highfreq = 0; cinfo->highfreq = 0;
...@@ -1311,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, ...@@ -1311,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
int match = 0; int match = 0;
unsigned long dss_sys_clk, max_dss_fck; 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); 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, ...@@ -1601,7 +1621,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
dsi->vdds_dsi_reg = vdds_dsi; dsi->vdds_dsi_reg = vdds_dsi;
} }
enable_clocks(1);
dsi_enable_pll_clock(dsidev, 1); dsi_enable_pll_clock(dsidev, 1);
/* /*
* Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
...@@ -1653,7 +1672,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, ...@@ -1653,7 +1672,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
} }
err0: err0:
dsi_disable_scp_clk(dsidev); dsi_disable_scp_clk(dsidev);
enable_clocks(0);
dsi_enable_pll_clock(dsidev, 0); dsi_enable_pll_clock(dsidev, 0);
return r; return r;
} }
...@@ -1671,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) ...@@ -1671,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
} }
dsi_disable_scp_clk(dsidev); dsi_disable_scp_clk(dsidev);
enable_clocks(0);
dsi_enable_pll_clock(dsidev, 0); dsi_enable_pll_clock(dsidev, 0);
DSSDBG("PLL uninit done\n"); DSSDBG("PLL uninit done\n");
...@@ -1688,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, ...@@ -1688,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
dispc_clk_src = dss_get_dispc_clk_source(); dispc_clk_src = dss_get_dispc_clk_source();
dsi_clk_src = dss_get_dsi_clk_source(dsi_module); 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); seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
...@@ -1731,7 +1749,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, ...@@ -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); 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) void dsi_dump_clocks(struct seq_file *s)
...@@ -1873,7 +1891,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, ...@@ -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)) #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); dsi_enable_scp_clk(dsidev);
DUMPREG(DSI_REVISION); DUMPREG(DSI_REVISION);
...@@ -1947,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev, ...@@ -1947,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
DUMPREG(DSI_PLL_CONFIGURATION2); DUMPREG(DSI_PLL_CONFIGURATION2);
dsi_disable_scp_clk(dsidev); dsi_disable_scp_clk(dsidev);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dsi_runtime_put(dsidev);
#undef DUMPREG #undef DUMPREG
} }
...@@ -2463,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev) ...@@ -2463,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev)
dsi->dsi_mux_pads(false); 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, static void dsi_config_tx_fifo(struct platform_device *dsidev,
enum fifo_size size1, enum fifo_size size2, enum fifo_size size1, enum fifo_size size2,
enum fifo_size size3, enum fifo_size size4) enum fifo_size size3, enum fifo_size size4)
...@@ -3386,6 +3383,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) ...@@ -3386,6 +3383,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion, dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); 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_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
dsi_if_enable(dsidev, false); dsi_if_enable(dsidev, false);
...@@ -4198,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, ...@@ -4198,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
dsi_pll_uninit(dsidev, disconnect_lanes); 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) int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
{ {
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(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) ...@@ -4229,37 +4214,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
r = omap_dss_start_device(dssdev); r = omap_dss_start_device(dssdev);
if (r) { if (r) {
DSSERR("failed to start device\n"); DSSERR("failed to start device\n");
goto err0; goto err_start_dev;
} }
enable_clocks(1); r = dsi_runtime_get(dsidev);
dsi_enable_pll_clock(dsidev, 1);
r = _dsi_reset(dsidev);
if (r) if (r)
goto err1; goto err_get_dsi;
dsi_core_init(dsidev); dsi_enable_pll_clock(dsidev, 1);
_dsi_initialize_irq(dsidev);
r = dsi_display_init_dispc(dssdev); r = dsi_display_init_dispc(dssdev);
if (r) if (r)
goto err1; goto err_init_dispc;
r = dsi_display_init_dsi(dssdev); r = dsi_display_init_dsi(dssdev);
if (r) if (r)
goto err2; goto err_init_dsi;
mutex_unlock(&dsi->lock); mutex_unlock(&dsi->lock);
return 0; return 0;
err2: err_init_dsi:
dsi_display_uninit_dispc(dssdev); dsi_display_uninit_dispc(dssdev);
err1: err_init_dispc:
enable_clocks(0);
dsi_enable_pll_clock(dsidev, 0); dsi_enable_pll_clock(dsidev, 0);
dsi_runtime_put(dsidev);
err_get_dsi:
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
err0: err_start_dev:
mutex_unlock(&dsi->lock); mutex_unlock(&dsi->lock);
DSSDBG("dsi_display_enable FAILED\n"); DSSDBG("dsi_display_enable FAILED\n");
return r; return r;
...@@ -4278,11 +4263,16 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, ...@@ -4278,11 +4263,16 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
mutex_lock(&dsi->lock); 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_dispc(dssdev);
dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
enable_clocks(0); dsi_runtime_put(dsidev);
dsi_enable_pll_clock(dsidev, 0); dsi_enable_pll_clock(dsidev, 0);
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
...@@ -4302,16 +4292,11 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) ...@@ -4302,16 +4292,11 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
EXPORT_SYMBOL(omapdss_dsi_enable_te); EXPORT_SYMBOL(omapdss_dsi_enable_te);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, 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) u32 *fifo_low, u32 *fifo_high)
{ {
unsigned burst_size_bytes; *fifo_high = fifo_size - burst_size;
*fifo_low = fifo_size - burst_size * 2;
*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;
} }
int dsi_init_display(struct omap_dss_device *dssdev) int dsi_init_display(struct omap_dss_device *dssdev)
...@@ -4437,7 +4422,47 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) ...@@ -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); 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_display_platform_data *dss_plat_data;
struct omap_dss_board_info *board_info; struct omap_dss_board_info *board_info;
...@@ -4449,7 +4474,7 @@ static int dsi_init(struct platform_device *dsidev) ...@@ -4449,7 +4474,7 @@ static int dsi_init(struct platform_device *dsidev)
dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
if (!dsi) { if (!dsi) {
r = -ENOMEM; r = -ENOMEM;
goto err0; goto err_alloc;
} }
dsi->pdev = dsidev; dsi->pdev = dsidev;
...@@ -4472,6 +4497,12 @@ static int dsi_init(struct platform_device *dsidev) ...@@ -4472,6 +4497,12 @@ static int dsi_init(struct platform_device *dsidev)
mutex_init(&dsi->lock); mutex_init(&dsi->lock);
sema_init(&dsi->bus_lock, 1); 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, INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
dsi_framedone_timeout_work_callback); dsi_framedone_timeout_work_callback);
...@@ -4484,26 +4515,26 @@ static int dsi_init(struct platform_device *dsidev) ...@@ -4484,26 +4515,26 @@ static int dsi_init(struct platform_device *dsidev)
if (!dsi_mem) { if (!dsi_mem) {
DSSERR("can't get IORESOURCE_MEM DSI\n"); DSSERR("can't get IORESOURCE_MEM DSI\n");
r = -EINVAL; r = -EINVAL;
goto err1; goto err_ioremap;
} }
dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
if (!dsi->base) { if (!dsi->base) {
DSSERR("can't ioremap DSI\n"); DSSERR("can't ioremap DSI\n");
r = -ENOMEM; r = -ENOMEM;
goto err1; goto err_ioremap;
} }
dsi->irq = platform_get_irq(dsi->pdev, 0); dsi->irq = platform_get_irq(dsi->pdev, 0);
if (dsi->irq < 0) { if (dsi->irq < 0) {
DSSERR("platform_get_irq failed\n"); DSSERR("platform_get_irq failed\n");
r = -ENODEV; r = -ENODEV;
goto err2; goto err_get_irq;
} }
r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
dev_name(&dsidev->dev), dsi->pdev); dev_name(&dsidev->dev), dsi->pdev);
if (r < 0) { if (r < 0) {
DSSERR("request_irq failed\n"); DSSERR("request_irq failed\n");
goto err2; goto err_get_irq;
} }
/* DSI VCs initialization */ /* DSI VCs initialization */
...@@ -4515,7 +4546,9 @@ static int dsi_init(struct platform_device *dsidev) ...@@ -4515,7 +4546,9 @@ static int dsi_init(struct platform_device *dsidev)
dsi_calc_clock_param_ranges(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); rev = dsi_read_reg(dsidev, DSI_REVISION);
dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
...@@ -4523,21 +4556,32 @@ static int dsi_init(struct platform_device *dsidev) ...@@ -4523,21 +4556,32 @@ static int dsi_init(struct platform_device *dsidev)
dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
enable_clocks(0); dsi_runtime_put(dsidev);
return 0; return 0;
err2:
err_get_dsi:
free_irq(dsi->irq, dsi->pdev);
err_get_irq:
iounmap(dsi->base); iounmap(dsi->base);
err1: err_ioremap:
pm_runtime_disable(&dsidev->dev);
err_get_clk:
kfree(dsi); kfree(dsi);
err0: err_alloc:
return r; 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); 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_reg != NULL) {
if (dsi->vdds_dsi_enabled) { if (dsi->vdds_dsi_enabled) {
regulator_disable(dsi->vdds_dsi_reg); regulator_disable(dsi->vdds_dsi_reg);
...@@ -4553,38 +4597,56 @@ static void dsi_exit(struct platform_device *dsidev) ...@@ -4553,38 +4597,56 @@ static void dsi_exit(struct platform_device *dsidev)
kfree(dsi); kfree(dsi);
DSSDBG("omap_dsi_exit\n"); return 0;
} }
/* DSI1 HW IP initialisation */ static int dsi_runtime_suspend(struct device *dev)
static int omap_dsi1hw_probe(struct platform_device *dsidev)
{ {
int r; struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
r = dsi_init(dsidev); clk_disable(dsi->dss_clk);
if (r) {
DSSERR("Failed to initialize DSI\n"); dispc_runtime_put();
goto err_dsi; dss_runtime_put();
}
err_dsi: return 0;
return r;
} }
static int omap_dsi1hw_remove(struct platform_device *dsidev) static int dsi_runtime_resume(struct device *dev)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
int r;
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);
dsi_exit(dsidev);
WARN_ON(dsi->scp_clk_refcount > 0);
return 0; return 0;
err_get_dispc:
dss_runtime_put();
err_get_dss:
return r;
} }
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 = { static struct platform_driver omap_dsi1hw_driver = {
.probe = omap_dsi1hw_probe, .probe = omap_dsi1hw_probe,
.remove = omap_dsi1hw_remove, .remove = omap_dsi1hw_remove,
.driver = { .driver = {
.name = "omapdss_dsi1", .name = "omapdss_dsi1",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &dsi_pm_ops,
}, },
}; };
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <plat/clock.h> #include <plat/clock.h>
...@@ -59,15 +61,9 @@ struct dss_reg { ...@@ -59,15 +61,9 @@ struct dss_reg {
static struct { static struct {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *base; void __iomem *base;
int ctx_id;
struct clk *dpll4_m4_ck; struct clk *dpll4_m4_ck;
struct clk *dss_ick; struct clk *dss_clk;
struct clk *dss_fck;
struct clk *dss_sys_clk;
struct clk *dss_tv_fck;
struct clk *dss_video_fck;
unsigned num_clks_enabled;
unsigned long cache_req_pck; unsigned long cache_req_pck;
unsigned long cache_prate; unsigned long cache_prate;
...@@ -78,6 +74,7 @@ static struct { ...@@ -78,6 +74,7 @@ static struct {
enum omap_dss_clk_source dispc_clk_source; enum omap_dss_clk_source dispc_clk_source;
enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
bool ctx_valid;
u32 ctx[DSS_SZ_REGS / sizeof(u32)]; u32 ctx[DSS_SZ_REGS / sizeof(u32)];
} dss; } dss;
...@@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = { ...@@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = {
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", [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) static inline void dss_write_reg(const struct dss_reg idx, u32 val)
{ {
__raw_writel(val, dss.base + idx.idx); __raw_writel(val, dss.base + idx.idx);
...@@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx) ...@@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx)
#define RR(reg) \ #define RR(reg) \
dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) 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()) DSSDBG("dss_save_context\n");
return;
SR(SYSCONFIG);
SR(CONTROL); SR(CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
...@@ -122,14 +110,19 @@ void dss_save_context(void) ...@@ -122,14 +110,19 @@ void dss_save_context(void)
SR(SDI_CONTROL); SR(SDI_CONTROL);
SR(PLL_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()) DSSDBG("dss_restore_context\n");
DSSERR("DSS not coming out of reset after sleep\n");
if (!dss.ctx_valid)
return;
RR(SYSCONFIG);
RR(CONTROL); RR(CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
...@@ -137,6 +130,8 @@ void dss_restore_context(void) ...@@ -137,6 +130,8 @@ void dss_restore_context(void)
RR(SDI_CONTROL); RR(SDI_CONTROL);
RR(PLL_CONTROL); RR(PLL_CONTROL);
} }
DSSDBG("context restored\n");
} }
#undef SR #undef SR
...@@ -234,6 +229,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) ...@@ -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]; return dss_generic_clk_source_names[clk_src];
} }
void dss_dump_clocks(struct seq_file *s) void dss_dump_clocks(struct seq_file *s)
{ {
unsigned long dpll4_ck_rate; unsigned long dpll4_ck_rate;
...@@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s) ...@@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s)
const char *fclk_name, *fclk_real_name; const char *fclk_name, *fclk_real_name;
unsigned long fclk_rate; unsigned long fclk_rate;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (dss_runtime_get())
return;
seq_printf(s, "- DSS -\n"); seq_printf(s, "- DSS -\n");
fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK); 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_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) { if (dss.dpll4_m4_ck) {
dpll4_ck_rate = clk_get_rate(clk_get_parent(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) ...@@ -273,14 +270,15 @@ void dss_dump_clocks(struct seq_file *s)
fclk_rate); fclk_rate);
} }
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dss_runtime_put();
} }
void dss_dump_regs(struct seq_file *s) void dss_dump_regs(struct seq_file *s)
{ {
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) #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_REVISION);
DUMPREG(DSS_SYSCONFIG); DUMPREG(DSS_SYSCONFIG);
...@@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s) ...@@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s)
DUMPREG(DSS_SDI_STATUS); DUMPREG(DSS_SDI_STATUS);
} }
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dss_runtime_put();
#undef DUMPREG #undef DUMPREG
} }
...@@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) ...@@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
} else { } else {
if (cinfo->fck_div != 0) if (cinfo->fck_div != 0)
return -EINVAL; return -EINVAL;
cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); cinfo->fck = clk_get_rate(dss.dss_clk);
} }
return 0; return 0;
...@@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) ...@@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
int dss_get_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) { if (dss.dpll4_m4_ck) {
unsigned long prate; unsigned long prate;
...@@ -512,7 +510,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, ...@@ -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); 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 && if (req_pck == dss.cache_req_pck &&
((cpu_is_omap34xx() && prate == dss.cache_prate) || ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
dss.cache_dss_cinfo.fck == fck)) { dss.cache_dss_cinfo.fck == fck)) {
...@@ -539,7 +537,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, ...@@ -539,7 +537,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
if (dss.dpll4_m4_ck == NULL) { if (dss.dpll4_m4_ck == NULL) {
struct dispc_clock_info cur_dispc; struct dispc_clock_info cur_dispc;
/* XXX can we change the clock on omap2? */ /* 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; fck_div = 1;
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
...@@ -616,28 +614,6 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, ...@@ -616,28 +614,6 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
return 0; 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) void dss_set_venc_output(enum omap_dss_venc_type type)
{ {
int l = 0; int l = 0;
...@@ -663,424 +639,88 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) ...@@ -663,424 +639,88 @@ 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 */ 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; int r;
u32 rev;
struct resource *dss_mem;
struct clk *dpll4_m4_ck;
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); clk = clk_get(&dss.pdev->dev, "fck");
if (!dss_mem) { if (IS_ERR(clk)) {
DSSERR("can't get IORESOURCE_MEM DSS\n"); DSSERR("can't get clock fck\n");
r = -EINVAL; r = PTR_ERR(clk);
goto fail0; goto err;
}
dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
if (!dss.base) {
DSSERR("can't ioremap DSS\n");
r = -ENOMEM;
goto fail0;
} }
/* disable LCD and DIGIT output. This seems to fix the synclost dss.dss_clk = clk;
* problem that we get, if the bootloader starts the DSS and
* the kernel resets it */
omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
#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
_omap_dss_reset();
/* autoidle */
REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
/* Select DPLL */
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
#ifdef CONFIG_OMAP2_DSS_VENC
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
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()) { if (cpu_is_omap34xx()) {
dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); clk = clk_get(NULL, "dpll4_m4_ck");
if (IS_ERR(dpll4_m4_ck)) { if (IS_ERR(clk)) {
DSSERR("Failed to get dpll4_m4_ck\n"); DSSERR("Failed to get dpll4_m4_ck\n");
r = PTR_ERR(dpll4_m4_ck); r = PTR_ERR(clk);
goto fail1; goto err;
} }
} else if (cpu_is_omap44xx()) { } else if (cpu_is_omap44xx()) {
dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); clk = 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)) { if (IS_ERR(clk)) {
DSSERR("can't get clock %s", clk_name); DSSERR("Failed to get dpll_per_m5x2_ck\n");
return PTR_ERR(clk); r = 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; goto err;
} }
} else { /* omap24xx */
if (pdata->opt_clock_available("tv_clk")) { clk = NULL;
r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
if (r)
goto err;
} }
if (pdata->opt_clock_available("video_clk")) { dss.dpll4_m4_ck = clk;
r = dss_get_clock(&dss.dss_video_fck, "video_clk");
if (r)
goto err;
}
return 0; return 0;
err: err:
if (dss.dss_ick) if (dss.dss_clk)
clk_put(dss.dss_ick); clk_put(dss.dss_clk);
if (dss.dss_fck) if (dss.dpll4_m4_ck)
clk_put(dss.dss_fck); clk_put(dss.dpll4_m4_ck);
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; return r;
} }
static void dss_put_clocks(void) static void dss_put_clocks(void)
{ {
if (dss.dss_video_fck) if (dss.dpll4_m4_ck)
clk_put(dss.dss_video_fck); clk_put(dss.dpll4_m4_ck);
if (dss.dss_tv_fck) clk_put(dss.dss_clk);
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) struct clk *dss_get_ick(void)
{ {
unsigned num_clks = count_clk_bits(clks); return clk_get(&dss.pdev->dev, "ick");
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) int dss_runtime_get(void)
{ {
if (cpu_is_omap34xx()) { int r;
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) DSSDBG("dss_runtime_get\n");
{
enum dss_clock clks;
clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; r = pm_runtime_get_sync(&dss.pdev->dev);
if (cpu_is_omap34xx()) WARN_ON(r < 0);
clks |= DSS_CLK_VIDFCK; return r < 0 ? r : 0;
dss_clk_enable_no_ctx(clks);
} }
static void dss_clk_disable_all_no_ctx(void) void dss_runtime_put(void)
{ {
enum dss_clock clks; int r;
clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; DSSDBG("dss_runtime_put\n");
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) r = pm_runtime_put(&dss.pdev->dev);
/* CLOCKS */ WARN_ON(r < 0);
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 */ /* DEBUGFS */
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
void dss_debug_dump_clocks(struct seq_file *s) void dss_debug_dump_clocks(struct seq_file *s)
{ {
core_dump_clocks(s);
dss_dump_clocks(s); dss_dump_clocks(s);
dispc_dump_clocks(s); dispc_dump_clocks(s);
#ifdef CONFIG_OMAP2_DSS_DSI #ifdef CONFIG_OMAP2_DSS_DSI
...@@ -1089,28 +729,51 @@ void dss_debug_dump_clocks(struct seq_file *s) ...@@ -1089,28 +729,51 @@ void dss_debug_dump_clocks(struct seq_file *s)
} }
#endif #endif
/* DSS HW IP initialisation */ /* DSS HW IP initialisation */
static int omap_dsshw_probe(struct platform_device *pdev) static int omap_dsshw_probe(struct platform_device *pdev)
{ {
struct resource *dss_mem;
u32 rev;
int r; int r;
dss.pdev = pdev; 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 err_ioremap;
}
dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
if (!dss.base) {
DSSERR("can't ioremap DSS\n");
r = -ENOMEM;
goto err_ioremap;
}
r = dss_get_clocks(); r = dss_get_clocks();
if (r) if (r)
goto err_clocks; goto err_clocks;
dss_clk_enable_all_no_ctx(); pm_runtime_enable(&pdev->dev);
dss.ctx_id = dss_get_ctx_id(); r = dss_runtime_get();
DSSDBG("initial ctx id %u\n", dss.ctx_id); if (r)
goto err_runtime_get;
r = dss_init(); /* Select DPLL */
if (r) { REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
DSSERR("Failed to initialize DSS\n");
goto err_dss; #ifdef CONFIG_OMAP2_DSS_VENC
} REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
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
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;
r = dpi_init(); r = dpi_init();
if (r) { if (r) {
...@@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev) ...@@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev)
goto err_sdi; 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; return 0;
err_sdi: err_sdi:
dpi_exit(); dpi_exit();
err_dpi: err_dpi:
dss_exit(); dss_runtime_put();
err_dss: err_runtime_get:
dss_clk_disable_all_no_ctx(); pm_runtime_disable(&pdev->dev);
dss_put_clocks(); dss_put_clocks();
err_clocks: err_clocks:
iounmap(dss.base);
err_ioremap:
return r; return r;
} }
static int omap_dsshw_remove(struct platform_device *pdev) static int omap_dsshw_remove(struct platform_device *pdev)
{ {
dpi_exit();
sdi_exit();
dss_exit(); iounmap(dss.base);
/* pm_runtime_disable(&pdev->dev);
* 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);
dss_put_clocks(); dss_put_clocks();
return 0;
}
static int dss_runtime_suspend(struct device *dev)
{
dss_save_context();
clk_disable(dss.dss_clk);
return 0; 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 = { static struct platform_driver omap_dsshw_driver = {
.probe = omap_dsshw_probe, .probe = omap_dsshw_probe,
.remove = omap_dsshw_remove, .remove = omap_dsshw_remove,
.driver = { .driver = {
.name = "omapdss_dss", .name = "omapdss_dss",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &dss_pm_ops,
}, },
}; };
......
...@@ -97,26 +97,12 @@ extern unsigned int dss_debug; ...@@ -97,26 +97,12 @@ extern unsigned int dss_debug;
#define FLD_MOD(orig, val, start, end) \ #define FLD_MOD(orig, val, start, end) \
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(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 { enum omap_parallel_interface_mode {
OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */ OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */ OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
OMAP_DSS_PARALLELMODE_DSI, 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 { enum dss_hdmi_venc_clk_source_select {
DSS_VENC_TV_CLK = 0, DSS_VENC_TV_CLK = 0,
DSS_HDMI_M_PCLK = 1, DSS_HDMI_M_PCLK = 1,
...@@ -194,7 +180,7 @@ void dss_uninit_device(struct platform_device *pdev, ...@@ -194,7 +180,7 @@ void dss_uninit_device(struct platform_device *pdev,
bool dss_use_replication(struct omap_dss_device *dssdev, bool dss_use_replication(struct omap_dss_device *dssdev,
enum omap_color_mode mode); enum omap_color_mode mode);
void default_get_overlay_fifo_thresholds(enum omap_plane plane, 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); u32 *fifo_low, u32 *fifo_high);
/* manager */ /* manager */
...@@ -220,13 +206,12 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); ...@@ -220,13 +206,12 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
int dss_init_platform_driver(void); int dss_init_platform_driver(void);
void dss_uninit_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_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); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s); void dss_dump_clocks(struct seq_file *s);
...@@ -283,15 +268,15 @@ struct file_operations; ...@@ -283,15 +268,15 @@ struct file_operations;
int dsi_init_platform_driver(void); int dsi_init_platform_driver(void);
void dsi_uninit_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_dump_clocks(struct seq_file *s);
void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
const struct file_operations *debug_fops); const struct file_operations *debug_fops);
void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
const struct file_operations *debug_fops); 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); int dsi_init_display(struct omap_dss_device *display);
void dsi_irq_handler(void); void dsi_irq_handler(void);
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); 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, ...@@ -304,7 +289,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv); bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, 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); u32 *fifo_low, u32 *fifo_high);
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
void dsi_wait_pll_hsdiv_dsi_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) ...@@ -317,6 +302,13 @@ static inline int dsi_init_platform_driver(void)
static inline void dsi_uninit_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) 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__); WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
...@@ -384,8 +376,8 @@ void dispc_dump_regs(struct seq_file *s); ...@@ -384,8 +376,8 @@ void dispc_dump_regs(struct seq_file *s);
void dispc_irq_handler(void); void dispc_irq_handler(void);
void dispc_fake_vsync_irq(void); void dispc_fake_vsync_irq(void);
void dispc_save_context(void); int dispc_runtime_get(void);
void dispc_restore_context(void); void dispc_runtime_put(void);
void dispc_enable_sidle(void); void dispc_enable_sidle(void);
void dispc_disable_sidle(void); void dispc_disable_sidle(void);
...@@ -398,10 +390,12 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable); ...@@ -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_lcd_size(enum omap_channel channel, u16 width, u16 height);
void dispc_set_digit_size(u16 width, u16 height); void dispc_set_digit_size(u16 width, u16 height);
u32 dispc_get_plane_fifo_size(enum omap_plane plane); 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_enable_fifomerge(bool enable);
void dispc_set_burst_size(enum omap_plane plane, u32 dispc_get_burst_size(enum omap_plane plane);
enum omap_burst_size burst_size); 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_ba0(enum omap_plane plane, u32 paddr);
void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr); void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
......
...@@ -49,6 +49,9 @@ struct omap_dss_features { ...@@ -49,6 +49,9 @@ struct omap_dss_features {
const enum omap_color_mode *supported_color_modes; const enum omap_color_mode *supported_color_modes;
const char * const *clksrc_names; const char * const *clksrc_names;
const struct dss_param_range *dss_params; 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 */ /* This struct is assigned to one of the below during initialization */
...@@ -274,6 +277,8 @@ static const struct omap_dss_features omap2_dss_features = { ...@@ -274,6 +277,8 @@ static const struct omap_dss_features omap2_dss_features = {
.supported_color_modes = omap2_dss_supported_color_modes, .supported_color_modes = omap2_dss_supported_color_modes,
.clksrc_names = omap2_dss_clk_source_names, .clksrc_names = omap2_dss_clk_source_names,
.dss_params = omap2_dss_param_range, .dss_params = omap2_dss_param_range,
.buffer_size_unit = 1,
.burst_size_unit = 8,
}; };
/* OMAP3 DSS Features */ /* OMAP3 DSS Features */
...@@ -286,7 +291,9 @@ static const struct omap_dss_features omap3430_dss_features = { ...@@ -286,7 +291,9 @@ static const struct omap_dss_features omap3430_dss_features = {
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | 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_mgrs = 2,
.num_ovls = 3, .num_ovls = 3,
...@@ -294,6 +301,8 @@ static const struct omap_dss_features omap3430_dss_features = { ...@@ -294,6 +301,8 @@ static const struct omap_dss_features omap3430_dss_features = {
.supported_color_modes = omap3_dss_supported_color_modes, .supported_color_modes = omap3_dss_supported_color_modes,
.clksrc_names = omap3_dss_clk_source_names, .clksrc_names = omap3_dss_clk_source_names,
.dss_params = omap3_dss_param_range, .dss_params = omap3_dss_param_range,
.buffer_size_unit = 1,
.burst_size_unit = 8,
}; };
static const struct omap_dss_features omap3630_dss_features = { static const struct omap_dss_features omap3630_dss_features = {
...@@ -306,7 +315,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_PRE_MULT_ALPHA | FEAT_FUNCGATED |
FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | 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_mgrs = 2,
.num_ovls = 3, .num_ovls = 3,
...@@ -314,6 +324,8 @@ static const struct omap_dss_features omap3630_dss_features = { ...@@ -314,6 +324,8 @@ static const struct omap_dss_features omap3630_dss_features = {
.supported_color_modes = omap3_dss_supported_color_modes, .supported_color_modes = omap3_dss_supported_color_modes,
.clksrc_names = omap3_dss_clk_source_names, .clksrc_names = omap3_dss_clk_source_names,
.dss_params = omap3_dss_param_range, .dss_params = omap3_dss_param_range,
.buffer_size_unit = 1,
.burst_size_unit = 8,
}; };
/* OMAP4 DSS Features */ /* OMAP4 DSS Features */
...@@ -327,7 +339,8 @@ static const struct omap_dss_features omap4430_es1_0_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_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | 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_mgrs = 3,
.num_ovls = 3, .num_ovls = 3,
...@@ -335,6 +348,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { ...@@ -335,6 +348,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = {
.supported_color_modes = omap4_dss_supported_color_modes, .supported_color_modes = omap4_dss_supported_color_modes,
.clksrc_names = omap4_dss_clk_source_names, .clksrc_names = omap4_dss_clk_source_names,
.dss_params = omap4_dss_param_range, .dss_params = omap4_dss_param_range,
.buffer_size_unit = 16,
.burst_size_unit = 16,
}; };
/* For all the other OMAP4 versions */ /* For all the other OMAP4 versions */
...@@ -348,7 +363,8 @@ static const struct omap_dss_features omap4_dss_features = { ...@@ -348,7 +363,8 @@ static const struct omap_dss_features omap4_dss_features = {
FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | 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_mgrs = 3,
.num_ovls = 3, .num_ovls = 3,
...@@ -356,6 +372,8 @@ static const struct omap_dss_features omap4_dss_features = { ...@@ -356,6 +372,8 @@ static const struct omap_dss_features omap4_dss_features = {
.supported_color_modes = omap4_dss_supported_color_modes, .supported_color_modes = omap4_dss_supported_color_modes,
.clksrc_names = omap4_dss_clk_source_names, .clksrc_names = omap4_dss_clk_source_names,
.dss_params = omap4_dss_param_range, .dss_params = omap4_dss_param_range,
.buffer_size_unit = 16,
.burst_size_unit = 16,
}; };
/* Functions returning values related to a DSS feature */ /* 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) ...@@ -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]; 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 */ /* DSS has_feature check */
bool dss_has_feature(enum dss_feat_id id) bool dss_has_feature(enum dss_feat_id id)
{ {
......
...@@ -51,6 +51,10 @@ enum dss_feat_id { ...@@ -51,6 +51,10 @@ enum dss_feat_id {
FEAT_HDMI_CTS_SWMODE = 1 << 19, FEAT_HDMI_CTS_SWMODE = 1 << 19,
FEAT_HANDLE_UV_SEPARATE = 1 << 20, FEAT_HANDLE_UV_SEPARATE = 1 << 20,
FEAT_ATTR2 = 1 << 21, 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 */ /* DSS register field id */
...@@ -90,6 +94,9 @@ bool dss_feat_color_mode_supported(enum omap_plane plane, ...@@ -90,6 +94,9 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
enum omap_color_mode color_mode); enum omap_color_mode color_mode);
const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); 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); 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_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
void dss_features_init(void); void dss_features_init(void);
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
...@@ -51,6 +54,9 @@ static struct { ...@@ -51,6 +54,9 @@ static struct {
u8 edid_set; u8 edid_set;
bool custom_set; bool custom_set;
struct hdmi_config cfg; struct hdmi_config cfg;
struct clk *sys_clk;
struct clk *hdmi_clk;
} hdmi; } hdmi;
/* /*
...@@ -162,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, ...@@ -162,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
return val; 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) int hdmi_init_display(struct omap_dss_device *dssdev)
{ {
DSSDBG("init_display\n"); DSSDBG("init_display\n");
...@@ -311,30 +338,11 @@ static int hdmi_phy_init(void) ...@@ -311,30 +338,11 @@ static int hdmi_phy_init(void)
return 0; 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) static int hdmi_pll_program(struct hdmi_pll_info *fmt)
{ {
u16 r = 0; u16 r = 0;
enum hdmi_clk_refsel refsel; 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); r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
if (r) if (r)
return r; return r;
...@@ -1064,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, ...@@ -1064,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
unsigned long clkin, refclk; unsigned long clkin, refclk;
u32 mf; 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 * Input clock is predivided by N + 1
* out put of which is reference clk * out put of which is reference clk
...@@ -1098,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, ...@@ -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); 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) static int hdmi_power_on(struct omap_dss_device *dssdev)
{ {
int r, code = 0; int r, code = 0;
...@@ -1115,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) ...@@ -1115,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
struct omap_video_timings *p; struct omap_video_timings *p;
unsigned long phy; unsigned long phy;
hdmi_enable_clocks(1); r = hdmi_runtime_get();
if (r)
return r;
dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
...@@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) ...@@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
return 0; return 0;
err: err:
hdmi_enable_clocks(0); hdmi_runtime_put();
return -EIO; return -EIO;
} }
...@@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) ...@@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
hdmi_wp_video_start(0); hdmi_wp_video_start(0);
hdmi_phy_off(); hdmi_phy_off();
hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
hdmi_enable_clocks(0); hdmi_runtime_put();
hdmi.edid_set = 0; hdmi.edid_set = 0;
} }
...@@ -1686,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = { ...@@ -1686,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
}; };
#endif #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 */ /* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev) static int omapdss_hdmihw_probe(struct platform_device *pdev)
{ {
struct resource *hdmi_mem; struct resource *hdmi_mem;
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ int r;
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
int ret;
#endif
hdmi.pdata = pdev->dev.platform_data; hdmi.pdata = pdev->dev.platform_data;
hdmi.pdev = pdev; hdmi.pdev = pdev;
...@@ -1713,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -1713,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
r = hdmi_get_clocks(pdev);
if (r) {
iounmap(hdmi.base_wp);
return r;
}
pm_runtime_enable(&pdev->dev);
hdmi_panel_init(); hdmi_panel_init();
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
/* Register ASoC codec DAI */ /* 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); &hdmi_codec_dai_drv, 1);
if (ret) { if (r) {
DSSERR("can't register ASoC HDMI audio codec\n"); DSSERR("can't register ASoC HDMI audio codec\n");
return ret; return r;
} }
#endif #endif
return 0; return 0;
...@@ -1738,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev) ...@@ -1738,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
snd_soc_unregister_codec(&pdev->dev); snd_soc_unregister_codec(&pdev->dev);
#endif #endif
pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();
iounmap(hdmi.base_wp); iounmap(hdmi.base_wp);
return 0; 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 = { static struct platform_driver omapdss_hdmihw_driver = {
.probe = omapdss_hdmihw_probe, .probe = omapdss_hdmihw_probe,
.remove = omapdss_hdmihw_remove, .remove = omapdss_hdmihw_remove,
.driver = { .driver = {
.name = "omapdss_hdmi", .name = "omapdss_hdmi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &hdmi_pm_ops,
}, },
}; };
......
...@@ -275,6 +275,108 @@ static ssize_t manager_alpha_blending_enabled_store( ...@@ -275,6 +275,108 @@ static ssize_t manager_alpha_blending_enabled_store(
return size; 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 manager_attribute {
struct attribute attr; struct attribute attr;
ssize_t (*show)(struct omap_overlay_manager *, char *); ssize_t (*show)(struct omap_overlay_manager *, char *);
...@@ -300,6 +402,12 @@ static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, ...@@ -300,6 +402,12 @@ static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
manager_alpha_blending_enabled_show, manager_alpha_blending_enabled_show,
manager_alpha_blending_enabled_store); 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[] = { static struct attribute *manager_sysfs_attrs[] = {
...@@ -310,6 +418,8 @@ 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_value.attr,
&manager_attr_trans_key_enabled.attr, &manager_attr_trans_key_enabled.attr,
&manager_attr_alpha_blending_enabled.attr, &manager_attr_alpha_blending_enabled.attr,
&manager_attr_cpr_enable.attr,
&manager_attr_cpr_coef.attr,
NULL NULL
}; };
...@@ -391,33 +501,14 @@ struct overlay_cache_data { ...@@ -391,33 +501,14 @@ struct overlay_cache_data {
bool enabled; bool enabled;
u32 paddr; struct omap_overlay_info info;
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;
enum omap_channel channel; enum omap_channel channel;
bool replication; bool replication;
bool ilace; bool ilace;
enum omap_burst_size burst_size;
u32 fifo_low; u32 fifo_low;
u32 fifo_high; u32 fifo_high;
bool manual_update;
}; };
struct manager_cache_data { struct manager_cache_data {
...@@ -429,15 +520,8 @@ struct manager_cache_data { ...@@ -429,15 +520,8 @@ struct manager_cache_data {
* VSYNC/EVSYNC */ * VSYNC/EVSYNC */
bool shadow_dirty; 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 manual_update;
bool do_manual_update; bool do_manual_update;
...@@ -539,24 +623,15 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) ...@@ -539,24 +623,15 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0; return 0;
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 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 { } else {
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_VSYNC DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
: DISPC_IRQ_VSYNC2;
}
} }
mc = &dss_cache.manager_cache[mgr->id]; mc = &dss_cache.manager_cache[mgr->id];
...@@ -617,24 +692,15 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) ...@@ -617,24 +692,15 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0; return 0;
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; 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 { } else {
irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
DISPC_IRQ_VSYNC DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
: DISPC_IRQ_VSYNC2;
}
} }
oc = &dss_cache.overlay_cache[ovl->id]; oc = &dss_cache.overlay_cache[ovl->id];
...@@ -720,10 +786,12 @@ static bool rectangle_intersects(int x1, int y1, int w1, int h1, ...@@ -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) 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; 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 true;
return false; return false;
...@@ -733,6 +801,8 @@ static int configure_overlay(enum omap_plane plane) ...@@ -733,6 +801,8 @@ static int configure_overlay(enum omap_plane plane)
{ {
struct overlay_cache_data *c; struct overlay_cache_data *c;
struct manager_cache_data *mc; struct manager_cache_data *mc;
struct omap_overlay_info *oi;
struct omap_overlay_manager_info *mi;
u16 outw, outh; u16 outw, outh;
u16 x, y, w, h; u16 x, y, w, h;
u32 paddr; u32 paddr;
...@@ -742,6 +812,7 @@ static int configure_overlay(enum omap_plane plane) ...@@ -742,6 +812,7 @@ static int configure_overlay(enum omap_plane plane)
DSSDBGF("%d", plane); DSSDBGF("%d", plane);
c = &dss_cache.overlay_cache[plane]; c = &dss_cache.overlay_cache[plane];
oi = &c->info;
if (!c->enabled) { if (!c->enabled) {
dispc_enable_plane(plane, 0); dispc_enable_plane(plane, 0);
...@@ -749,21 +820,22 @@ static int configure_overlay(enum omap_plane plane) ...@@ -749,21 +820,22 @@ static int configure_overlay(enum omap_plane plane)
} }
mc = &dss_cache.manager_cache[c->channel]; mc = &dss_cache.manager_cache[c->channel];
mi = &mc->info;
x = c->pos_x; x = oi->pos_x;
y = c->pos_y; y = oi->pos_y;
w = c->width; w = oi->width;
h = c->height; h = oi->height;
outw = c->out_width == 0 ? c->width : c->out_width; outw = oi->out_width == 0 ? oi->width : oi->out_width;
outh = c->out_height == 0 ? c->height : c->out_height; outh = oi->out_height == 0 ? oi->height : oi->out_height;
paddr = c->paddr; paddr = oi->paddr;
orig_w = w; orig_w = w;
orig_h = h; orig_h = h;
orig_outw = outw; orig_outw = outw;
orig_outh = outh; orig_outh = outh;
if (c->manual_update && mc->do_manual_update) { if (mc->manual_update && mc->do_manual_update) {
unsigned bpp; unsigned bpp;
unsigned scale_x_m = w, scale_x_d = outw; unsigned scale_x_m = w, scale_x_d = outw;
unsigned scale_y_m = h, scale_y_d = outh; unsigned scale_y_m = h, scale_y_d = outh;
...@@ -775,7 +847,7 @@ static int configure_overlay(enum omap_plane plane) ...@@ -775,7 +847,7 @@ static int configure_overlay(enum omap_plane plane)
return 0; return 0;
} }
switch (c->color_mode) { switch (oi->color_mode) {
case OMAP_DSS_COLOR_NV12: case OMAP_DSS_COLOR_NV12:
bpp = 8; bpp = 8;
break; break;
...@@ -805,23 +877,23 @@ static int configure_overlay(enum omap_plane plane) ...@@ -805,23 +877,23 @@ static int configure_overlay(enum omap_plane plane)
BUG(); BUG();
} }
if (mc->x > c->pos_x) { if (mc->x > oi->pos_x) {
x = 0; x = 0;
outw -= (mc->x - c->pos_x); outw -= (mc->x - oi->pos_x);
paddr += (mc->x - c->pos_x) * paddr += (mc->x - oi->pos_x) *
scale_x_m / scale_x_d * bpp / 8; scale_x_m / scale_x_d * bpp / 8;
} else { } 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; y = 0;
outh -= (mc->y - c->pos_y); outh -= (mc->y - oi->pos_y);
paddr += (mc->y - c->pos_y) * paddr += (mc->y - oi->pos_y) *
scale_y_m / scale_y_d * scale_y_m / scale_y_d *
c->screen_width * bpp / 8; oi->screen_width * bpp / 8;
} else { } else {
y = c->pos_y - mc->y; y = oi->pos_y - mc->y;
} }
if (mc->w < (x + outw)) if (mc->w < (x + outw))
...@@ -840,8 +912,8 @@ static int configure_overlay(enum omap_plane plane) ...@@ -840,8 +912,8 @@ static int configure_overlay(enum omap_plane plane)
* the width if the original width was bigger. * the width if the original width was bigger.
*/ */
if ((w & 1) && if ((w & 1) &&
(c->color_mode == OMAP_DSS_COLOR_YUV2 || (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
c->color_mode == OMAP_DSS_COLOR_UYVY)) { oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
if (orig_w > w) if (orig_w > w)
w += 1; w += 1;
else else
...@@ -851,19 +923,19 @@ static int configure_overlay(enum omap_plane plane) ...@@ -851,19 +923,19 @@ static int configure_overlay(enum omap_plane plane)
r = dispc_setup_plane(plane, r = dispc_setup_plane(plane,
paddr, paddr,
c->screen_width, oi->screen_width,
x, y, x, y,
w, h, w, h,
outw, outh, outw, outh,
c->color_mode, oi->color_mode,
c->ilace, c->ilace,
c->rotation_type, oi->rotation_type,
c->rotation, oi->rotation,
c->mirror, oi->mirror,
c->global_alpha, oi->global_alpha,
c->pre_mult_alpha, oi->pre_mult_alpha,
c->channel, c->channel,
c->p_uv_addr); oi->p_uv_addr);
if (r) { if (r) {
/* this shouldn't happen */ /* this shouldn't happen */
...@@ -874,8 +946,7 @@ static int configure_overlay(enum omap_plane plane) ...@@ -874,8 +946,7 @@ static int configure_overlay(enum omap_plane plane)
dispc_enable_replication(plane, c->replication); dispc_enable_replication(plane, c->replication);
dispc_set_burst_size(plane, c->burst_size); dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
dispc_enable_plane(plane, 1); dispc_enable_plane(plane, 1);
...@@ -884,16 +955,21 @@ static int configure_overlay(enum omap_plane plane) ...@@ -884,16 +955,21 @@ static int configure_overlay(enum omap_plane plane)
static void configure_manager(enum omap_channel channel) static void configure_manager(enum omap_channel channel)
{ {
struct manager_cache_data *c; struct omap_overlay_manager_info *mi;
DSSDBGF("%d", channel); 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_default_color(channel, mi->default_color);
dispc_set_trans_key(channel, c->trans_key_type, c->trans_key); dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
dispc_enable_trans_key(channel, c->trans_enabled); dispc_enable_trans_key(channel, mi->trans_enabled);
dispc_enable_alpha_blending(channel, c->alpha_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. /* configure_dispc() tries to write values from cache to shadow registers.
...@@ -928,7 +1004,7 @@ static int configure_dispc(void) ...@@ -928,7 +1004,7 @@ static int configure_dispc(void)
if (!oc->dirty) if (!oc->dirty)
continue; continue;
if (oc->manual_update && !mc->do_manual_update) if (mc->manual_update && !mc->do_manual_update)
continue; continue;
if (mgr_busy[oc->channel]) { if (mgr_busy[oc->channel]) {
...@@ -976,7 +1052,7 @@ static int configure_dispc(void) ...@@ -976,7 +1052,7 @@ static int configure_dispc(void)
/* We don't need GO with manual update display. LCD iface will /* We don't need GO with manual update display. LCD iface will
* always be turned off after frame, and new settings will be * always be turned off after frame, and new settings will be
* taken in to use at next update */ * taken in to use at next update */
if (!mc->manual_upd_display) if (!mc->manual_update)
dispc_go(i); dispc_go(i);
} }
...@@ -1011,6 +1087,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, ...@@ -1011,6 +1087,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
{ {
struct overlay_cache_data *oc; struct overlay_cache_data *oc;
struct manager_cache_data *mc; struct manager_cache_data *mc;
struct omap_overlay_info *oi;
const int num_ovls = dss_feat_get_num_ovls(); const int num_ovls = dss_feat_get_num_ovls();
struct omap_overlay_manager *mgr; struct omap_overlay_manager *mgr;
int i; int i;
...@@ -1053,6 +1130,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, ...@@ -1053,6 +1130,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
unsigned outw, outh; unsigned outw, outh;
oc = &dss_cache.overlay_cache[i]; oc = &dss_cache.overlay_cache[i];
oi = &oc->info;
if (oc->channel != mgr->id) if (oc->channel != mgr->id)
continue; continue;
...@@ -1068,39 +1146,39 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, ...@@ -1068,39 +1146,39 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
if (!dispc_is_overlay_scaled(oc)) if (!dispc_is_overlay_scaled(oc))
continue; continue;
outw = oc->out_width == 0 ? outw = oi->out_width == 0 ?
oc->width : oc->out_width; oi->width : oi->out_width;
outh = oc->out_height == 0 ? outh = oi->out_height == 0 ?
oc->height : oc->out_height; oi->height : oi->out_height;
/* is the overlay outside the update region? */ /* is the overlay outside the update region? */
if (!rectangle_intersects(x, y, w, h, if (!rectangle_intersects(x, y, w, h,
oc->pos_x, oc->pos_y, oi->pos_x, oi->pos_y,
outw, outh)) outw, outh))
continue; continue;
/* if the overlay totally inside the update region? */ /* 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)) x, y, w, h))
continue; continue;
if (x > oc->pos_x) if (x > oi->pos_x)
x1 = oc->pos_x; x1 = oi->pos_x;
else else
x1 = x; x1 = x;
if (y > oc->pos_y) if (y > oi->pos_y)
y1 = oc->pos_y; y1 = oi->pos_y;
else else
y1 = y; y1 = y;
if ((x + w) < (oc->pos_x + outw)) if ((x + w) < (oi->pos_x + outw))
x2 = oc->pos_x + outw; x2 = oi->pos_x + outw;
else else
x2 = x + w; x2 = x + w;
if ((y + h) < (oc->pos_y + outh)) if ((y + h) < (oi->pos_y + outh))
y2 = oc->pos_y + outh; y2 = oi->pos_y + outh;
else else
y2 = y + h; y2 = y + h;
...@@ -1236,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1236,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
r = dispc_runtime_get();
if (r)
return r;
spin_lock_irqsave(&dss_cache.lock, flags); spin_lock_irqsave(&dss_cache.lock, flags);
/* Configure overlays */ /* Configure overlays */
...@@ -1275,23 +1357,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1275,23 +1357,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
ovl->info_dirty = false; ovl->info_dirty = false;
oc->dirty = true; oc->dirty = true;
oc->info = ovl->info;
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->replication = oc->replication =
dss_use_replication(dssdev, ovl->info.color_mode); dss_use_replication(dssdev, ovl->info.color_mode);
...@@ -1302,11 +1368,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1302,11 +1368,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
oc->enabled = true; 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; ++num_planes_enabled;
} }
...@@ -1334,20 +1395,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1334,20 +1395,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
mgr->info_dirty = false; mgr->info_dirty = false;
mc->dirty = true; mc->dirty = true;
mc->info = mgr->info;
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->manual_update = mc->manual_update =
dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE && dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
dssdev->driver->get_update_mode(dssdev) !=
OMAP_DSS_UPDATE_AUTO;
} }
/* XXX TODO: Try to get fifomerge working. The problem is that it /* 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) ...@@ -1368,7 +1419,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
/* Configure overlay fifos */ /* Configure overlay fifos */
for (i = 0; i < omap_dss_get_num_overlays(); ++i) { for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
struct omap_dss_device *dssdev; struct omap_dss_device *dssdev;
u32 size; u32 size, burst_size;
ovl = omap_dss_get_overlay(i); ovl = omap_dss_get_overlay(i);
...@@ -1386,6 +1437,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1386,6 +1437,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
if (use_fifomerge) if (use_fifomerge)
size *= 3; size *= 3;
burst_size = dispc_get_burst_size(ovl->id);
switch (dssdev->type) { switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_DPI: case OMAP_DISPLAY_TYPE_DPI:
case OMAP_DISPLAY_TYPE_DBI: case OMAP_DISPLAY_TYPE_DBI:
...@@ -1393,13 +1446,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1393,13 +1446,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_HDMI: case OMAP_DISPLAY_TYPE_HDMI:
default_get_overlay_fifo_thresholds(ovl->id, size, default_get_overlay_fifo_thresholds(ovl->id, size,
&oc->burst_size, &oc->fifo_low, burst_size, &oc->fifo_low,
&oc->fifo_high); &oc->fifo_high);
break; break;
#ifdef CONFIG_OMAP2_DSS_DSI #ifdef CONFIG_OMAP2_DSS_DSI
case OMAP_DISPLAY_TYPE_DSI: case OMAP_DISPLAY_TYPE_DSI:
dsi_get_overlay_fifo_thresholds(ovl->id, size, dsi_get_overlay_fifo_thresholds(ovl->id, size,
&oc->burst_size, &oc->fifo_low, burst_size, &oc->fifo_low,
&oc->fifo_high); &oc->fifo_high);
break; break;
#endif #endif
...@@ -1409,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1409,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
} }
r = 0; r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
if (!dss_cache.irq_enabled) { if (!dss_cache.irq_enabled) {
u32 mask; u32 mask;
...@@ -1422,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) ...@@ -1422,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
dss_cache.irq_enabled = true; dss_cache.irq_enabled = true;
} }
configure_dispc(); configure_dispc();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
spin_unlock_irqrestore(&dss_cache.lock, flags); spin_unlock_irqrestore(&dss_cache.lock, flags);
dispc_runtime_put();
return r; return r;
} }
......
...@@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, ...@@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
old_mgr = ovl->manager; old_mgr = ovl->manager;
r = dispc_runtime_get();
if (r)
return r;
/* detach old manager */ /* detach old manager */
if (old_mgr) { if (old_mgr) {
r = ovl->unset_manager(ovl); r = ovl->unset_manager(ovl);
if (r) { if (r) {
DSSERR("detach failed\n"); DSSERR("detach failed\n");
return r; goto err;
} }
r = old_mgr->apply(old_mgr); r = old_mgr->apply(old_mgr);
if (r) if (r)
return r; goto err;
} }
if (mgr) { if (mgr) {
r = ovl->set_manager(ovl, mgr); r = ovl->set_manager(ovl, mgr);
if (r) { if (r) {
DSSERR("Failed to attach overlay\n"); DSSERR("Failed to attach overlay\n");
return r; goto err;
} }
r = mgr->apply(mgr); r = mgr->apply(mgr);
if (r) if (r)
return r; goto err;
} }
dispc_runtime_put();
return size; return size;
err:
dispc_runtime_put();
return r;
} }
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) 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, ...@@ -238,6 +248,9 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
u8 alpha; u8 alpha;
struct omap_overlay_info info; struct omap_overlay_info info;
if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
return -ENODEV;
r = kstrtou8(buf, 0, &alpha); r = kstrtou8(buf, 0, &alpha);
if (r) if (r)
return r; return r;
...@@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, ...@@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
ovl->manager = mgr; 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 /* 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 * the overlay is first disabled, then moved to tv, and enabled, we
* seem to get SYNC_LOST_DIGIT error. * seem to get SYNC_LOST_DIGIT error.
...@@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, ...@@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
* the overlay, but before moving the overlay to TV. * the overlay, but before moving the overlay to TV.
*/ */
dispc_set_channel_out(ovl->id, mgr->id); dispc_set_channel_out(ovl->id, mgr->id);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return 0; return 0;
} }
...@@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) ...@@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
} }
if (mgr) { if (mgr) {
dispc_runtime_get();
for (i = 0; i < dss_feat_get_num_ovls(); i++) { for (i = 0; i < dss_feat_get_num_ovls(); i++) {
struct omap_overlay *ovl; struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i); ovl = omap_dss_get_overlay(i);
...@@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) ...@@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
omap_dss_set_manager(ovl, mgr); omap_dss_set_manager(ovl, mgr);
} }
} }
dispc_runtime_put();
} }
} }
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include "dss.h" #include "dss.h"
...@@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx) ...@@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
return __raw_readl(rfbi.base + idx.idx); return __raw_readl(rfbi.base + idx.idx);
} }
static void rfbi_enable_clocks(bool enable) static int rfbi_runtime_get(void)
{ {
if (enable) int r;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else DSSDBG("rfbi_runtime_get\n");
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
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) void rfbi_bus_lock(void)
...@@ -805,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s) ...@@ -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)) #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_REVISION);
DUMPREG(RFBI_SYSCONFIG); DUMPREG(RFBI_SYSCONFIG);
...@@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s) ...@@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
DUMPREG(RFBI_VSYNC_WIDTH); DUMPREG(RFBI_VSYNC_WIDTH);
DUMPREG(RFBI_HSYNC_WIDTH); DUMPREG(RFBI_HSYNC_WIDTH);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); rfbi_runtime_put();
#undef DUMPREG #undef DUMPREG
} }
...@@ -844,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) ...@@ -844,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{ {
int r; int r;
rfbi_enable_clocks(1); r = rfbi_runtime_get();
if (r)
return r;
r = omap_dss_start_device(dssdev); r = omap_dss_start_device(dssdev);
if (r) { if (r) {
...@@ -879,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) ...@@ -879,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
err1: err1:
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
err0: err0:
rfbi_runtime_put();
return r; return r;
} }
EXPORT_SYMBOL(omapdss_rfbi_display_enable); EXPORT_SYMBOL(omapdss_rfbi_display_enable);
...@@ -889,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) ...@@ -889,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
DISPC_IRQ_FRAMEDONE); DISPC_IRQ_FRAMEDONE);
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
rfbi_enable_clocks(0); rfbi_runtime_put();
} }
EXPORT_SYMBOL(omapdss_rfbi_display_disable); EXPORT_SYMBOL(omapdss_rfbi_display_disable);
...@@ -904,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev) ...@@ -904,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
static int omap_rfbihw_probe(struct platform_device *pdev) static int omap_rfbihw_probe(struct platform_device *pdev)
{ {
u32 rev; u32 rev;
u32 l;
struct resource *rfbi_mem; struct resource *rfbi_mem;
struct clk *clk;
int r;
rfbi.pdev = pdev; rfbi.pdev = pdev;
...@@ -914,46 +934,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev) ...@@ -914,46 +934,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
if (!rfbi_mem) { if (!rfbi_mem) {
DSSERR("can't get IORESOURCE_MEM RFBI\n"); 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)); rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
if (!rfbi.base) { if (!rfbi.base) {
DSSERR("can't ioremap RFBI\n"); 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); 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;
}
rfbi.l4_khz = clk_get_rate(clk) / 1000;
/* Enable autoidle and smart-idle */ clk_put(clk);
l = rfbi_read_reg(RFBI_SYSCONFIG);
l |= (1 << 0) | (2 << 3);
rfbi_write_reg(RFBI_SYSCONFIG, l);
rev = rfbi_read_reg(RFBI_REVISION); rev = rfbi_read_reg(RFBI_REVISION);
dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
rfbi_enable_clocks(0); rfbi_runtime_put();
return 0; 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) static int omap_rfbihw_remove(struct platform_device *pdev)
{ {
pm_runtime_disable(&pdev->dev);
iounmap(rfbi.base); iounmap(rfbi.base);
return 0; 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 = { static struct platform_driver omap_rfbihw_driver = {
.probe = omap_rfbihw_probe, .probe = omap_rfbihw_probe,
.remove = omap_rfbihw_remove, .remove = omap_rfbihw_remove,
.driver = { .driver = {
.name = "omapdss_rfbi", .name = "omapdss_rfbi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &rfbi_pm_ops,
}, },
}; };
......
...@@ -20,13 +20,11 @@ ...@@ -20,13 +20,11 @@
#define DSS_SUBSYS_NAME "SDI" #define DSS_SUBSYS_NAME "SDI"
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h" #include "dss.h"
static struct { static struct {
...@@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) ...@@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
r = omap_dss_start_device(dssdev); r = omap_dss_start_device(dssdev);
if (r) { if (r) {
DSSERR("failed to start device\n"); DSSERR("failed to start device\n");
goto err0; goto err_start_dev;
} }
r = regulator_enable(sdi.vdds_sdi_reg); r = regulator_enable(sdi.vdds_sdi_reg);
if (r) 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); sdi_basic_init(dssdev);
...@@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *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, r = dss_calc_clock_div(1, t->pixel_clock * 1000,
&dss_cinfo, &dispc_cinfo); &dss_cinfo, &dispc_cinfo);
if (r) if (r)
goto err2; goto err_calc_clock_div;
fck = dss_cinfo.fck; fck = dss_cinfo.fck;
lck_div = dispc_cinfo.lck_div; lck_div = dispc_cinfo.lck_div;
...@@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) ...@@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
r = dss_set_clock_div(&dss_cinfo); r = dss_set_clock_div(&dss_cinfo);
if (r) if (r)
goto err2; goto err_set_dss_clock_div;
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r) if (r)
goto err2; goto err_set_dispc_clock_div;
dss_sdi_init(dssdev->phy.sdi.datapairs); dss_sdi_init(dssdev->phy.sdi.datapairs);
r = dss_sdi_enable(); r = dss_sdi_enable();
if (r) if (r)
goto err1; goto err_sdi_enable;
mdelay(2); mdelay(2);
dssdev->manager->enable(dssdev->manager); dssdev->manager->enable(dssdev->manager);
return 0; 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); regulator_disable(sdi.vdds_sdi_reg);
err1: err_reg_enable:
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
err0: err_start_dev:
return r; return r;
} }
EXPORT_SYMBOL(omapdss_sdi_display_enable); EXPORT_SYMBOL(omapdss_sdi_display_enable);
...@@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) ...@@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
dss_sdi_disable(); dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); dispc_runtime_put();
dss_runtime_put();
regulator_disable(sdi.vdds_sdi_reg); regulator_disable(sdi.vdds_sdi_reg);
......
...@@ -33,11 +33,13 @@ ...@@ -33,11 +33,13 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <plat/cpu.h> #include <plat/cpu.h>
#include "dss.h" #include "dss.h"
#include "dss_features.h"
/* Venc registers */ /* Venc registers */
#define VENC_REV_ID 0x00 #define VENC_REV_ID 0x00
...@@ -292,6 +294,9 @@ static struct { ...@@ -292,6 +294,9 @@ static struct {
struct mutex venc_lock; struct mutex venc_lock;
u32 wss_data; u32 wss_data;
struct regulator *vdda_dac_reg; struct regulator *vdda_dac_reg;
struct clk *tv_clk;
struct clk *tv_dac_clk;
} venc; } venc;
static inline void venc_write_reg(int idx, u32 val) static inline void venc_write_reg(int idx, u32 val)
...@@ -380,14 +385,25 @@ static void venc_reset(void) ...@@ -380,14 +385,25 @@ static void venc_reset(void)
#endif #endif
} }
static void venc_enable_clocks(int enable) static int venc_runtime_get(void)
{ {
if (enable) int r;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
DSS_CLK_VIDFCK); DSSDBG("venc_runtime_get\n");
else
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | r = pm_runtime_get_sync(&venc.pdev->dev);
DSS_CLK_VIDFCK); 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( static const struct venc_config *venc_timings_to_config(
...@@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev) ...@@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
{ {
u32 l; u32 l;
venc_enable_clocks(1);
venc_reset(); venc_reset();
venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
...@@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev) ...@@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
dssdev->platform_disable(dssdev); dssdev->platform_disable(dssdev);
regulator_disable(venc.vdda_dac_reg); regulator_disable(venc.vdda_dac_reg);
venc_enable_clocks(0);
} }
...@@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) ...@@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
goto err1; goto err1;
} }
r = venc_runtime_get();
if (r)
goto err1;
venc_power_on(dssdev); venc_power_on(dssdev);
venc.wss_data = 0; venc.wss_data = 0;
...@@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) ...@@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
venc_power_off(dssdev); venc_power_off(dssdev);
venc_runtime_put();
dssdev->state = OMAP_DSS_DISPLAY_DISABLED; dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
omap_dss_stop_device(dssdev); omap_dss_stop_device(dssdev);
...@@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev) ...@@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
return venc_panel_enable(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, static void venc_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings) struct omap_video_timings *timings)
{ {
...@@ -598,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev) ...@@ -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) static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{ {
const struct venc_config *config; const struct venc_config *config;
int r;
DSSDBG("venc_set_wss\n"); DSSDBG("venc_set_wss\n");
...@@ -608,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) ...@@ -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 */ /* Invert due to VENC_L21_WC_CTL:INV=1 */
venc.wss_data = (wss ^ 0xfffff) << 8; 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_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
venc.wss_data); venc.wss_data);
venc_enable_clocks(0); venc_runtime_put();
err:
mutex_unlock(&venc.venc_lock); mutex_unlock(&venc.venc_lock);
return 0; return r;
} }
static struct omap_dss_driver venc_driver = { static struct omap_dss_driver venc_driver = {
...@@ -632,9 +640,6 @@ 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_resolution = omapdss_default_get_resolution,
.get_recommended_bpp = omapdss_default_get_recommended_bpp, .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, .get_timings = venc_get_timings,
.set_timings = venc_set_timings, .set_timings = venc_set_timings,
.check_timings = venc_check_timings, .check_timings = venc_check_timings,
...@@ -673,7 +678,8 @@ void venc_dump_regs(struct seq_file *s) ...@@ -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)) #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_F_CONTROL);
DUMPREG(VENC_VIDOUT_CTRL); DUMPREG(VENC_VIDOUT_CTRL);
...@@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s) ...@@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s)
DUMPREG(VENC_OUTPUT_CONTROL); DUMPREG(VENC_OUTPUT_CONTROL);
DUMPREG(VENC_OUTPUT_TEST); DUMPREG(VENC_OUTPUT_TEST);
venc_enable_clocks(0); venc_runtime_put();
#undef DUMPREG #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 */ /* VENC HW IP initialisation */
static int omap_venchw_probe(struct platform_device *pdev) static int omap_venchw_probe(struct platform_device *pdev)
{ {
u8 rev_id; u8 rev_id;
struct resource *venc_mem; struct resource *venc_mem;
int r;
venc.pdev = pdev; venc.pdev = pdev;
...@@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev) ...@@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
if (!venc_mem) { if (!venc_mem) {
DSSERR("can't get IORESOURCE_MEM VENC\n"); 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)); venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
if (!venc.base) { if (!venc.base) {
DSSERR("can't ioremap VENC\n"); 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); rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); 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); 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) static int omap_venchw_remove(struct platform_device *pdev)
...@@ -763,16 +827,61 @@ 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); omap_dss_unregister_driver(&venc_driver);
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
iounmap(venc.base); iounmap(venc.base);
return 0; 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 = { static struct platform_driver omap_venchw_driver = {
.probe = omap_venchw_probe, .probe = omap_venchw_probe,
.remove = omap_venchw_remove, .remove = omap_venchw_remove,
.driver = { .driver = {
.name = "omapdss_venc", .name = "omapdss_venc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &venc_pm_ops,
}, },
}; };
......
...@@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi, ...@@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi,
} }
EXPORT_SYMBOL(omapfb_update_window); 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) enum omapfb_update_mode mode)
{ {
struct omap_dss_device *display = fb2display(fbi); 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; int r;
if (!display || !display->driver->set_update_mode) if (!display)
return -EINVAL; return -EINVAL;
switch (mode) { if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
case OMAPFB_UPDATE_DISABLED: return -EINVAL;
um = OMAP_DSS_UPDATE_DISABLED;
break;
case OMAPFB_AUTO_UPDATE: omapfb_lock(fbdev);
um = OMAP_DSS_UPDATE_AUTO;
break;
case OMAPFB_MANUAL_UPDATE: d = get_display_data(fbdev, display);
um = OMAP_DSS_UPDATE_MANUAL;
break;
default: if (d->update_mode == mode) {
return -EINVAL; omapfb_unlock(fbdev);
return 0;
}
r = 0;
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;
} }
r = display->driver->set_update_mode(display, um); omapfb_unlock(fbdev);
return r; return r;
} }
static int omapfb_get_update_mode(struct fb_info *fbi, int omapfb_get_update_mode(struct fb_info *fbi,
enum omapfb_update_mode *mode) enum omapfb_update_mode *mode)
{ {
struct omap_dss_device *display = fb2display(fbi); struct omap_dss_device *display = fb2display(fbi);
enum omap_dss_update_mode m; struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb_display_data *d;
if (!display) if (!display)
return -EINVAL; return -EINVAL;
if (!display->driver->get_update_mode) { omapfb_lock(fbdev);
*mode = OMAPFB_AUTO_UPDATE;
return 0;
}
m = display->driver->get_update_mode(display); d = get_display_data(fbdev, display);
switch (m) { *mode = d->update_mode;
case OMAP_DSS_UPDATE_DISABLED:
*mode = OMAPFB_UPDATE_DISABLED; omapfb_unlock(fbdev);
break;
case OMAP_DSS_UPDATE_AUTO:
*mode = OMAPFB_AUTO_UPDATE;
break;
case OMAP_DSS_UPDATE_MANUAL:
*mode = OMAPFB_MANUAL_UPDATE;
break;
default:
BUG();
}
return 0; return 0;
} }
......
...@@ -46,6 +46,10 @@ static char *def_vram; ...@@ -46,6 +46,10 @@ static char *def_vram;
static int def_vrfb; static int def_vrfb;
static int def_rotate; static int def_rotate;
static int def_mirror; 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 #ifdef DEBUG
unsigned int omapfb_debug; unsigned int omapfb_debug;
...@@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) ...@@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi); struct omap_dss_device *display = fb2display(fbi);
struct omapfb_display_data *d;
int r = 0; int r = 0;
if (!display) if (!display)
...@@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) ...@@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
omapfb_lock(fbdev); omapfb_lock(fbdev);
d = get_display_data(fbdev, display);
switch (blank) { switch (blank) {
case FB_BLANK_UNBLANK: case FB_BLANK_UNBLANK:
if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
...@@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi) ...@@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->driver->resume) if (display->driver->resume)
r = display->driver->resume(display); 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; break;
case FB_BLANK_NORMAL: case FB_BLANK_NORMAL:
...@@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) ...@@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
if (display->state != OMAP_DSS_DISPLAY_ACTIVE) if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
goto exit; goto exit;
if (d->auto_update_work_enabled)
omapfb_stop_auto_update(fbdev, display);
if (display->driver->suspend) if (display->driver->suspend)
r = display->driver->suspend(display); r = display->driver->suspend(display);
...@@ -1724,6 +1739,78 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) ...@@ -1724,6 +1739,78 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
return r; 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 */ /* 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) 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) ...@@ -1858,10 +1945,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
} }
for (i = 0; i < fbdev->num_displays; i++) { for (i = 0; i < fbdev->num_displays; i++) {
if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED) struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
fbdev->displays[i]->driver->disable(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);
}
omap_dss_put_device(fbdev->displays[i]); 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); dev_set_drvdata(fbdev->dev, NULL);
...@@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, ...@@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
int r; int r;
u8 bpp; u8 bpp;
struct omap_video_timings timings, temp_timings; struct omap_video_timings timings, temp_timings;
struct omapfb_display_data *d;
r = omapfb_mode_to_timings(mode_str, &timings, &bpp); r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
if (r) if (r)
return r; return r;
fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display; d = get_display_data(fbdev, display);
fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp; d->bpp_override = bpp;
++fbdev->num_bpp_overrides;
if (display->driver->check_timings) { if (display->driver->check_timings) {
r = display->driver->check_timings(display, &timings); r = display->driver->check_timings(display, &timings);
...@@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, ...@@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev, static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
struct omap_dss_device *dssdev) struct omap_dss_device *dssdev)
{ {
int i; struct omapfb_display_data *d;
BUG_ON(dssdev->driver->get_recommended_bpp == NULL); BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
for (i = 0; i < fbdev->num_bpp_overrides; ++i) { d = get_display_data(fbdev, dssdev);
if (dssdev == fbdev->bpp_overrides[i].dssdev)
return fbdev->bpp_overrides[i].bpp; if (d->bpp_override != 0)
} return d->bpp_override;
return dssdev->driver->get_recommended_bpp(dssdev); return dssdev->driver->get_recommended_bpp(dssdev);
} }
...@@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) ...@@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
display = NULL; display = NULL;
for (i = 0; i < fbdev->num_displays; ++i) { 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_str) == 0) {
display = fbdev->displays[i]; display = fbdev->displays[i].dssdev;
break; break;
} }
} }
...@@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, ...@@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
struct omap_dss_device *dssdev) struct omap_dss_device *dssdev)
{ {
struct omap_dss_driver *dssdrv = dssdev->driver; struct omap_dss_driver *dssdrv = dssdev->driver;
struct omapfb_display_data *d;
int r; int r;
r = dssdrv->enable(dssdev); r = dssdrv->enable(dssdev);
...@@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, ...@@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
return r; return r;
} }
d = get_display_data(fbdev, dssdev);
d->fbdev = fbdev;
if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
u16 w, h; 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) { if (dssdrv->enable_te) {
r = dssdrv->enable_te(dssdev, 1); r = dssdrv->enable_te(dssdev, 1);
if (r) { if (r) {
...@@ -2201,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, ...@@ -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); dssdrv->get_resolution(dssdev, &w, &h);
r = dssdrv->update(dssdev, 0, 0, w, h); r = dssdrv->update(dssdev, 0, 0, w, h);
if (r) { if (r) {
...@@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, ...@@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
return r; return r;
} }
} else { } else {
if (dssdrv->set_update_mode) { d->update_mode = OMAPFB_AUTO_UPDATE;
r = dssdrv->set_update_mode(dssdev,
OMAP_DSS_UPDATE_AUTO);
if (r) {
dev_err(fbdev->dev,
"Failed to set update mode\n");
return r;
}
}
} }
return 0; return 0;
...@@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev) ...@@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev)
fbdev->num_displays = 0; fbdev->num_displays = 0;
dssdev = NULL; dssdev = NULL;
for_each_dss_dev(dssdev) { for_each_dss_dev(dssdev) {
struct omapfb_display_data *d;
omap_dss_get_device(dssdev); omap_dss_get_device(dssdev);
if (!dssdev->driver) { if (!dssdev->driver) {
...@@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev) ...@@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev)
r = -ENODEV; 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) if (r)
......
...@@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev, ...@@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); 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[] = { static struct device_attribute omapfb_attrs[] = {
__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
store_rotate_type), store_rotate_type),
...@@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = { ...@@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
store_overlays_rotate), store_overlays_rotate),
__ATTR(phys_addr, S_IRUGO, show_phys, NULL), __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
__ATTR(virt_addr, S_IRUGO, show_virt, 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) int omapfb_create_sysfs(struct omapfb2_device *fbdev)
......
...@@ -73,6 +73,15 @@ struct omapfb_info { ...@@ -73,6 +73,15 @@ struct omapfb_info {
bool mirror; 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 omapfb2_device {
struct device *dev; struct device *dev;
struct mutex mtx; struct mutex mtx;
...@@ -86,17 +95,13 @@ struct omapfb2_device { ...@@ -86,17 +95,13 @@ struct omapfb2_device {
struct omapfb2_mem_region regions[10]; struct omapfb2_mem_region regions[10];
unsigned num_displays; unsigned num_displays;
struct omap_dss_device *displays[10]; struct omapfb_display_data displays[10];
unsigned num_overlays; unsigned num_overlays;
struct omap_overlay *overlays[10]; struct omap_overlay *overlays[10];
unsigned num_managers; unsigned num_managers;
struct omap_overlay_manager *managers[10]; struct omap_overlay_manager *managers[10];
unsigned num_bpp_overrides; struct workqueue_struct *auto_update_wq;
struct {
struct omap_dss_device *dssdev;
u8 bpp;
} bpp_overrides[10];
}; };
struct omapfb_colormode { struct omapfb_colormode {
...@@ -128,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode, ...@@ -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, int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh); 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 */ /* find the display connected to this fb, if any */
static inline struct omap_dss_device *fb2display(struct fb_info *fbi) 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) ...@@ -143,6 +155,19 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
return NULL; 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) static inline void omapfb_lock(struct omapfb2_device *fbdev)
{ {
mutex_lock(&fbdev->mtx); mutex_lock(&fbdev->mtx);
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/atomic.h>
#define DISPC_IRQ_FRAMEDONE (1 << 0) #define DISPC_IRQ_FRAMEDONE (1 << 0)
#define DISPC_IRQ_VSYNC (1 << 1) #define DISPC_IRQ_VSYNC (1 << 1)
...@@ -136,12 +134,6 @@ enum omap_display_caps { ...@@ -136,12 +134,6 @@ enum omap_display_caps {
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1, 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 { enum omap_dss_display_state {
OMAP_DSS_DISPLAY_DISABLED = 0, OMAP_DSS_DISPLAY_DISABLED = 0,
OMAP_DSS_DISPLAY_ACTIVE, OMAP_DSS_DISPLAY_ACTIVE,
...@@ -246,7 +238,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel); ...@@ -246,7 +238,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
/* Board specific data */ /* Board specific data */
struct omap_dss_board_info { 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; int num_devices;
struct omap_dss_device **devices; struct omap_dss_device **devices;
struct omap_dss_device *default_device; struct omap_dss_device *default_device;
...@@ -266,8 +258,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data) ...@@ -266,8 +258,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data)
struct omap_display_platform_data { struct omap_display_platform_data {
struct omap_dss_board_info *board_data; struct omap_dss_board_info *board_data;
/* TODO: Additional members to be added when PM is considered */ /* TODO: Additional members to be added when PM is considered */
bool (*opt_clock_available)(const char *clk_role);
}; };
struct omap_video_timings { struct omap_video_timings {
...@@ -300,6 +290,12 @@ extern const struct omap_video_timings omap_dss_pal_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; extern const struct omap_video_timings omap_dss_ntsc_timings;
#endif #endif
struct omap_dss_cpr_coefs {
s16 rr, rg, rb;
s16 gr, gg, gb;
s16 br, bg, bb;
};
struct omap_overlay_info { struct omap_overlay_info {
bool enabled; bool enabled;
...@@ -359,6 +355,9 @@ struct omap_overlay_manager_info { ...@@ -359,6 +355,9 @@ struct omap_overlay_manager_info {
bool trans_enabled; bool trans_enabled;
bool alpha_enabled; bool alpha_enabled;
bool cpr_enable;
struct omap_dss_cpr_coefs cpr_coefs;
}; };
struct omap_overlay_manager { struct omap_overlay_manager {
...@@ -526,11 +525,6 @@ struct omap_dss_driver { ...@@ -526,11 +525,6 @@ struct omap_dss_driver {
int (*resume)(struct omap_dss_device *display); int (*resume)(struct omap_dss_device *display);
int (*run_test)(struct omap_dss_device *display, int test); 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, int (*update)(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h); u16 x, u16 y, u16 w, u16 h);
int (*sync)(struct omap_dss_device *dssdev); int (*sync)(struct omap_dss_device *dssdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment