Commit 4fbafaf3 authored by Tomi Valkeinen's avatar Tomi Valkeinen

OMAP: DSS2: Use PM runtime & HWMOD support

Use PM runtime and HWMOD support to handle enabling and disabling of DSS
modules.

Each DSS module will have get and put functions which can be used to
enable and disable that module. The functions use pm_runtime and hwmod
opt-clocks to enable the hardware.
Acked-by: default avatarKevin Hilman <khilman@ti.com>
Signed-off-by: default avatarTomi Valkeinen <tomi.valkeinen@ti.com>
parent de3050a7
This diff is collapsed.
......@@ -23,7 +23,6 @@
#define DSS_SUBSYS_NAME "DPI"
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
......@@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
bool is_tft;
int r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
dssdev->panel.acbi, dssdev->panel.acb);
......@@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
&fck, &lck_div, &pck_div);
if (r)
goto err0;
return r;
pck = fck / lck_div / pck_div / 1000;
......@@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
dispc_set_lcd_timings(dssdev->manager->id, t);
err0:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return r;
return 0;
}
static int dpi_basic_init(struct omap_dss_device *dssdev)
static void dpi_basic_init(struct omap_dss_device *dssdev)
{
bool is_tft;
......@@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
dispc_set_tft_data_lines(dssdev->manager->id,
dssdev->phy.dpi.data_lines);
return 0;
}
int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
......@@ -186,30 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
goto err0;
goto err_start_dev;
}
if (cpu_is_omap34xx()) {
r = regulator_enable(dpi.vdds_dsi_reg);
if (r)
goto err1;
goto err_reg_enable;
}
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
r = dss_runtime_get();
if (r)
goto err_get_dss;
r = dpi_basic_init(dssdev);
r = dispc_runtime_get();
if (r)
goto err2;
goto err_get_dispc;
dpi_basic_init(dssdev);
if (dpi_use_dsi_pll(dssdev)) {
r = dsi_runtime_get(dpi.dsidev);
if (r)
goto err_get_dsi;
r = dsi_pll_init(dpi.dsidev, 0, 1);
if (r)
goto err2;
goto err_dsi_pll_init;
}
r = dpi_set_mode(dssdev);
if (r)
goto err3;
goto err_set_mode;
mdelay(2);
......@@ -217,16 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
return 0;
err3:
err_set_mode:
if (dpi_use_dsi_pll(dssdev))
dsi_pll_uninit(dpi.dsidev, true);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev))
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
dispc_runtime_put();
err_get_dispc:
dss_runtime_put();
err_get_dss:
if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg);
err1:
err_reg_enable:
omap_dss_stop_device(dssdev);
err0:
err_start_dev:
return r;
}
EXPORT_SYMBOL(omapdss_dpi_display_enable);
......@@ -238,9 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
if (dpi_use_dsi_pll(dssdev)) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true);
dsi_runtime_put(dpi.dsidev);
}
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
dispc_runtime_put();
dss_runtime_put();
if (cpu_is_omap34xx())
regulator_disable(dpi.vdds_dsi_reg);
......@@ -252,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable);
void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
int r;
DSSDBG("dpi_set_timings\n");
dssdev->panel.timings = *timings;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
r = dss_runtime_get();
if (r)
return;
r = dispc_runtime_get();
if (r) {
dss_runtime_put();
return;
}
dpi_set_mode(dssdev);
dispc_go(dssdev->manager->id);
dispc_runtime_put();
dss_runtime_put();
}
}
EXPORT_SYMBOL(dpi_set_timings);
......
This diff is collapsed.
This diff is collapsed.
......@@ -103,14 +103,6 @@ enum omap_parallel_interface_mode {
OMAP_DSS_PARALLELMODE_DSI,
};
enum dss_clock {
DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */
DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */
DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */
DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */
DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/
};
enum dss_hdmi_venc_clk_source_select {
DSS_VENC_TV_CLK = 0,
DSS_HDMI_M_PCLK = 1,
......@@ -214,12 +206,10 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
int dss_init_platform_driver(void);
void dss_uninit_platform_driver(void);
int dss_runtime_get(void);
void dss_runtime_put(void);
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);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s);
......@@ -276,15 +266,15 @@ struct file_operations;
int dsi_init_platform_driver(void);
void dsi_uninit_platform_driver(void);
int dsi_runtime_get(struct platform_device *dsidev);
void dsi_runtime_put(struct platform_device *dsidev);
void dsi_dump_clocks(struct seq_file *s);
void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
const struct file_operations *debug_fops);
void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
const struct file_operations *debug_fops);
void dsi_save_context(void);
void dsi_restore_context(void);
int dsi_init_display(struct omap_dss_device *display);
void dsi_irq_handler(void);
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
......@@ -310,6 +300,13 @@ static inline int dsi_init_platform_driver(void)
static inline void dsi_uninit_platform_driver(void)
{
}
static inline int dsi_runtime_get(struct platform_device *dsidev)
{
return 0;
}
static inline void dsi_runtime_put(struct platform_device *dsidev)
{
}
static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
{
WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
......@@ -377,8 +374,8 @@ void dispc_dump_regs(struct seq_file *s);
void dispc_irq_handler(void);
void dispc_fake_vsync_irq(void);
void dispc_save_context(void);
void dispc_restore_context(void);
int dispc_runtime_get(void);
void dispc_runtime_put(void);
void dispc_enable_sidle(void);
void dispc_disable_sidle(void);
......
......@@ -30,6 +30,8 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <video/omapdss.h>
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
......@@ -52,6 +54,9 @@ static struct {
u8 edid_set;
bool custom_set;
struct hdmi_config cfg;
struct clk *sys_clk;
struct clk *hdmi_clk;
} hdmi;
/*
......@@ -163,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
return val;
}
static int hdmi_runtime_get(void)
{
int r;
DSSDBG("hdmi_runtime_get\n");
r = pm_runtime_get_sync(&hdmi.pdev->dev);
WARN_ON(r < 0);
return r < 0 ? r : 0;
}
static void hdmi_runtime_put(void)
{
int r;
DSSDBG("hdmi_runtime_put\n");
r = pm_runtime_put(&hdmi.pdev->dev);
WARN_ON(r < 0);
}
int hdmi_init_display(struct omap_dss_device *dssdev)
{
DSSDBG("init_display\n");
......@@ -312,30 +338,11 @@ static int hdmi_phy_init(void)
return 0;
}
static int hdmi_wait_softreset(void)
{
/* reset W1 */
REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
/* wait till SOFTRESET == 0 */
if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
DSSERR("sysconfig reset failed\n");
return -ETIMEDOUT;
}
return 0;
}
static int hdmi_pll_program(struct hdmi_pll_info *fmt)
{
u16 r = 0;
enum hdmi_clk_refsel refsel;
/* wait for wrapper reset */
r = hdmi_wait_softreset();
if (r)
return r;
r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
if (r)
return r;
......@@ -1065,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
unsigned long clkin, refclk;
u32 mf;
clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
clkin = clk_get_rate(hdmi.sys_clk) / 10000;
/*
* Input clock is predivided by N + 1
* out put of which is reference clk
......@@ -1099,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
}
static void hdmi_enable_clocks(int enable)
{
if (enable)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
else
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
}
static int hdmi_power_on(struct omap_dss_device *dssdev)
{
int r, code = 0;
......@@ -1116,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
struct omap_video_timings *p;
unsigned long phy;
hdmi_enable_clocks(1);
r = hdmi_runtime_get();
if (r)
return r;
dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
......@@ -1181,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
return 0;
err:
hdmi_enable_clocks(0);
hdmi_runtime_put();
return -EIO;
}
......@@ -1192,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
hdmi_wp_video_start(0);
hdmi_phy_off();
hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
hdmi_enable_clocks(0);
hdmi_runtime_put();
hdmi.edid_set = 0;
}
......@@ -1687,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
};
#endif
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
hdmi.sys_clk = clk;
clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(clk)) {
DSSERR("can't get fck\n");
clk_put(hdmi.sys_clk);
return PTR_ERR(clk);
}
hdmi.hdmi_clk = clk;
return 0;
}
static void hdmi_put_clocks(void)
{
if (hdmi.sys_clk)
clk_put(hdmi.sys_clk);
if (hdmi.hdmi_clk)
clk_put(hdmi.hdmi_clk);
}
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
struct resource *hdmi_mem;
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
int ret;
#endif
int r;
hdmi.pdata = pdev->dev.platform_data;
hdmi.pdev = pdev;
......@@ -1714,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
return -ENOMEM;
}
r = hdmi_get_clocks(pdev);
if (r) {
iounmap(hdmi.base_wp);
return r;
}
pm_runtime_enable(&pdev->dev);
hdmi_panel_init();
#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
/* Register ASoC codec DAI */
ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
&hdmi_codec_dai_drv, 1);
if (ret) {
if (r) {
DSSERR("can't register ASoC HDMI audio codec\n");
return ret;
return r;
}
#endif
return 0;
......@@ -1739,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
snd_soc_unregister_codec(&pdev->dev);
#endif
pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();
iounmap(hdmi.base_wp);
return 0;
}
static int hdmi_runtime_suspend(struct device *dev)
{
clk_disable(hdmi.hdmi_clk);
clk_disable(hdmi.sys_clk);
dispc_runtime_put();
dss_runtime_put();
return 0;
}
static int hdmi_runtime_resume(struct device *dev)
{
int r;
r = dss_runtime_get();
if (r < 0)
goto err_get_dss;
r = dispc_runtime_get();
if (r < 0)
goto err_get_dispc;
clk_enable(hdmi.sys_clk);
clk_enable(hdmi.hdmi_clk);
return 0;
err_get_dispc:
dss_runtime_put();
err_get_dss:
return r;
}
static const struct dev_pm_ops hdmi_pm_ops = {
.runtime_suspend = hdmi_runtime_suspend,
.runtime_resume = hdmi_runtime_resume,
};
static struct platform_driver omapdss_hdmihw_driver = {
.probe = omapdss_hdmihw_probe,
.remove = omapdss_hdmihw_remove,
.driver = {
.name = "omapdss_hdmi",
.owner = THIS_MODULE,
.pm = &hdmi_pm_ops,
},
};
......
......@@ -1314,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
r = dispc_runtime_get();
if (r)
return r;
spin_lock_irqsave(&dss_cache.lock, flags);
/* Configure overlays */
......@@ -1458,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
}
r = 0;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
if (!dss_cache.irq_enabled) {
u32 mask;
......@@ -1471,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
dss_cache.irq_enabled = true;
}
configure_dispc();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
spin_unlock_irqrestore(&dss_cache.lock, flags);
dispc_runtime_put();
return r;
}
......
......@@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
old_mgr = ovl->manager;
r = dispc_runtime_get();
if (r)
return r;
/* detach old manager */
if (old_mgr) {
r = ovl->unset_manager(ovl);
if (r) {
DSSERR("detach failed\n");
return r;
goto err;
}
r = old_mgr->apply(old_mgr);
if (r)
return r;
goto err;
}
if (mgr) {
r = ovl->set_manager(ovl, mgr);
if (r) {
DSSERR("Failed to attach overlay\n");
return r;
goto err;
}
r = mgr->apply(mgr);
if (r)
return r;
goto err;
}
dispc_runtime_put();
return size;
err:
dispc_runtime_put();
return r;
}
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
......@@ -507,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
ovl->manager = mgr;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
/* XXX: When there is an overlay on a DSI manual update display, and
* the overlay is first disabled, then moved to tv, and enabled, we
* seem to get SYNC_LOST_DIGIT error.
......@@ -521,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
* the overlay, but before moving the overlay to TV.
*/
dispc_set_channel_out(ovl->id, mgr->id);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
return 0;
}
......@@ -722,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
}
if (mgr) {
dispc_runtime_get();
for (i = 0; i < dss_feat_get_num_ovls(); i++) {
struct omap_overlay *ovl;
ovl = omap_dss_get_overlay(i);
......@@ -731,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
omap_dss_set_manager(ovl, mgr);
}
}
dispc_runtime_put();
}
}
......
......@@ -34,6 +34,7 @@
#include <linux/seq_file.h>
#include <linux/semaphore.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h>
#include "dss.h"
......@@ -121,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
return __raw_readl(rfbi.base + idx.idx);
}
static void rfbi_enable_clocks(bool enable)
static int rfbi_runtime_get(void)
{
if (enable)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
else
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
int r;
DSSDBG("rfbi_runtime_get\n");
r = pm_runtime_get_sync(&rfbi.pdev->dev);
WARN_ON(r < 0);
return r < 0 ? r : 0;
}
static void rfbi_runtime_put(void)
{
int r;
DSSDBG("rfbi_runtime_put\n");
r = pm_runtime_put(&rfbi.pdev->dev);
WARN_ON(r < 0);
}
void rfbi_bus_lock(void)
......@@ -806,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
if (rfbi_runtime_get())
return;
DUMPREG(RFBI_REVISION);
DUMPREG(RFBI_SYSCONFIG);
......@@ -837,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
DUMPREG(RFBI_VSYNC_WIDTH);
DUMPREG(RFBI_HSYNC_WIDTH);
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
rfbi_runtime_put();
#undef DUMPREG
}
......@@ -845,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
{
int r;
rfbi_enable_clocks(1);
r = rfbi_runtime_get();
if (r)
return r;
r = omap_dss_start_device(dssdev);
if (r) {
......@@ -880,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
err1:
omap_dss_stop_device(dssdev);
err0:
rfbi_runtime_put();
return r;
}
EXPORT_SYMBOL(omapdss_rfbi_display_enable);
......@@ -890,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
DISPC_IRQ_FRAMEDONE);
omap_dss_stop_device(dssdev);
rfbi_enable_clocks(0);
rfbi_runtime_put();
}
EXPORT_SYMBOL(omapdss_rfbi_display_disable);
......@@ -905,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
static int omap_rfbihw_probe(struct platform_device *pdev)
{
u32 rev;
u32 l;
struct resource *rfbi_mem;
struct clk *clk;
int r;
rfbi.pdev = pdev;
......@@ -915,46 +934,99 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
if (!rfbi_mem) {
DSSERR("can't get IORESOURCE_MEM RFBI\n");
return -EINVAL;
r = -EINVAL;
goto err_ioremap;
}
rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
if (!rfbi.base) {
DSSERR("can't ioremap RFBI\n");
return -ENOMEM;
r = -ENOMEM;
goto err_ioremap;
}
rfbi_enable_clocks(1);
pm_runtime_enable(&pdev->dev);
r = rfbi_runtime_get();
if (r)
goto err_get_rfbi;
msleep(10);
rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
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 */
l = rfbi_read_reg(RFBI_SYSCONFIG);
l |= (1 << 0) | (2 << 3);
rfbi_write_reg(RFBI_SYSCONFIG, l);
clk_put(clk);
rev = rfbi_read_reg(RFBI_REVISION);
dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
rfbi_enable_clocks(0);
rfbi_runtime_put();
return 0;
err_get_ick:
rfbi_runtime_put();
err_get_rfbi:
pm_runtime_disable(&pdev->dev);
iounmap(rfbi.base);
err_ioremap:
return r;
}
static int omap_rfbihw_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
iounmap(rfbi.base);
return 0;
}
static int rfbi_runtime_suspend(struct device *dev)
{
dispc_runtime_put();
dss_runtime_put();
return 0;
}
static int rfbi_runtime_resume(struct device *dev)
{
int r;
r = dss_runtime_get();
if (r < 0)
goto err_get_dss;
r = dispc_runtime_get();
if (r < 0)
goto err_get_dispc;
return 0;
err_get_dispc:
dss_runtime_put();
err_get_dss:
return r;
}
static const struct dev_pm_ops rfbi_pm_ops = {
.runtime_suspend = rfbi_runtime_suspend,
.runtime_resume = rfbi_runtime_resume,
};
static struct platform_driver omap_rfbihw_driver = {
.probe = omap_rfbihw_probe,
.remove = omap_rfbihw_remove,
.driver = {
.name = "omapdss_rfbi",
.owner = THIS_MODULE,
.pm = &rfbi_pm_ops,
},
};
......
......@@ -20,13 +20,11 @@
#define DSS_SUBSYS_NAME "SDI"
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
#include "dss.h"
static struct {
......@@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
goto err0;
goto err_start_dev;
}
r = regulator_enable(sdi.vdds_sdi_reg);
if (r)
goto err1;
goto err_reg_enable;
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
r = dss_runtime_get();
if (r)
goto err_get_dss;
r = dispc_runtime_get();
if (r)
goto err_get_dispc;
sdi_basic_init(dssdev);
......@@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
&dss_cinfo, &dispc_cinfo);
if (r)
goto err2;
goto err_calc_clock_div;
fck = dss_cinfo.fck;
lck_div = dispc_cinfo.lck_div;
......@@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
r = dss_set_clock_div(&dss_cinfo);
if (r)
goto err2;
goto err_set_dss_clock_div;
r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
if (r)
goto err2;
goto err_set_dispc_clock_div;
dss_sdi_init(dssdev->phy.sdi.datapairs);
r = dss_sdi_enable();
if (r)
goto err1;
goto err_sdi_enable;
mdelay(2);
dssdev->manager->enable(dssdev->manager);
return 0;
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
err_sdi_enable:
err_set_dispc_clock_div:
err_set_dss_clock_div:
err_calc_clock_div:
dispc_runtime_put();
err_get_dispc:
dss_runtime_put();
err_get_dss:
regulator_disable(sdi.vdds_sdi_reg);
err1:
err_reg_enable:
omap_dss_stop_device(dssdev);
err0:
err_start_dev:
return r;
}
EXPORT_SYMBOL(omapdss_sdi_display_enable);
......@@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
dispc_runtime_put();
dss_runtime_put();
regulator_disable(sdi.vdds_sdi_reg);
......
......@@ -33,6 +33,7 @@
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <video/omapdss.h>
#include <plat/cpu.h>
......@@ -293,6 +294,9 @@ static struct {
struct mutex venc_lock;
u32 wss_data;
struct regulator *vdda_dac_reg;
struct clk *tv_clk;
struct clk *tv_dac_clk;
} venc;
static inline void venc_write_reg(int idx, u32 val)
......@@ -381,17 +385,25 @@ static void venc_reset(void)
#endif
}
static void venc_enable_clocks(int enable)
static int venc_runtime_get(void)
{
if (enable) {
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK);
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK))
dss_clk_enable(DSS_CLK_VIDFCK);
} else {
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK);
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK))
dss_clk_disable(DSS_CLK_VIDFCK);
}
int r;
DSSDBG("venc_runtime_get\n");
r = pm_runtime_get_sync(&venc.pdev->dev);
WARN_ON(r < 0);
return r < 0 ? r : 0;
}
static void venc_runtime_put(void)
{
int r;
DSSDBG("venc_runtime_put\n");
r = pm_runtime_put(&venc.pdev->dev);
WARN_ON(r < 0);
}
static const struct venc_config *venc_timings_to_config(
......@@ -410,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
{
u32 l;
venc_enable_clocks(1);
venc_reset();
venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
......@@ -452,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
dssdev->platform_disable(dssdev);
regulator_disable(venc.vdda_dac_reg);
venc_enable_clocks(0);
}
......@@ -491,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
goto err1;
}
r = venc_runtime_get();
if (r)
goto err1;
venc_power_on(dssdev);
venc.wss_data = 0;
......@@ -524,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
venc_power_off(dssdev);
venc_runtime_put();
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
omap_dss_stop_device(dssdev);
......@@ -588,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev)
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
{
const struct venc_config *config;
int r;
DSSDBG("venc_set_wss\n");
......@@ -598,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
/* Invert due to VENC_L21_WC_CTL:INV=1 */
venc.wss_data = (wss ^ 0xfffff) << 8;
venc_enable_clocks(1);
r = venc_runtime_get();
if (r)
goto err;
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
venc.wss_data);
venc_enable_clocks(0);
venc_runtime_put();
err:
mutex_unlock(&venc.venc_lock);
return 0;
return r;
}
static struct omap_dss_driver venc_driver = {
......@@ -660,7 +678,8 @@ void venc_dump_regs(struct seq_file *s)
{
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
venc_enable_clocks(1);
if (venc_runtime_get())
return;
DUMPREG(VENC_F_CONTROL);
DUMPREG(VENC_VIDOUT_CTRL);
......@@ -704,16 +723,53 @@ void venc_dump_regs(struct seq_file *s)
DUMPREG(VENC_OUTPUT_CONTROL);
DUMPREG(VENC_OUTPUT_TEST);
venc_enable_clocks(0);
venc_runtime_put();
#undef DUMPREG
}
static int venc_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(clk)) {
DSSERR("can't get fck\n");
return PTR_ERR(clk);
}
venc.tv_clk = clk;
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
clk = clk_get(&pdev->dev, "tv_dac_clk");
if (IS_ERR(clk)) {
DSSERR("can't get tv_dac_clk\n");
clk_put(venc.tv_clk);
return PTR_ERR(clk);
}
} else {
clk = NULL;
}
venc.tv_dac_clk = clk;
return 0;
}
static void venc_put_clocks(void)
{
if (venc.tv_clk)
clk_put(venc.tv_clk);
if (venc.tv_dac_clk)
clk_put(venc.tv_dac_clk);
}
/* VENC HW IP initialisation */
static int omap_venchw_probe(struct platform_device *pdev)
{
u8 rev_id;
struct resource *venc_mem;
int r;
venc.pdev = pdev;
......@@ -724,22 +780,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
if (!venc_mem) {
DSSERR("can't get IORESOURCE_MEM VENC\n");
return -EINVAL;
r = -EINVAL;
goto err_ioremap;
}
venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
if (!venc.base) {
DSSERR("can't ioremap VENC\n");
return -ENOMEM;
r = -ENOMEM;
goto err_ioremap;
}
venc_enable_clocks(1);
r = venc_get_clocks(pdev);
if (r)
goto err_get_clk;
pm_runtime_enable(&pdev->dev);
r = venc_runtime_get();
if (r)
goto err_get_venc;
rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
venc_enable_clocks(0);
venc_runtime_put();
return omap_dss_register_driver(&venc_driver);
err_get_venc:
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
err_get_clk:
iounmap(venc.base);
err_ioremap:
return r;
}
static int omap_venchw_remove(struct platform_device *pdev)
......@@ -750,16 +824,61 @@ static int omap_venchw_remove(struct platform_device *pdev)
}
omap_dss_unregister_driver(&venc_driver);
pm_runtime_disable(&pdev->dev);
venc_put_clocks();
iounmap(venc.base);
return 0;
}
static int venc_runtime_suspend(struct device *dev)
{
if (venc.tv_dac_clk)
clk_disable(venc.tv_dac_clk);
clk_disable(venc.tv_clk);
dispc_runtime_put();
dss_runtime_put();
return 0;
}
static int venc_runtime_resume(struct device *dev)
{
int r;
r = dss_runtime_get();
if (r < 0)
goto err_get_dss;
r = dispc_runtime_get();
if (r < 0)
goto err_get_dispc;
clk_enable(venc.tv_clk);
if (venc.tv_dac_clk)
clk_enable(venc.tv_dac_clk);
return 0;
err_get_dispc:
dss_runtime_put();
err_get_dss:
return r;
}
static const struct dev_pm_ops venc_pm_ops = {
.runtime_suspend = venc_runtime_suspend,
.runtime_resume = venc_runtime_resume,
};
static struct platform_driver omap_venchw_driver = {
.probe = omap_venchw_probe,
.remove = omap_venchw_remove,
.driver = {
.name = "omapdss_venc",
.owner = THIS_MODULE,
.pm = &venc_pm_ops,
},
};
......
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