|
@@ -28,6 +28,8 @@
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/seq_file.h>
|
|
|
#include <linux/clk.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
|
|
#include <video/omapdss.h>
|
|
|
#include <plat/clock.h>
|
|
@@ -59,15 +61,9 @@ struct dss_reg {
|
|
|
static struct {
|
|
|
struct platform_device *pdev;
|
|
|
void __iomem *base;
|
|
|
- int ctx_id;
|
|
|
|
|
|
struct clk *dpll4_m4_ck;
|
|
|
- struct clk *dss_ick;
|
|
|
- struct clk *dss_fck;
|
|
|
- struct clk *dss_sys_clk;
|
|
|
- struct clk *dss_tv_fck;
|
|
|
- struct clk *dss_video_fck;
|
|
|
- unsigned num_clks_enabled;
|
|
|
+ struct clk *dss_clk;
|
|
|
|
|
|
unsigned long cache_req_pck;
|
|
|
unsigned long cache_prate;
|
|
@@ -78,6 +74,7 @@ static struct {
|
|
|
enum omap_dss_clk_source dispc_clk_source;
|
|
|
enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
|
|
|
|
|
|
+ bool ctx_valid;
|
|
|
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
|
|
|
} dss;
|
|
|
|
|
@@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = {
|
|
|
[OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
|
|
|
};
|
|
|
|
|
|
-static void dss_clk_enable_all_no_ctx(void);
|
|
|
-static void dss_clk_disable_all_no_ctx(void);
|
|
|
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
|
|
|
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
|
|
|
-
|
|
|
-static int _omap_dss_wait_reset(void);
|
|
|
-
|
|
|
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
|
|
|
{
|
|
|
__raw_writel(val, dss.base + idx.idx);
|
|
@@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx)
|
|
|
#define RR(reg) \
|
|
|
dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
|
|
|
|
|
|
-void dss_save_context(void)
|
|
|
+static void dss_save_context(void)
|
|
|
{
|
|
|
- if (cpu_is_omap24xx())
|
|
|
- return;
|
|
|
+ DSSDBG("dss_save_context\n");
|
|
|
|
|
|
- SR(SYSCONFIG);
|
|
|
SR(CONTROL);
|
|
|
|
|
|
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
|
@@ -122,14 +110,19 @@ void dss_save_context(void)
|
|
|
SR(SDI_CONTROL);
|
|
|
SR(PLL_CONTROL);
|
|
|
}
|
|
|
+
|
|
|
+ dss.ctx_valid = true;
|
|
|
+
|
|
|
+ DSSDBG("context saved\n");
|
|
|
}
|
|
|
|
|
|
-void dss_restore_context(void)
|
|
|
+static void dss_restore_context(void)
|
|
|
{
|
|
|
- if (_omap_dss_wait_reset())
|
|
|
- DSSERR("DSS not coming out of reset after sleep\n");
|
|
|
+ DSSDBG("dss_restore_context\n");
|
|
|
+
|
|
|
+ if (!dss.ctx_valid)
|
|
|
+ return;
|
|
|
|
|
|
- RR(SYSCONFIG);
|
|
|
RR(CONTROL);
|
|
|
|
|
|
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
|
|
@@ -137,6 +130,8 @@ void dss_restore_context(void)
|
|
|
RR(SDI_CONTROL);
|
|
|
RR(PLL_CONTROL);
|
|
|
}
|
|
|
+
|
|
|
+ DSSDBG("context restored\n");
|
|
|
}
|
|
|
|
|
|
#undef SR
|
|
@@ -234,6 +229,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
|
|
|
return dss_generic_clk_source_names[clk_src];
|
|
|
}
|
|
|
|
|
|
+
|
|
|
void dss_dump_clocks(struct seq_file *s)
|
|
|
{
|
|
|
unsigned long dpll4_ck_rate;
|
|
@@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s)
|
|
|
const char *fclk_name, *fclk_real_name;
|
|
|
unsigned long fclk_rate;
|
|
|
|
|
|
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
+ if (dss_runtime_get())
|
|
|
+ return;
|
|
|
|
|
|
seq_printf(s, "- DSS -\n");
|
|
|
|
|
|
fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
|
|
fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
|
|
|
- fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
|
|
|
+ fclk_rate = clk_get_rate(dss.dss_clk);
|
|
|
|
|
|
if (dss.dpll4_m4_ck) {
|
|
|
dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
|
@@ -273,14 +270,15 @@ void dss_dump_clocks(struct seq_file *s)
|
|
|
fclk_rate);
|
|
|
}
|
|
|
|
|
|
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
+ dss_runtime_put();
|
|
|
}
|
|
|
|
|
|
void dss_dump_regs(struct seq_file *s)
|
|
|
{
|
|
|
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
|
|
|
|
|
|
- dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
+ if (dss_runtime_get())
|
|
|
+ return;
|
|
|
|
|
|
DUMPREG(DSS_REVISION);
|
|
|
DUMPREG(DSS_SYSCONFIG);
|
|
@@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s)
|
|
|
DUMPREG(DSS_SDI_STATUS);
|
|
|
}
|
|
|
|
|
|
- dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
+ dss_runtime_put();
|
|
|
#undef DUMPREG
|
|
|
}
|
|
|
|
|
@@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
|
|
|
} else {
|
|
|
if (cinfo->fck_div != 0)
|
|
|
return -EINVAL;
|
|
|
- cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
|
|
|
+ cinfo->fck = clk_get_rate(dss.dss_clk);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
|
|
|
|
|
|
int dss_get_clock_div(struct dss_clock_info *cinfo)
|
|
|
{
|
|
|
- cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
|
|
|
+ cinfo->fck = clk_get_rate(dss.dss_clk);
|
|
|
|
|
|
if (dss.dpll4_m4_ck) {
|
|
|
unsigned long prate;
|
|
@@ -512,7 +510,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
|
|
|
|
|
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
|
|
|
|
|
- fck = dss_clk_get_rate(DSS_CLK_FCK);
|
|
|
+ fck = clk_get_rate(dss.dss_clk);
|
|
|
if (req_pck == dss.cache_req_pck &&
|
|
|
((cpu_is_omap34xx() && prate == dss.cache_prate) ||
|
|
|
dss.cache_dss_cinfo.fck == fck)) {
|
|
@@ -539,7 +537,7 @@ retry:
|
|
|
if (dss.dpll4_m4_ck == NULL) {
|
|
|
struct dispc_clock_info cur_dispc;
|
|
|
/* XXX can we change the clock on omap2? */
|
|
|
- fck = dss_clk_get_rate(DSS_CLK_FCK);
|
|
|
+ fck = clk_get_rate(dss.dss_clk);
|
|
|
fck_div = 1;
|
|
|
|
|
|
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
|
|
@@ -616,28 +614,6 @@ found:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int _omap_dss_wait_reset(void)
|
|
|
-{
|
|
|
- int t = 0;
|
|
|
-
|
|
|
- while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
|
|
|
- if (++t > 1000) {
|
|
|
- DSSERR("soft reset failed\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
- udelay(1);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int _omap_dss_reset(void)
|
|
|
-{
|
|
|
- /* Soft reset */
|
|
|
- REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
|
|
|
- return _omap_dss_wait_reset();
|
|
|
-}
|
|
|
-
|
|
|
void dss_set_venc_output(enum omap_dss_venc_type type)
|
|
|
{
|
|
|
int l = 0;
|
|
@@ -663,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 */
|
|
|
}
|
|
|
|
|
|
-static int dss_init(void)
|
|
|
+static int dss_get_clocks(void)
|
|
|
{
|
|
|
+ struct clk *clk;
|
|
|
int r;
|
|
|
- u32 rev;
|
|
|
- struct resource *dss_mem;
|
|
|
- struct clk *dpll4_m4_ck;
|
|
|
|
|
|
- dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
|
|
|
- if (!dss_mem) {
|
|
|
- DSSERR("can't get IORESOURCE_MEM DSS\n");
|
|
|
- r = -EINVAL;
|
|
|
- goto fail0;
|
|
|
- }
|
|
|
- dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
|
|
|
- if (!dss.base) {
|
|
|
- DSSERR("can't ioremap DSS\n");
|
|
|
- r = -ENOMEM;
|
|
|
- goto fail0;
|
|
|
+ clk = clk_get(&dss.pdev->dev, "fck");
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
+ DSSERR("can't get clock fck\n");
|
|
|
+ r = PTR_ERR(clk);
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- /* disable LCD and DIGIT output. This seems to fix the synclost
|
|
|
- * problem that we get, if the bootloader starts the DSS and
|
|
|
- * the kernel resets it */
|
|
|
- omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
|
|
|
-
|
|
|
-#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();
|
|
|
+ dss.dss_clk = clk;
|
|
|
|
|
|
- /* 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()) {
|
|
|
- dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
|
|
|
- if (IS_ERR(dpll4_m4_ck)) {
|
|
|
+ clk = clk_get(NULL, "dpll4_m4_ck");
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
DSSERR("Failed to get dpll4_m4_ck\n");
|
|
|
- r = PTR_ERR(dpll4_m4_ck);
|
|
|
- goto fail1;
|
|
|
+ r = PTR_ERR(clk);
|
|
|
+ goto err;
|
|
|
}
|
|
|
} else if (cpu_is_omap44xx()) {
|
|
|
- dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
|
|
|
- if (IS_ERR(dpll4_m4_ck)) {
|
|
|
- DSSERR("Failed to get dpll4_m4_ck\n");
|
|
|
- r = PTR_ERR(dpll4_m4_ck);
|
|
|
- goto fail1;
|
|
|
+ clk = clk_get(NULL, "dpll_per_m5x2_ck");
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
+ DSSERR("Failed to get dpll_per_m5x2_ck\n");
|
|
|
+ r = PTR_ERR(clk);
|
|
|
+ goto err;
|
|
|
}
|
|
|
} else { /* omap24xx */
|
|
|
- dpll4_m4_ck = NULL;
|
|
|
+ clk = 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));
|
|
|
+ dss.dpll4_m4_ck = clk;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
-fail1:
|
|
|
- iounmap(dss.base);
|
|
|
-fail0:
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-static void dss_exit(void)
|
|
|
-{
|
|
|
+err:
|
|
|
+ if (dss.dss_clk)
|
|
|
+ clk_put(dss.dss_clk);
|
|
|
if (dss.dpll4_m4_ck)
|
|
|
clk_put(dss.dpll4_m4_ck);
|
|
|
|
|
|
- iounmap(dss.base);
|
|
|
-}
|
|
|
-
|
|
|
-/* CONTEXT */
|
|
|
-static int dss_get_ctx_id(void)
|
|
|
-{
|
|
|
- struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
|
|
|
- int r;
|
|
|
-
|
|
|
- if (!pdata->board_data->get_last_off_on_transaction_id)
|
|
|
- return 0;
|
|
|
- r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
|
|
|
- if (r < 0) {
|
|
|
- dev_err(&dss.pdev->dev, "getting transaction ID failed, "
|
|
|
- "will force context restore\n");
|
|
|
- r = -1;
|
|
|
- }
|
|
|
- return r;
|
|
|
-}
|
|
|
-
|
|
|
-int dss_need_ctx_restore(void)
|
|
|
-{
|
|
|
- int id = dss_get_ctx_id();
|
|
|
-
|
|
|
- if (id < 0 || id != dss.ctx_id) {
|
|
|
- DSSDBG("ctx id %d -> id %d\n",
|
|
|
- dss.ctx_id, id);
|
|
|
- dss.ctx_id = id;
|
|
|
- return 1;
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void save_all_ctx(void)
|
|
|
-{
|
|
|
- DSSDBG("save context\n");
|
|
|
-
|
|
|
- dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
-
|
|
|
- dss_save_context();
|
|
|
- dispc_save_context();
|
|
|
-#ifdef CONFIG_OMAP2_DSS_DSI
|
|
|
- dsi_save_context();
|
|
|
-#endif
|
|
|
-
|
|
|
- dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
|
|
|
-}
|
|
|
-
|
|
|
-static void restore_all_ctx(void)
|
|
|
-{
|
|
|
- DSSDBG("restore context\n");
|
|
|
-
|
|
|
- dss_clk_enable_all_no_ctx();
|
|
|
-
|
|
|
- dss_restore_context();
|
|
|
- dispc_restore_context();
|
|
|
-#ifdef CONFIG_OMAP2_DSS_DSI
|
|
|
- dsi_restore_context();
|
|
|
-#endif
|
|
|
-
|
|
|
- dss_clk_disable_all_no_ctx();
|
|
|
-}
|
|
|
-
|
|
|
-static int dss_get_clock(struct clk **clock, const char *clk_name)
|
|
|
-{
|
|
|
- struct clk *clk;
|
|
|
-
|
|
|
- clk = clk_get(&dss.pdev->dev, clk_name);
|
|
|
-
|
|
|
- if (IS_ERR(clk)) {
|
|
|
- DSSERR("can't get clock %s", clk_name);
|
|
|
- return PTR_ERR(clk);
|
|
|
- }
|
|
|
-
|
|
|
- *clock = clk;
|
|
|
-
|
|
|
- DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int dss_get_clocks(void)
|
|
|
-{
|
|
|
- int r;
|
|
|
- struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
|
|
|
-
|
|
|
- dss.dss_ick = NULL;
|
|
|
- dss.dss_fck = NULL;
|
|
|
- dss.dss_sys_clk = NULL;
|
|
|
- dss.dss_tv_fck = NULL;
|
|
|
- dss.dss_video_fck = NULL;
|
|
|
-
|
|
|
- r = dss_get_clock(&dss.dss_ick, "ick");
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
-
|
|
|
- r = dss_get_clock(&dss.dss_fck, "fck");
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
-
|
|
|
- if (!pdata->opt_clock_available) {
|
|
|
- r = -ENODEV;
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- if (pdata->opt_clock_available("sys_clk")) {
|
|
|
- r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- if (pdata->opt_clock_available("tv_clk")) {
|
|
|
- r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- if (pdata->opt_clock_available("video_clk")) {
|
|
|
- r = dss_get_clock(&dss.dss_video_fck, "video_clk");
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-err:
|
|
|
- if (dss.dss_ick)
|
|
|
- clk_put(dss.dss_ick);
|
|
|
- if (dss.dss_fck)
|
|
|
- clk_put(dss.dss_fck);
|
|
|
- if (dss.dss_sys_clk)
|
|
|
- clk_put(dss.dss_sys_clk);
|
|
|
- if (dss.dss_tv_fck)
|
|
|
- clk_put(dss.dss_tv_fck);
|
|
|
- if (dss.dss_video_fck)
|
|
|
- clk_put(dss.dss_video_fck);
|
|
|
-
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
static void dss_put_clocks(void)
|
|
|
{
|
|
|
- if (dss.dss_video_fck)
|
|
|
- clk_put(dss.dss_video_fck);
|
|
|
- if (dss.dss_tv_fck)
|
|
|
- clk_put(dss.dss_tv_fck);
|
|
|
- if (dss.dss_sys_clk)
|
|
|
- clk_put(dss.dss_sys_clk);
|
|
|
- clk_put(dss.dss_fck);
|
|
|
- clk_put(dss.dss_ick);
|
|
|
-}
|
|
|
-
|
|
|
-unsigned long dss_clk_get_rate(enum dss_clock clk)
|
|
|
-{
|
|
|
- switch (clk) {
|
|
|
- case DSS_CLK_ICK:
|
|
|
- return clk_get_rate(dss.dss_ick);
|
|
|
- case DSS_CLK_FCK:
|
|
|
- return clk_get_rate(dss.dss_fck);
|
|
|
- case DSS_CLK_SYSCK:
|
|
|
- return clk_get_rate(dss.dss_sys_clk);
|
|
|
- case DSS_CLK_TVFCK:
|
|
|
- return clk_get_rate(dss.dss_tv_fck);
|
|
|
- case DSS_CLK_VIDFCK:
|
|
|
- return clk_get_rate(dss.dss_video_fck);
|
|
|
- }
|
|
|
-
|
|
|
- BUG();
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static unsigned count_clk_bits(enum dss_clock clks)
|
|
|
-{
|
|
|
- unsigned num_clks = 0;
|
|
|
-
|
|
|
- if (clks & DSS_CLK_ICK)
|
|
|
- ++num_clks;
|
|
|
- if (clks & DSS_CLK_FCK)
|
|
|
- ++num_clks;
|
|
|
- if (clks & DSS_CLK_SYSCK)
|
|
|
- ++num_clks;
|
|
|
- if (clks & DSS_CLK_TVFCK)
|
|
|
- ++num_clks;
|
|
|
- if (clks & DSS_CLK_VIDFCK)
|
|
|
- ++num_clks;
|
|
|
-
|
|
|
- return num_clks;
|
|
|
-}
|
|
|
-
|
|
|
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
|
|
|
-{
|
|
|
- unsigned num_clks = count_clk_bits(clks);
|
|
|
-
|
|
|
- if (clks & DSS_CLK_ICK)
|
|
|
- clk_enable(dss.dss_ick);
|
|
|
- if (clks & DSS_CLK_FCK)
|
|
|
- clk_enable(dss.dss_fck);
|
|
|
- if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
|
|
|
- clk_enable(dss.dss_sys_clk);
|
|
|
- if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
|
|
|
- clk_enable(dss.dss_tv_fck);
|
|
|
- if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
|
|
|
- clk_enable(dss.dss_video_fck);
|
|
|
-
|
|
|
- dss.num_clks_enabled += num_clks;
|
|
|
-}
|
|
|
-
|
|
|
-void dss_clk_enable(enum dss_clock clks)
|
|
|
-{
|
|
|
- bool check_ctx = dss.num_clks_enabled == 0;
|
|
|
-
|
|
|
- dss_clk_enable_no_ctx(clks);
|
|
|
-
|
|
|
- /*
|
|
|
- * HACK: On omap4 the registers may not be accessible right after
|
|
|
- * enabling the clocks. At some point this will be handled by
|
|
|
- * pm_runtime, but for the time begin this should make things work.
|
|
|
- */
|
|
|
- if (cpu_is_omap44xx() && check_ctx)
|
|
|
- udelay(10);
|
|
|
-
|
|
|
- if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
|
|
|
- restore_all_ctx();
|
|
|
+ if (dss.dpll4_m4_ck)
|
|
|
+ clk_put(dss.dpll4_m4_ck);
|
|
|
+ clk_put(dss.dss_clk);
|
|
|
}
|
|
|
|
|
|
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
|
|
|
+struct clk *dss_get_ick(void)
|
|
|
{
|
|
|
- unsigned num_clks = count_clk_bits(clks);
|
|
|
-
|
|
|
- if (clks & DSS_CLK_ICK)
|
|
|
- clk_disable(dss.dss_ick);
|
|
|
- if (clks & DSS_CLK_FCK)
|
|
|
- clk_disable(dss.dss_fck);
|
|
|
- if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
|
|
|
- clk_disable(dss.dss_sys_clk);
|
|
|
- if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
|
|
|
- clk_disable(dss.dss_tv_fck);
|
|
|
- if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
|
|
|
- clk_disable(dss.dss_video_fck);
|
|
|
-
|
|
|
- dss.num_clks_enabled -= num_clks;
|
|
|
+ return clk_get(&dss.pdev->dev, "ick");
|
|
|
}
|
|
|
|
|
|
-void dss_clk_disable(enum dss_clock clks)
|
|
|
+int dss_runtime_get(void)
|
|
|
{
|
|
|
- if (cpu_is_omap34xx()) {
|
|
|
- unsigned num_clks = count_clk_bits(clks);
|
|
|
-
|
|
|
- BUG_ON(dss.num_clks_enabled < num_clks);
|
|
|
+ int r;
|
|
|
|
|
|
- if (dss.num_clks_enabled == num_clks)
|
|
|
- save_all_ctx();
|
|
|
- }
|
|
|
+ DSSDBG("dss_runtime_get\n");
|
|
|
|
|
|
- dss_clk_disable_no_ctx(clks);
|
|
|
+ r = pm_runtime_get_sync(&dss.pdev->dev);
|
|
|
+ WARN_ON(r < 0);
|
|
|
+ return r < 0 ? r : 0;
|
|
|
}
|
|
|
|
|
|
-static void dss_clk_enable_all_no_ctx(void)
|
|
|
+void dss_runtime_put(void)
|
|
|
{
|
|
|
- enum dss_clock clks;
|
|
|
-
|
|
|
- clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
|
|
|
- if (cpu_is_omap34xx())
|
|
|
- clks |= DSS_CLK_VIDFCK;
|
|
|
- dss_clk_enable_no_ctx(clks);
|
|
|
-}
|
|
|
-
|
|
|
-static void dss_clk_disable_all_no_ctx(void)
|
|
|
-{
|
|
|
- enum dss_clock clks;
|
|
|
+ int r;
|
|
|
|
|
|
- clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
|
|
|
- if (cpu_is_omap34xx())
|
|
|
- clks |= DSS_CLK_VIDFCK;
|
|
|
- dss_clk_disable_no_ctx(clks);
|
|
|
-}
|
|
|
+ DSSDBG("dss_runtime_put\n");
|
|
|
|
|
|
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
|
|
-/* CLOCKS */
|
|
|
-static void core_dump_clocks(struct seq_file *s)
|
|
|
-{
|
|
|
- int i;
|
|
|
- struct clk *clocks[5] = {
|
|
|
- dss.dss_ick,
|
|
|
- dss.dss_fck,
|
|
|
- dss.dss_sys_clk,
|
|
|
- dss.dss_tv_fck,
|
|
|
- dss.dss_video_fck
|
|
|
- };
|
|
|
-
|
|
|
- const char *names[5] = {
|
|
|
- "ick",
|
|
|
- "fck",
|
|
|
- "sys_clk",
|
|
|
- "tv_fck",
|
|
|
- "video_fck"
|
|
|
- };
|
|
|
-
|
|
|
- seq_printf(s, "- CORE -\n");
|
|
|
-
|
|
|
- seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
|
|
|
-
|
|
|
- for (i = 0; i < 5; i++) {
|
|
|
- if (!clocks[i])
|
|
|
- continue;
|
|
|
- seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
|
|
|
- names[i],
|
|
|
- clocks[i]->name,
|
|
|
- 24 - strlen(names[i]) - strlen(clocks[i]->name),
|
|
|
- "",
|
|
|
- clk_get_rate(clocks[i]),
|
|
|
- clocks[i]->usecount);
|
|
|
- }
|
|
|
+ r = pm_runtime_put(&dss.pdev->dev);
|
|
|
+ WARN_ON(r < 0);
|
|
|
}
|
|
|
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
|
|
|
|
|
|
/* DEBUGFS */
|
|
|
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
|
|
void dss_debug_dump_clocks(struct seq_file *s)
|
|
|
{
|
|
|
- core_dump_clocks(s);
|
|
|
dss_dump_clocks(s);
|
|
|
dispc_dump_clocks(s);
|
|
|
#ifdef CONFIG_OMAP2_DSS_DSI
|
|
@@ -1089,28 +729,51 @@ void dss_debug_dump_clocks(struct seq_file *s)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-
|
|
|
/* DSS HW IP initialisation */
|
|
|
static int omap_dsshw_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
+ struct resource *dss_mem;
|
|
|
+ u32 rev;
|
|
|
int r;
|
|
|
|
|
|
dss.pdev = pdev;
|
|
|
|
|
|
+ dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
|
|
|
+ if (!dss_mem) {
|
|
|
+ DSSERR("can't get IORESOURCE_MEM DSS\n");
|
|
|
+ r = -EINVAL;
|
|
|
+ goto 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();
|
|
|
if (r)
|
|
|
goto err_clocks;
|
|
|
|
|
|
- dss_clk_enable_all_no_ctx();
|
|
|
+ pm_runtime_enable(&pdev->dev);
|
|
|
|
|
|
- dss.ctx_id = dss_get_ctx_id();
|
|
|
- DSSDBG("initial ctx id %u\n", dss.ctx_id);
|
|
|
+ r = dss_runtime_get();
|
|
|
+ if (r)
|
|
|
+ goto err_runtime_get;
|
|
|
|
|
|
- r = dss_init();
|
|
|
- if (r) {
|
|
|
- DSSERR("Failed to initialize DSS\n");
|
|
|
- goto err_dss;
|
|
|
- }
|
|
|
+ /* 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
|
|
|
+ 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();
|
|
|
if (r) {
|
|
@@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev)
|
|
|
goto err_sdi;
|
|
|
}
|
|
|
|
|
|
- dss_clk_disable_all_no_ctx();
|
|
|
+ rev = dss_read_reg(DSS_REVISION);
|
|
|
+ printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
|
|
+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
|
|
+
|
|
|
+ dss_runtime_put();
|
|
|
+
|
|
|
return 0;
|
|
|
err_sdi:
|
|
|
dpi_exit();
|
|
|
err_dpi:
|
|
|
- dss_exit();
|
|
|
-err_dss:
|
|
|
- dss_clk_disable_all_no_ctx();
|
|
|
+ dss_runtime_put();
|
|
|
+err_runtime_get:
|
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
|
dss_put_clocks();
|
|
|
err_clocks:
|
|
|
+ iounmap(dss.base);
|
|
|
+err_ioremap:
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
static int omap_dsshw_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
+ dpi_exit();
|
|
|
+ sdi_exit();
|
|
|
|
|
|
- dss_exit();
|
|
|
+ iounmap(dss.base);
|
|
|
|
|
|
- /*
|
|
|
- * As part of hwmod changes, DSS is not the only controller of dss
|
|
|
- * clocks; hwmod framework itself will also enable clocks during hwmod
|
|
|
- * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
|
|
|
- * need to disable clocks if their usecounts > 1.
|
|
|
- */
|
|
|
- WARN_ON(dss.num_clks_enabled > 0);
|
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
|
|
|
|
dss_put_clocks();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dss_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ dss_save_context();
|
|
|
+ clk_disable(dss.dss_clk);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int dss_runtime_resume(struct device *dev)
|
|
|
+{
|
|
|
+ clk_enable(dss.dss_clk);
|
|
|
+ dss_restore_context();
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct dev_pm_ops dss_pm_ops = {
|
|
|
+ .runtime_suspend = dss_runtime_suspend,
|
|
|
+ .runtime_resume = dss_runtime_resume,
|
|
|
+};
|
|
|
+
|
|
|
static struct platform_driver omap_dsshw_driver = {
|
|
|
.probe = omap_dsshw_probe,
|
|
|
.remove = omap_dsshw_remove,
|
|
|
.driver = {
|
|
|
.name = "omapdss_dss",
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .pm = &dss_pm_ops,
|
|
|
},
|
|
|
};
|
|
|
|