diff options
-rw-r--r-- | drivers/gpu/drm/imx/imx-drm-core.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 102 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/Kconfig | 4 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 1 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-ic.c | 1 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-pre.c | 29 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prg.c | 84 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prv.h | 4 | ||||
-rw-r--r-- | include/video/imx-ipu-v3.h | 2 |
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 | ||
80 | static const uint64_t ipu_format_modifiers[] = { | ||
81 | DRM_FORMAT_MOD_LINEAR, | ||
82 | DRM_FORMAT_MOD_INVALID | ||
83 | }; | ||
84 | |||
85 | static 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 | |||
80 | int ipu_plane_irq(struct ipu_plane *ipu_plane) | 92 | int 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 | ||
318 | static 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 | |||
306 | static const struct drm_plane_funcs ipu_plane_funcs = { | 334 | static 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 | ||
315 | static int ipu_plane_atomic_check(struct drm_plane *plane, | 344 | static 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 = { | |||
700 | int ipu_planes_assign_pre(struct drm_device *dev, | 729 | int 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 @@ | |||
1 | config IMX_IPUV3_CORE | 1 | config 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 | ||
164 | void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, | 168 | void 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 | } |
137 | EXPORT_SYMBOL_GPL(ipu_prg_format_supported); | 145 | EXPORT_SYMBOL_GPL(ipu_prg_format_supported); |
138 | 146 | ||
139 | int ipu_prg_enable(struct ipu_soc *ipu) | 147 | int 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 | |||
153 | fail_disable_ipg: | ||
154 | clk_disable_unprepare(prg->clk_ipg); | ||
155 | |||
156 | return ret; | ||
157 | } | 155 | } |
158 | EXPORT_SYMBOL_GPL(ipu_prg_enable); | 156 | EXPORT_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 | } |
169 | EXPORT_SYMBOL_GPL(ipu_prg_disable); | 167 | EXPORT_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); | |||
275 | int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, | 273 | int 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 | ||
419 | static 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 | |||
429 | static 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 | |||
448 | static const struct dev_pm_ops prg_pm_ops = { | ||
449 | SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL) | ||
450 | }; | ||
451 | |||
417 | static const struct of_device_id ipu_prg_dt_ids[] = { | 452 | static 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); | |||
269 | void ipu_pre_put(struct ipu_pre *pre); | 269 | void ipu_pre_put(struct ipu_pre *pre); |
270 | u32 ipu_pre_get_baddr(struct ipu_pre *pre); | 270 | u32 ipu_pre_get_baddr(struct ipu_pre *pre); |
271 | void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, | 271 | void 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); |
274 | void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr); | 274 | void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr); |
275 | 275 | ||
276 | struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name, | 276 | struct 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); | |||
344 | int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, | 344 | int 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 |