aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c1
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c102
-rw-r--r--drivers/gpu/ipu-v3/Kconfig4
-rw-r--r--drivers/gpu/ipu-v3/ipu-cpmem.c1
-rw-r--r--drivers/gpu/ipu-v3/ipu-ic.c1
-rw-r--r--drivers/gpu/ipu-v3/ipu-pre.c29
-rw-r--r--drivers/gpu/ipu-v3/ipu-prg.c84
-rw-r--r--drivers/gpu/ipu-v3/ipu-prv.h4
-rw-r--r--include/video/imx-ipu-v3.h2
9 files changed, 189 insertions, 39 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 3f2b4afcb8a7..1d053bbefc02 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -257,6 +257,7 @@ static int imx_drm_bind(struct device *dev)
257 drm->mode_config.max_height = 4096; 257 drm->mode_config.max_height = 4096;
258 drm->mode_config.funcs = &imx_drm_mode_config_funcs; 258 drm->mode_config.funcs = &imx_drm_mode_config_funcs;
259 drm->mode_config.helper_private = &imx_drm_mode_config_helpers; 259 drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
260 drm->mode_config.allow_fb_modifiers = true;
260 261
261 drm_mode_config_init(drm); 262 drm_mode_config_init(drm);
262 263
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 5a67daedcf4d..57ed56d8623f 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -77,6 +77,18 @@ static const uint32_t ipu_plane_formats[] = {
77 DRM_FORMAT_BGRX8888_A8, 77 DRM_FORMAT_BGRX8888_A8,
78}; 78};
79 79
80static const uint64_t ipu_format_modifiers[] = {
81 DRM_FORMAT_MOD_LINEAR,
82 DRM_FORMAT_MOD_INVALID
83};
84
85static const uint64_t pre_format_modifiers[] = {
86 DRM_FORMAT_MOD_LINEAR,
87 DRM_FORMAT_MOD_VIVANTE_TILED,
88 DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
89 DRM_FORMAT_MOD_INVALID
90};
91
80int ipu_plane_irq(struct ipu_plane *ipu_plane) 92int ipu_plane_irq(struct ipu_plane *ipu_plane)
81{ 93{
82 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch, 94 return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
@@ -303,6 +315,22 @@ void ipu_plane_destroy_state(struct drm_plane *plane,
303 kfree(ipu_state); 315 kfree(ipu_state);
304} 316}
305 317
318static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
319 uint32_t format, uint64_t modifier)
320{
321 struct ipu_soc *ipu = to_ipu_plane(plane)->ipu;
322
323 /* linear is supported for all planes and formats */
324 if (modifier == DRM_FORMAT_MOD_LINEAR)
325 return true;
326
327 /* without a PRG there are no supported modifiers */
328 if (!ipu_prg_present(ipu))
329 return false;
330
331 return ipu_prg_format_supported(ipu, format, modifier);
332}
333
306static const struct drm_plane_funcs ipu_plane_funcs = { 334static const struct drm_plane_funcs ipu_plane_funcs = {
307 .update_plane = drm_atomic_helper_update_plane, 335 .update_plane = drm_atomic_helper_update_plane,
308 .disable_plane = drm_atomic_helper_disable_plane, 336 .disable_plane = drm_atomic_helper_disable_plane,
@@ -310,6 +338,7 @@ static const struct drm_plane_funcs ipu_plane_funcs = {
310 .reset = ipu_plane_state_reset, 338 .reset = ipu_plane_state_reset,
311 .atomic_duplicate_state = ipu_plane_duplicate_state, 339 .atomic_duplicate_state = ipu_plane_duplicate_state,
312 .atomic_destroy_state = ipu_plane_destroy_state, 340 .atomic_destroy_state = ipu_plane_destroy_state,
341 .format_mod_supported = ipu_plane_format_mod_supported,
313}; 342};
314 343
315static int ipu_plane_atomic_check(struct drm_plane *plane, 344static int ipu_plane_atomic_check(struct drm_plane *plane,
@@ -550,8 +579,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
550 ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id, 579 ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
551 drm_rect_width(&state->src) >> 16, 580 drm_rect_width(&state->src) >> 16,
552 drm_rect_height(&state->src) >> 16, 581 drm_rect_height(&state->src) >> 16,
553 fb->pitches[0], 582 fb->pitches[0], fb->format->format,
554 fb->format->format, &eba); 583 fb->modifier, &eba);
555 } 584 }
556 585
557 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { 586 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
@@ -700,18 +729,71 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
700int ipu_planes_assign_pre(struct drm_device *dev, 729int ipu_planes_assign_pre(struct drm_device *dev,
701 struct drm_atomic_state *state) 730 struct drm_atomic_state *state)
702{ 731{
732 struct drm_crtc_state *old_crtc_state, *crtc_state;
703 struct drm_plane_state *plane_state; 733 struct drm_plane_state *plane_state;
734 struct ipu_plane_state *ipu_state;
735 struct ipu_plane *ipu_plane;
704 struct drm_plane *plane; 736 struct drm_plane *plane;
737 struct drm_crtc *crtc;
705 int available_pres = ipu_prg_max_active_channels(); 738 int available_pres = ipu_prg_max_active_channels();
706 int i; 739 int ret, i;
707 740
741 for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) {
742 ret = drm_atomic_add_affected_planes(state, crtc);
743 if (ret)
744 return ret;
745 }
746
747 /*
748 * We are going over the planes in 2 passes: first we assign PREs to
749 * planes with a tiling modifier, which need the PREs to resolve into
750 * linear. Any failure to assign a PRE there is fatal. In the second
751 * pass we try to assign PREs to linear FBs, to improve memory access
752 * patterns for them. Failure at this point is non-fatal, as we can
753 * scan out linear FBs without a PRE.
754 */
708 for_each_new_plane_in_state(state, plane, plane_state, i) { 755 for_each_new_plane_in_state(state, plane, plane_state, i) {
709 struct ipu_plane_state *ipu_state = 756 ipu_state = to_ipu_plane_state(plane_state);
710 to_ipu_plane_state(plane_state); 757 ipu_plane = to_ipu_plane(plane);
711 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 758
759 if (!plane_state->fb) {
760 ipu_state->use_pre = false;
761 continue;
762 }
763
764 if (!(plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) ||
765 plane_state->fb->modifier == DRM_FORMAT_MOD_LINEAR)
766 continue;
767
768 if (!ipu_prg_present(ipu_plane->ipu) || !available_pres)
769 return -EINVAL;
770
771 if (!ipu_prg_format_supported(ipu_plane->ipu,
772 plane_state->fb->format->format,
773 plane_state->fb->modifier))
774 return -EINVAL;
775
776 ipu_state->use_pre = true;
777 available_pres--;
778 }
779
780 for_each_new_plane_in_state(state, plane, plane_state, i) {
781 ipu_state = to_ipu_plane_state(plane_state);
782 ipu_plane = to_ipu_plane(plane);
783
784 if (!plane_state->fb) {
785 ipu_state->use_pre = false;
786 continue;
787 }
788
789 if ((plane_state->fb->flags & DRM_MODE_FB_MODIFIERS) &&
790 plane_state->fb->modifier != DRM_FORMAT_MOD_LINEAR)
791 continue;
792
793 /* make sure that modifier is initialized */
794 plane_state->fb->modifier = DRM_FORMAT_MOD_LINEAR;
712 795
713 if (ipu_prg_present(ipu_plane->ipu) && available_pres && 796 if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
714 plane_state->fb &&
715 ipu_prg_format_supported(ipu_plane->ipu, 797 ipu_prg_format_supported(ipu_plane->ipu,
716 plane_state->fb->format->format, 798 plane_state->fb->format->format,
717 plane_state->fb->modifier)) { 799 plane_state->fb->modifier)) {
@@ -731,6 +813,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
731 enum drm_plane_type type) 813 enum drm_plane_type type)
732{ 814{
733 struct ipu_plane *ipu_plane; 815 struct ipu_plane *ipu_plane;
816 const uint64_t *modifiers = ipu_format_modifiers;
734 int ret; 817 int ret;
735 818
736 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", 819 DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
@@ -746,10 +829,13 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
746 ipu_plane->dma = dma; 829 ipu_plane->dma = dma;
747 ipu_plane->dp_flow = dp; 830 ipu_plane->dp_flow = dp;
748 831
832 if (ipu_prg_present(ipu))
833 modifiers = pre_format_modifiers;
834
749 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs, 835 ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
750 &ipu_plane_funcs, ipu_plane_formats, 836 &ipu_plane_funcs, ipu_plane_formats,
751 ARRAY_SIZE(ipu_plane_formats), 837 ARRAY_SIZE(ipu_plane_formats),
752 NULL, type, NULL); 838 modifiers, type, NULL);
753 if (ret) { 839 if (ret) {
754 DRM_ERROR("failed to initialize plane\n"); 840 DRM_ERROR("failed to initialize plane\n");
755 kfree(ipu_plane); 841 kfree(ipu_plane);
diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig
index 87a20b3dcf7a..fe6f8c5b4445 100644
--- a/drivers/gpu/ipu-v3/Kconfig
+++ b/drivers/gpu/ipu-v3/Kconfig
@@ -1,7 +1,9 @@
1config IMX_IPUV3_CORE 1config IMX_IPUV3_CORE
2 tristate "IPUv3 core support" 2 tristate "IPUv3 core support"
3 depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM 3 depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST
4 depends on DRM || !DRM # if DRM=m, this can't be 'y' 4 depends on DRM || !DRM # if DRM=m, this can't be 'y'
5 select BITREVERSE
6 select GENERIC_ALLOCATOR if DRM
5 select GENERIC_IRQ_CHIP 7 select GENERIC_IRQ_CHIP
6 help 8 help
7 Choose this if you have a i.MX5/6 system and want to use the Image 9 Choose this if you have a i.MX5/6 system and want to use the Image
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 1cb82f445f91..bb9c087e6c0d 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -12,6 +12,7 @@
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/bitrev.h> 13#include <linux/bitrev.h>
14#include <linux/io.h> 14#include <linux/io.h>
15#include <linux/sizes.h>
15#include <drm/drm_fourcc.h> 16#include <drm/drm_fourcc.h>
16#include "ipu-prv.h" 17#include "ipu-prv.h"
17 18
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 321eb983c2f5..67cc820253a9 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -17,6 +17,7 @@
17#include <linux/bitrev.h> 17#include <linux/bitrev.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/err.h> 19#include <linux/err.h>
20#include <linux/sizes.h>
20#include "ipu-prv.h" 21#include "ipu-prv.h"
21 22
22/* IC Register Offsets */ 23/* IC Register Offsets */
diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c
index c860a7997cb5..f1cec3d70498 100644
--- a/drivers/gpu/ipu-v3/ipu-pre.c
+++ b/drivers/gpu/ipu-v3/ipu-pre.c
@@ -49,6 +49,10 @@
49#define IPU_PRE_TPR_CTRL 0x070 49#define IPU_PRE_TPR_CTRL 0x070
50#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0) 50#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
51#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff 51#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
52#define IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0)
53#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4)
54#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5)
55#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6)
52 56
53#define IPU_PRE_PREFETCH_ENG_CTRL 0x080 57#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
54#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0) 58#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
@@ -147,7 +151,7 @@ int ipu_pre_get(struct ipu_pre *pre)
147 val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN | 151 val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
148 IPU_PRE_CTRL_HANDSHAKE_EN | 152 IPU_PRE_CTRL_HANDSHAKE_EN |
149 IPU_PRE_CTRL_TPR_REST_SEL | 153 IPU_PRE_CTRL_TPR_REST_SEL |
150 IPU_PRE_CTRL_BLOCK_16 | IPU_PRE_CTRL_SDW_UPDATE; 154 IPU_PRE_CTRL_SDW_UPDATE;
151 writel(val, pre->regs + IPU_PRE_CTRL); 155 writel(val, pre->regs + IPU_PRE_CTRL);
152 156
153 pre->in_use = true; 157 pre->in_use = true;
@@ -163,14 +167,17 @@ void ipu_pre_put(struct ipu_pre *pre)
163 167
164void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, 168void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
165 unsigned int height, unsigned int stride, u32 format, 169 unsigned int height, unsigned int stride, u32 format,
166 unsigned int bufaddr) 170 uint64_t modifier, unsigned int bufaddr)
167{ 171{
168 const struct drm_format_info *info = drm_format_info(format); 172 const struct drm_format_info *info = drm_format_info(format);
169 u32 active_bpp = info->cpp[0] >> 1; 173 u32 active_bpp = info->cpp[0] >> 1;
170 u32 val; 174 u32 val;
171 175
172 /* calculate safe window for ctrl register updates */ 176 /* calculate safe window for ctrl register updates */
173 pre->safe_window_end = height - 2; 177 if (modifier == DRM_FORMAT_MOD_LINEAR)
178 pre->safe_window_end = height - 2;
179 else
180 pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
174 181
175 writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF); 182 writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
176 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); 183 writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
@@ -203,9 +210,25 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
203 210
204 writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR); 211 writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
205 212
213 val = readl(pre->regs + IPU_PRE_TPR_CTRL);
214 val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
215 if (modifier != DRM_FORMAT_MOD_LINEAR) {
216 /* only support single buffer formats for now */
217 val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
218 if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
219 val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
220 if (info->cpp[0] == 2)
221 val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
222 }
223 writel(val, pre->regs + IPU_PRE_TPR_CTRL);
224
206 val = readl(pre->regs + IPU_PRE_CTRL); 225 val = readl(pre->regs + IPU_PRE_CTRL);
207 val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE | 226 val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
208 IPU_PRE_CTRL_SDW_UPDATE; 227 IPU_PRE_CTRL_SDW_UPDATE;
228 if (modifier == DRM_FORMAT_MOD_LINEAR)
229 val &= ~IPU_PRE_CTRL_BLOCK_EN;
230 else
231 val |= IPU_PRE_CTRL_BLOCK_EN;
209 writel(val, pre->regs + IPU_PRE_CTRL); 232 writel(val, pre->regs + IPU_PRE_CTRL);
210} 233}
211 234
diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c
index 0013ca9f72c8..067365c733c6 100644
--- a/drivers/gpu/ipu-v3/ipu-prg.c
+++ b/drivers/gpu/ipu-v3/ipu-prg.c
@@ -20,6 +20,7 @@
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/of.h> 21#include <linux/of.h>
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/pm_runtime.h>
23#include <linux/regmap.h> 24#include <linux/regmap.h>
24#include <video/imx-ipu-v3.h> 25#include <video/imx-ipu-v3.h>
25 26
@@ -132,28 +133,25 @@ bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
132 if (info->num_planes != 1) 133 if (info->num_planes != 1)
133 return false; 134 return false;
134 135
135 return true; 136 switch (modifier) {
137 case DRM_FORMAT_MOD_LINEAR:
138 case DRM_FORMAT_MOD_VIVANTE_TILED:
139 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
140 return true;
141 default:
142 return false;
143 }
136} 144}
137EXPORT_SYMBOL_GPL(ipu_prg_format_supported); 145EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
138 146
139int ipu_prg_enable(struct ipu_soc *ipu) 147int ipu_prg_enable(struct ipu_soc *ipu)
140{ 148{
141 struct ipu_prg *prg = ipu->prg_priv; 149 struct ipu_prg *prg = ipu->prg_priv;
142 int ret;
143 150
144 if (!prg) 151 if (!prg)
145 return 0; 152 return 0;
146 153
147 ret = clk_prepare_enable(prg->clk_axi); 154 return pm_runtime_get_sync(prg->dev);
148 if (ret)
149 goto fail_disable_ipg;
150
151 return 0;
152
153fail_disable_ipg:
154 clk_disable_unprepare(prg->clk_ipg);
155
156 return ret;
157} 155}
158EXPORT_SYMBOL_GPL(ipu_prg_enable); 156EXPORT_SYMBOL_GPL(ipu_prg_enable);
159 157
@@ -164,7 +162,7 @@ void ipu_prg_disable(struct ipu_soc *ipu)
164 if (!prg) 162 if (!prg)
165 return; 163 return;
166 164
167 clk_disable_unprepare(prg->clk_axi); 165 pm_runtime_put(prg->dev);
168} 166}
169EXPORT_SYMBOL_GPL(ipu_prg_disable); 167EXPORT_SYMBOL_GPL(ipu_prg_disable);
170 168
@@ -255,7 +253,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
255 if (!chan->enabled || prg_chan < 0) 253 if (!chan->enabled || prg_chan < 0)
256 return; 254 return;
257 255
258 clk_prepare_enable(prg->clk_ipg); 256 pm_runtime_get_sync(prg->dev);
259 257
260 val = readl(prg->regs + IPU_PRG_CTL); 258 val = readl(prg->regs + IPU_PRG_CTL);
261 val |= IPU_PRG_CTL_BYPASS(prg_chan); 259 val |= IPU_PRG_CTL_BYPASS(prg_chan);
@@ -264,7 +262,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
264 val = IPU_PRG_REG_UPDATE_REG_UPDATE; 262 val = IPU_PRG_REG_UPDATE_REG_UPDATE;
265 writel(val, prg->regs + IPU_PRG_REG_UPDATE); 263 writel(val, prg->regs + IPU_PRG_REG_UPDATE);
266 264
267 clk_disable_unprepare(prg->clk_ipg); 265 pm_runtime_put(prg->dev);
268 266
269 ipu_prg_put_pre(prg, prg_chan); 267 ipu_prg_put_pre(prg, prg_chan);
270 268
@@ -275,7 +273,7 @@ EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
275int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, 273int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
276 unsigned int axi_id, unsigned int width, 274 unsigned int axi_id, unsigned int width,
277 unsigned int height, unsigned int stride, 275 unsigned int height, unsigned int stride,
278 u32 format, unsigned long *eba) 276 u32 format, uint64_t modifier, unsigned long *eba)
279{ 277{
280 int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); 278 int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
281 struct ipu_prg *prg = ipu_chan->ipu->prg_priv; 279 struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
@@ -296,14 +294,10 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
296 return ret; 294 return ret;
297 295
298 ipu_pre_configure(prg->pres[chan->used_pre], 296 ipu_pre_configure(prg->pres[chan->used_pre],
299 width, height, stride, format, *eba); 297 width, height, stride, format, modifier, *eba);
300 298
301 299
302 ret = clk_prepare_enable(prg->clk_ipg); 300 pm_runtime_get_sync(prg->dev);
303 if (ret) {
304 ipu_prg_put_pre(prg, prg_chan);
305 return ret;
306 }
307 301
308 val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK; 302 val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
309 writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan)); 303 writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
@@ -336,7 +330,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
336 (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)), 330 (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)),
337 5, 1000); 331 5, 1000);
338 332
339 clk_disable_unprepare(prg->clk_ipg); 333 pm_runtime_put(prg->dev);
340 334
341 chan->enabled = true; 335 chan->enabled = true;
342 return 0; 336 return 0;
@@ -384,6 +378,12 @@ static int ipu_prg_probe(struct platform_device *pdev)
384 if (ret) 378 if (ret)
385 return ret; 379 return ret;
386 380
381 ret = clk_prepare_enable(prg->clk_axi);
382 if (ret) {
383 clk_disable_unprepare(prg->clk_ipg);
384 return ret;
385 }
386
387 /* init to free running mode */ 387 /* init to free running mode */
388 val = readl(prg->regs + IPU_PRG_CTL); 388 val = readl(prg->regs + IPU_PRG_CTL);
389 val |= IPU_PRG_CTL_SHADOW_EN; 389 val |= IPU_PRG_CTL_SHADOW_EN;
@@ -392,7 +392,8 @@ static int ipu_prg_probe(struct platform_device *pdev)
392 /* disable address threshold */ 392 /* disable address threshold */
393 writel(0xffffffff, prg->regs + IPU_PRG_THD); 393 writel(0xffffffff, prg->regs + IPU_PRG_THD);
394 394
395 clk_disable_unprepare(prg->clk_ipg); 395 pm_runtime_set_active(dev);
396 pm_runtime_enable(dev);
396 397
397 prg->dev = dev; 398 prg->dev = dev;
398 platform_set_drvdata(pdev, prg); 399 platform_set_drvdata(pdev, prg);
@@ -414,6 +415,40 @@ static int ipu_prg_remove(struct platform_device *pdev)
414 return 0; 415 return 0;
415} 416}
416 417
418#ifdef CONFIG_PM
419static int prg_suspend(struct device *dev)
420{
421 struct ipu_prg *prg = dev_get_drvdata(dev);
422
423 clk_disable_unprepare(prg->clk_axi);
424 clk_disable_unprepare(prg->clk_ipg);
425
426 return 0;
427}
428
429static int prg_resume(struct device *dev)
430{
431 struct ipu_prg *prg = dev_get_drvdata(dev);
432 int ret;
433
434 ret = clk_prepare_enable(prg->clk_ipg);
435 if (ret)
436 return ret;
437
438 ret = clk_prepare_enable(prg->clk_axi);
439 if (ret) {
440 clk_disable_unprepare(prg->clk_ipg);
441 return ret;
442 }
443
444 return 0;
445}
446#endif
447
448static const struct dev_pm_ops prg_pm_ops = {
449 SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL)
450};
451
417static const struct of_device_id ipu_prg_dt_ids[] = { 452static const struct of_device_id ipu_prg_dt_ids[] = {
418 { .compatible = "fsl,imx6qp-prg", }, 453 { .compatible = "fsl,imx6qp-prg", },
419 { /* sentinel */ }, 454 { /* sentinel */ },
@@ -424,6 +459,7 @@ struct platform_driver ipu_prg_drv = {
424 .remove = ipu_prg_remove, 459 .remove = ipu_prg_remove,
425 .driver = { 460 .driver = {
426 .name = "imx-ipu-prg", 461 .name = "imx-ipu-prg",
462 .pm = &prg_pm_ops,
427 .of_match_table = ipu_prg_dt_ids, 463 .of_match_table = ipu_prg_dt_ids,
428 }, 464 },
429}; 465};
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h
index ac4b8d658500..d6beee99b6b8 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/ipu-v3/ipu-prv.h
@@ -269,8 +269,8 @@ int ipu_pre_get(struct ipu_pre *pre);
269void ipu_pre_put(struct ipu_pre *pre); 269void ipu_pre_put(struct ipu_pre *pre);
270u32 ipu_pre_get_baddr(struct ipu_pre *pre); 270u32 ipu_pre_get_baddr(struct ipu_pre *pre);
271void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, 271void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
272 unsigned int height, 272 unsigned int height, unsigned int stride, u32 format,
273 unsigned int stride, u32 format, unsigned int bufaddr); 273 uint64_t modifier, unsigned int bufaddr);
274void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr); 274void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
275 275
276struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name, 276struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index ce4c07688b13..abbad94e14a1 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -344,7 +344,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan);
344int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, 344int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
345 unsigned int axi_id, unsigned int width, 345 unsigned int axi_id, unsigned int width,
346 unsigned int height, unsigned int stride, 346 unsigned int height, unsigned int stride,
347 u32 format, unsigned long *eba); 347 u32 format, uint64_t modifier, unsigned long *eba);
348 348
349/* 349/*
350 * IPU CMOS Sensor Interface (csi) functions 350 * IPU CMOS Sensor Interface (csi) functions