summaryrefslogtreecommitdiff
path: root/drivers/gpu/imx/dpu
diff options
context:
space:
mode:
authorLiu Ying <victor.liu@nxp.com>2017-10-13 13:08:41 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commitb537950819a18ced5bd76cdf8f949c39c0d1461d (patch)
tree9552481a4c67bf07571db328be0aaa9c4b1bff5b /drivers/gpu/imx/dpu
parentc789f3f42eec7b3b215990a3fd935ff52adec723 (diff)
MLK-16581-6 gpu: imx: dpu: Add system power management support
The dpu core driver currently depends on the client drivers to do suspend operations to leave dpu a cleaned up state machine status before the system enters sleep mode. When the system resumes, the dpu core driver resume operation will re-initialize the machine state by enabling intsteer lines, re-initializing pixel links and re-initializing dpu sub-units. Signed-off-by: Liu Ying <victor.liu@nxp.com>
Diffstat (limited to 'drivers/gpu/imx/dpu')
-rw-r--r--drivers/gpu/imx/dpu/dpu-common.c62
-rw-r--r--drivers/gpu/imx/dpu/dpu-constframe.c16
-rw-r--r--drivers/gpu/imx/dpu/dpu-disengcfg.c4
-rw-r--r--drivers/gpu/imx/dpu/dpu-extdst.c34
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchdecode.c32
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetcheco.c29
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchlayer.c4
-rw-r--r--drivers/gpu/imx/dpu/dpu-framegen.c35
-rw-r--r--drivers/gpu/imx/dpu/dpu-hscaler.c22
-rw-r--r--drivers/gpu/imx/dpu/dpu-layerblend.c28
-rw-r--r--drivers/gpu/imx/dpu/dpu-prv.h15
-rw-r--r--drivers/gpu/imx/dpu/dpu-tcon.c4
-rw-r--r--drivers/gpu/imx/dpu/dpu-vscaler.c28
13 files changed, 271 insertions, 42 deletions
diff --git a/drivers/gpu/imx/dpu/dpu-common.c b/drivers/gpu/imx/dpu/dpu-common.c
index ff8dd52e0624..b14ce5414d8a 100644
--- a/drivers/gpu/imx/dpu/dpu-common.c
+++ b/drivers/gpu/imx/dpu/dpu-common.c
@@ -648,6 +648,39 @@ int dpu_format_plane_height(int height, u32 format, int plane)
return height / dpu_format_vert_chroma_subsampling(format);
}
+#define _DPU_UNITS_INIT(unit) \
+{ \
+ const struct dpu_unit *us = devtype->unit##s; \
+ int i; \
+ \
+ /* software check */ \
+ if (WARN_ON(us->num > ARRAY_SIZE(unit##_ids))) \
+ return -EINVAL; \
+ \
+ for (i = 0; i < us->num; i++) \
+ _dpu_##unit##_init(dpu, us->ids[i]); \
+}
+
+static int
+_dpu_submodules_init(struct dpu_soc *dpu, struct platform_device *pdev)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+
+ _DPU_UNITS_INIT(cf);
+ _DPU_UNITS_INIT(dec);
+ _DPU_UNITS_INIT(ed);
+ _DPU_UNITS_INIT(fd);
+ _DPU_UNITS_INIT(fe);
+ _DPU_UNITS_INIT(fg);
+ _DPU_UNITS_INIT(fl);
+ _DPU_UNITS_INIT(hs);
+ _DPU_UNITS_INIT(lb);
+ _DPU_UNITS_INIT(tcon);
+ _DPU_UNITS_INIT(vs);
+
+ return 0;
+}
+
#define DPU_UNIT_INIT(dpu, base, unit, name, id, pec_ofs, ofs) \
{ \
int ret; \
@@ -1509,8 +1542,37 @@ static int dpu_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int dpu_suspend(struct device *dev)
+{
+ /*
+ * The dpu core driver currently depends on the client drivers
+ * to do suspend operations to leave dpu a cleaned up state
+ * machine status before the system enters sleep mode.
+ */
+ return 0;
+}
+
+static int dpu_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dpu_soc *dpu = platform_get_drvdata(pdev);
+
+ dpu_intsteer_enable_lines(dpu);
+
+ dpu_pixel_link_init(dpu->id);
+
+ _dpu_submodules_init(dpu, pdev);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dpu_pm_ops, dpu_suspend, dpu_resume);
+
static struct platform_driver dpu_driver = {
.driver = {
+ .pm = &dpu_pm_ops,
.name = "dpu-core",
.of_match_table = dpu_dt_ids,
},
diff --git a/drivers/gpu/imx/dpu/dpu-constframe.c b/drivers/gpu/imx/dpu/dpu-constframe.c
index 77718cdd1d6d..1290545809e8 100644
--- a/drivers/gpu/imx/dpu/dpu-constframe.c
+++ b/drivers/gpu/imx/dpu/dpu-constframe.c
@@ -166,6 +166,20 @@ void dpu_cf_put(struct dpu_constframe *cf)
}
EXPORT_SYMBOL_GPL(dpu_cf_put);
+void _dpu_cf_init(struct dpu_soc *dpu, unsigned int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+ if (cf_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(cf_ids)))
+ return;
+
+ constframe_shden(dpu->cf_priv[i], true);
+}
+
int dpu_cf_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -196,7 +210,7 @@ int dpu_cf_init(struct dpu_soc *dpu, unsigned int id,
mutex_init(&cf->mutex);
- constframe_shden(cf, true);
+ _dpu_cf_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-disengcfg.c b/drivers/gpu/imx/dpu/dpu-disengcfg.c
index 05688929b2c5..007da25d4f98 100644
--- a/drivers/gpu/imx/dpu/dpu-disengcfg.c
+++ b/drivers/gpu/imx/dpu/dpu-disengcfg.c
@@ -115,6 +115,10 @@ void dpu_dec_put(struct dpu_disengcfg *dec)
}
EXPORT_SYMBOL_GPL(dpu_dec_put);
+void _dpu_dec_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
int dpu_dec_init(struct dpu_soc *dpu, unsigned int id,
unsigned long unused, unsigned long base)
{
diff --git a/drivers/gpu/imx/dpu/dpu-extdst.c b/drivers/gpu/imx/dpu/dpu-extdst.c
index fdb85723c668..ab79fe6a02c8 100644
--- a/drivers/gpu/imx/dpu/dpu-extdst.c
+++ b/drivers/gpu/imx/dpu/dpu-extdst.c
@@ -440,6 +440,31 @@ void dpu_ed_put(struct dpu_extdst *ed)
}
EXPORT_SYMBOL_GPL(dpu_ed_put);
+void _dpu_ed_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_extdst *ed;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+ if (ed_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(ed_ids)))
+ return;
+
+ ed = dpu->ed_priv[i];
+
+ extdst_pixengcfg_src_sel(ed, ED_SRC_DISABLE);
+ extdst_pixengcfg_shden(ed, true);
+ extdst_pixengcfg_powerdown(ed, false);
+ extdst_pixengcfg_sync_mode(ed, SINGLE);
+ extdst_pixengcfg_reset(ed, false);
+ extdst_pixengcfg_div(ed, DIV_RESET);
+ extdst_shden(ed, true);
+ extdst_perfcountmode(ed, false);
+ extdst_kick_mode(ed, EXTERNAL);
+}
+
int dpu_ed_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -472,14 +497,7 @@ int dpu_ed_init(struct dpu_soc *dpu, unsigned int id,
if (ret < 0)
return ret;
- extdst_pixengcfg_shden(ed, true);
- extdst_pixengcfg_powerdown(ed, false);
- extdst_pixengcfg_sync_mode(ed, SINGLE);
- extdst_pixengcfg_reset(ed, false);
- extdst_pixengcfg_div(ed, DIV_RESET);
- extdst_shden(ed, true);
- extdst_perfcountmode(ed, false);
- extdst_kick_mode(ed, EXTERNAL);
+ _dpu_ed_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-fetchdecode.c b/drivers/gpu/imx/dpu/dpu-fetchdecode.c
index c28e110ec7a6..fe5dd37dbedf 100644
--- a/drivers/gpu/imx/dpu/dpu-fetchdecode.c
+++ b/drivers/gpu/imx/dpu/dpu-fetchdecode.c
@@ -714,6 +714,30 @@ void dpu_fd_put(struct dpu_fetchdecode *fd)
}
EXPORT_SYMBOL_GPL(dpu_fd_put);
+void _dpu_fd_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetchdecode *fd;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fd_ids); i++)
+ if (fd_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fd_ids)))
+ return;
+
+ fd = dpu->fd_priv[i];
+
+ fetchdecode_pixengcfg_dynamic_src_sel(fd, FD_SRC_DISABLE);
+ fetchdecode_baddr_autoupdate(fd, 0x0);
+ fetchdecode_shden(fd, true);
+
+ mutex_lock(&fd->mutex);
+ dpu_fd_write(fd, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fd->mutex);
+}
+
int dpu_fd_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -752,13 +776,7 @@ int dpu_fd_init(struct dpu_soc *dpu, unsigned int id,
if (ret < 0)
return ret;
- fetchdecode_baddr_autoupdate(fd, 0x0);
- fetchdecode_shden(fd, true);
-
- mutex_lock(&fd->mutex);
- dpu_fd_write(fd, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
- BURSTBUFFERMANAGEMENT);
- mutex_unlock(&fd->mutex);
+ _dpu_fd_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-fetcheco.c b/drivers/gpu/imx/dpu/dpu-fetcheco.c
index c3ac6fd7cdf2..28d6e80afe89 100644
--- a/drivers/gpu/imx/dpu/dpu-fetcheco.c
+++ b/drivers/gpu/imx/dpu/dpu-fetcheco.c
@@ -478,6 +478,28 @@ void dpu_fe_put(struct dpu_fetcheco *fe)
}
EXPORT_SYMBOL_GPL(dpu_fe_put);
+void _dpu_fe_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetcheco *fe;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+ if (fe_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fe_ids)))
+ return;
+
+ fe = dpu->fe_priv[i];
+
+ fetcheco_shden(fe, true);
+
+ mutex_lock(&fe->mutex);
+ dpu_fe_write(fe, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fe->mutex);
+}
+
int dpu_fe_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -506,12 +528,7 @@ int dpu_fe_init(struct dpu_soc *dpu, unsigned int id,
fe->id = id;
mutex_init(&fe->mutex);
- fetcheco_shden(fe, true);
-
- mutex_lock(&fe->mutex);
- dpu_fe_write(fe, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
- BURSTBUFFERMANAGEMENT);
- mutex_unlock(&fe->mutex);
+ _dpu_fe_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-fetchlayer.c b/drivers/gpu/imx/dpu/dpu-fetchlayer.c
index fdc8c1437888..4fe74ee3cd58 100644
--- a/drivers/gpu/imx/dpu/dpu-fetchlayer.c
+++ b/drivers/gpu/imx/dpu/dpu-fetchlayer.c
@@ -257,6 +257,10 @@ void dpu_fl_put(struct dpu_fetchlayer *fl)
}
EXPORT_SYMBOL_GPL(dpu_fl_put);
+void _dpu_fl_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
int dpu_fl_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
diff --git a/drivers/gpu/imx/dpu/dpu-framegen.c b/drivers/gpu/imx/dpu/dpu-framegen.c
index b068e7ca313c..d7dba5a3c8d0 100644
--- a/drivers/gpu/imx/dpu/dpu-framegen.c
+++ b/drivers/gpu/imx/dpu/dpu-framegen.c
@@ -261,6 +261,9 @@ void framegen_cfg_videomode(struct dpu_framegen *fg, struct drm_display_mode *m)
dpu_fg_write(fg, 0, FGCCR);
mutex_unlock(&fg->mutex);
+ clk_get_rate(fg->clk_pll);
+ clk_get_rate(fg->clk_disp);
+
disp_clock_rate = m->clock * 1000;
if (devtype->version == DPU_V1) {
@@ -412,11 +415,33 @@ void dpu_fg_put(struct dpu_framegen *fg)
}
EXPORT_SYMBOL_GPL(dpu_fg_put);
+void _dpu_fg_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_framegen *fg;
+ u32 val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fg_ids); i++)
+ if (fg_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fg_ids)))
+ return;
+
+ fg = dpu->fg_priv[i];
+
+ mutex_lock(&fg->mutex);
+ val = dpu_fg_read(fg, FGSTCTRL);
+ val &= ~FGSYNCMODE_MASK;
+ val |= FGSYNCMODE__OFF;
+ dpu_fg_write(fg, val, FGSTCTRL);
+ mutex_unlock(&fg->mutex);
+}
+
int dpu_fg_init(struct dpu_soc *dpu, unsigned int id,
unsigned long unused, unsigned long base)
{
struct dpu_framegen *fg;
- u32 val;
fg = devm_kzalloc(dpu->dev, sizeof(*fg), GFP_KERNEL);
if (!fg)
@@ -440,13 +465,7 @@ int dpu_fg_init(struct dpu_soc *dpu, unsigned int id,
fg->id = id;
mutex_init(&fg->mutex);
- mutex_lock(&fg->mutex);
- val = dpu_fg_read(fg, FGSTCTRL);
- val &= ~FGSYNCMODE_MASK;
- val |= FGSYNCMODE__OFF;
- dpu_fg_write(fg, val, FGSTCTRL);
-
- mutex_unlock(&fg->mutex);
+ _dpu_fg_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-hscaler.c b/drivers/gpu/imx/dpu/dpu-hscaler.c
index 1ce92d6ee97b..d9e34bce46bc 100644
--- a/drivers/gpu/imx/dpu/dpu-hscaler.c
+++ b/drivers/gpu/imx/dpu/dpu-hscaler.c
@@ -338,6 +338,25 @@ void dpu_hs_put(struct dpu_hscaler *hs)
}
EXPORT_SYMBOL_GPL(dpu_hs_put);
+void _dpu_hs_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_hscaler *hs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+ if (hs_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(hs_ids)))
+ return;
+
+ hs = dpu->hs_priv[i];
+
+ hscaler_shden(hs, true);
+ hscaler_setup2(hs, 0);
+ hscaler_pixengcfg_dynamic_src_sel(hs, HS_SRC_SEL__DISABLE);
+}
+
int dpu_hs_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -367,8 +386,7 @@ int dpu_hs_init(struct dpu_soc *dpu, unsigned int id,
mutex_init(&hs->mutex);
- hscaler_shden(hs, true);
- hscaler_setup2(hs, 0);
+ _dpu_hs_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-layerblend.c b/drivers/gpu/imx/dpu/dpu-layerblend.c
index bc78299bb7a4..f09b58172f82 100644
--- a/drivers/gpu/imx/dpu/dpu-layerblend.c
+++ b/drivers/gpu/imx/dpu/dpu-layerblend.c
@@ -346,6 +346,28 @@ void dpu_lb_put(struct dpu_layerblend *lb)
}
EXPORT_SYMBOL_GPL(dpu_lb_put);
+void _dpu_lb_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_layerblend *lb;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lb_ids); i++)
+ if (lb_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(lb_ids)))
+ return;
+
+ lb = dpu->lb_priv[i];
+
+ layerblend_pixengcfg_dynamic_prim_sel(lb, LB_PRIM_SEL__DISABLE);
+ layerblend_pixengcfg_dynamic_sec_sel(lb, LB_SEC_SEL__DISABLE);
+ layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
+ layerblend_shdldsel(lb, BOTH);
+ layerblend_shdtoksel(lb, BOTH);
+ layerblend_shden(lb, true);
+}
+
int dpu_lb_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -374,11 +396,7 @@ int dpu_lb_init(struct dpu_soc *dpu, unsigned int id,
if (ret < 0)
return ret;
- layerblend_pixengcfg_dynamic_sec_sel(lb, LB_SEC_SEL__DISABLE);
- layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
- layerblend_shdldsel(lb, BOTH);
- layerblend_shdtoksel(lb, BOTH);
- layerblend_shden(lb, true);
+ _dpu_lb_init(dpu, id);
return 0;
}
diff --git a/drivers/gpu/imx/dpu/dpu-prv.h b/drivers/gpu/imx/dpu/dpu-prv.h
index 5f22cfbf28cc..b18e5b628b41 100644
--- a/drivers/gpu/imx/dpu/dpu-prv.h
+++ b/drivers/gpu/imx/dpu/dpu-prv.h
@@ -238,6 +238,21 @@ int dpu_format_num_planes(u32 format);
int dpu_format_plane_width(int width, u32 format, int plane);
int dpu_format_plane_height(int height, u32 format, int plane);
+#define _DECLARE_DPU_UNIT_INIT_FUNC(block) \
+void _dpu_##block##_init(struct dpu_soc *dpu, unsigned int id) \
+
+_DECLARE_DPU_UNIT_INIT_FUNC(cf);
+_DECLARE_DPU_UNIT_INIT_FUNC(dec);
+_DECLARE_DPU_UNIT_INIT_FUNC(ed);
+_DECLARE_DPU_UNIT_INIT_FUNC(fd);
+_DECLARE_DPU_UNIT_INIT_FUNC(fe);
+_DECLARE_DPU_UNIT_INIT_FUNC(fg);
+_DECLARE_DPU_UNIT_INIT_FUNC(fl);
+_DECLARE_DPU_UNIT_INIT_FUNC(hs);
+_DECLARE_DPU_UNIT_INIT_FUNC(lb);
+_DECLARE_DPU_UNIT_INIT_FUNC(tcon);
+_DECLARE_DPU_UNIT_INIT_FUNC(vs);
+
#define DECLARE_DPU_UNIT_INIT_FUNC(block) \
int dpu_##block##_init(struct dpu_soc *dpu, unsigned int id, \
unsigned long pec_base, unsigned long base)
diff --git a/drivers/gpu/imx/dpu/dpu-tcon.c b/drivers/gpu/imx/dpu/dpu-tcon.c
index 8995e75ed76b..ff3fda021216 100644
--- a/drivers/gpu/imx/dpu/dpu-tcon.c
+++ b/drivers/gpu/imx/dpu/dpu-tcon.c
@@ -211,6 +211,10 @@ void dpu_tcon_put(struct dpu_tcon *tcon)
}
EXPORT_SYMBOL_GPL(dpu_tcon_put);
+void _dpu_tcon_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
int dpu_tcon_init(struct dpu_soc *dpu, unsigned int id,
unsigned long unused, unsigned long base)
{
diff --git a/drivers/gpu/imx/dpu/dpu-vscaler.c b/drivers/gpu/imx/dpu/dpu-vscaler.c
index b31ad87a3adc..8c8fddfc8cba 100644
--- a/drivers/gpu/imx/dpu/dpu-vscaler.c
+++ b/drivers/gpu/imx/dpu/dpu-vscaler.c
@@ -378,6 +378,28 @@ void dpu_vs_put(struct dpu_vscaler *vs)
}
EXPORT_SYMBOL_GPL(dpu_vs_put);
+void _dpu_vs_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_vscaler *vs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+ if (vs_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(vs_ids)))
+ return;
+
+ vs = dpu->vs_priv[i];
+
+ vscaler_shden(vs, true);
+ vscaler_setup2(vs, 0);
+ vscaler_setup3(vs, 0);
+ vscaler_setup4(vs, 0);
+ vscaler_setup5(vs, 0);
+ vscaler_pixengcfg_dynamic_src_sel(vs, VS_SRC_SEL__DISABLE);
+}
+
int dpu_vs_init(struct dpu_soc *dpu, unsigned int id,
unsigned long pec_base, unsigned long base)
{
@@ -407,11 +429,7 @@ int dpu_vs_init(struct dpu_soc *dpu, unsigned int id,
mutex_init(&vs->mutex);
- vscaler_shden(vs, true);
- vscaler_setup2(vs, 0);
- vscaler_setup3(vs, 0);
- vscaler_setup4(vs, 0);
- vscaler_setup5(vs, 0);
+ _dpu_vs_init(dpu, id);
return 0;
}