Backlight control broken on UM325 (OLED) on 5.15 (bisected)
Hello, the backlight control no longer works on my ASUS UM325 (Ryzen 5700U) OLED laptop. I have bisected the breakage to commit 7fd13baeb7a3a48. commit 7fd13baeb7a3a48cae12c36c52f06bf4e9e7d728 (HEAD, refs/bisect/bad) Author: Alex Deucher Date: Thu Jul 8 16:31:10 2021 -0400 drm/amdgpu/display: add support for multiple backlights On platforms that support multiple backlights, register each one separately. This lets us manage them independently rather than registering a single backlight and applying the same settings to both. v2: fix typo: Reported-by: kernel test robot Reviewed-by: Roman Li Signed-off-by: Alex Deucher I have encountered another user with the same issue on reddit[0]. The node in /sys/class/backlight exists, writing to it just does nothing. I would be glad to help debugging the issue. Thank you very much. Regards, Samuel Čavoj [0]: https://www.reddit.com/r/AMDLaptops/comments/qst0fm/after_updating_to_linux_515_my_brightness/
Panic with linus/master and panfrost
Hello, I'm getting some fence refcounting related panics with the current Linus's master branch: It happens immediately whenever I start Xorg or sway. Anyone has any ideas where to start looking? It works fine with v5.15. (sorry for the interleaved log, it's coming from multiple CPUs at once I guess) kind regards, o. [ cut here ] refcount_t: underflow; use-after-free. WARNING: CPU: 4 PID: 560 at lib/refcount.c:28 refcount_warn_saturate+0xec/0x140 Modules linked in: CPU: 4 PID: 560 Comm: sway Not tainted 5.15.0-13547-g5169ae41ace0 #24 Hardware name: Pine64 PinePhonePro (DT) pstate: 4005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : refcount_warn_saturate+0xec/0x140 lr : refcount_warn_saturate+0xec/0x140 sp : 8000127b3be0 x29: 8000127b3be0 x28: 8000127b3d50 x27: 1927e700 x26: x25: 0001 x24: 0004 x23: 1e31da80 x22: 05497580 x21: 1e31da90 x20: 1e31da80 x19: 1e31da90 x18: 0003 x17: x16: x15: 8000127b3b68 x14: x13: 2e656572662d7265 x12: 7466612d65737520 x11: 3b776f6c66726564 x10: 800011d7e8a0 x9 : 800010178a1c x8 : efff x7 : 800011dd68a0 x6 : 0001 x5 : f778e788 x4 : x3 : 0027 x2 : 0023 x1 : f778e790 x0 : 0026 Call trace: refcount_warn_saturate+0xec/0x140 drm_syncobj_replace_fence+0x16c/0x17c panfrost_ioctl_submit+0x364/0x440 drm_ioctl_kernel+0x9c/0x154 drm_ioctl+0x1f0/0x410 __arm64_sys_ioctl+0xb4/0xdc invoke_syscall+0x4c/0x110 el0_svc_common.constprop.0+0x48/0xf0 do_el0_svc+0x2c/0x90 el0_svc+0x14/0x50 el0t_64_sync_handler+0x9c/0x120 el0t_64_sync+0x158/0x15c ---[ end trace 51cdc14807ba9222 ]--- [ cut here ] Unable to handle kernel write to read-only memory at virtual address 800010820b10 refcount_t: saturated; leaking memory. Mem abort info: WARNING: CPU: 1 PID: 223 at lib/refcount.c:22 refcount_warn_saturate+0x6c/0x140 ESR = 0x964e Modules linked in: EC = 0x25: DABT (current EL), IL = 32 bits CPU: 1 PID: 223 Comm: pan_js Tainted: GW 5.15.0-13547-g5169ae41ace0 #24 SET = 0, FnV = 0 Hardware name: Pine64 PinePhonePro (DT) EA = 0, S1PTW = 0 pstate: 4005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) FSC = 0x0e: level 2 permission fault pc : refcount_warn_saturate+0x6c/0x140 Data abort info: lr : refcount_warn_saturate+0x6c/0x140 ISV = 0, ISS = 0x004e sp : 800012a2bd90 CM = 0, WnR = 1 x29: 800012a2bd90 swapper pgtable: 4k pages, 48-bit VAs, pgdp=019ba000 x28: [800010820b10] pgd=1000f7fff003 x27: , p4d=1000f7fff003 , pud=1000f7ffe003 x26: , pmd=004000a00781 x25: 800011906000 x24: 13ee7a20 Internal error: Oops: 964e [#1] SMP Modules linked in: x23: 8000108211e0 x22: 800011906000 CPU: 2 PID: 222 Comm: pan_js Tainted: GW 5.15.0-13547-g5169ae41ace0 #24 x21: 251ef000 Hardware name: Pine64 PinePhonePro (DT) pstate: 00c5 (nzcv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) x20: 05497580 pc : dma_fence_add_callback+0xc8/0x120 x19: 1532b4c0 lr : dma_fence_add_callback+0x78/0x120 x18: sp : 800012a23d60 x29: 800012a23d60 x17: 00040044 x28: x16: 0032b5503510 x27: x15: x26: x14: 0550c380 x25: 800011906000 x13: 2e79726f6d656d20 x24: x12: 676e696b61656c20 x23: x11: 3b64657461727574 x22: 8000108211e0 x10: 6173203a745f746e x21: 054975d0 x9 : 80001022e51c x20: 1532b468 x8 : 0001 x19: 05497580 x7 : 0e08 x18: x6 : 0001 x17: 00040044 x5 : x16: 0032b5503510 x4 : f773a788 x15: x3 : f77466f0 x14: 0550d100 x2 : f773a788 x13: 8000e5e4e000 x1 : 8000e5e32000 x12: 34d4d91d x0 : 0026 x11: Call trace: x10: 0002 refcount_warn_saturate+0x6c/0x140 x9 : 800010899578 drm_sched_entity_pop_job+0x418/0x490 drm_sched_main+0xb0/0x41c x8 : 148dcd60 kthread+0x14c/0x160 x7 : ret_from_fork+0x10/0x20 x6 : 010a4760 ---[ end trace 51cdc14807ba9223 ]--- x5 : 13ee79f8 x4 : 0001 x3 : 054975b0 x2 : x1 : 800010820b10 x0 : 05497590 Call trace: dma_fence_add_callback+0xc8/0x120 drm_sched_entity_pop_job+0xa4/0x490 drm_sched_main+0xb0/0x41c kthread+0x14c/0x160 ret_from_fork+0x10/0x20 Code: 91004260 f9400e61 f9000e74 a9000680 (f934) ---[ end trace 51cdc14807ba9224 ]--- Kernel panic - not syncing: Oops:
Re: [PATCH] drm/amd/amdgpu: remove useless break after return
On Sun, 2021-11-14 at 23:14 -0800, Bernard Zhao wrote: > This change is to remove useless break after return. [] > diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c > b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c [] > @@ -2092,22 +2092,18 @@ static int dce_v8_0_pick_dig_encoder(struct > drm_encoder *encoder) > return 1; > else > return 0; > - break; > case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: > if (dig->linkb) > return 3; > else > return 2; > - break; > case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: > if (dig->linkb) > return 5; > else > return 4; > - break; > case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: > return 6; > - break; > default: > DRM_ERROR("invalid encoder_id: 0x%x\n", > amdgpu_encoder->encoder_id); > return 0; Perhaps rewrite to make the sequential numbering more obvious. --- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 19 +++ 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index b200b9e722d97..7307524b706b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2088,26 +2088,13 @@ static int dce_v8_0_pick_dig_encoder(struct drm_encoder *encoder) switch (amdgpu_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (dig->linkb) - return 1; - else - return 0; - break; + return !dig->linkb ? 0 : 1; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig->linkb) - return 3; - else - return 2; - break; + return !dig->linkb ? 2 : 3; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig->linkb) - return 5; - else - return 4; - break; + return !dig->linkb ? 4 : 5; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: return 6; - break; default: DRM_ERROR("invalid encoder_id: 0x%x\n", amdgpu_encoder->encoder_id); return 0;
Re: Questions about KMS flip
Am 12.11.21 um 17:10 schrieb Michel Dänzer: On 2021-11-12 16:03, Christian König wrote: Am 12.11.21 um 15:30 schrieb Michel Dänzer: On 2021-11-12 15:29, Michel Dänzer wrote: On 2021-11-12 13:47, Christian König wrote: Anyway this unfortunately turned out to be work for Harray and Nicholas. In detail it's about this bug report here: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fbugzilla.kernel.org%2Fshow_bug.cgi%3Fid%3D214621data=04%7C01%7Cchristian.koenig%40amd.com%7Cca557eab16864ab544a108d9a5f6f288%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637723302340621335%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000sdata=pvLGq%2FJRvVy0k5GMGF2UPotCSdbiQNfndtjI14luAUg%3Dreserved=0 Lang was able to reproduce the issue and narrow it down to the pin in amdgpu_display_crtc_page_flip_target(). In other words we somehow have an unbalanced pinning of the scanout buffer in DC. DC doesn't use amdgpu_display_crtc_page_flip_target AFAICT. The corresponding pin with DC would be in dm_plane_helper_prepare_fb, paired with the unpin in dm_plane_helper_cleanup_fb. With non-DC, the pin in amdgpu_display_crtc_page_flip_target is paired with the unpin in dm_plane_helper_cleanup_fb This should say amdgpu_display_unpin_work_func. Ah! So that is the classic (e.g. non atomic) path? Presumably. & dce_v*_crtc_disable. One thing I notice is that the pin is guarded by if (!adev->enable_virtual_display), but the unpins seem unconditional. So could this be about virtual display, and the problem is actually trying to unpin a BO that was never pinned? Nope, my educated guess is rather that we free up the BO before amdgpu_display_unpin_work_func is called. E.g. not pin unbalance, but rather use after free. amdgpu_display_crtc_page_flip_target calls amdgpu_bo_ref(work->old_abo), and amdgpu_display_unpin_work_func calls amdgpu_bo_unref(>old_abo) only after amdgpu_bo_unpin. So what you describe could only happen if there's an imbalance elsewhere such that amdgpu_bo_unref is called more often than amdgpu_bo_ref, or maybe if amdgpu_bo_reserve fails in amdgpu_display_unpin_work_func (in which case the "failed to reserve buffer after flip" error message should appear in dmesg). Yeah, seen that in the meantime as well. But we also have a WARN_ON() when the pincount overruns, so that can't be it either. Long story short I have no idea what's going on here. Regards, Christian.
[PATCH] drm/exynos: remove useless type conversion
This change is to cleanup the code a bit. Signed-off-by: Bernard Zhao --- drivers/gpu/drm/exynos/exynos_drm_fimc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index ecfd82d0afb7..023f54ee61a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -782,8 +782,8 @@ static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, sc->hratio = (src_w << 14) / (dst_w << hfactor); sc->vratio = (src_h << 14) / (dst_h << vfactor); - sc->up_h = (dst_w >= src_w) ? true : false; - sc->up_v = (dst_h >= src_h) ? true : false; + sc->up_h = (dst_w >= src_w); + sc->up_v = (dst_h >= src_h); DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n", sc->hratio, sc->vratio, sc->up_h, sc->up_v); -- 2.33.1
Re: [git pull] drm fixes + one missed next for 5.16-rc1
On 11/14/21 22:19, Linus Torvalds wrote: On Sun, Nov 14, 2021 at 1:00 PM Dave Airlie wrote: i915 will no longer be x86-64 only in theory, since Intel now produces PCIe graphics cards using the same hw designs. Well, at least in my tree, it still has the "depends on X86", along with several other x86-only things (like "select INTEL_GTT", which is also x86-only) So by the time that non-x86 theory becomes reality, hopefully the i915 people will also have figured out how to do the cache flushing properly. And hopefully that "do it properly" ends up being simply that the particular configuration that ends up being portable simply doesn't need to do it at all and can statically just not build it, sidestepping the issue entirely. Fingers crossed. For non-x86 / discrete graphics, plan is only coherent mappings, although the "Just not build it" part hasn't been properly figured out yet I guess. But point taken. Thanks, /Thomas
[PATCH] drm/amd/amdgpu: remove useless break after return
This change is to remove useless break after return. Signed-off-by: Bernard Zhao --- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 4 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index b200b9e722d9..8318ee8339f1 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2092,22 +2092,18 @@ static int dce_v8_0_pick_dig_encoder(struct drm_encoder *encoder) return 1; else return 0; - break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: if (dig->linkb) return 3; else return 2; - break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: if (dig->linkb) return 5; else return 4; - break; case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: return 6; - break; default: DRM_ERROR("invalid encoder_id: 0x%x\n", amdgpu_encoder->encoder_id); return 0; -- 2.33.1
[PATCH] drm/amd/amdgpu: cleanup the code style a bit
This change is to cleanup the code style a bit. Signed-off-by: Bernard Zhao --- drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 04cf9b207e62..90070b41136a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -286,12 +286,14 @@ static int amdgpu_virt_init_ras_err_handler_data(struct amdgpu_device *adev) return -ENOMEM; bps = kmalloc_array(align_space, sizeof((*data)->bps), GFP_KERNEL); + if (!bps) { + kfree(*data); + return -ENOMEM; + } bps_bo = kmalloc_array(align_space, sizeof((*data)->bps_bo), GFP_KERNEL); - - if (!bps || !bps_bo) { - kfree(bps); - kfree(bps_bo); + if (!bps_bo) { kfree(*data); + kfree(bps); return -ENOMEM; } -- 2.33.1
Re: [PATCH] fbdev: sh7760fb: document fallthrough cases
On Sun, Nov 14, 2021 at 10:32:57PM -0800, Randy Dunlap wrote: > Fix fallthrough warnings in sh776fb.c: > > ../drivers/video/fbdev/sh7760fb.c: In function 'sh7760fb_get_color_info': > ../drivers/video/fbdev/sh7760fb.c:138:23: warning: this statement may fall > through [-Wimplicit-fallthrough=] > 138 | lgray = 1; > ../drivers/video/fbdev/sh7760fb.c:143:23: warning: this statement may fall > through [-Wimplicit-fallthrough=] > 143 | lgray = 1; > > Just document the current state of code execution/flow. > > Fixes: 4a25e41831ee ("video: sh7760fb: SH7760/SH7763 LCDC framebuffer driver") > Signed-off-by: Randy Dunlap > Cc: "Gustavo A. R. Silva" > Cc: Nobuhiro Iwamatsu > Cc: Manuel Lauss > Cc: Yoshinori Sato > Cc: Rich Felker > Cc: linux...@vger.kernel.org > Cc: linux-fb...@vger.kernel.org > Cc: dri-devel@lists.freedesktop.org Reviewed-by: Gustavo A. R. Silva Thanks, Randy. -- Gustavo > --- > drivers/video/fbdev/sh7760fb.c |2 ++ > 1 file changed, 2 insertions(+) > > --- linux-next-2022.orig/drivers/video/fbdev/sh7760fb.c > +++ linux-next-2022/drivers/video/fbdev/sh7760fb.c > @@ -136,11 +136,13 @@ static int sh7760fb_get_color_info(struc > break; > case LDDFR_4BPP_MONO: > lgray = 1; > + fallthrough; > case LDDFR_4BPP: > lbpp = 4; > break; > case LDDFR_6BPP_MONO: > lgray = 1; > + fallthrough; > case LDDFR_8BPP: > lbpp = 8; > break;
[PATCH] fbdev: sh7760fb: document fallthrough cases
Fix fallthrough warnings in sh776fb.c: ../drivers/video/fbdev/sh7760fb.c: In function 'sh7760fb_get_color_info': ../drivers/video/fbdev/sh7760fb.c:138:23: warning: this statement may fall through [-Wimplicit-fallthrough=] 138 | lgray = 1; ../drivers/video/fbdev/sh7760fb.c:143:23: warning: this statement may fall through [-Wimplicit-fallthrough=] 143 | lgray = 1; Just document the current state of code execution/flow. Fixes: 4a25e41831ee ("video: sh7760fb: SH7760/SH7763 LCDC framebuffer driver") Signed-off-by: Randy Dunlap Cc: "Gustavo A. R. Silva" Cc: Nobuhiro Iwamatsu Cc: Manuel Lauss Cc: Yoshinori Sato Cc: Rich Felker Cc: linux...@vger.kernel.org Cc: linux-fb...@vger.kernel.org Cc: dri-devel@lists.freedesktop.org --- drivers/video/fbdev/sh7760fb.c |2 ++ 1 file changed, 2 insertions(+) --- linux-next-2022.orig/drivers/video/fbdev/sh7760fb.c +++ linux-next-2022/drivers/video/fbdev/sh7760fb.c @@ -136,11 +136,13 @@ static int sh7760fb_get_color_info(struc break; case LDDFR_4BPP_MONO: lgray = 1; + fallthrough; case LDDFR_4BPP: lbpp = 4; break; case LDDFR_6BPP_MONO: lgray = 1; + fallthrough; case LDDFR_8BPP: lbpp = 8; break;
[PATCH] drm/xen: fix potential memleak in error branch
In function xen_drm_front_gem_import_sg_table, if in error branch, there maybe potential memleak if not call gem_free_pages_array. Signed-off-by: Bernard Zhao --- drivers/gpu/drm/xen/xen_drm_front_gem.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c index b293c67230ef..732c3eec0666 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_gem.c +++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c @@ -222,15 +222,19 @@ xen_drm_front_gem_import_sg_table(struct drm_device *dev, ret = drm_prime_sg_to_page_array(sgt, xen_obj->pages, xen_obj->num_pages); - if (ret < 0) + if (ret < 0) { + gem_free_pages_array(xen_obj); return ERR_PTR(ret); + } ret = xen_drm_front_dbuf_create(drm_info->front_info, xen_drm_front_dbuf_to_cookie(_obj->base), 0, 0, 0, size, sgt->sgl->offset, xen_obj->pages); - if (ret < 0) + if (ret < 0) { + gem_free_pages_array(xen_obj); return ERR_PTR(ret); + } DRM_DEBUG("Imported buffer of size %zu with nents %u\n", size, sgt->orig_nents); -- 2.33.1
[PATCH] backlight: ili922x: fix kernel-doc warnings & notation
Convert function-like macro comments to kernel-doc notation and fix other kernel-doc warnings: drivers/video/backlight/ili922x.c:85: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * START_BYTE(id, rs, rw) drivers/video/backlight/ili922x.c:118: warning: expecting prototype for CHECK_FREQ_REG(spi_device s, spi_transfer x)(). Prototype was for CHECK_FREQ_REG() instead ili922x.c:92: warning: contents before sections ili922x.c:150: warning: No description found for return value of 'ili922x_read_status' ili922x.c:193: warning: No description found for return value of 'ili922x_read' ili922x.c:247: warning: No description found for return value of 'ili922x_write' ili922x.c:353: warning: No description found for return value of 'ili922x_poweron' ili922x.c:382: warning: No description found for return value of 'ili922x_poweroff' Fixes: 4cfbfa971478 ("video: backlight: add ili922x lcd driver") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Cc: Lee Jones Cc: Daniel Thompson Cc: Jingoo Han Cc: dri-devel@lists.freedesktop.org Cc: Stefano Babic Cc: Anatolij Gustschin --- drivers/video/backlight/ili922x.c | 29 ++-- 1 file changed, 19 insertions(+), 10 deletions(-) --- linux-next-20211102.orig/drivers/video/backlight/ili922x.c +++ linux-next-20211102/drivers/video/backlight/ili922x.c @@ -82,13 +82,7 @@ #define START_RW_READ 1 /** - * START_BYTE(id, rs, rw) - * - * Set the start byte according to the required operation. - * The start byte is defined as: - * -- - * | 0 | 1 | 1 | 1 | 0 | ID | RS | RW | - * -- + * START_BYTE() - Set the start byte according to the required operation * @id: display's id as set by the manufacturer * @rs: operation type bit, one of: * - START_RS_INDEX set the index register @@ -96,14 +90,19 @@ * @rw: read/write operation * - START_RW_WRITE write * - START_RW_READread + * + * The start byte is defined as: + * -- + * | 0 | 1 | 1 | 1 | 0 | ID | RS | RW | + * -- */ #define START_BYTE(id, rs, rw) \ (0x70 | (((id) & 0x01) << 2) | (((rs) & 0x01) << 1) | ((rw) & 0x01)) /** - * CHECK_FREQ_REG(spi_device s, spi_transfer x) - Check the frequency - * for the SPI transfer. According to the datasheet, the controller - * accept higher frequency for the GRAM transfer, but it requires + * CHECK_FREQ_REG() - Check the frequency for the SPI transfer + * According to the datasheet, the controller + * accepts higher frequency for the GRAM transfer, but it requires * lower frequency when the registers are read/written. * The macro sets the frequency in the spi_transfer structure if * the frequency exceeds the maximum value. @@ -145,6 +144,8 @@ struct ili922x { * ili922x_read_status - read status register from display * @spi: spi device * @rs: output value + * + * Return: %0 on success or a negative error code on failure */ static int ili922x_read_status(struct spi_device *spi, u16 *rs) { @@ -188,6 +189,8 @@ static int ili922x_read_status(struct sp * @spi: spi device * @reg: offset of the register to be read * @rx: output value + * + * Return: %0 on success or a negative error code on failure */ static int ili922x_read(struct spi_device *spi, u8 reg, u16 *rx) { @@ -242,6 +245,8 @@ static int ili922x_read(struct spi_devic * @spi: struct spi_device * * @reg: offset of the register to be written * @value: value to be written + * + * Return: %0 on success or a negative error code on failure */ static int ili922x_write(struct spi_device *spi, u8 reg, u16 value) { @@ -348,6 +353,8 @@ static void set_write_to_gram_reg(struct * The sequence to turn on the display is taken from * the datasheet and/or the example code provided by the * manufacturer. + * + * Return: %0 on success or a negative value on failure */ static int ili922x_poweron(struct spi_device *spi) { @@ -377,6 +384,8 @@ static int ili922x_poweron(struct spi_de /** * ili922x_poweroff - turn the display off * @spi: spi device + * + * Return: %0 on success or a negative value on failure */ static int ili922x_poweroff(struct spi_device *spi) {
[PATCH] drm/amd/amdgpu: fix potential memleak
In function amdgpu_get_xgmi_hive, when kobject_init_and_add failed There is a potential memleak if not call kobject_put. Signed-off-by: Bernard Zhao --- drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 0fad2bf854ae..567df2db23ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -386,6 +386,7 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) "%s", "xgmi_hive_info"); if (ret) { dev_err(adev->dev, "XGMI: failed initializing kobject for xgmi hive\n"); + kobject_put(>kobj); kfree(hive); hive = NULL; goto pro_end; -- 2.33.1
[Bug 211277] sometimes crash at s2ram-wake (Ryzen 3500U): amdgpu, drm, commit_tail, amdgpu_dm_atomic_commit_tail
https://bugzilla.kernel.org/show_bug.cgi?id=211277 --- Comment #73 from kolAflash (kolafl...@kolahilft.de) --- (In reply to Jerome C from comment #72) > Hi James, > > I noticed the patch that you asked us to try from comment 52 were also > submitted to kernel 5.14.7 > > tested it, all is good for now Pleased to hear that :-) I'm just compiling 5.15.2 to run a test myself. @James Will those patches be backported to the Linux-5.10 LTS kernel? master and Linux-5.15 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=f02abeb0779700c308e661a412451b38962b8a0b https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8066008482e533e91934bee49765bf8b4a7c40db https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=fefc01f042f44ede373ee66773b8238dd8fdcb55 Linux-5.14.7 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=fe232886fb710a4bf0532f61ebdb87463a780e7e https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=413a8644966a9b4709b114bdb102f64f505d57ef https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=64ca7170c9b17042dc63828b56681aaea88ca38e -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[Bug 215025] [amdgpu] Thinkpad A275 hangs on shutdown / screen does not turn on after reboot
https://bugzilla.kernel.org/show_bug.cgi?id=215025 --- Comment #2 from Bjoern Franke (b...@nord-west.org) --- Tested 5.14.16 - ok Tried 5.15.0 and 5.15.1 -> don't even boot, the first 3 lines look misarranged. I will try to bisect between 5.14.16 and 5.15.2. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[Bug 215025] [amdgpu] Thinkpad A275 hangs on shutdown / screen does not turn on after reboot
https://bugzilla.kernel.org/show_bug.cgi?id=215025 --- Comment #1 from Bjoern Franke (b...@nord-west.org) --- BTW, iommu is enabled: [0.739887] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank). -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[Bug 215025] New: [amdgpu] Thinkpad A275 hangs on shutdown / screen does not turn on after reboot
https://bugzilla.kernel.org/show_bug.cgi?id=215025 Bug ID: 215025 Summary: [amdgpu] Thinkpad A275 hangs on shutdown / screen does not turn on after reboot Product: Drivers Version: 2.5 Kernel Version: 5.15.2 Hardware: All OS: Linux Tree: Mainline Status: NEW Severity: normal Priority: P1 Component: Video(DRI - non Intel) Assignee: drivers_video-...@kernel-bugs.osdl.org Reporter: b...@nord-west.org Regression: No My Thinkpad A275 hangs while going into suspend. The screen turned off, but it does not really enter suspend mode (according to journalctl it started suspending). Even after reboots the screen does not turn on again, I have to power off the Thinkpad and then power it on again. The issue did not exist with 5.14.x. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
Re: [PATCH v10, 00/19] Support multi hardware decode using of_platform_populate
Hi Yunfei, On Thu, 11 Nov 2021 at 01:15, Yunfei Dong wrote: > > This series adds support for multi hardware decode into mtk-vcodec, by first > adding use > of_platform_populate to manage each hardware information: interrupt, clock, > register > bases and power. Secondly add core work queue to deal with core hardware > message, > at the same time, add msg queue for different hardware share messages. > Lastly, the > architecture of different specs are not the same, using specs type to > separate them. > > This series has been tested with both MT8183 and MT8173. Decoding was working > for both chips. > How are you testing Decoding? If you are running some test suite, it would be good to add such information. Are you testing some edge-cases such as parallel/concurrent decoding, removing the driver while streaming, and so on? This should help catch some typical issues. Thanks, Ezequiel > Patches 1~3 rewrite get register bases and power on/off interface. > Patches 4 export decoder pm interfaces. > Patches 5 add to support 8192. > Patch 6 support multi hardware. > Patch 7 separate video encoder and decoder document > Patch 8-17 add interfaces to support core hardware. > Patch 18-19 remove mtk_vcodec_release_dec/enc_pm interfaces. > --- > changes compared with v9: > - need not to build ko, just export pm interfaces for patch 04/19. > - fix comments for patch 06/19 > > changes compared with v8: > - add new patch 18~19 to remove mtk_vcodec_release_de/enc_pm interfaces. > - fix spelling mistakes for patch 17/19 > - fix yaml comments for patch 15/19 > > Changes compared with v7: > - add new patch 4 to build decoder pm file as module > - add new patch 5 to support 8192 > - fix comments for patch 6/17 > - change some logic for using work queue instead of create thread for core > hardware decode for patch 10/17 > - using work queue for hardware decode instead of create thread for patch > 13/17 > - add returen value for patch 14/17 > - fix yaml check fail 15/17 > > Changes compared with v6: > - Use of_platform_populate to manage multi hardware, not component framework > for patch 4/15 > - Re-write dtsi document for hardware architecture changed for patch 13/15 > -The dtsi will write like below in patch 13/15: > vcodec_dec: vcodec_dec@1600 { > compatible = "mediatek,mt8192-vcodec-dec"; > #address-cells = <2>; > #size-cells = <2>; > ranges; > reg = <0 0x1600 0 0x1000>; /* VDEC_SYS */ > mediatek,scp = <>; > iommus = < M4U_PORT_L4_VDEC_MC_EXT>; > dma-ranges = <0x1 0x0 0x0 0x4000 0x0 0xfff0>; > vcodec_lat { > compatible = "mediatek,mtk-vcodec-lat"; > reg = <0 0x1601 0 0x800>; /* VDEC_MISC */ > reg-name = "reg-misc"; > interrupts = ; > iommus = < M4U_PORT_L5_VDEC_LAT0_VLD_EXT>, > < M4U_PORT_L5_VDEC_LAT0_VLD2_EXT>, > < M4U_PORT_L5_VDEC_LAT0_AVC_MV_EXT>, > < M4U_PORT_L5_VDEC_LAT0_PRED_RD_EXT>, > < M4U_PORT_L5_VDEC_LAT0_TILE_EXT>, > < M4U_PORT_L5_VDEC_LAT0_WDMA_EXT>, > < M4U_PORT_L5_VDEC_LAT0_RG_CTRL_DMA_EXT>, > < M4U_PORT_L5_VDEC_UFO_ENC_EXT>; > clocks = < CLK_TOP_VDEC_SEL>, > <_soc CLK_VDEC_SOC_VDEC>, > <_soc CLK_VDEC_SOC_LAT>, > <_soc CLK_VDEC_SOC_LARB1>, > < CLK_TOP_MAINPLL_D4>; > clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat", > "vdec-vdec", "vdec-top"; > assigned-clocks = < CLK_TOP_VDEC_SEL>; > assigned-clock-parents = < CLK_TOP_MAINPLL_D4>; > power-domains = < MT8192_POWER_DOMAIN_VDEC>; > }; > > vcodec_core { > compatible = "mediatek,mtk-vcodec-core"; > reg = <0 0x16025000 0 0x1000>; /* VDEC_CORE_MISC */ > reg-names = "reg-misc"; > interrupts = ; > iommus = < M4U_PORT_L4_VDEC_MC_EXT>, > < M4U_PORT_L4_VDEC_UFO_EXT>, > < M4U_PORT_L4_VDEC_PP_EXT>, > < M4U_PORT_L4_VDEC_PRED_RD_EXT>, > < M4U_PORT_L4_VDEC_PRED_WR_EXT>, > < M4U_PORT_L4_VDEC_PPWRAP_EXT>, > < M4U_PORT_L4_VDEC_TILE_EXT>, > < M4U_PORT_L4_VDEC_VLD_EXT>, > < M4U_PORT_L4_VDEC_VLD2_EXT>, > < M4U_PORT_L4_VDEC_AVC_MV_EXT>, > < M4U_PORT_L4_VDEC_RG_CTRL_DMA_EXT>; > clocks = < CLK_TOP_VDEC_SEL>, > < CLK_VDEC_VDEC>, > < CLK_VDEC_LAT>, > < CLK_VDEC_LARB1>, > < CLK_TOP_MAINPLL_D4>; > clock-names = "vdec-sel", "vdec-soc-vdec", "vdec-soc-lat", > "vdec-vdec", "vdec-top"; > assigned-clocks = < CLK_TOP_VDEC_SEL>; >
Re: [PATCH v10, 15/19] dt-bindings: media: mtk-vcodec: Adds decoder dt-bindings for mt8192
Yunfei, On Thu, 11 Nov 2021 at 01:15, Yunfei Dong wrote: > > Adds decoder dt-bindings for mt8192. > > Signed-off-by: Yunfei Dong > --- > .../media/mediatek,vcodec-subdev-decoder.yaml | 261 ++ > 1 file changed, 261 insertions(+) > create mode 100644 > Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml > > diff --git > a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml > b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml > new file mode 100644 > index ..1886fae6e39d > --- /dev/null > +++ > b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml > @@ -0,0 +1,261 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > + > +%YAML 1.2 > +--- > +$id: > "http://devicetree.org/schemas/media/mediatek,vcodec-subdev-decoder.yaml#; > +$schema: "http://devicetree.org/meta-schemas/core.yaml#; > + > +title: Mediatek Video Decode Accelerator With Multi Hardware > + > +maintainers: > + - Yunfei Dong > + > +description: | > + Mediatek Video Decode is the video decode hardware present in Mediatek > + SoCs which supports high resolution decoding functionalities. Required > + main and subdev device node. > + > + About the Decoder Hardware Block Diagram, please check below: > + > ++-++ > +| || > +| input -> lat HW -> lat buffer --|--> lat buffer -> core HW -> output | To be completely honest, I can't really understand what is the meaning of the blocks with input -> lat hw -> lat buffer, and how this means lat- and core- are children of some parent. > +||| | || | > ++||---+-||-+ > + || lat thread | core thread|| > + > -||-|| > + || || > + \/\/ > + +--+ > + |enable/disable| > + | clk powerirqiommu port | > + | (lat/lat soc/core0/core1)| > + +--+ > + > + As above, mean in main device, mean in subdev device. The > information > + of each hardware will be stored in subdev device. There are two workqueues > in main device: > + lat and core. Enable/disable the lat clk/power/irq when lat need to work > through hardware > + index, core is the same. > + > + Normally the smi common may not the same for each hardware, can't combine > all hardware in > + one node, or leading to iommu fault when access dram data. > + To what extent the lat- and core- devices are really "children" or "subdevices" of the video-codec@1600 device? I.e. what resources do they share? What are the details of their bus topology? > + > +examples: > + - | > +#include > +#include > +#include > +#include > +#include > + > +video-codec@1600 { > +compatible = "mediatek,mt8192-vcodec-dec"; > +reg = <0x1600 0x1000>; /* VDEC_SYS */ > +mediatek,scp = <>; > +iommus = < M4U_PORT_L4_VDEC_MC_EXT>; > +dma-ranges = <0x1 0x0 0x0 0x4000 0x0 0xfff0>; > +#address-cells = <1>; > +#size-cells = <1>; > +ranges; > +vcodec-lat@1601 { > +compatible = "mediatek,mtk-vcodec-lat"; > +reg = <0x1601 0x800>; > +interrupts = ; > +iommus = < M4U_PORT_L5_VDEC_LAT0_VLD_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_VLD2_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_AVC_MV_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_PRED_RD_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_TILE_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_WDMA_EXT>, > +< M4U_PORT_L5_VDEC_LAT0_RG_CTRL_DMA_EXT>, > +< M4U_PORT_L5_VDEC_UFO_ENC_EXT>; > +clocks = < CLK_TOP_VDEC_SEL>, > +<_soc CLK_VDEC_SOC_VDEC>, > +<_soc CLK_VDEC_SOC_LAT>, > +<_soc CLK_VDEC_SOC_LARB1>, > +< CLK_TOP_MAINPLL_D4>; > +clock-names = "sel", "soc-vdec", "soc-lat", "vdec", "top"; > +assigned-clocks = < CLK_TOP_VDEC_SEL>; > +assigned-clock-parents = < CLK_TOP_MAINPLL_D4>; > +power-domains = < MT8192_POWER_DOMAIN_VDEC>; > +}; > + > +vcodec-core@16025000 { > +compatible = "mediatek,mtk-vcodec-core"; > +reg = <0x16025000 0x1000>; The children address space might
Re: [git pull] drm fixes + one missed next for 5.16-rc1
On Sun, Nov 14, 2021 at 1:00 PM Dave Airlie wrote: > > i915 will no longer be x86-64 only in theory, since Intel now produces > PCIe graphics cards using the same hw designs. Well, at least in my tree, it still has the "depends on X86", along with several other x86-only things (like "select INTEL_GTT", which is also x86-only) So by the time that non-x86 theory becomes reality, hopefully the i915 people will also have figured out how to do the cache flushing properly. And hopefully that "do it properly" ends up being simply that the particular configuration that ends up being portable simply doesn't need to do it at all and can statically just not build it, sidestepping the issue entirely. Fingers crossed. .. of course, I'm also sure some clueless hardware engineer is still convinced that non-coherent IO is the way to go for graphics, and that doing cross-CPU IPIs to write back all caches is somehow still a valid model. Because some people were still convinced about that not _that_ long ago. Hopefully reality (perhaps in the form of Apple) has caused people to finally reconsider. Linus
Re: [git pull] drm fixes + one missed next for 5.16-rc1
On Sat, 13 Nov 2021 at 06:16, Linus Torvalds wrote: > > On Thu, Nov 11, 2021 at 7:25 PM Dave Airlie wrote: > > > > I missed a drm-misc-next pull for the main pull last week. It wasn't > > that major and isn't the bulk of this at all. This has a bunch of > > fixes all over, a lot for amdgpu and i915. > > Ugh. > > The i915 conflict was trivial, but made me aware of that absolutely > disgusting "wbinvd_on_all_cpus()" hack. > > And that thing is much too ugly to survive. I made my merge resolution > remove that disgusting thing. > > That driver is x86-only anyway, so it all seemed completely bogus in > the first place. > > And if there is some actual non-x86 work in progress for i915, then > that wbinvd_on_all_cpus() needs to be replaced with something proper > and architecture-neutral anyway, most definitely involving a name > change, and almost certainly also involving a range for the cache > writeback. > > Because that "create broken macro on other architectures" thing is > *NOT* acceptable. > > And I sincerely hope to the gods that no cache-incoherent i915 mess > ever makes it out of the x86 world. Incoherent IO was always a > historical mistake and should never ever happen again, so we should > not spread that horrific pattern around. i915 will no longer be x86-64 only in theory, since Intel now produces PCIe graphics cards using the same hw designs. These shouldn't AFAIK require the same incoherent architecture, though PCIe unsnooped transactions are a thing in the real world. The thing is the same driver needs to build/work for the integrated and discrete cards, hence this hack, but I'm sure someone can Intel can do better. I'll leave it to Daniel to figure out who/how. Dave.
[Bug 214921] amdgpu hangs HP Laptop on shutdown
https://bugzilla.kernel.org/show_bug.cgi?id=214921 spassw...@web.de changed: What|Removed |Added Kernel Version|5.15, 5.15.1|5.15, 5.15.1, ||5.15.0-next-2022 --- Comment #4 from spassw...@web.de --- This still bug is still present in the 5.15.0-next-2022 where it breaks suspend: static int uvd_v6_0_suspend(void *handle) { int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; /* * Proper cleanups before halting the HW engine: * - cancel the delayed idle work * - enable powergating * - enable clockgating * - disable dpm * * TODO: to align with the VCN implementation, move the * jobs for clockgating/powergating/dpm setting to * ->set_powergating_state(). */ #if 0 cancel_delayed_work_sync(>uvd.idle_work); if (adev->pm.dpm_enabled) { amdgpu_dpm_enable_uvd(adev, false); } else { amdgpu_asic_set_uvd_clocks(adev, 0, 0); /* shutdown the UVD block */ amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_UVD, AMD_PG_STATE_GATE); amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_UVD, AMD_CG_STATE_GATE); } #endif r = uvd_v6_0_hw_fini(adev); if (r) return r; return amdgpu_uvd_suspend(adev); } This makes suspend work again. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[PATCH v1 2/2] drm/panel: sharp: lq101r1sx01: Support LQ101R1SX03
From: Anton Bambura LQ101R1SX03 is compatible with LQ101R1SX01, add compatible to the driver. Signed-off-by: Anton Bambura --- drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index f8cd2a42ed13..bbd1d889e069 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c @@ -304,6 +304,7 @@ static const struct drm_panel_funcs sharp_panel_funcs = { static const struct of_device_id sharp_of_match[] = { { .compatible = "sharp,lq101r1sx01", }, + { .compatible = "sharp,lq101r1sx03", }, { } }; MODULE_DEVICE_TABLE(of, sharp_of_match); -- 2.33.1
[PATCH v1 0/2] Support Sharp LQ101R1SX03 display panel
Add support for Sharp LQ101R1SX03 display panel used by ASUS Transformer TF701T tablet device. Anton Bambura (2): dt-bindings: sharp,lq101r1sx01: Add compatible for LQ101R1SX03 drm/panel: sharp: lq101r1sx01: Support LQ101R1SX03 .../devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml | 4 +++- drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) -- 2.33.1
[PATCH v1 1/2] dt-bindings: sharp, lq101r1sx01: Add compatible for LQ101R1SX03
From: Anton Bambura LQ101R1SX03 is compatible with LQ101R1SX01, document it. Signed-off-by: Anton Bambura --- .../devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml b/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml index a679d3647dbd..f7514eb9ebda 100644 --- a/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml +++ b/Documentation/devicetree/bindings/display/panel/sharp,lq101r1sx01.yaml @@ -30,7 +30,9 @@ allOf: properties: compatible: -const: sharp,lq101r1sx01 +enum: + - sharp,lq101r1sx01 + - sharp,lq101r1sx03 reg: true power-supply: true -- 2.33.1
[PATCH v1 0/2] Support HannStar HSD101PWW2 display panel
Add support for HannStar HSD101PWW2 display panel used by ASUS Transformer TF201T tablet device. Svyatoslav Ryhel (2): dt-bindings: display: simple: Add HannStar HSD101PWW2 drm/panel: simple: Add support for HannStar HSD101PWW2 panel .../bindings/display/panel/panel-simple.yaml | 2 ++ drivers/gpu/drm/panel/panel-simple.c | 28 +++ 2 files changed, 30 insertions(+) -- 2.33.1
[PATCH v1 1/2] dt-bindings: display: simple: Add HannStar HSD101PWW2
From: Svyatoslav Ryhel Add HannStar HSD101PWW2 10.1" WXGA (1280x800) TFT-LCD LVDS panel to the list of compatibles. Signed-off-by: Svyatoslav Ryhel --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index f3c9395d23b6..ecb9a79c2e78 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -156,6 +156,8 @@ properties: - hannstar,hsd070pww1 # HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel - hannstar,hsd100pxn1 +# HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel + - hannstar,hsd101pww2 # Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel - hit,tx23d38vm0caa # InfoVision Optoelectronics M133NWF4 R0 13.3" FHD (1920x1080) TFT LCD panel -- 2.33.1
[PATCH v1 2/2] drm/panel: simple: Add support for HannStar HSD101PWW2 panel
From: Svyatoslav Ryhel Add definition of the HannStar HSD101PWW2 Rev0-A00/A01 LCD SuperIPS+ HD panel. Signed-off-by: Svyatoslav Ryhel --- drivers/gpu/drm/panel/panel-simple.c | 28 1 file changed, 28 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index eb475a3a774b..8b7033048f83 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1927,6 +1927,31 @@ static const struct panel_desc hannstar_hsd100pxn1 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing hannstar_hsd101pww2_timing = { + .pixelclock = { 6430, 7110, 8200 }, + .hactive = { 1280, 1280, 1280 }, + .hfront_porch = { 1, 1, 10 }, + .hback_porch = { 1, 1, 10 }, + .hsync_len = { 58, 158, 661 }, + .vactive = { 800, 800, 800 }, + .vfront_porch = { 1, 1, 10 }, + .vback_porch = { 1, 1, 10 }, + .vsync_len = { 1, 21, 203 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc hannstar_hsd101pww2 = { + .timings = _hsd101pww2_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 217, + .height = 136, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = { .clock = 3, .hdisplay = 800, @@ -3725,6 +3750,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "hannstar,hsd100pxn1", .data = _hsd100pxn1, + }, { + .compatible = "hannstar,hsd101pww2", + .data = _hsd101pww2, }, { .compatible = "hit,tx23d38vm0caa", .data = _tx23d38vm0caa -- 2.33.1
[PATCH v15 14/39] drm/tegra: vic: Stop channel on suspend
CDMA must be stopped before hardware is suspended. Add channel stopping to RPM suspend callback. Add system level suspend-resume callbacks. Runtime PM initialization is moved to host1x client init phase because RPM callback now uses host1x channel that is available only when host1x client is registered. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/vic.c | 36 ++-- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index b58e2b99f81a..9622ca96c539 100644 --- a/drivers/gpu/drm/tegra/vic.c +++ b/drivers/gpu/drm/tegra/vic.c @@ -151,9 +151,13 @@ static int vic_init(struct host1x_client *client) goto free_channel; } + pm_runtime_enable(client->dev); + pm_runtime_use_autosuspend(client->dev); + pm_runtime_set_autosuspend_delay(client->dev, 500); + err = tegra_drm_register_client(tegra, drm); if (err < 0) - goto free_syncpt; + goto disable_rpm; /* * Inherit the DMA parameters (such as maximum segment size) from the @@ -163,7 +167,10 @@ static int vic_init(struct host1x_client *client) return 0; -free_syncpt: +disable_rpm: + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_syncpt_put(client->syncpts[0]); free_channel: host1x_channel_put(vic->channel); @@ -188,10 +195,15 @@ static int vic_exit(struct host1x_client *client) if (err < 0) return err; + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(vic->channel); host1x_client_iommu_detach(client); + vic->channel = NULL; + if (client->group) { dma_unmap_single(vic->dev, vic->falcon.firmware.phys, vic->falcon.firmware.size, DMA_TO_DEVICE); @@ -315,6 +327,8 @@ static int vic_runtime_suspend(struct device *dev) struct vic *vic = dev_get_drvdata(dev); int err; + host1x_channel_stop(vic->channel); + err = reset_control_assert(vic->rst); if (err < 0) return err; @@ -482,19 +496,8 @@ static int vic_probe(struct platform_device *pdev) goto exit_falcon; } - pm_runtime_enable(>dev); - if (!pm_runtime_enabled(>dev)) { - err = vic_runtime_resume(>dev); - if (err < 0) - goto unregister_client; - } - pm_runtime_set_autosuspend_delay(>dev, 500); - pm_runtime_use_autosuspend(>dev); - return 0; -unregister_client: - host1x_client_unregister(>client.base); exit_falcon: falcon_exit(>falcon); @@ -513,11 +516,6 @@ static int vic_remove(struct platform_device *pdev) return err; } - if (pm_runtime_enabled(>dev)) - pm_runtime_disable(>dev); - else - vic_runtime_suspend(>dev); - falcon_exit(>falcon); return 0; @@ -525,6 +523,8 @@ static int vic_remove(struct platform_device *pdev) static const struct dev_pm_ops vic_pm_ops = { SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver tegra_vic_driver = { -- 2.33.1
[PATCH v15 36/39] ARM: tegra: Add OPP tables and power domains to Tegra30 device-trees
Add OPP tables and power domains to all peripheral devices which support power management on Tegra30 SoC. Tested-by: Peter Geis # Ouya T30 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20-trimslice.dts |2 +- .../tegra30-asus-nexus7-grouper-common.dtsi |1 + arch/arm/boot/dts/tegra30-beaver.dts |1 + arch/arm/boot/dts/tegra30-cardhu.dtsi |1 + arch/arm/boot/dts/tegra30-colibri.dtsi| 17 +- arch/arm/boot/dts/tegra30-ouya.dts|1 + .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 1227 - arch/arm/boot/dts/tegra30.dtsi| 153 ++ 8 files changed, 1398 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index 306e5f33e7f8..7646a4a1f2be 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -445,7 +445,7 @@ pci_vdd_reg: regulator-pcivdd { regulator-always-on; }; - vdd_core: regulator@5 { + vdd_core: regulator-core { compatible = "regulator-fixed"; regulator-name = "vdd_core"; regulator-min-microvolt = <130>; diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi index e6aed19a5f3b..e7a3327e603c 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi @@ -980,6 +980,7 @@ pmc@7000e400 { nvidia,core-pwr-off-time = <0>; nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; + core-supply = <_core>; }; ahub@7008 { diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index 2ec5e47d9623..24de27a8594e 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -1915,6 +1915,7 @@ pmc@7000e400 { nvidia,core-pwr-off-time = <0>; nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; + core-supply = <_vdd_reg>; }; ahub@7008 { diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index d2f6121049a4..506cb747b2db 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -391,6 +391,7 @@ pmc@7000e400 { nvidia,core-pwr-off-time = <0>; nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; + core-supply = <_core>; }; ahub@7008 { diff --git a/arch/arm/boot/dts/tegra30-colibri.dtsi b/arch/arm/boot/dts/tegra30-colibri.dtsi index 413e35215804..0627b64f044d 100644 --- a/arch/arm/boot/dts/tegra30-colibri.dtsi +++ b/arch/arm/boot/dts/tegra30-colibri.dtsi @@ -765,9 +765,14 @@ vdd1_reg: vdd1 { vddctrl_reg: vddctrl { regulator-name = "+V1.0_VDD_CPU"; - regulator-min-microvolt = <115>; - regulator-max-microvolt = <115>; + regulator-min-microvolt = <80>; + regulator-max-microvolt = <125>; + regulator-coupled-with = <_core>; + regulator-coupled-max-spread = <30>; + regulator-max-step-microvolt = <10>; regulator-always-on; + + nvidia,tegra-cpu-regulator; }; reg_1v8_vio: vio { @@ -890,18 +895,23 @@ temp-sensor@4c { }; /* SW: +V1.2_VDD_CORE */ - regulator@60 { + vdd_core: regulator@60 { compatible = "ti,tps62362"; reg = <0x60>; regulator-name = "tps62362-vout"; regulator-min-microvolt = <90>; regulator-max-microvolt = <140>; + regulator-coupled-with = <_reg>; + regulator-coupled-max-spread = <30>; + regulator-max-step-microvolt = <10>; regulator-boot-on; regulator-always-on; ti,vsel0-state-low; /* VSEL1: EN_CORE_DVFS_N low for DVFS */ ti,vsel1-state-low; + + nvidia,tegra-core-regulator; }; }; @@ -914,6 +924,7 @@ pmc@7000e400 { nvidia,core-pwr-off-time = <0>;
[PATCH v15 34/39] ARM: tegra: Add 500MHz entry to Tegra30 memory OPP table
Extend memory OPPs with 500MHz entry. This clock rate is used by ASUS Transformer tablets. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra30-peripherals-opp.dtsi | 18 ++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi index ff25350869b3..af9640401402 100644 --- a/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi @@ -216,6 +216,18 @@ opp-45000-1250 { opp-supported-hw = <0x0008>; }; + opp-5-1200 { + opp-microvolt = <120 120 135>; + opp-hz = /bits/ 64 <5>; + opp-supported-hw = <0x0007>; + }; + + opp-5-1250 { + opp-microvolt = <125 125 135>; + opp-hz = /bits/ 64 <5>; + opp-supported-hw = <0x0008>; + }; + opp-53300-1200 { opp-microvolt = <120 120 135>; opp-hz = /bits/ 64 <53300>; @@ -347,6 +359,12 @@ opp-45000 { opp-peak-kBps = <360>; }; + opp-5 { + opp-hz = /bits/ 64 <5>; + opp-supported-hw = <0x000F>; + opp-peak-kBps = <400>; + }; + opp-53300 { opp-hz = /bits/ 64 <53300>; opp-supported-hw = <0x000F>; -- 2.33.1
[PATCH v15 39/39] ARM: tegra20/30: Disable unused host1x hardware
MPE, VI, EPP and ISP were never used and we don't have drivers for them. Since these modules are enabled by default in a device-tree, a device is created for them, blocking voltage scaling because there is no driver to bind, and thus, state of PMC driver is never synced. Disable them. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20.dtsi | 4 arch/arm/boot/dts/tegra30.dtsi | 8 2 files changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 7b69ffc57abe..8010b40d7377 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -59,6 +59,7 @@ mpe@5404 { reset-names = "mpe"; power-domains = <_mpe>; operating-points-v2 = <_dvfs_opp_table>; + status = "disabled"; }; vi@5408 { @@ -70,6 +71,7 @@ vi@5408 { reset-names = "vi"; power-domains = <_venc>; operating-points-v2 = <_dvfs_opp_table>; + status = "disabled"; }; epp@540c { @@ -81,6 +83,7 @@ epp@540c { reset-names = "epp"; power-domains = <_core>; operating-points-v2 = <_dvfs_opp_table>; + status = "disabled"; }; isp@5410 { @@ -91,6 +94,7 @@ isp@5410 { resets = <_car 23>; reset-names = "isp"; power-domains = <_venc>; + status = "disabled"; }; gr2d@5414 { diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index c1be136aac7d..d961ce3761e6 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -145,6 +145,8 @@ mpe@5404 { operating-points-v2 = <_dvfs_opp_table>; iommus = < TEGRA_SWGROUP_MPE>; + + status = "disabled"; }; vi@5408 { @@ -158,6 +160,8 @@ vi@5408 { operating-points-v2 = <_dvfs_opp_table>; iommus = < TEGRA_SWGROUP_VI>; + + status = "disabled"; }; epp@540c { @@ -171,6 +175,8 @@ epp@540c { operating-points-v2 = <_dvfs_opp_table>; iommus = < TEGRA_SWGROUP_EPP>; + + status = "disabled"; }; isp@5410 { @@ -183,6 +189,8 @@ isp@5410 { power-domains = <_venc>; iommus = < TEGRA_SWGROUP_ISP>; + + status = "disabled"; }; gr2d@5414 { -- 2.33.1
[PATCH v15 37/39] ARM: tegra: Add Memory Client resets to Tegra20 GR2D, GR3D and Host1x
Memory access must be blocked before hardware reset is asserted and before power is gated, otherwise a serious hardware fault is inevitable. Add reset for memory clients to the GR2D, GR3D and Host1x nodes. Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20.dtsi | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 1898351a099f..7b69ffc57abe 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -40,8 +40,8 @@ host1x@5000 { interrupt-names = "syncpt", "host1x"; clocks = <_car TEGRA20_CLK_HOST1X>; clock-names = "host1x"; - resets = <_car 28>; - reset-names = "host1x"; + resets = <_car 28>, < TEGRA20_MC_RESET_HC>; + reset-names = "host1x", "mc"; power-domains = <_core>; operating-points-v2 = <_dvfs_opp_table>; @@ -98,8 +98,8 @@ gr2d@5414 { reg = <0x5414 0x0004>; interrupts = ; clocks = <_car TEGRA20_CLK_GR2D>; - resets = <_car 21>; - reset-names = "2d"; + resets = <_car 21>, < TEGRA20_MC_RESET_2D>; + reset-names = "2d", "mc"; power-domains = <_core>; operating-points-v2 = <_dvfs_opp_table>; }; @@ -108,8 +108,8 @@ gr3d@5418 { compatible = "nvidia,tegra20-gr3d"; reg = <0x5418 0x0004>; clocks = <_car TEGRA20_CLK_GR3D>; - resets = <_car 24>; - reset-names = "3d"; + resets = <_car 24>, < TEGRA20_MC_RESET_3D>; + reset-names = "3d", "mc"; power-domains = <_3d>; operating-points-v2 = <_dvfs_opp_table>; }; -- 2.33.1
[PATCH v15 23/39] spi: tegra20-slink: Add OPP support
The SPI on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now SPI driver must use OPP API for driving the controller's clock rate because OPP API takes care of reconfiguring the domain's performance state in accordance to the rate. Add OPP support to the driver. Acked-by: Mark Brown Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/spi/spi-tegra20-slink.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index e8204e155484..2a03739a0c60 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -18,12 +18,15 @@ #include #include #include +#include #include #include #include #include #include +#include + #define SLINK_COMMAND 0x000 #define SLINK_BIT_LENGTH(x)(((x) & 0x1f) << 0) #define SLINK_WORD_SIZE(x) (((x) & 0x1f) << 5) @@ -680,7 +683,7 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi, bits_per_word = t->bits_per_word; speed = t->speed_hz; if (speed != tspi->cur_speed) { - clk_set_rate(tspi->clk, speed * 4); + dev_pm_opp_set_rate(tspi->dev, speed * 4); tspi->cur_speed = speed; } @@ -1066,6 +1069,10 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_master; } + ret = devm_tegra_core_dev_init_opp_table_common(>dev); + if (ret) + goto exit_free_master; + tspi->max_buf_size = SLINK_FIFO_DEPTH << 2; tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN; -- 2.33.1
[PATCH v15 30/39] soc/tegra: pmc: Rename 3d power domains
Device-tree schema doesn't allow domain name to start with a number. We don't use 3d domain yet in device-trees, so rename it to the name used by Tegra TRMs: TD, TD2. Reported-by: David Heidelberg Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/pmc.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 1a55b8319d63..e1fae1a5e36a 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2992,7 +2992,7 @@ static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); static const char * const tegra20_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -3100,7 +3100,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu0", - [TEGRA_POWERGATE_3D] = "3d0", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -3112,7 +3112,7 @@ static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU2] = "cpu2", [TEGRA_POWERGATE_CPU3] = "cpu3", [TEGRA_POWERGATE_CELP] = "celp", - [TEGRA_POWERGATE_3D1] = "3d1", + [TEGRA_POWERGATE_3D1] = "td2", }; static const u8 tegra30_cpu_powergates[] = { @@ -3161,7 +3161,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { static const char * const tegra114_powergates[] = { [TEGRA_POWERGATE_CPU] = "crail", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_MPE] = "mpe", -- 2.33.1
[PATCH v15 38/39] ARM: tegra: Add Memory Client resets to Tegra30 GR2D, GR3D and Host1x
Memory access must be blocked before hardware reset is asserted and before power is gated, otherwise a serious hardware fault is inevitable. Add reset for memory clients to the GR2D, GR3D and Host1x nodes. Tested-by: Peter Geis # Ouya T30 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra30.dtsi | 14 -- 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index e40d5563778b..c1be136aac7d 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -123,8 +123,8 @@ host1x@5000 { interrupt-names = "syncpt", "host1x"; clocks = <_car TEGRA30_CLK_HOST1X>; clock-names = "host1x"; - resets = <_car 28>; - reset-names = "host1x"; + resets = <_car 28>, < TEGRA30_MC_RESET_HC>; + reset-names = "host1x", "mc"; iommus = < TEGRA_SWGROUP_HC>; power-domains = <_heg>; operating-points-v2 = <_dvfs_opp_table>; @@ -190,8 +190,8 @@ gr2d@5414 { reg = <0x5414 0x0004>; interrupts = ; clocks = <_car TEGRA30_CLK_GR2D>; - resets = <_car 21>; - reset-names = "2d"; + resets = <_car 21>, < TEGRA30_MC_RESET_2D>; + reset-names = "2d", "mc"; power-domains = <_heg>; operating-points-v2 = <_dvfs_opp_table>; @@ -205,8 +205,10 @@ gr3d@5418 { <_car TEGRA30_CLK_GR3D2>; clock-names = "3d", "3d2"; resets = <_car 24>, -<_car 98>; - reset-names = "3d", "3d2"; +<_car 98>, +< TEGRA30_MC_RESET_3D>, +< TEGRA30_MC_RESET_3D2>; + reset-names = "3d", "3d2", "mc", "mc2"; power-domains = <_3d0>, <_3d1>; power-domain-names = "3d0", "3d1"; operating-points-v2 = <_dvfs_opp_table>; -- 2.33.1
[PATCH v15 22/39] mtd: rawnand: tegra: Add runtime PM and OPP support
The NAND on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now NAND must be resumed using runtime PM API in order to initialize the NAND power state. Add runtime PM and OPP support to the NAND driver. Reviewed-by: Ulf Hansson Acked-by: Miquel Raynal Signed-off-by: Dmitry Osipenko --- drivers/mtd/nand/raw/tegra_nand.c | 58 ++- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index 32431bbe69b8..b36e5260ae27 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -17,8 +17,11 @@ #include #include #include +#include #include +#include + #define COMMAND0x00 #define COMMAND_GO BIT(31) #define COMMAND_CLE BIT(30) @@ -1151,6 +1154,7 @@ static int tegra_nand_probe(struct platform_device *pdev) return -ENOMEM; ctrl->dev = >dev; + platform_set_drvdata(pdev, ctrl); nand_controller_init(>controller); ctrl->controller.ops = _nand_controller_ops; @@ -1166,14 +1170,23 @@ static int tegra_nand_probe(struct platform_device *pdev) if (IS_ERR(ctrl->clk)) return PTR_ERR(ctrl->clk); - err = clk_prepare_enable(ctrl->clk); + err = devm_tegra_core_dev_init_opp_table_common(>dev); + if (err) + return err; + + /* +* This driver doesn't support active power management yet, +* so we will simply keep device resumed. +*/ + pm_runtime_enable(>dev); + err = pm_runtime_resume_and_get(>dev); if (err) return err; err = reset_control_reset(rst); if (err) { dev_err(ctrl->dev, "Failed to reset HW: %d\n", err); - goto err_disable_clk; + goto err_put_pm; } writel_relaxed(HWSTATUS_CMD_DEFAULT, ctrl->regs + HWSTATUS_CMD); @@ -1188,21 +1201,20 @@ static int tegra_nand_probe(struct platform_device *pdev) dev_name(>dev), ctrl); if (err) { dev_err(ctrl->dev, "Failed to get IRQ: %d\n", err); - goto err_disable_clk; + goto err_put_pm; } writel_relaxed(DMA_MST_CTRL_IS_DONE, ctrl->regs + DMA_MST_CTRL); err = tegra_nand_chips_init(ctrl->dev, ctrl); if (err) - goto err_disable_clk; - - platform_set_drvdata(pdev, ctrl); + goto err_put_pm; return 0; -err_disable_clk: - clk_disable_unprepare(ctrl->clk); +err_put_pm: + pm_runtime_put_sync_suspend(ctrl->dev); + pm_runtime_force_suspend(ctrl->dev); return err; } @@ -1219,11 +1231,40 @@ static int tegra_nand_remove(struct platform_device *pdev) nand_cleanup(chip); + pm_runtime_put_sync_suspend(ctrl->dev); + pm_runtime_force_suspend(ctrl->dev); + + return 0; +} + +static int __maybe_unused tegra_nand_runtime_resume(struct device *dev) +{ + struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(ctrl->clk); + if (err) { + dev_err(dev, "Failed to enable clock: %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra_nand_runtime_suspend(struct device *dev) +{ + struct tegra_nand_controller *ctrl = dev_get_drvdata(dev); + clk_disable_unprepare(ctrl->clk); return 0; } +static const struct dev_pm_ops tegra_nand_pm = { + SET_RUNTIME_PM_OPS(tegra_nand_runtime_suspend, tegra_nand_runtime_resume, + NULL) +}; + static const struct of_device_id tegra_nand_of_match[] = { { .compatible = "nvidia,tegra20-nand" }, { /* sentinel */ } @@ -1234,6 +1275,7 @@ static struct platform_driver tegra_nand_driver = { .driver = { .name = "tegra-nand", .of_match_table = tegra_nand_of_match, + .pm = _nand_pm, }, .probe = tegra_nand_probe, .remove = tegra_nand_remove, -- 2.33.1
[PATCH v15 35/39] ARM: tegra: Add OPP tables and power domains to Tegra20 device-trees
Add OPP tables and power domains to all peripheral devices which support power management on Tegra20 SoC. Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 Signed-off-by: Dmitry Osipenko --- .../boot/dts/tegra20-acer-a500-picasso.dts| 1 + arch/arm/boot/dts/tegra20-colibri.dtsi| 3 +- arch/arm/boot/dts/tegra20-harmony.dts | 3 +- arch/arm/boot/dts/tegra20-paz00.dts | 1 + .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 913 ++ arch/arm/boot/dts/tegra20-seaboard.dts| 3 +- arch/arm/boot/dts/tegra20-tamonten.dtsi | 3 +- arch/arm/boot/dts/tegra20-trimslice.dts | 9 + arch/arm/boot/dts/tegra20-ventana.dts | 1 + arch/arm/boot/dts/tegra20.dtsi| 102 +- 10 files changed, 1034 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index e1b33d25b6e0..db388ddd062f 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -716,6 +716,7 @@ pmc@7000e400 { nvidia,core-pwr-good-time = <3845 3845>; nvidia,core-pwr-off-time = <458>; nvidia,sys-clock-req-active-high; + core-supply = <_core>; }; usb@c500 { diff --git a/arch/arm/boot/dts/tegra20-colibri.dtsi b/arch/arm/boot/dts/tegra20-colibri.dtsi index 3f9cb5cd6bd8..eb5b3feb5907 100644 --- a/arch/arm/boot/dts/tegra20-colibri.dtsi +++ b/arch/arm/boot/dts/tegra20-colibri.dtsi @@ -495,7 +495,7 @@ reg_3v3_vsys: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "VDD_CORE_1.2V"; regulator-min-microvolt = <120>; regulator-max-microvolt = <120>; @@ -601,6 +601,7 @@ pmc@7000e400 { nvidia,core-pwr-good-time = <3845 3845>; nvidia,core-pwr-off-time = <3875>; nvidia,sys-clock-req-active-high; + core-supply = <_core>; /* Set SLEEP MODE bit in SUPPLYENE register of TPS658643 PMIC */ i2c-thermtrip { diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index a8494378c382..b4cc88b0f130 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -339,7 +339,7 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; regulator-min-microvolt = <120>; regulator-max-microvolt = <120>; @@ -565,6 +565,7 @@ pmc@7000e400 { nvidia,core-pwr-good-time = <3845 3845>; nvidia,core-pwr-off-time = <3875>; nvidia,sys-clock-req-active-high; + core-supply = <_core>; }; pcie@80003000 { diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 1fd5a7458c7a..f68d37ae6c64 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -519,6 +519,7 @@ pmc@7000e400 { nvidia,core-pwr-good-time = <3845 3845>; nvidia,core-pwr-off-time = <0>; nvidia,sys-clock-req-active-high; + core-supply = <_vdd_reg>; }; usb@c500 { diff --git a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi index d4d0a5fa7015..e7477b129e34 100644 --- a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi @@ -1,6 +1,46 @@ // SPDX-License-Identifier: GPL-2.0 / { + core_opp_table: opp-table-core { + compatible = "operating-points-v2"; + opp-shared; + + core_opp_950: opp-95 { + opp-microvolt = <95 95 130>; + opp-level = <95>; + }; + + core_opp_1000: opp-100 { + opp-microvolt = <100 100 130>; + opp-level = <100>; + }; + + core_opp_1100: opp-110 { + opp-microvolt = <110 110 130>; + opp-level = <110>; + }; + + core_opp_1200: opp-120 { + opp-microvolt = <120 120 130>; + opp-level = <120>; + }; + +
[PATCH v15 24/39] media: dt: bindings: tegra-vde: Convert to schema
Convert NVIDIA Tegra video decoder binding to schema. Reviewed-by: Rob Herring Acked-by: Hans Verkuil Signed-off-by: Dmitry Osipenko --- .../bindings/media/nvidia,tegra-vde.txt | 64 --- .../bindings/media/nvidia,tegra-vde.yaml | 107 ++ 2 files changed, 107 insertions(+), 64 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt create mode 100644 Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt deleted file mode 100644 index 602169b8aa19.. --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt +++ /dev/null @@ -1,64 +0,0 @@ -NVIDIA Tegra Video Decoder Engine - -Required properties: -- compatible : Must contain one of the following values: - - "nvidia,tegra20-vde" - - "nvidia,tegra30-vde" - - "nvidia,tegra114-vde" - - "nvidia,tegra124-vde" - - "nvidia,tegra132-vde" -- reg : Must contain an entry for each entry in reg-names. -- reg-names : Must include the following entries: - - sxe - - bsev - - mbe - - ppe - - mce - - tfe - - ppb - - vdma - - frameid -- iram : Must contain phandle to the mmio-sram device node that represents - IRAM region used by VDE. -- interrupts : Must contain an entry for each entry in interrupt-names. -- interrupt-names : Must include the following entries: - - sync-token - - bsev - - sxe -- clocks : Must include the following entries: - - vde -- resets : Must contain an entry for each entry in reset-names. -- reset-names : Should include the following entries: - - vde - -Optional properties: -- resets : Must contain an entry for each entry in reset-names. -- reset-names : Must include the following entries: - - mc -- iommus: Must contain phandle to the IOMMU device node. - -Example: - -video-codec@6001a000 { - compatible = "nvidia,tegra20-vde"; - reg = <0x6001a000 0x1000 /* Syntax Engine */ - 0x6001b000 0x1000 /* Video Bitstream Engine */ - 0x6001c000 0x100 /* Macroblock Engine */ - 0x6001c200 0x100 /* Post-processing Engine */ - 0x6001c400 0x100 /* Motion Compensation Engine */ - 0x6001c600 0x100 /* Transform Engine */ - 0x6001c800 0x100 /* Pixel prediction block */ - 0x6001ca00 0x100 /* Video DMA */ - 0x6001d800 0x300 /* Video frame controls */>; - reg-names = "sxe", "bsev", "mbe", "ppe", "mce", - "tfe", "ppb", "vdma", "frameid"; - iram = <_pool>; /* IRAM region */ - interrupts = , /* Sync token interrupt */ -, /* BSE-V interrupt */ -; /* SXE interrupt */ - interrupt-names = "sync-token", "bsev", "sxe"; - clocks = <_car TEGRA20_CLK_VDE>; - reset-names = "vde", "mc"; - resets = <_car 61>, < TEGRA20_MC_RESET_VDE>; - iommus = < TEGRA_SWGROUP_VDE>; -}; diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml new file mode 100644 index ..c143aaa06346 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nvidia,tegra-vde.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NVIDIA Tegra Video Decoder Engine + +maintainers: + - Dmitry Osipenko + - Jon Hunter + - Thierry Reding + +properties: + compatible: +oneOf: + - items: + - enum: + - nvidia,tegra132-vde + - nvidia,tegra124-vde + - nvidia,tegra114-vde + - items: + - const: nvidia,tegra30-vde + - const: nvidia,tegra20-vde + - items: + - const: nvidia,tegra20-vde + + reg: +maxItems: 9 + + reg-names: +items: + - const: sxe + - const: bsev + - const: mbe + - const: ppe + - const: mce + - const: tfe + - const: ppb + - const: vdma + - const: frameid + + clocks: +maxItems: 1 + + resets: +maxItems: 2 + + reset-names: +items: + - const: vde + - const: mc + + interrupts: +maxItems: 3 + + interrupt-names: +items: + - const: sync-token + - const: bsev + - const: sxe + + iommus: +maxItems: 1 + + iram: +$ref: /schemas/types.yaml#/definitions/phandle +description: + Phandle of the SRAM MMIO node. + +required: + - compatible + - reg + - reg-names + - clocks + - resets + - reset-names + - interrupts + - interrupt-names + +additionalProperties: false + +examples: + - | +video-codec@6001a000 { + compatible = "nvidia,tegra20-vde"; + reg = <0x6001a000 0x1000>, /* Syntax Engine */ +<0x6001b000 0x1000>, /* Video
[PATCH v15 21/39] mmc: sdhci-tegra: Add runtime PM and OPP support
The SDHCI on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now SDHCI must be resumed using runtime PM API in order to initialize the SDHCI power state. The SDHCI clock rate must be changed using OPP API that will reconfigure the power domain performance state in accordance to the rate. Add runtime PM and OPP support to the SDHCI driver. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/mmc/host/sdhci-tegra.c | 81 +++--- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index a5001875876b..6435a75142a6 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -24,6 +26,8 @@ #include #include +#include + #include "sdhci-pltfm.h" #include "cqhci.h" @@ -760,7 +764,9 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct device *dev = mmc_dev(host->mmc); unsigned long host_clk; + int err; if (!clock) return sdhci_set_clock(host, clock); @@ -778,7 +784,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * from clk_get_rate() is used. */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; - clk_set_rate(pltfm_host->clk, host_clk); + + err = dev_pm_opp_set_rate(dev, host_clk); + if (err) + dev_err(dev, "failed to set clk rate to %luHz: %d\n", + host_clk, err); + tegra_host->curr_clk_rate = host_clk; if (tegra_host->ddr_signaling) host->max_clk = host_clk; @@ -1705,7 +1716,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) "failed to get clock\n"); goto err_clk_get; } - clk_prepare_enable(clk); pltfm_host->clk = clk; tegra_host->rst = devm_reset_control_get_exclusive(>dev, @@ -1716,15 +1726,24 @@ static int sdhci_tegra_probe(struct platform_device *pdev) goto err_rst_get; } - rc = reset_control_assert(tegra_host->rst); + rc = devm_tegra_core_dev_init_opp_table_common(>dev); if (rc) goto err_rst_get; + pm_runtime_enable(>dev); + rc = pm_runtime_resume_and_get(>dev); + if (rc) + goto err_pm_get; + + rc = reset_control_assert(tegra_host->rst); + if (rc) + goto err_rst_assert; + usleep_range(2000, 4000); rc = reset_control_deassert(tegra_host->rst); if (rc) - goto err_rst_get; + goto err_rst_assert; usleep_range(2000, 4000); @@ -1736,8 +1755,11 @@ static int sdhci_tegra_probe(struct platform_device *pdev) err_add_host: reset_control_assert(tegra_host->rst); +err_rst_assert: + pm_runtime_put_sync_suspend(>dev); +err_pm_get: + pm_runtime_disable(>dev); err_rst_get: - clk_disable_unprepare(pltfm_host->clk); err_clk_get: clk_disable_unprepare(tegra_host->tmclk); err_power_req: @@ -1756,19 +1778,38 @@ static int sdhci_tegra_remove(struct platform_device *pdev) reset_control_assert(tegra_host->rst); usleep_range(2000, 4000); - clk_disable_unprepare(pltfm_host->clk); - clk_disable_unprepare(tegra_host->tmclk); + pm_runtime_put_sync_suspend(>dev); + pm_runtime_force_suspend(>dev); + + clk_disable_unprepare(tegra_host->tmclk); sdhci_pltfm_free(pdev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int __maybe_unused sdhci_tegra_suspend(struct device *dev) +static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + clk_disable_unprepare(pltfm_host->clk); + + return 0; +} + +static int __maybe_unused sdhci_tegra_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_prepare_enable(pltfm_host->clk); +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_tegra_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); int ret; if (host->mmc->caps2 & MMC_CAP2_CQE) { @@ -1783,17 +1824,22 @@ static int __maybe_unused sdhci_tegra_suspend(struct device *dev) return ret; } - clk_disable_unprepare(pltfm_host->clk); + ret = pm_runtime_force_suspend(dev); + if (ret) { + sdhci_resume_host(host); +
[PATCH v15 25/39] media: dt: bindings: tegra-vde: Document OPP and power domain
Document new OPP table and power domain properties of the video decoder hardware. Reviewed-by: Rob Herring Acked-by: Hans Verkuil Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/media/nvidia,tegra-vde.yaml | 12 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml index c143aaa06346..4ecdee1be37e 100644 --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml @@ -68,6 +68,16 @@ properties: description: Phandle of the SRAM MMIO node. + operating-points-v2: +description: + Should contain freqs and voltages and opp-supported-hw property, + which is a bitfield indicating SoC speedo or process ID mask. + + power-domains: +maxItems: 1 +description: + Phandle to the SoC core power domain. + required: - compatible - reg @@ -104,4 +114,6 @@ examples: reset-names = "vde", "mc"; resets = < 61>, < 13>; iommus = < 15>; + operating-points-v2 = <_opp_table>; + power-domains = <>; }; -- 2.33.1
[PATCH v15 15/39] drm/tegra: nvdec: Stop channel on suspend
CDMA must be stopped before hardware is suspended. Add channel stopping to RPM suspend callback. Add system level suspend-resume callbacks. Runtime PM initialization is moved to host1x client init phase because RPM callback now uses host1x channel that is available only when host1x client is registered. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/nvdec.c | 29 ++--- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c index 791bf1acf5f0..15f036e09e5c 100644 --- a/drivers/gpu/drm/tegra/nvdec.c +++ b/drivers/gpu/drm/tegra/nvdec.c @@ -113,9 +113,13 @@ static int nvdec_init(struct host1x_client *client) goto free_channel; } + pm_runtime_enable(client->dev); + pm_runtime_use_autosuspend(client->dev); + pm_runtime_set_autosuspend_delay(client->dev, 500); + err = tegra_drm_register_client(tegra, drm); if (err < 0) - goto free_syncpt; + goto disable_rpm; /* * Inherit the DMA parameters (such as maximum segment size) from the @@ -125,7 +129,10 @@ static int nvdec_init(struct host1x_client *client) return 0; -free_syncpt: +disable_rpm: + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_syncpt_put(client->syncpts[0]); free_channel: host1x_channel_put(nvdec->channel); @@ -150,10 +157,15 @@ static int nvdec_exit(struct host1x_client *client) if (err < 0) return err; + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(nvdec->channel); host1x_client_iommu_detach(client); + nvdec->channel = NULL; + if (client->group) { dma_unmap_single(nvdec->dev, nvdec->falcon.firmware.phys, nvdec->falcon.firmware.size, DMA_TO_DEVICE); @@ -268,6 +280,8 @@ static __maybe_unused int nvdec_runtime_suspend(struct device *dev) { struct nvdec *nvdec = dev_get_drvdata(dev); + host1x_channel_stop(nvdec->channel); + clk_disable_unprepare(nvdec->clk); return 0; @@ -412,10 +426,6 @@ static int nvdec_probe(struct platform_device *pdev) goto exit_falcon; } - pm_runtime_enable(>dev); - pm_runtime_set_autosuspend_delay(>dev, 500); - pm_runtime_use_autosuspend(>dev); - return 0; exit_falcon: @@ -436,11 +446,6 @@ static int nvdec_remove(struct platform_device *pdev) return err; } - if (pm_runtime_enabled(>dev)) - pm_runtime_disable(>dev); - else - nvdec_runtime_suspend(>dev); - falcon_exit(>falcon); return 0; @@ -448,6 +453,8 @@ static int nvdec_remove(struct platform_device *pdev) static const struct dev_pm_ops nvdec_pm_ops = { SET_RUNTIME_PM_OPS(nvdec_runtime_suspend, nvdec_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; struct platform_driver tegra_nvdec_driver = { -- 2.33.1
[PATCH v15 32/39] soc/tegra: pmc: Enable core domain support for Tegra20 and Tegra30
All device drivers got runtime PM and OPP support. Flip the core domain support status for Tegra20 and Tegra30 SoCs. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index de6234ec4f9b..585a05968ea9 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3070,7 +3070,7 @@ static void tegra20_pmc_setup_irq_polarity(struct tegra_pmc *pmc, } static const struct tegra_pmc_soc tegra20_pmc_soc = { - .supports_core_domain = false, + .supports_core_domain = true, .num_powergates = ARRAY_SIZE(tegra20_powergates), .powergates = tegra20_powergates, .num_cpu_powergates = 0, @@ -3131,7 +3131,7 @@ static const char * const tegra30_reset_sources[] = { }; static const struct tegra_pmc_soc tegra30_pmc_soc = { - .supports_core_domain = false, + .supports_core_domain = true, .num_powergates = ARRAY_SIZE(tegra30_powergates), .powergates = tegra30_powergates, .num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates), -- 2.33.1
[PATCH v15 33/39] ARM: tegra: Rename CPU and EMC OPP table device-tree nodes
OPP table name now should start with "opp-table" and OPP entries shouldn't contain commas and @ signs in accordance to the new schema requirement. Reorganize CPU and EMC OPP table device-tree nodes. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra124-apalis-emc.dtsi| 4 +- .../arm/boot/dts/tegra124-jetson-tk1-emc.dtsi | 4 +- arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi | 8 +- .../arm/boot/dts/tegra124-nyan-blaze-emc.dtsi | 8 +- .../boot/dts/tegra124-peripherals-opp.dtsi| 140 - .../boot/dts/tegra20-acer-a500-picasso.dts| 4 +- arch/arm/boot/dts/tegra20-colibri.dtsi| 2 +- .../boot/dts/tegra20-cpu-opp-microvolt.dtsi | 82 +- arch/arm/boot/dts/tegra20-cpu-opp.dtsi| 82 +- arch/arm/boot/dts/tegra20-paz00.dts | 2 +- .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 36 ++--- ...30-asus-nexus7-grouper-memory-timings.dtsi | 12 +- .../boot/dts/tegra30-cpu-opp-microvolt.dtsi | 144 +- arch/arm/boot/dts/tegra30-cpu-opp.dtsi| 144 +- arch/arm/boot/dts/tegra30-ouya.dts| 4 +- .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 128 16 files changed, 402 insertions(+), 402 deletions(-) diff --git a/arch/arm/boot/dts/tegra124-apalis-emc.dtsi b/arch/arm/boot/dts/tegra124-apalis-emc.dtsi index a7ac805eeed5..3d9cf16f233c 100644 --- a/arch/arm/boot/dts/tegra124-apalis-emc.dtsi +++ b/arch/arm/boot/dts/tegra124-apalis-emc.dtsi @@ -1467,9 +1467,9 @@ timing-92400 { }; _icc_dvfs_opp_table { - /delete-node/ opp@12,1100; + /delete-node/ opp-12-1100; }; _bw_dfs_opp_table { - /delete-node/ opp@12; + /delete-node/ opp-12; }; diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1-emc.dtsi b/arch/arm/boot/dts/tegra124-jetson-tk1-emc.dtsi index df4e463afbd1..bb10cf9fc0f9 100644 --- a/arch/arm/boot/dts/tegra124-jetson-tk1-emc.dtsi +++ b/arch/arm/boot/dts/tegra124-jetson-tk1-emc.dtsi @@ -2422,9 +2422,9 @@ timing-92400 { }; _icc_dvfs_opp_table { - /delete-node/ opp@12,1100; + /delete-node/ opp-12-1100; }; _bw_dfs_opp_table { - /delete-node/ opp@12; + /delete-node/ opp-12; }; diff --git a/arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi b/arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi index a0f56cc9da5c..6f2ea9469d49 100644 --- a/arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi +++ b/arch/arm/boot/dts/tegra124-nyan-big-emc.dtsi @@ -6651,11 +6651,11 @@ timing-79200 { }; _icc_dvfs_opp_table { - /delete-node/ opp@92400,1100; - /delete-node/ opp@12,1100; + /delete-node/ opp-92400-1100; + /delete-node/ opp-12-1100; }; _bw_dfs_opp_table { - /delete-node/ opp@92400; - /delete-node/ opp@12; + /delete-node/ opp-92400; + /delete-node/ opp-12; }; diff --git a/arch/arm/boot/dts/tegra124-nyan-blaze-emc.dtsi b/arch/arm/boot/dts/tegra124-nyan-blaze-emc.dtsi index 35c98734d35f..d47cdb863f88 100644 --- a/arch/arm/boot/dts/tegra124-nyan-blaze-emc.dtsi +++ b/arch/arm/boot/dts/tegra124-nyan-blaze-emc.dtsi @@ -2050,11 +2050,11 @@ timing-79200 { }; _icc_dvfs_opp_table { - /delete-node/ opp@92400,1100; - /delete-node/ opp@12,1100; + /delete-node/ opp-92400-1100; + /delete-node/ opp-12-1100; }; _bw_dfs_opp_table { - /delete-node/ opp@92400; - /delete-node/ opp@12; + /delete-node/ opp-92400; + /delete-node/ opp-12; }; diff --git a/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi index 781ac8601030..b262c1289da5 100644 --- a/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra124-peripherals-opp.dtsi @@ -1,421 +1,421 @@ // SPDX-License-Identifier: GPL-2.0 / { - emc_icc_dvfs_opp_table: emc-dvfs-opp-table { + emc_icc_dvfs_opp_table: opp-table-emc { compatible = "operating-points-v2"; - opp@1275,800 { + opp-1275-800 { opp-microvolt = <80 80 115>; opp-hz = /bits/ 64 <1275>; opp-supported-hw = <0x0003>; }; - opp@1275,950 { + opp-1275-950 { opp-microvolt = <95 95 115>; opp-hz = /bits/ 64 <1275>; opp-supported-hw = <0x0008>; }; - opp@1275,1050 { + opp-1275-1050 { opp-microvolt = <105 105 115>; opp-hz = /bits/ 64 <1275>; opp-supported-hw = <0x0010>; }; - opp@1275,1110 { + opp-1275-1110 {
[PATCH v15 31/39] soc/tegra: pmc: Rename core power domain
CORE power domain uses name of device-tree node, which is inconsistent with the names of PMC domains. Set the name to "core" to make it consistent. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index e1fae1a5e36a..de6234ec4f9b 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1369,7 +1369,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) if (!genpd) return -ENOMEM; - genpd->name = np->name; + genpd->name = "core"; genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; -- 2.33.1
[PATCH v15 17/39] drm/tegra: submit: Add missing pm_runtime_mark_last_busy()
Runtime PM auto-suspension doesn't work without pm_runtime_mark_last_busy(), add it. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/submit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c index 3bbd8de5711c..6d6dd8c35475 100644 --- a/drivers/gpu/drm/tegra/submit.c +++ b/drivers/gpu/drm/tegra/submit.c @@ -504,6 +504,7 @@ static void release_job(struct host1x_job *job) kfree(job_data->used_mappings); kfree(job_data); + pm_runtime_mark_last_busy(client->base.dev); pm_runtime_put_autosuspend(client->base.dev); } -- 2.33.1
[PATCH v15 20/39] pwm: tegra: Add runtime PM and OPP support
The PWM on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now PWM must be resumed using runtime PM API in order to initialize the PWM power state. The PWM clock rate must be changed using OPP API that will reconfigure the power domain performance state in accordance to the rate. Add runtime PM and OPP support to the PWM driver. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/pwm/pwm-tegra.c | 82 - 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 11a10b575ace..18cf974ac776 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -42,12 +42,16 @@ #include #include #include +#include #include #include #include +#include #include #include +#include + #define PWM_ENABLE (1 << 31) #define PWM_DUTY_WIDTH 8 #define PWM_DUTY_SHIFT 16 @@ -145,7 +149,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, required_clk_rate = (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH; - err = clk_set_rate(pc->clk, required_clk_rate); + err = dev_pm_opp_set_rate(pc->dev, required_clk_rate); if (err < 0) return -EINVAL; @@ -181,8 +185,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * before writing the register. Otherwise, keep it enabled. */ if (!pwm_is_enabled(pwm)) { - err = clk_prepare_enable(pc->clk); - if (err < 0) + err = pm_runtime_resume_and_get(pc->dev); + if (err) return err; } else val |= PWM_ENABLE; @@ -193,7 +197,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM is not enabled, turn the clock off again to save power. */ if (!pwm_is_enabled(pwm)) - clk_disable_unprepare(pc->clk); + pm_runtime_put(pc->dev); return 0; } @@ -204,8 +208,8 @@ static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) int rc = 0; u32 val; - rc = clk_prepare_enable(pc->clk); - if (rc < 0) + rc = pm_runtime_resume_and_get(pc->dev); + if (rc) return rc; val = pwm_readl(pc, pwm->hwpwm); @@ -224,7 +228,7 @@ static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) val &= ~PWM_ENABLE; pwm_writel(pc, pwm->hwpwm, val); - clk_disable_unprepare(pc->clk); + pm_runtime_put_sync(pc->dev); } static const struct pwm_ops tegra_pwm_ops = { @@ -256,11 +260,20 @@ static int tegra_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); + ret = devm_tegra_core_dev_init_opp_table_common(>dev); + if (ret) + return ret; + + pm_runtime_enable(>dev); + ret = pm_runtime_resume_and_get(>dev); + if (ret) + return ret; + /* Set maximum frequency of the IP */ - ret = clk_set_rate(pwm->clk, pwm->soc->max_frequency); + ret = dev_pm_opp_set_rate(pwm->dev, pwm->soc->max_frequency); if (ret < 0) { dev_err(>dev, "Failed to set max frequency: %d\n", ret); - return ret; + goto put_pm; } /* @@ -278,7 +291,7 @@ static int tegra_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm->rst)) { ret = PTR_ERR(pwm->rst); dev_err(>dev, "Reset control is not found: %d\n", ret); - return ret; + goto put_pm; } reset_control_deassert(pwm->rst); @@ -291,10 +304,16 @@ static int tegra_pwm_probe(struct platform_device *pdev) if (ret < 0) { dev_err(>dev, "pwmchip_add() failed: %d\n", ret); reset_control_assert(pwm->rst); - return ret; + goto put_pm; } + pm_runtime_put(>dev); + return 0; +put_pm: + pm_runtime_put_sync_suspend(>dev); + pm_runtime_force_suspend(>dev); + return ret; } static int tegra_pwm_remove(struct platform_device *pdev) @@ -305,20 +324,44 @@ static int tegra_pwm_remove(struct platform_device *pdev) reset_control_assert(pc->rst); + pm_runtime_force_suspend(>dev); + return 0; } -#ifdef CONFIG_PM_SLEEP -static int tegra_pwm_suspend(struct device *dev) +static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev) { - return pinctrl_pm_select_sleep_state(dev); + struct tegra_pwm_chip *pc = dev_get_drvdata(dev); + int err; + + clk_disable_unprepare(pc->clk); + + err = pinctrl_pm_select_sleep_state(dev); + if (err) { +
[PATCH v15 19/39] bus: tegra-gmi: Add runtime PM and OPP support
The GMI bus on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now GMI must be resumed using runtime PM API in order to initialize the GMI power state. Add runtime PM and OPP support to the GMI driver. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/bus/tegra-gmi.c | 50 - 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index a6570789f7af..35b59f92fa66 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -13,8 +13,11 @@ #include #include #include +#include #include +#include + #define TEGRA_GMI_CONFIG 0x00 #define TEGRA_GMI_CONFIG_GOBIT(31) #define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30) @@ -54,9 +57,10 @@ static int tegra_gmi_enable(struct tegra_gmi *gmi) { int err; - err = clk_prepare_enable(gmi->clk); - if (err < 0) { - dev_err(gmi->dev, "failed to enable clock: %d\n", err); + pm_runtime_enable(gmi->dev); + err = pm_runtime_resume_and_get(gmi->dev); + if (err) { + pm_runtime_disable(gmi->dev); return err; } @@ -83,7 +87,9 @@ static void tegra_gmi_disable(struct tegra_gmi *gmi) writel(config, gmi->base + TEGRA_GMI_CONFIG); reset_control_assert(gmi->rst); - clk_disable_unprepare(gmi->clk); + + pm_runtime_put_sync_suspend(gmi->dev); + pm_runtime_force_suspend(gmi->dev); } static int tegra_gmi_parse_dt(struct tegra_gmi *gmi) @@ -213,6 +219,7 @@ static int tegra_gmi_probe(struct platform_device *pdev) if (!gmi) return -ENOMEM; + platform_set_drvdata(pdev, gmi); gmi->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -232,6 +239,10 @@ static int tegra_gmi_probe(struct platform_device *pdev) return PTR_ERR(gmi->rst); } + err = devm_tegra_core_dev_init_opp_table_common(>dev); + if (err) + return err; + err = tegra_gmi_parse_dt(gmi); if (err) return err; @@ -247,8 +258,6 @@ static int tegra_gmi_probe(struct platform_device *pdev) return err; } - platform_set_drvdata(pdev, gmi); - return 0; } @@ -262,6 +271,34 @@ static int tegra_gmi_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev) +{ + struct tegra_gmi *gmi = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(gmi->clk); + if (err < 0) { + dev_err(gmi->dev, "failed to enable clock: %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra_gmi_runtime_suspend(struct device *dev) +{ + struct tegra_gmi *gmi = dev_get_drvdata(dev); + + clk_disable_unprepare(gmi->clk); + + return 0; +} + +static const struct dev_pm_ops tegra_gmi_pm = { + SET_RUNTIME_PM_OPS(tegra_gmi_runtime_suspend, tegra_gmi_runtime_resume, + NULL) +}; + static const struct of_device_id tegra_gmi_id_table[] = { { .compatible = "nvidia,tegra20-gmi", }, { .compatible = "nvidia,tegra30-gmi", }, @@ -275,6 +312,7 @@ static struct platform_driver tegra_gmi_driver = { .driver = { .name = "tegra-gmi", .of_match_table = tegra_gmi_id_table, + .pm = _gmi_pm, }, }; module_platform_driver(tegra_gmi_driver); -- 2.33.1
[PATCH v15 26/39] media: staging: tegra-vde: Support generic power domain
Currently driver supports legacy power domain API, this patch adds generic power domain support. This allows us to utilize a modern GENPD API for newer device-trees. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Acked-by: Hans Verkuil Signed-off-by: Dmitry Osipenko --- drivers/staging/media/tegra-vde/vde.c | 63 ++- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index ed4c1250b303..859f60a70904 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "uapi.h" @@ -920,13 +921,17 @@ static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev) struct tegra_vde *vde = dev_get_drvdata(dev); int err; - err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC); - if (err) { - dev_err(dev, "Failed to power down HW: %d\n", err); - return err; + if (!dev->pm_domain) { + err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC); + if (err) { + dev_err(dev, "Failed to power down HW: %d\n", err); + return err; + } } clk_disable_unprepare(vde->clk); + reset_control_release(vde->rst); + reset_control_release(vde->rst_mc); return 0; } @@ -936,14 +941,45 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev) struct tegra_vde *vde = dev_get_drvdata(dev); int err; - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, - vde->clk, vde->rst); + err = reset_control_acquire(vde->rst_mc); if (err) { - dev_err(dev, "Failed to power up HW : %d\n", err); + dev_err(dev, "Failed to acquire mc reset: %d\n", err); return err; } + err = reset_control_acquire(vde->rst); + if (err) { + dev_err(dev, "Failed to acquire reset: %d\n", err); + goto release_mc_reset; + } + + if (!dev->pm_domain) { + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, + vde->clk, vde->rst); + if (err) { + dev_err(dev, "Failed to power up HW : %d\n", err); + goto release_reset; + } + } else { + /* +* tegra_powergate_sequence_power_up() leaves clocks enabled, +* while GENPD not. +*/ + err = clk_prepare_enable(vde->clk); + if (err) { + dev_err(dev, "Failed to enable clock: %d\n", err); + goto release_reset; + } + } + return 0; + +release_reset: + reset_control_release(vde->rst); +release_mc_reset: + reset_control_release(vde->rst_mc); + + return err; } static int tegra_vde_probe(struct platform_device *pdev) @@ -1001,14 +1037,14 @@ static int tegra_vde_probe(struct platform_device *pdev) return err; } - vde->rst = devm_reset_control_get(dev, NULL); + vde->rst = devm_reset_control_get_exclusive_released(dev, NULL); if (IS_ERR(vde->rst)) { err = PTR_ERR(vde->rst); dev_err(dev, "Could not get VDE reset %d\n", err); return err; } - vde->rst_mc = devm_reset_control_get_optional(dev, "mc"); + vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, "mc"); if (IS_ERR(vde->rst_mc)) { err = PTR_ERR(vde->rst_mc); dev_err(dev, "Could not get MC reset %d\n", err); @@ -1026,6 +1062,12 @@ static int tegra_vde_probe(struct platform_device *pdev) return err; } + err = devm_tegra_core_dev_init_opp_table_common(dev); + if (err) { + dev_err(dev, "Could initialize OPP table %d\n", err); + return err; + } + vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0); if (!vde->iram_pool) { dev_err(dev, "Could not get IRAM pool\n"); @@ -1133,8 +1175,7 @@ static void tegra_vde_shutdown(struct platform_device *pdev) * On some devices bootloader isn't ready to a power-gated VDE on * a warm-reboot, machine will hang in that case. */ - if (pm_runtime_status_suspended(>dev)) - tegra_vde_runtime_resume(>dev); + pm_runtime_get_sync(>dev); } static __maybe_unused int tegra_vde_pm_suspend(struct device *dev) -- 2.33.1
[PATCH v15 29/39] soc/tegra: regulators: Prepare for suspend
Depending on hardware version, Tegra SoC may require a higher voltages during resume from system suspend, otherwise hardware will crash. Set SoC voltages to a nominal levels during suspend. Link: https://lore.kernel.org/all/a8280b5b-7347-8995-c97b-10b798cdf...@gmail.com/ Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/regulators-tegra20.c | 99 drivers/soc/tegra/regulators-tegra30.c | 122 + 2 files changed, 221 insertions(+) diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index b8ce9fd0650d..6a2f90ab9d3e 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -16,7 +16,9 @@ #include #include #include +#include +#include #include struct tegra_regulator_coupler { @@ -25,9 +27,12 @@ struct tegra_regulator_coupler { struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -105,6 +110,28 @@ static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev, return 15; } +static int tegra20_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 110; + case 1: + return 1025000; + default: + return 1125000; + } +} + +static int tegra20_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + default: + return 1225000; + case 2: + return 130; + } +} + static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *core_rdev, struct regulator_dev *rtc_rdev, @@ -144,6 +171,11 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra20_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -279,6 +311,11 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra20_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -320,6 +357,7 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, @@ -334,6 +372,63 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, +bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + /* +* All power domains are enabled early during resume from suspend +* by GENPD core. Domains like VENC may require a higher voltage +* when enabled during resume from suspend. This also prepares +* hardware for resuming from LP0. +*/ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra20_regulator_suspend(struct notifier_block *notifier, +unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, +suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret =
[PATCH v15 27/39] soc/tegra: fuse: Reset hardware
The FUSE controller is enabled at a boot time. Reset it in order to put hardware and clock into clean and disabled state. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/fuse/fuse-tegra.c | 25 + drivers/soc/tegra/fuse/fuse.h | 1 + 2 files changed, 26 insertions(+) diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index f2151815db58..cc032729a143 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -243,6 +244,30 @@ static int tegra_fuse_probe(struct platform_device *pdev) goto restore; } + fuse->rst = devm_reset_control_get_optional(>dev, "fuse"); + if (IS_ERR(fuse->rst)) { + err = PTR_ERR(fuse->rst); + dev_err(>dev, "failed to get FUSE reset: %pe\n", + fuse->rst); + goto restore; + } + + /* +* FUSE clock is enabled at a boot time, hence this resume/suspend +* disables the clock besides the h/w resetting. +*/ + err = pm_runtime_resume_and_get(>dev); + if (err) + goto restore; + + err = reset_control_reset(fuse->rst); + pm_runtime_put(>dev); + + if (err < 0) { + dev_err(>dev, "failed to reset FUSE: %d\n", err); + goto restore; + } + /* release the early I/O memory mapping */ iounmap(base); diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index de58feba0435..1b719d85bd04 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -43,6 +43,7 @@ struct tegra_fuse { void __iomem *base; phys_addr_t phys; struct clk *clk; + struct reset_control *rst; u32 (*read_early)(struct tegra_fuse *fuse, unsigned int offset); u32 (*read)(struct tegra_fuse *fuse, unsigned int offset); -- 2.33.1
[PATCH v15 28/39] soc/tegra: fuse: Use resource-managed helpers
Use resource-managed helpers to make code cleaner and more correct, properly releasing all resources in case of driver probe error. Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/fuse/fuse-tegra.c | 32 ++ drivers/soc/tegra/fuse/fuse-tegra20.c | 33 --- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index cc032729a143..fe4f935ce73a 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -182,6 +182,12 @@ static const struct nvmem_cell_info tegra_fuse_cells[] = { }, }; +static void tegra_fuse_restore(void *base) +{ + fuse->clk = NULL; + fuse->base = base; +} + static int tegra_fuse_probe(struct platform_device *pdev) { void __iomem *base = fuse->base; @@ -189,13 +195,16 @@ static int tegra_fuse_probe(struct platform_device *pdev) struct resource *res; int err; + err = devm_add_action(>dev, tegra_fuse_restore, base); + if (err) + return err; + /* take over the memory region from the early initialization */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); fuse->phys = res->start; fuse->base = devm_ioremap_resource(>dev, res); if (IS_ERR(fuse->base)) { err = PTR_ERR(fuse->base); - fuse->base = base; return err; } @@ -205,19 +214,20 @@ static int tegra_fuse_probe(struct platform_device *pdev) dev_err(>dev, "failed to get FUSE clock: %ld", PTR_ERR(fuse->clk)); - fuse->base = base; return PTR_ERR(fuse->clk); } platform_set_drvdata(pdev, fuse); fuse->dev = >dev; - pm_runtime_enable(>dev); + err = devm_pm_runtime_enable(>dev); + if (err) + return err; if (fuse->soc->probe) { err = fuse->soc->probe(fuse); if (err < 0) - goto restore; + return err; } memset(, 0, sizeof(nvmem)); @@ -241,7 +251,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->nvmem); dev_err(>dev, "failed to register NVMEM device: %d\n", err); - goto restore; + return err; } fuse->rst = devm_reset_control_get_optional(>dev, "fuse"); @@ -249,7 +259,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->rst); dev_err(>dev, "failed to get FUSE reset: %pe\n", fuse->rst); - goto restore; + return err; } /* @@ -258,26 +268,20 @@ static int tegra_fuse_probe(struct platform_device *pdev) */ err = pm_runtime_resume_and_get(>dev); if (err) - goto restore; + return err; err = reset_control_reset(fuse->rst); pm_runtime_put(>dev); if (err < 0) { dev_err(>dev, "failed to reset FUSE: %d\n", err); - goto restore; + return err; } /* release the early I/O memory mapping */ iounmap(base); return 0; - -restore: - fuse->clk = NULL; - fuse->base = base; - pm_runtime_disable(>dev); - return err; } static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev) diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 8ec9fc5e5e4b..12503f563e36 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -94,9 +94,28 @@ static bool dma_filter(struct dma_chan *chan, void *filter_param) return of_device_is_compatible(np, "nvidia,tegra20-apbdma"); } +static void tegra20_fuse_release_channel(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_release_channel(fuse->apbdma.chan); + fuse->apbdma.chan = NULL; +} + +static void tegra20_fuse_free_coherent(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_free_coherent(fuse->dev, sizeof(u32), fuse->apbdma.virt, + fuse->apbdma.phys); + fuse->apbdma.virt = NULL; + fuse->apbdma.phys = 0x0; +} + static int tegra20_fuse_probe(struct tegra_fuse *fuse) { dma_cap_mask_t mask; + int err; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -105,13 +124,21 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) if (!fuse->apbdma.chan) return -EPROBE_DEFER; + err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_release_channel, + fuse); + if (err) + return err; + fuse->apbdma.virt =
[PATCH v15 18/39] usb: chipidea: tegra: Add runtime PM and OPP support
The Tegra USB controller belongs to the core power domain and we're going to enable GENPD support for the core domain. Now USB controller must be resumed using runtime PM API in order to initialize the USB power state. We already support runtime PM for the CI device, but CI's PM is separated from the RPM managed by tegra-usb driver. Add runtime PM and OPP support to the driver. Acked-by: Peter Chen Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/usb/chipidea/ci_hdrc_tegra.c | 53 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 60361141ac04..a72a9474afea 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -15,6 +16,8 @@ #include #include +#include + #include "../host/ehci.h" #include "ci.h" @@ -278,6 +281,8 @@ static int tegra_usb_probe(struct platform_device *pdev) if (!usb) return -ENOMEM; + platform_set_drvdata(pdev, usb); + soc = of_device_get_match_data(>dev); if (!soc) { dev_err(>dev, "failed to match OF data\n"); @@ -296,11 +301,14 @@ static int tegra_usb_probe(struct platform_device *pdev) return err; } - err = clk_prepare_enable(usb->clk); - if (err < 0) { - dev_err(>dev, "failed to enable clock: %d\n", err); + err = devm_tegra_core_dev_init_opp_table_common(>dev); + if (err) + return err; + + pm_runtime_enable(>dev); + err = pm_runtime_resume_and_get(>dev); + if (err) return err; - } if (device_property_present(>dev, "nvidia,needs-double-reset")) usb->needs_double_reset = true; @@ -320,8 +328,6 @@ static int tegra_usb_probe(struct platform_device *pdev) if (err) goto fail_power_off; - platform_set_drvdata(pdev, usb); - /* setup and register ChipIdea HDRC device */ usb->soc = soc; usb->data.name = "tegra-usb"; @@ -350,7 +356,9 @@ static int tegra_usb_probe(struct platform_device *pdev) phy_shutdown: usb_phy_shutdown(usb->phy); fail_power_off: - clk_disable_unprepare(usb->clk); + pm_runtime_put_sync_suspend(>dev); + pm_runtime_force_suspend(>dev); + return err; } @@ -360,15 +368,46 @@ static int tegra_usb_remove(struct platform_device *pdev) ci_hdrc_remove_device(usb->dev); usb_phy_shutdown(usb->phy); + + pm_runtime_put_sync_suspend(>dev); + pm_runtime_force_suspend(>dev); + + return 0; +} + +static int __maybe_unused tegra_usb_runtime_resume(struct device *dev) +{ + struct tegra_usb *usb = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(usb->clk); + if (err < 0) { + dev_err(dev, "failed to enable clock: %d\n", err); + return err; + } + + return 0; +} + +static int __maybe_unused tegra_usb_runtime_suspend(struct device *dev) +{ + struct tegra_usb *usb = dev_get_drvdata(dev); + clk_disable_unprepare(usb->clk); return 0; } +static const struct dev_pm_ops tegra_usb_pm = { + SET_RUNTIME_PM_OPS(tegra_usb_runtime_suspend, tegra_usb_runtime_resume, + NULL) +}; + static struct platform_driver tegra_usb_driver = { .driver = { .name = "tegra-usb", .of_match_table = tegra_usb_of_match, + .pm = _usb_pm, }, .probe = tegra_usb_probe, .remove = tegra_usb_remove, -- 2.33.1
[PATCH v15 16/39] drm/tegra: submit: Remove pm_runtime_enabled() checks
Runtime PM is now universally available, make it mandatory by removing the pm_runtime_enabled() checks. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/submit.c | 13 + 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c index c32698404e36..3bbd8de5711c 100644 --- a/drivers/gpu/drm/tegra/submit.c +++ b/drivers/gpu/drm/tegra/submit.c @@ -504,8 +504,7 @@ static void release_job(struct host1x_job *job) kfree(job_data->used_mappings); kfree(job_data); - if (pm_runtime_enabled(client->base.dev)) - pm_runtime_put_autosuspend(client->base.dev); + pm_runtime_put_autosuspend(client->base.dev); } int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data, @@ -589,12 +588,10 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data, } /* Boot engine. */ - if (pm_runtime_enabled(context->client->base.dev)) { - err = pm_runtime_resume_and_get(context->client->base.dev); - if (err < 0) { - SUBMIT_ERR(context, "could not power up engine: %d", err); - goto unpin_job; - } + err = pm_runtime_resume_and_get(context->client->base.dev); + if (err < 0) { + SUBMIT_ERR(context, "could not power up engine: %d", err); + goto unpin_job; } job->user_data = job_data; -- 2.33.1
[PATCH v15 09/39] gpu: host1x: Add host1x_channel_stop()
Add host1x_channel_stop() which waits till channel becomes idle and then stops the channel hardware. This is needed for supporting suspend/resume by host1x drivers since the hardware state is lost after power-gating, thus the channel needs to be stopped before client enters into suspend. Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/gpu/host1x/channel.c | 8 include/linux/host1x.h | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 4cd212bb570d..2a9a3a8d5931 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -75,6 +75,14 @@ struct host1x_channel *host1x_channel_get_index(struct host1x *host, return ch; } +void host1x_channel_stop(struct host1x_channel *channel) +{ + struct host1x *host = dev_get_drvdata(channel->dev->parent); + + host1x_hw_cdma_stop(host, >cdma); +} +EXPORT_SYMBOL(host1x_channel_stop); + static void release_channel(struct kref *kref) { struct host1x_channel *channel = diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 2ca53d7ed7ca..e8dc5bc41f79 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -226,6 +226,7 @@ struct host1x_job; struct host1x_channel *host1x_channel_request(struct host1x_client *client); struct host1x_channel *host1x_channel_get(struct host1x_channel *channel); +void host1x_channel_stop(struct host1x_channel *channel); void host1x_channel_put(struct host1x_channel *channel); int host1x_job_submit(struct host1x_job *job); -- 2.33.1
[PATCH v15 06/39] dt-bindings: host1x: Document OPP and power domain properties
Document new DVFS OPP table and power domain properties of the Host1x bus and devices sitting on the bus. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko --- .../display/tegra/nvidia,tegra20-host1x.txt | 49 +++ 1 file changed, 49 insertions(+) diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index 8a6d3e1ee306..62861a8fb5c6 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -20,6 +20,18 @@ Required properties: - reset-names: Must include the following entries: - host1x +Optional properties: +- operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. + +For each opp entry in 'operating-points-v2' table of host1x and its modules: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. + Each host1x client module having to perform DMA through the Memory Controller should have the interconnect endpoints set to the Memory Client and External Memory respectively. @@ -45,6 +57,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to MPE power domain. - vi: video input @@ -128,6 +142,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to VENC power domain. - epp: encoder pre-processor @@ -147,6 +163,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. - isp: image signal processor @@ -166,6 +184,7 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - power-domains: Phandle to VENC or core power domain. - gr2d: 2D graphics engine @@ -185,6 +204,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to HEG or core power domain. - gr3d: 3D graphics engine @@ -209,6 +230,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandles to 3D or core power domain. - dc: display controller @@ -241,6 +264,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to core power domain. - hdmi: High Definition Multimedia Interface @@ -267,6 +292,7 @@ of the following host1x client modules: - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob - nvidia,panel: phandle of a display panel + - operating-points-v2: See ../bindings/opp/opp.txt for details. - tvo: TV encoder output @@ -277,6 +303,10 @@ of the following host1x client modules: - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + Optional properties: + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - power-domains: Phandle to core power domain. + - dsi: display serial interface Required properties: @@
[PATCH v15 12/39] drm/tegra: gr2d: Support generic power domain and runtime PM
Add runtime power management and support generic power domains. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/gr2d.c | 184 --- 1 file changed, 148 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index ba3722f1b865..b4cd7655b3dc 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -8,12 +8,21 @@ #include #include #include +#include #include +#include + #include "drm.h" #include "gem.h" #include "gr2d.h" +enum { + RST_MC, + RST_GR2D, + RST_GR2D_MAX, +}; + struct gr2d_soc { unsigned int version; }; @@ -21,9 +30,11 @@ struct gr2d_soc { struct gr2d { struct tegra_drm_client client; struct host1x_channel *channel; - struct reset_control *rst; struct clk *clk; + struct reset_control_bulk_data resets[RST_GR2D_MAX]; + unsigned int nresets; + const struct gr2d_soc *soc; DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS); @@ -59,15 +70,22 @@ static int gr2d_init(struct host1x_client *client) goto free; } + pm_runtime_enable(client->dev); + pm_runtime_use_autosuspend(client->dev); + pm_runtime_set_autosuspend_delay(client->dev, 200); + err = tegra_drm_register_client(dev->dev_private, drm); if (err < 0) { dev_err(client->dev, "failed to register client: %d\n", err); - goto detach; + goto disable_rpm; } return 0; -detach: +disable_rpm: + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_client_iommu_detach(client); free: host1x_syncpt_put(client->syncpts[0]); @@ -88,10 +106,15 @@ static int gr2d_exit(struct host1x_client *client) if (err < 0) return err; + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_client_iommu_detach(client); host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr2d->channel); + gr2d->channel = NULL; + return 0; } @@ -104,10 +127,17 @@ static int gr2d_open_channel(struct tegra_drm_client *client, struct tegra_drm_context *context) { struct gr2d *gr2d = to_gr2d(client); + int err; + + err = pm_runtime_resume_and_get(client->base.dev); + if (err) + return err; context->channel = host1x_channel_get(gr2d->channel); - if (!context->channel) + if (!context->channel) { + pm_runtime_put(context->client->base.dev); return -ENOMEM; + } return 0; } @@ -115,6 +145,7 @@ static int gr2d_open_channel(struct tegra_drm_client *client, static void gr2d_close_channel(struct tegra_drm_context *context) { host1x_channel_put(context->channel); + pm_runtime_put(context->client->base.dev); } static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) @@ -193,6 +224,27 @@ static const u32 gr2d_addr_regs[] = { GR2D_VA_BASE_ADDR_SB, }; +static int gr2d_get_resets(struct device *dev, struct gr2d *gr2d) +{ + int err; + + gr2d->resets[RST_MC].id = "mc"; + gr2d->resets[RST_GR2D].id = "2d"; + gr2d->nresets = RST_GR2D_MAX; + + err = devm_reset_control_bulk_get_optional_exclusive_released( + dev, gr2d->nresets, gr2d->resets); + if (err) { + dev_err(dev, "failed to get reset: %d\n", err); + return err; + } + + if (WARN_ON(!gr2d->resets[RST_GR2D].rstc)) + return -ENOENT; + + return 0; +} + static int gr2d_probe(struct platform_device *pdev) { struct device *dev = >dev; @@ -205,37 +257,23 @@ static int gr2d_probe(struct platform_device *pdev) if (!gr2d) return -ENOMEM; + platform_set_drvdata(pdev, gr2d); + gr2d->soc = of_device_get_match_data(dev); syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); if (!syncpts) return -ENOMEM; - gr2d->rst = devm_reset_control_get(dev, NULL); - if (IS_ERR(gr2d->rst)) { - dev_err(dev, "cannot get reset\n"); - return PTR_ERR(gr2d->rst); - } - gr2d->clk = devm_clk_get(dev, NULL); if (IS_ERR(gr2d->clk)) { dev_err(dev, "cannot get clock\n"); return PTR_ERR(gr2d->clk); } - err = clk_prepare_enable(gr2d->clk); - if (err) { - dev_err(dev, "cannot turn on clock\n"); + err = gr2d_get_resets(dev, gr2d); + if (err) return err;
[PATCH v15 04/39] dt-bindings: clock: tegra-car: Document new clock sub-nodes
Document sub-nodes which describe Tegra SoC clocks that require a higher voltage of the core power domain in order to operate properly on a higher clock rates. Each node contains a phandle to OPP table and power domain. The root PLLs and system clocks don't have any specific device dedicated to them, clock controller is in charge of managing power for them. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko --- .../bindings/clock/nvidia,tegra20-car.yaml| 37 +++ 1 file changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml index 459d2a525393..f832abb7f11a 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.yaml @@ -42,6 +42,36 @@ properties: "#reset-cells": const: 1 +patternProperties: + "^(sclk)|(pll-[cem])$": +type: object +properties: + compatible: +enum: + - nvidia,tegra20-sclk + - nvidia,tegra30-sclk + - nvidia,tegra30-pllc + - nvidia,tegra30-plle + - nvidia,tegra30-pllm + + operating-points-v2: true + + clocks: +items: + - description: node's clock + + power-domains: +maxItems: 1 +description: phandle to the core SoC power domain + +required: + - compatible + - operating-points-v2 + - clocks + - power-domains + +additionalProperties: false + required: - compatible - reg @@ -59,6 +89,13 @@ examples: reg = <0x60006000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; + +sclk { +compatible = "nvidia,tegra20-sclk"; +operating-points-v2 = <_table>; +clocks = <_car TEGRA20_CLK_SCLK>; +power-domains = <>; +}; }; usb-controller@c5004000 { -- 2.33.1
[PATCH v15 13/39] drm/tegra: gr3d: Support generic power domain and runtime PM
Add runtime power management and support generic power domains. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/gr3d.c | 363 +-- 1 file changed, 305 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 24442ade0da3..25f3f9820e92 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -5,32 +5,47 @@ */ #include +#include #include #include #include #include #include +#include +#include +#include #include +#include #include #include "drm.h" #include "gem.h" #include "gr3d.h" +enum { + RST_MC, + RST_GR3D, + RST_MC2, + RST_GR3D2, + RST_GR3D_MAX, +}; + struct gr3d_soc { unsigned int version; + unsigned int num_clocks; + unsigned int num_resets; }; struct gr3d { struct tegra_drm_client client; struct host1x_channel *channel; - struct clk *clk_secondary; - struct clk *clk; - struct reset_control *rst_secondary; - struct reset_control *rst; const struct gr3d_soc *soc; + struct clk_bulk_data *clocks; + unsigned int nclocks; + struct reset_control_bulk_data resets[RST_GR3D_MAX]; + unsigned int nresets; DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); }; @@ -65,15 +80,22 @@ static int gr3d_init(struct host1x_client *client) goto free; } + pm_runtime_enable(client->dev); + pm_runtime_use_autosuspend(client->dev); + pm_runtime_set_autosuspend_delay(client->dev, 200); + err = tegra_drm_register_client(dev->dev_private, drm); if (err < 0) { dev_err(client->dev, "failed to register client: %d\n", err); - goto detach; + goto disable_rpm; } return 0; -detach: +disable_rpm: + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_client_iommu_detach(client); free: host1x_syncpt_put(client->syncpts[0]); @@ -93,10 +115,15 @@ static int gr3d_exit(struct host1x_client *client) if (err < 0) return err; + pm_runtime_dont_use_autosuspend(client->dev); + pm_runtime_force_suspend(client->dev); + host1x_client_iommu_detach(client); host1x_syncpt_put(client->syncpts[0]); host1x_channel_put(gr3d->channel); + gr3d->channel = NULL; + return 0; } @@ -109,10 +136,17 @@ static int gr3d_open_channel(struct tegra_drm_client *client, struct tegra_drm_context *context) { struct gr3d *gr3d = to_gr3d(client); + int err; + + err = pm_runtime_resume_and_get(client->base.dev); + if (err) + return err; context->channel = host1x_channel_get(gr3d->channel); - if (!context->channel) + if (!context->channel) { + pm_runtime_put(context->client->base.dev); return -ENOMEM; + } return 0; } @@ -120,6 +154,7 @@ static int gr3d_open_channel(struct tegra_drm_client *client, static void gr3d_close_channel(struct tegra_drm_context *context) { host1x_channel_put(context->channel); + pm_runtime_put(context->client->base.dev); } static int gr3d_is_addr_reg(struct device *dev, u32 class, u32 offset) @@ -155,14 +190,20 @@ static const struct tegra_drm_client_ops gr3d_ops = { static const struct gr3d_soc tegra20_gr3d_soc = { .version = 0x20, + .num_clocks = 1, + .num_resets = 2, }; static const struct gr3d_soc tegra30_gr3d_soc = { .version = 0x30, + .num_clocks = 2, + .num_resets = 4, }; static const struct gr3d_soc tegra114_gr3d_soc = { .version = 0x35, + .num_clocks = 1, + .num_resets = 2, }; static const struct of_device_id tegra_gr3d_match[] = { @@ -278,69 +319,216 @@ static const u32 gr3d_addr_regs[] = { GR3D_GLOBAL_SAMP23SURFADDR(15), }; -static int gr3d_probe(struct platform_device *pdev) +static int gr3d_power_up_legacy_domain(struct device *dev, const char *name, + unsigned int id) { - struct device_node *np = pdev->dev.of_node; - struct host1x_syncpt **syncpts; - struct gr3d *gr3d; + struct gr3d *gr3d = dev_get_drvdata(dev); + struct reset_control *reset; + struct clk *clk; unsigned int i; int err; - gr3d = devm_kzalloc(>dev, sizeof(*gr3d), GFP_KERNEL); - if (!gr3d) - return -ENOMEM; - - gr3d->soc = of_device_get_match_data(>dev); + /* +* Tegra20 device-tree doesn't specify 3d clock name and there is only +* one clock for Tegra20.
[PATCH v15 11/39] drm/tegra: hdmi: Add OPP support
The HDMI on Tegra belongs to the core power domain and we're going to enable GENPD support for the core domain. Now HDMI driver must use OPP API for driving the controller's clock rate because OPP API takes care of reconfiguring the domain's performance state based on HDMI clock rate. Add OPP support to the HDMI driver. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/hdmi.c | 16 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index e5d2a4026028..9a87d351a828 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -11,10 +11,13 @@ #include #include #include +#include #include #include #include +#include + #include #include #include @@ -1195,7 +1198,7 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) h_back_porch = mode->htotal - mode->hsync_end; h_front_porch = mode->hsync_start - mode->hdisplay; - err = clk_set_rate(hdmi->clk, hdmi->pixel_clock); + err = dev_pm_opp_set_rate(hdmi->dev, hdmi->pixel_clock); if (err < 0) { dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n", err); @@ -1732,7 +1735,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, hdmi); - pm_runtime_enable(>dev); + + err = devm_pm_runtime_enable(>dev); + if (err) + return err; + + err = devm_tegra_core_dev_init_opp_table_common(>dev); + if (err) + return err; INIT_LIST_HEAD(>client.list); hdmi->client.ops = _client_ops; @@ -1753,8 +1763,6 @@ static int tegra_hdmi_remove(struct platform_device *pdev) struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); int err; - pm_runtime_disable(>dev); - err = host1x_client_unregister(>client); if (err < 0) { dev_err(>dev, "failed to unregister host1x client: %d\n", -- 2.33.1
[PATCH v15 08/39] gpu: host1x: Add initial runtime PM and OPP support
Add runtime PM and OPP support to the Host1x driver. For the starter we will keep host1x always-on because dynamic power management require a major refactoring of the driver code since lot's of code paths are missing the RPM handling and we're going to remove some of these paths in the future. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/gpu/host1x/debug.c | 15 +++ drivers/gpu/host1x/dev.c | 150 +++-- drivers/gpu/host1x/dev.h | 3 +- drivers/gpu/host1x/hw/channel_hw.c | 44 - drivers/gpu/host1x/intr.c | 3 - drivers/gpu/host1x/syncpt.c| 5 +- 6 files changed, 164 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index 8a14880c61bb..18d9c8d206e3 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -7,6 +7,7 @@ */ #include +#include #include #include @@ -52,6 +53,11 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) { struct host1x *m = dev_get_drvdata(ch->dev->parent); struct output *o = data; + int err; + + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return err; mutex_lock(>cdma.lock); mutex_lock(_lock); @@ -64,6 +70,8 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) mutex_unlock(_lock); mutex_unlock(>cdma.lock); + pm_runtime_put(m->dev); + return 0; } @@ -71,9 +79,14 @@ static void show_syncpts(struct host1x *m, struct output *o) { struct list_head *pos; unsigned int i; + int err; host1x_debug_output(o, " syncpts \n"); + err = pm_runtime_resume_and_get(m->dev); + if (err < 0) + return; + for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { u32 max = host1x_syncpt_read_max(m->syncpt + i); u32 min = host1x_syncpt_load(m->syncpt + i); @@ -101,6 +114,8 @@ static void show_syncpts(struct host1x *m, struct output *o) base_val); } + pm_runtime_put(m->dev); + host1x_debug_output(o, "\n"); } diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 3d4cabdbc78d..c42ab78327e7 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -6,14 +6,18 @@ */ #include +#include #include #include #include #include #include #include +#include #include +#include + #define CREATE_TRACE_POINTS #include #undef CREATE_TRACE_POINTS @@ -208,6 +212,9 @@ static void host1x_setup_sid_table(struct host1x *host) const struct host1x_info *info = host->info; unsigned int i; + if (!info->has_hypervisor) + return; + for (i = 0; i < info->num_sid_entries; i++) { const struct host1x_sid_entry *entry = >sid_table[i]; @@ -365,6 +372,27 @@ static void host1x_iommu_exit(struct host1x *host) } } +static int host1x_get_resets(struct host1x *host) +{ + int err; + + host->resets[0].id = "mc"; + host->resets[1].id = "host1x"; + host->nresets = ARRAY_SIZE(host->resets); + + err = devm_reset_control_bulk_get_optional_exclusive_released( + host->dev, host->nresets, host->resets); + if (err) { + dev_err(host->dev, "failed to get reset: %d\n", err); + return err; + } + + if (WARN_ON(!host->resets[1].rstc)) + return -ENOENT; + + return 0; +} + static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -442,12 +470,9 @@ static int host1x_probe(struct platform_device *pdev) return err; } - host->rst = devm_reset_control_get(>dev, "host1x"); - if (IS_ERR(host->rst)) { - err = PTR_ERR(host->rst); - dev_err(>dev, "failed to get reset: %d\n", err); + err = host1x_get_resets(host); + if (err) return err; - } err = host1x_iommu_init(host); if (err < 0) { @@ -462,22 +487,10 @@ static int host1x_probe(struct platform_device *pdev) goto iommu_exit; } - err = clk_prepare_enable(host->clk); - if (err < 0) { - dev_err(>dev, "failed to enable clock\n"); - goto free_channels; - } - - err = reset_control_deassert(host->rst); - if (err < 0) { - dev_err(>dev, "failed to deassert reset: %d\n", err); - goto unprepare_disable; - } - err = host1x_syncpt_init(host); if (err) { dev_err(>dev, "failed to initialize syncpts\n"); -
[PATCH v15 10/39] drm/tegra: dc: Support OPP and SoC core voltage scaling
Add OPP and SoC core voltage scaling support to the display controller driver. This is required for enabling system-wide DVFS on pre-Tegra186 SoCs. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/dc.c | 79 ++ drivers/gpu/drm/tegra/dc.h | 2 + 2 files changed, 81 insertions(+) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index a457ee954a49..eb70eee8992a 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -11,9 +11,12 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -1834,6 +1837,52 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc, return 0; } +static void tegra_dc_update_voltage_state(struct tegra_dc *dc, + struct tegra_dc_state *state) +{ + unsigned long rate, pstate; + struct dev_pm_opp *opp; + int err; + + if (!dc->has_opp_table) + return; + + /* calculate actual pixel clock rate which depends on internal divider */ + rate = DIV_ROUND_UP(clk_get_rate(dc->clk) * 2, state->div + 2); + + /* find suitable OPP for the rate */ + opp = dev_pm_opp_find_freq_ceil(dc->dev, ); + + /* +* Very high resolution modes may results in a clock rate that is +* above the characterized maximum. In this case it's okay to fall +* back to the characterized maximum. +*/ + if (opp == ERR_PTR(-ERANGE)) + opp = dev_pm_opp_find_freq_floor(dc->dev, ); + + if (IS_ERR(opp)) { + dev_err(dc->dev, "failed to find OPP for %luHz: %pe\n", + rate, opp); + return; + } + + pstate = dev_pm_opp_get_required_pstate(opp, 0); + dev_pm_opp_put(opp); + + /* +* The minimum core voltage depends on the pixel clock rate (which +* depends on internal clock divider of the CRTC) and not on the +* rate of the display controller clock. This is why we're not using +* dev_pm_opp_set_rate() API and instead controlling the power domain +* directly. +*/ + err = dev_pm_genpd_set_performance_state(dc->dev, pstate); + if (err) + dev_err(dc->dev, "failed to set power domain state to %lu: %d\n", + pstate, err); +} + static void tegra_dc_set_clock_rate(struct tegra_dc *dc, struct tegra_dc_state *state) { @@ -1867,6 +1916,8 @@ static void tegra_dc_set_clock_rate(struct tegra_dc *dc, DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), state->div); DRM_DEBUG_KMS("pclk: %lu\n", state->pclk); + + tegra_dc_update_voltage_state(dc, state); } static void tegra_dc_stop(struct tegra_dc *dc) @@ -2057,6 +2108,13 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, err = host1x_client_suspend(>client); if (err < 0) dev_err(dc->dev, "failed to suspend: %d\n", err); + + if (dc->has_opp_table) { + err = dev_pm_genpd_set_performance_state(dc->dev, 0); + if (err) + dev_err(dc->dev, + "failed to clear power domain state: %d\n", err); + } } static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, @@ -3058,6 +3116,23 @@ static int tegra_dc_couple(struct tegra_dc *dc) return 0; } +static int tegra_dc_init_opp_table(struct tegra_dc *dc) +{ + struct tegra_core_opp_params opp_params = {}; + int err; + + err = devm_tegra_core_dev_init_opp_table(dc->dev, _params); + if (err && err != -ENODEV) + return err; + + if (err) + dc->has_opp_table = false; + else + dc->has_opp_table = true; + + return 0; +} + static int tegra_dc_probe(struct platform_device *pdev) { u64 dma_mask = dma_get_mask(pdev->dev.parent); @@ -3123,6 +3198,10 @@ static int tegra_dc_probe(struct platform_device *pdev) tegra_powergate_power_off(dc->powergate); } + err = tegra_dc_init_opp_table(dc); + if (err < 0) + return err; + dc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dc->regs)) return PTR_ERR(dc->regs); diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index c9c4c45c0518..3f91a10ea6c7 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -101,6 +101,8 @@ struct tegra_dc { struct drm_info_list *debugfs_files; const struct tegra_dc_soc_info *soc; + + bool has_opp_table; }; static inline struct tegra_dc * -- 2.33.1
[PATCH v15 05/39] clk: tegra: Support runtime PM and power domain
The Clock-and-Reset controller resides in a core power domain on NVIDIA Tegra SoCs. In order to support voltage scaling of the core power domain, we hook up DVFS-capable clocks to the core GENPD for managing of the GENPD's performance state based on the clock changes. Some clocks don't have any specific physical hardware unit that backs them, like root PLLs and system clock and they have theirs own voltage requirements. This patch adds new clk-device driver that backs the clocks and provides runtime PM functionality for them. A virtual clk-device is created for each such DVFS-capable clock at the clock's registration time by the new tegra_clk_register() helper. Driver changes clock's device GENPD performance state based on clk-rate notifications. In result we have this sequence of events: 1. Clock driver creates virtual device for selective clocks, enables runtime PM for the created device and registers the clock. 2. Clk-device driver starts to listen to clock rate changes. 3. Something changes clk rate or enables/disables clk. 4. CCF core propagates the change through the clk tree. 5. Clk-device driver gets clock rate-change notification or GENPD core handles prepare/unprepare of the clock. 6. Clk-device driver changes GENPD performance state on clock rate change. 7. GENPD driver changes voltage regulator state change. 8. The regulator state is committed to hardware via I2C. We rely on fact that DVFS is not needed for Tegra I2C and that Tegra I2C driver already keeps clock always-prepared. Hence I2C subsystem stays independent from the clk power management and there are no deadlock spots in the sequence. Currently all clocks are registered very early during kernel boot when the device driver core isn't available yet. The clk-device can't be created at that time. This patch splits the registration of the clocks in two phases: 1. Register all essential clocks which don't use RPM and are needed during early boot. 2. Register at a later boot time the rest of clocks. This patch adds power management support for Tegra20 and Tegra30 clocks. Reviewed-by: Ulf Hansson Tested-by: Peter Geis # Ouya T30 Tested-by: Paul Fertser # PAZ00 T20 Tested-by: Nicolas Chauvet # PAZ00 T20 and TK1 T124 Tested-by: Matt Merhar # Ouya T30 Signed-off-by: Dmitry Osipenko --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-device.c | 199 drivers/clk/tegra/clk-pll.c | 2 +- drivers/clk/tegra/clk-super.c | 2 +- drivers/clk/tegra/clk-tegra20.c | 77 +--- drivers/clk/tegra/clk-tegra30.c | 116 ++- drivers/clk/tegra/clk.c | 75 +++- drivers/clk/tegra/clk.h | 2 + 8 files changed, 420 insertions(+), 54 deletions(-) create mode 100644 drivers/clk/tegra/clk-device.c diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 7b1816856eb5..a0715cdfc1a4 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += clk.o obj-y += clk-audio-sync.o +obj-y += clk-device.o obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o diff --git a/drivers/clk/tegra/clk-device.c b/drivers/clk/tegra/clk-device.c new file mode 100644 index ..c58beaf8afbc --- /dev/null +++ b/drivers/clk/tegra/clk-device.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +/* + * This driver manages performance state of the core power domain for the + * independent PLLs and system clocks. We created a virtual clock device + * for such clocks, see tegra_clk_dev_register(). + */ + +struct tegra_clk_device { + struct notifier_block clk_nb; + struct device *dev; + struct clk_hw *hw; + struct mutex lock; +}; + +static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev, + unsigned long rate) +{ + struct device *dev = clk_dev->dev; + struct dev_pm_opp *opp; + unsigned int pstate; + + opp = dev_pm_opp_find_freq_ceil(dev, ); + if (opp == ERR_PTR(-ERANGE)) { + /* +* Some clocks may be unused by a particular board and they +* may have uninitiated clock rate that is overly high. In +* this case clock is expected to be disabled, but still we +* need to set up performance state of the power domain and +* not error out clk initialization. A typical example is +* a PCIe clock on Android tablets. +*/ + dev_dbg(dev, "failed to find ceil
[PATCH v15 07/39] dt-bindings: host1x: Document Memory Client resets of Host1x, GR2D and GR3D
Memory Client should be blocked before hardware reset is asserted in order to prevent memory corruption and hanging of memory controller. Document Memory Client resets of Host1x, GR2D and GR3D hardware units. Reviewed-by: Rob Herring Signed-off-by: Dmitry Osipenko --- .../bindings/display/tegra/nvidia,tegra20-host1x.txt | 4 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index 62861a8fb5c6..e61999ce54e9 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -19,6 +19,7 @@ Required properties: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - host1x + - mc Optional properties: - operating-points-v2: See ../bindings/opp/opp.txt for details. @@ -198,6 +199,7 @@ of the following host1x client modules: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - 2d +- mc Optional properties: - interconnects: Must contain entry for the GR2D memory clients. @@ -224,6 +226,8 @@ of the following host1x client modules: - reset-names: Must include the following entries: - 3d - 3d2 (Only required on SoCs with two 3D clocks) +- mc +- mc2 (Only required on SoCs with two 3D clocks) Optional properties: - interconnects: Must contain entry for the GR3D memory clients. -- 2.33.1
[PATCH v15 03/39] soc/tegra: Don't print error message when OPPs not available
Previously we assumed that devm_tegra_core_dev_init_opp_table() will be used only by drivers that will always have device with OPP table, but this is not true anymore. For example now Tegra30 will have OPP table for PWM, but Tegra20 not and both use the same driver. Hence let's not print the error message about missing OPP table in the common helper, we can print it elsewhere. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 35c882da55fc..32c346b72635 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -136,9 +136,7 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev, */ err = devm_pm_opp_of_add_table(dev); if (err) { - if (err == -ENODEV) - dev_err_once(dev, "OPP table not found, please update device-tree\n"); - else + if (err != -ENODEV) dev_err(dev, "failed to add OPP table: %d\n", err); return err; -- 2.33.1
[PATCH v15 01/39] soc/tegra: Enable runtime PM during OPP state-syncing
GENPD core now can set up domain's performance state properly while device is RPM-suspended. Runtime PM of a device must be enabled during setup because GENPD checks whether device is suspended and check doesn't work while RPM is disabled. Instead of replicating the boilerplate RPM-enable code around OPP helper for each driver, let's make OPP helper to take care of enabling it. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/common.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index cd33e99249c3..35c882da55fc 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ static int tegra_core_dev_init_opp_state(struct device *dev) { unsigned long rate; struct clk *clk; + bool rpm_enabled; int err; clk = devm_clk_get(dev, NULL); @@ -57,8 +59,31 @@ static int tegra_core_dev_init_opp_state(struct device *dev) return -EINVAL; } + /* +* Runtime PM of the device must be enabled in order to set up +* GENPD's performance properly because GENPD core checks whether +* device is suspended and this check doesn't work while RPM is +* disabled. This makes sure the OPP vote below gets cached in +* GENPD for the device. Instead, the vote is done the next time +* the device gets runtime resumed. +*/ + rpm_enabled = pm_runtime_enabled(dev); + if (!rpm_enabled) + pm_runtime_enable(dev); + + /* should never happen in practice */ + if (!pm_runtime_enabled(dev)) { + dev_WARN(dev, "failed to enable runtime PM\n"); + pm_runtime_disable(dev); + return -EINVAL; + } + /* first dummy rate-setting initializes voltage vote */ err = dev_pm_opp_set_rate(dev, rate); + + if (!rpm_enabled) + pm_runtime_disable(dev); + if (err) { dev_err(dev, "failed to initialize OPP clock: %d\n", err); return err; -- 2.33.1
[PATCH v15 02/39] soc/tegra: Add devm_tegra_core_dev_init_opp_table_common()
Only couple drivers need to get the -ENODEV error code and majority of drivers need to explicitly initialize the performance state. Add new common helper which sets up OPP table for these drivers. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- include/soc/tegra/common.h | 15 +++ 1 file changed, 15 insertions(+) diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index af41ad80ec21..8ec1ac07fc85 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -39,4 +39,19 @@ devm_tegra_core_dev_init_opp_table(struct device *dev, } #endif +static inline int +devm_tegra_core_dev_init_opp_table_common(struct device *dev) +{ + struct tegra_core_opp_params opp_params = {}; + int err; + + opp_params.init_state = true; + + err = devm_tegra_core_dev_init_opp_table(dev, _params); + if (err != -ENODEV) + return err; + + return 0; +} + #endif /* __SOC_TEGRA_COMMON_H__ */ -- 2.33.1
[PATCH v15 00/39] NVIDIA Tegra power management patches for 5.17
This series adds runtime PM support to Tegra drivers and enables core voltage scaling for Tegra20/30 SoCs, resolving overheating troubles. All patches in this series are interdependent and should go via Tegra tree for simplicity. Changelog: v15: - Added r-b from Ulf Hansson to "soc/tegra: Enable runtime PM during OPP state-syncing" patch and added extra sanity-check to this patch which ensures that RPM is indeed enabled. - Fixed double RPM-disable on unbind for drivers that used devm_pm_runtime_enable() + pm_runtime_force_suspend(). - Added link with additional info to commit message of "regulators: Prepare for suspend" patch. v14: - Fixed missing runtime PM syncing on removal of drivers, which was spotted by Ulf Hansson in v13. - clk-device driver now resumes RPM on system suspend instead of preparing clock which it backs. This was suggested by Ulf Hansson. - clk-device driver now syncs power domain performance unconditionally during driver's probe time since GENPD API allows to do this now. It was spotted by Ulf Hansson. - Added new "Enable runtime PM during OPP state-syncing" patch, which allows drivers to sync state at any time. Previously drivers were obligated to take care of enabling RPM at the "right" time. - Moved runtime PM initialization/uninitialization of DRM drivers that use host1x channel to host1x client init/deinit phase. I noticed that there is UAF problem because RPM-suspend callback waits until channel is idling and channel is already released/freed during driver's removal phase. - Added system suspend support to the new NVDEC DRM driver. - Added missing pm_runtime_mark_last_busy() to DRM driver. - Corrected VDE GENPD patch which previously made video decoder clock always-enabled by mistake if legacy PD code path was used. It was spotted while we were testing VDE on Tegra114 that doesn't support GENPD yet. - Added ack from Peter Chen to the USB patch that he gave to v13. - Changed OPP table names in accordance to the new naming scheme required by the recent core OPP binding. - Added 500MHz memory OPP entry used by ASUS Transformer tablets. v13: - Fixed compile-test error reported by build bot by reverting the mmc/ patch to v11. The sdhci_suspend/resume_host() functions aren't available with the disabled CONFIG_PM_SLEEP, some code needs the ifdef. - Added last r-b from Rob Herring for the DT patches. - Corrected clk/ PM domain-support patch by not using the devm_tegra_core_dev_init_opp_table_common() helper, which I utilized in v12. The clk driver implements its own power domain state syncing and common helper shouldn't be used. This fixes driver probing for some clocks on some devices. It was reported by Svyatoslav Ryhel for PLLE OPP error on T30 Asus Transformer tablet. v12: - Added r-b from Rob Herring to the host1x binding patch. - Added acks from Hans Verkuil to the video decoder patches. - In the v11 changelog I forgot to mention that the clk-binding patch was also changed with a corrected regex pattern and removed 'clocks' sub-node. This patch needs r-b or ack too. - Added new "Rename 3d power domains" patch to match the DT schema naming requirement. Thanks to David Heidelberg for spotting this problem. - Replaced #ifdef CONFIG_PM_SLEEP with maybe_unused in the MMC patch to make code cleaner. v11: - Added acks and r-b from Rob Herring, Mark Brown and Miquel Raynal that were given to v8. - Corrected order of the new memory controller reset entry in device-trees and host1x DT binding patch, which was requested by Rob Herring. - Switched consumer drivers to use power domain state syncing done by new Tegra's common OPP-initialization helper. - Made use of new devm_pm_runtime_enable() helper that was added to v5.15 kernel, where appropriate. - Added "fuse: Use resource-managed helpers" patch. - Converted Tegra20/30 clk drivers to a proper platform drivers, which was requested by Thierry Reding. - Removed clk-bulk API usage from the MMC patch, which was requested by Thierry Reding. - Changed CORE power domain name to "core" in a new patch "Change name of core power domain". - Misc small fixes for problems that I found since v8, like couple typos in error code paths and restored working RPM for Tegra DRM UAPI v1 that was removed in v8 by accident. v9-v10: Figured out remaining GENPD API changes with Ulf Hansson and Viresh Kumar. The OPP-sync helper that was used in v8 isn't needed anymore because GENPD API now allows consumer drivers to init rpm_pstate of power domains. v8: - Added new generic dev_pm_opp_sync() helper
Re: [PATCH] drm: change logs to print connectors in the form CONNECTOR:id:name
On Sat, Nov 13, 2021 at 09:39:46PM +0100, Sam Ravnborg wrote: > Hi Claudio, > > On Sat, Nov 13, 2021 at 08:27:30PM +0100, Claudio Suarez wrote: > > The prefered way to log connectors is [CONNECTOR:id:name]. Change it in > > drm core programs. > > > > Suggested-by: Ville Syrjälä > > Signed-off-by: Claudio Suarez > > While touching all these logging calls, could you convernt them to the > newer drm_dbg_kms variants? > DRM_DEBUG_* are all deprecated. > Yes, I can, but it is recommended to do it in a different patch: https://www.kernel.org/doc/html/latest/process/submitting-patches.html#separate-your-changes C: "Separate your changes Separate each logical change into a separate patch. For example, if your changes include both bug fixes and performance enhancements..." I will study and send a new separate patch with your suggestion. Best regards, Claudio Suarez
Re: [PATCH] drm: change logs to print connectors in the form CONNECTOR:id:name
On Sat, Nov 13, 2021 at 08:27:30PM +0100, Claudio Suarez wrote: > The prefered way to log connectors is [CONNECTOR:id:name]. Change it in > drm core programs. > > Suggested-by: Ville Syrjälä > Signed-off-by: Claudio Suarez > --- > drivers/gpu/drm/drm_client_modeset.c | 51 ++-- > drivers/gpu/drm/drm_connector.c | 12 --- > drivers/gpu/drm/drm_edid.c | 36 ++-- > drivers/gpu/drm/drm_edid_load.c | 11 +++--- > drivers/gpu/drm/drm_mode_config.c| 3 +- > 5 files changed, 59 insertions(+), 54 deletions(-) > > diff --git a/drivers/gpu/drm/drm_client_modeset.c > b/drivers/gpu/drm/drm_client_modeset.c > index ced09c7c06f9..4f35dc375bdd 100644 > --- a/drivers/gpu/drm/drm_client_modeset.c > +++ b/drivers/gpu/drm/drm_client_modeset.c > @@ -240,7 +240,7 @@ static void drm_client_connectors_enabled(struct > drm_connector **connectors, > for (i = 0; i < connector_count; i++) { > connector = connectors[i]; > enabled[i] = drm_connector_enabled(connector, true); > - DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, > + DRM_DEBUG_KMS("[CONNECTOR:%d;%s] enabled? %s\n", > connector->base.id, connector->name, > connector->display_info.non_desktop ? "non > desktop" : enabled[i] ? "yes" : "no"); > > any_enabled |= enabled[i]; > @@ -350,8 +350,8 @@ static int drm_client_get_tile_offsets(struct > drm_connector **connectors, > continue; > > if (!modes[i] && (h_idx || v_idx)) { > - DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, > - connector->base.id); > + DRM_DEBUG_KMS("no modes for [CONNECTOR:%d:%s] tiled > %d\n", > + connector->base.id, connector->name, i); > continue; > } > if (connector->tile_h_loc < h_idx) > @@ -419,14 +419,15 @@ static bool drm_client_target_preferred(struct > drm_connector **connectors, > drm_client_get_tile_offsets(connectors, > connector_count, modes, offsets, i, > connector->tile_h_loc, > connector->tile_v_loc); > } > - DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", > - connector->base.id); > + DRM_DEBUG_KMS("looking for cmdline mode on [CONNECTOR:%d:%s]\n", > + connector->base.id, connector->name); > > /* got for command line mode first */ > modes[i] = drm_connector_pick_cmdline_mode(connector); > if (!modes[i]) { > - DRM_DEBUG_KMS("looking for preferred mode on connector > %d %d\n", > - connector->base.id, connector->tile_group > ? connector->tile_group->id : 0); > + DRM_DEBUG_KMS("looking for preferred mode on > [CONNECTOR:%d:%s] %d\n", > + connector->base.id, connector->name, > + connector->tile_group ? > connector->tile_group->id : 0); > modes[i] = drm_connector_has_preferred_mode(connector, > width, height); > } > /* No preferred modes, pick one off the list */ > @@ -448,8 +449,8 @@ static bool drm_client_target_preferred(struct > drm_connector **connectors, > (connector->tile_h_loc == 0 && >connector->tile_v_loc == 0 && >!drm_connector_get_tiled_mode(connector))) { > - DRM_DEBUG_KMS("Falling back to non tiled mode > on Connector %d\n", > - connector->base.id); > + DRM_DEBUG_KMS("Falling back to non tiled mode > on [CONNECTOR:%d:%s]\n", > + connector->base.id, > connector->name); > modes[i] = > drm_connector_fallback_non_tiled_mode(connector); > } else { > modes[i] = > drm_connector_get_tiled_mode(connector); > @@ -617,15 +618,15 @@ static bool drm_client_firmware_config(struct > drm_client_dev *client, > num_connectors_detected++; > > if (!enabled[i]) { > - DRM_DEBUG_KMS("connector %s not enabled, skipping\n", > - connector->name); > + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] not enabled, > skipping\n", > + connector->base.id, connector->name); > conn_configured |= BIT(i); > continue; > } > > if (connector->force == DRM_FORCE_OFF) { > -
Re: [PATCH] drm: change logs to print connectors in the form CONNECTOR:id:name
+CC: Ville Syrjälä +CC: Daniel Vetter On Sat, Nov 13, 2021 at 08:27:30PM +0100, Claudio Suarez wrote: > The prefered way to log connectors is [CONNECTOR:id:name]. Change it in > drm core programs. > > Suggested-by: Ville Syrjälä > Signed-off-by: Claudio Suarez > --- > drivers/gpu/drm/drm_client_modeset.c | 51 ++-- > drivers/gpu/drm/drm_connector.c | 12 --- > drivers/gpu/drm/drm_edid.c | 36 ++-- > drivers/gpu/drm/drm_edid_load.c | 11 +++--- > drivers/gpu/drm/drm_mode_config.c| 3 +- > 5 files changed, 59 insertions(+), 54 deletions(-) > > diff --git a/drivers/gpu/drm/drm_client_modeset.c > b/drivers/gpu/drm/drm_client_modeset.c > index ced09c7c06f9..4f35dc375bdd 100644 > --- a/drivers/gpu/drm/drm_client_modeset.c > +++ b/drivers/gpu/drm/drm_client_modeset.c > @@ -240,7 +240,7 @@ static void drm_client_connectors_enabled(struct > drm_connector **connectors, > for (i = 0; i < connector_count; i++) { > connector = connectors[i]; > enabled[i] = drm_connector_enabled(connector, true); > - DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, > + DRM_DEBUG_KMS("[CONNECTOR:%d;%s] enabled? %s\n", > connector->base.id, connector->name, > connector->display_info.non_desktop ? "non > desktop" : enabled[i] ? "yes" : "no"); > > any_enabled |= enabled[i]; > @@ -350,8 +350,8 @@ static int drm_client_get_tile_offsets(struct > drm_connector **connectors, > continue; > > if (!modes[i] && (h_idx || v_idx)) { > - DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, > - connector->base.id); > + DRM_DEBUG_KMS("no modes for [CONNECTOR:%d:%s] tiled > %d\n", > + connector->base.id, connector->name, i); > continue; > } > if (connector->tile_h_loc < h_idx) > @@ -419,14 +419,15 @@ static bool drm_client_target_preferred(struct > drm_connector **connectors, > drm_client_get_tile_offsets(connectors, > connector_count, modes, offsets, i, > connector->tile_h_loc, > connector->tile_v_loc); > } > - DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", > - connector->base.id); > + DRM_DEBUG_KMS("looking for cmdline mode on [CONNECTOR:%d:%s]\n", > + connector->base.id, connector->name); > > /* got for command line mode first */ > modes[i] = drm_connector_pick_cmdline_mode(connector); > if (!modes[i]) { > - DRM_DEBUG_KMS("looking for preferred mode on connector > %d %d\n", > - connector->base.id, connector->tile_group > ? connector->tile_group->id : 0); > + DRM_DEBUG_KMS("looking for preferred mode on > [CONNECTOR:%d:%s] %d\n", > + connector->base.id, connector->name, > + connector->tile_group ? > connector->tile_group->id : 0); > modes[i] = drm_connector_has_preferred_mode(connector, > width, height); > } > /* No preferred modes, pick one off the list */ > @@ -448,8 +449,8 @@ static bool drm_client_target_preferred(struct > drm_connector **connectors, > (connector->tile_h_loc == 0 && >connector->tile_v_loc == 0 && >!drm_connector_get_tiled_mode(connector))) { > - DRM_DEBUG_KMS("Falling back to non tiled mode > on Connector %d\n", > - connector->base.id); > + DRM_DEBUG_KMS("Falling back to non tiled mode > on [CONNECTOR:%d:%s]\n", > + connector->base.id, > connector->name); > modes[i] = > drm_connector_fallback_non_tiled_mode(connector); > } else { > modes[i] = > drm_connector_get_tiled_mode(connector); > @@ -617,15 +618,15 @@ static bool drm_client_firmware_config(struct > drm_client_dev *client, > num_connectors_detected++; > > if (!enabled[i]) { > - DRM_DEBUG_KMS("connector %s not enabled, skipping\n", > - connector->name); > + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] not enabled, > skipping\n", > + connector->base.id, connector->name); > conn_configured |= BIT(i); > continue; > } > > if (connector->force == DRM_FORCE_OFF) { >
Re: AUTOSEL series truncated was -- Re: [PATCH AUTOSEL 5.15 001/146] dma-buf: WARN on dmabuf release with pending attachments
On Tue, Nov 09, 2021 at 08:05:23AM -0800, Randy Dunlap wrote: On 11/8/21 11:54 PM, Pavel Machek wrote: Hi! This series is truncated .. I only got first patches. Similary, 5.10 series is truncated, [PATCH AUTOSEL 5.10 035/101] media: s5p-mfc: Add checking to s5p_mfc_probe... is last one I got. I got all the patches before that, so I believe it is not problem on my side, but I'd not mind someone confirming they are seeing the same problem... Yes, several of the patch series were incomplete for me also... Odd. I'll keep a closer look next time I send a series out to figure out what's going on. Thanks for the heads-up! -- Thanks, Sasha
[Bug 213823] Broken power management for amdgpu
https://bugzilla.kernel.org/show_bug.cgi?id=213823 --- Comment #6 from Bruno Pagani (bruno.n.pag...@gmail.com) --- So while I still don’t have time to setup bisecting, I’m now affected even on LTS kernel. Also, I’ve been in touch with other users having a similar laptop (the XPS version instead of the Precision, but still KabyLake-G), and they don’t seem affected. Thus I’m not sure anymore this is a kernel issue (and whether BOCO vs ATPX is relevant). Where should I seek for guidance in understanding why my dGPU stays stuck in D0 instead of going into D3? Is this or https://gitlab.freedesktop.org/drm/amd and appropriate place? -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[PATCH v3 6/6] drm/i915/ttm: Update i915_gem_obj_copy_ttm() to be asynchronous
Update the copy function i915_gem_obj_copy_ttm() to be asynchronous for future users and update the only current user to sync the objects as needed after this function. Signed-off-by: Thomas Hellström --- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c | 40 ++-- drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c | 2 + 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c index ae2c49fc3500..53ed3972c7be 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c @@ -811,33 +811,49 @@ int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, .interruptible = intr, }; struct i915_refct_sgt *dst_rsgt; - struct dma_fence *copy_fence; - int ret; + struct dma_fence *copy_fence, *dep_fence; + struct i915_deps deps; + int ret, shared_err; assert_object_held(dst); assert_object_held(src); + i915_deps_init(, GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN); /* -* Sync for now. This will change with async moves. +* We plan to add a shared fence only for the source. If that +* fails, we await all source fences before commencing +* the copy instead of only the exclusive. */ - ret = ttm_bo_wait_ctx(dst_bo, ); + shared_err = dma_resv_reserve_shared(src_bo->base.resv, 1); + ret = i915_deps_add_resv(, dst_bo->base.resv, true, false, ); if (!ret) - ret = ttm_bo_wait_ctx(src_bo, ); + ret = i915_deps_add_resv(, src_bo->base.resv, +!!shared_err, false, ); if (ret) return ret; + dep_fence = i915_deps_to_fence(, ); + if (IS_ERR(dep_fence)) + return PTR_ERR(dep_fence); + dst_rsgt = i915_ttm_resource_get_st(dst, dst_bo->resource); copy_fence = __i915_ttm_move(src_bo, false, dst_bo->resource, -dst_bo->ttm, dst_rsgt, allow_accel, NULL); +dst_bo->ttm, dst_rsgt, allow_accel, +dep_fence); i915_refct_sgt_put(dst_rsgt); - if (IS_ERR(copy_fence)) - return PTR_ERR(copy_fence); + if (IS_ERR_OR_NULL(copy_fence)) + return PTR_ERR_OR_ZERO(copy_fence); - if (copy_fence) { - dma_fence_wait(copy_fence, false); - dma_fence_put(copy_fence); - } + dma_resv_add_excl_fence(dst_bo->base.resv, copy_fence); + + /* If we failed to reserve a shared slot, add an exclusive fence */ + if (shared_err) + dma_resv_add_excl_fence(src_bo->base.resv, copy_fence); + else + dma_resv_add_shared_fence(src_bo->base.resv, copy_fence); + + dma_fence_put(copy_fence); return 0; } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c index 60d10ab55d1e..9aad84059d56 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c @@ -80,6 +80,7 @@ static int i915_ttm_backup(struct i915_gem_apply_to_region *apply, err = i915_gem_obj_copy_ttm(backup, obj, pm_apply->allow_gpu, false); GEM_WARN_ON(err); + ttm_bo_wait_ctx(backup_bo, ); obj->ttm.backup = backup; return 0; @@ -170,6 +171,7 @@ static int i915_ttm_restore(struct i915_gem_apply_to_region *apply, err = i915_gem_obj_copy_ttm(obj, backup, pm_apply->allow_gpu, false); GEM_WARN_ON(err); + ttm_bo_wait_ctx(backup_bo, ); obj->ttm.backup = NULL; err = 0; -- 2.31.1
[PATCH v3 5/6] drm/i915/ttm: Implement asynchronous TTM moves
Don't wait sync while migrating, but rather make the GPU blit await the dependencies and add a moving fence to the object. This also enables asynchronous VRAM management in that on eviction, rather than waiting for the moving fence to expire before freeing VRAM, it is freed immediately and the fence is stored with the VRAM manager and handed out to newly allocated objects to await before clears and swapins, or for kernel objects before setting up gpu vmas or mapping. To collect dependencies before migrating, add a set of utilities that coalesce these to a single dma_fence. What is still missing for fully asynchronous operation is asynchronous vma unbinding, which is still to be implemented. This commit substantially reduces execution time in the gem_lmem_swapping test. v2: - Make a couple of functions static. Signed-off-by: Thomas Hellström --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 10 + drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 2 +- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c | 329 +-- drivers/gpu/drm/i915/gem/i915_gem_wait.c | 4 +- 4 files changed, 318 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index a1df49378a0f..111a4282d779 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -326,6 +326,9 @@ static bool i915_ttm_eviction_valuable(struct ttm_buffer_object *bo, { struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); + if (!obj) + return false; + /* * EXTERNAL objects should never be swapped out by TTM, instead we need * to handle that ourselves. TTM will already skip such objects for us, @@ -448,6 +451,10 @@ static int i915_ttm_shrinker_release_pages(struct drm_i915_gem_object *obj, if (bo->ttm->page_flags & TTM_TT_FLAG_SWAPPED) return 0; + ret = ttm_bo_wait_ctx(bo, ); + if (ret) + return ret; + bo->ttm->page_flags |= TTM_TT_FLAG_SWAPPED; ret = ttm_bo_validate(bo, , ); if (ret) { @@ -549,6 +556,9 @@ static void i915_ttm_swap_notify(struct ttm_buffer_object *bo) struct drm_i915_gem_object *obj = i915_ttm_to_gem(bo); int ret = i915_ttm_move_notify(bo); + if (!obj) + return; + GEM_WARN_ON(ret); GEM_WARN_ON(obj->ttm.cached_io_rsgt); if (!ret && obj->mm.madv != I915_MADV_WILLNEED) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h index 82cdabb542be..9d698ad00853 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h @@ -37,7 +37,7 @@ void i915_ttm_bo_destroy(struct ttm_buffer_object *bo); static inline struct drm_i915_gem_object * i915_ttm_to_gem(struct ttm_buffer_object *bo) { - if (GEM_WARN_ON(bo->destroy != i915_ttm_bo_destroy)) + if (bo->destroy != i915_ttm_bo_destroy) return NULL; return container_of(bo, struct drm_i915_gem_object, __do_not_access); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c index f35b386c56ca..ae2c49fc3500 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c @@ -3,6 +3,8 @@ * Copyright © 2021 Intel Corporation */ +#include + #include #include "i915_drv.h" @@ -41,6 +43,228 @@ void i915_ttm_migrate_set_failure_modes(bool gpu_migration, } #endif +/** + * DOC: Set of utilities to dynamically collect dependencies and + * eventually coalesce them into a single fence which is fed into + * the migration code. That single fence is, in the case of dependencies + * from multiple contexts, a struct dma_fence_array, since the + * i915 request code can break that up and await the individual + * fences. + * + * While collecting the individual dependencies, we store the refcounted + * struct dma_fence pointers in a realloc-type-managed pointer array, since + * that can be easily fed into a dma_fence_array. Other options are + * available, like for example an xarray for similarity with drm/sched. + * Can be changed easily if needed. + * + * We might want to break this out into a separate file as a utility. + */ + +#define I915_DEPS_MIN_ALLOC_CHUNK 8U + +/** + * struct i915_deps - Collect dependencies into a single dma-fence + * @single: Storage for pointer if the collection is a single fence. + * @fence: Allocated array of fence pointers if more than a single fence; + * otherwise points to the address of @single. + * @num_deps: Current number of dependency fences. + * @fences_size: Size of the @fences array in number of pointers. + * @gfp: Allocation mode. + */ +struct i915_deps { + struct dma_fence *single; + struct dma_fence **fences; + unsigned int num_deps; + unsigned int fences_size; + gfp_t gfp; +}; + +static void
[PATCH v3 4/6] drm/i915/ttm: Break refcounting loops at device region unref time
There is an interesting refcounting loop: struct intel_memory_region has a struct ttm_resource_manager, ttm_resource_manager->move may hold a reference to i915_request, i915_request may hold a reference to intel_context, intel_context may hold a reference to drm_i915_gem_object, drm_i915_gem_object may hold a reference to intel_memory_region. Break this loop when we drop the device reference count on the region by putting the region move fence. Also hold dropping the device reference count until all objects of the region has been deleted, to avoid issues if proceeding with the device takedown while the region is still present. Signed-off-by: Thomas Hellström --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 1 + drivers/gpu/drm/i915/gt/intel_region_lmem.c | 1 + drivers/gpu/drm/i915/intel_memory_region.c | 5 +++- drivers/gpu/drm/i915/intel_memory_region.h | 1 + drivers/gpu/drm/i915/intel_region_ttm.c | 28 + drivers/gpu/drm/i915/intel_region_ttm.h | 2 ++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 537a81445b90..a1df49378a0f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1044,6 +1044,7 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, static const struct intel_memory_region_ops ttm_system_region_ops = { .init_object = __i915_gem_ttm_object_init, + .disable = intel_region_ttm_disable, }; struct intel_memory_region * diff --git a/drivers/gpu/drm/i915/gt/intel_region_lmem.c b/drivers/gpu/drm/i915/gt/intel_region_lmem.c index aec838ecb2ef..956916fd21f8 100644 --- a/drivers/gpu/drm/i915/gt/intel_region_lmem.c +++ b/drivers/gpu/drm/i915/gt/intel_region_lmem.c @@ -108,6 +108,7 @@ region_lmem_init(struct intel_memory_region *mem) static const struct intel_memory_region_ops intel_region_lmem_ops = { .init = region_lmem_init, .release = region_lmem_release, + .disable = intel_region_ttm_disable, .init_object = __i915_gem_ttm_object_init, }; diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index e7f7e6627750..1f67d2b68c24 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -233,8 +233,11 @@ void intel_memory_regions_driver_release(struct drm_i915_private *i915) struct intel_memory_region *region = fetch_and_zero(>mm.regions[i]); - if (region) + if (region) { + if (region->ops->disable) + region->ops->disable(region); intel_memory_region_put(region); + } } } diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index 3feae3353d33..9bb77eacd206 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -52,6 +52,7 @@ struct intel_memory_region_ops { int (*init)(struct intel_memory_region *mem); void (*release)(struct intel_memory_region *mem); + void (*disable)(struct intel_memory_region *mem); int (*init_object)(struct intel_memory_region *mem, struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915/intel_region_ttm.c index 2e901a27e259..4219d83a2b19 100644 --- a/drivers/gpu/drm/i915/intel_region_ttm.c +++ b/drivers/gpu/drm/i915/intel_region_ttm.c @@ -114,6 +114,34 @@ void intel_region_ttm_fini(struct intel_memory_region *mem) mem->region_private = NULL; } +/** + * intel_region_ttm_disable - A TTM region disable callback helper + * @mem: The memory region. + * + * A helper that ensures that nothing any longer references a region at + * device takedown. Breaks refcounting loops and waits for objects in the + * region to be deleted. + */ +void intel_region_ttm_disable(struct intel_memory_region *mem) +{ + struct ttm_resource_manager *man = mem->region_private; + + /* +* Put the region's move fences. This releases requests that +* may hold on to contexts and vms that may hold on to buffer +* objects that may have a refcount on the region. :/ +*/ + if (man) + ttm_resource_manager_cleanup(man); + + /* Flush objects that may just have been freed */ + i915_gem_flush_free_objects(mem->i915); + + /* Wait until the only region reference left is our own. */ + while (kref_read(>kref) > 1) + msleep(20); +} + /** * intel_region_ttm_resource_to_rsgt - * Convert an opaque TTM resource manager resource to a refcounted sg_table. diff --git a/drivers/gpu/drm/i915/intel_region_ttm.h b/drivers/gpu/drm/i915/intel_region_ttm.h index 7bbe2b46b504..197a8c179370
[PATCH v3 2/6] drm/i915: Add support for asynchronous moving fence waiting
From: Maarten Lankhorst For now, we will only allow async migration when TTM is used, so the paths we care about are related to TTM. The mmap path is handled by having the fence in ttm_bo->moving, when pinning, the binding only becomes available after the moving fence is signaled, and pinning a cpu map will only work after the moving fence signals. This should close all holes where userspace can read a buffer before it's fully migrated. v2: - Fix a couple of SPARSE warnings v3: - Fix a NULL pointer dereference Co-developed-by: Thomas Hellström Signed-off-by: Thomas Hellström Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/i915/display/intel_fbdev.c| 7 ++-- drivers/gpu/drm/i915/display/intel_overlay.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 6 +++ .../i915/gem/selftests/i915_gem_coherency.c | 4 +- .../drm/i915/gem/selftests/i915_gem_mman.c| 22 ++- drivers/gpu/drm/i915/i915_vma.c | 39 ++- drivers/gpu/drm/i915/i915_vma.h | 3 ++ drivers/gpu/drm/i915/selftests/i915_vma.c | 4 +- 8 files changed, 69 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index adc3a81be9f7..5902ad0c2bd8 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -265,11 +265,12 @@ static int intelfb_create(struct drm_fb_helper *helper, info->fix.smem_len = vma->node.size; } - vaddr = i915_vma_pin_iomap(vma); + vaddr = i915_vma_pin_iomap_unlocked(vma); if (IS_ERR(vaddr)) { - drm_err(_priv->drm, - "Failed to remap framebuffer into virtual memory\n"); ret = PTR_ERR(vaddr); + if (ret != -EINTR && ret != -ERESTARTSYS) + drm_err(_priv->drm, + "Failed to remap framebuffer into virtual memory\n"); goto out_unpin; } info->screen_base = vaddr; diff --git a/drivers/gpu/drm/i915/display/intel_overlay.c b/drivers/gpu/drm/i915/display/intel_overlay.c index 7e3f5c6ca484..21593f3f2664 100644 --- a/drivers/gpu/drm/i915/display/intel_overlay.c +++ b/drivers/gpu/drm/i915/display/intel_overlay.c @@ -1357,7 +1357,7 @@ static int get_registers(struct intel_overlay *overlay, bool use_phys) overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl); else overlay->flip_addr = i915_ggtt_offset(vma); - overlay->regs = i915_vma_pin_iomap(vma); + overlay->regs = i915_vma_pin_iomap_unlocked(vma); i915_vma_unpin(vma); if (IS_ERR(overlay->regs)) { diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index c4f684b7cc51..49c6e55c68ce 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -418,6 +418,12 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, } if (!ptr) { + err = i915_gem_object_wait_moving_fence(obj, true); + if (err) { + ptr = ERR_PTR(err); + goto err_unpin; + } + if (GEM_WARN_ON(type == I915_MAP_WC && !static_cpu_has(X86_FEATURE_PAT))) ptr = ERR_PTR(-ENODEV); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c index 13b088cc787e..067c512961ba 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c @@ -101,7 +101,7 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v) intel_gt_pm_get(vma->vm->gt); - map = i915_vma_pin_iomap(vma); + map = i915_vma_pin_iomap_unlocked(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { err = PTR_ERR(map); @@ -134,7 +134,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) intel_gt_pm_get(vma->vm->gt); - map = i915_vma_pin_iomap(vma); + map = i915_vma_pin_iomap_unlocked(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { err = PTR_ERR(map); diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c index 6d30cdfa80f3..5d54181c2145 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -125,12 +125,13 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj, n = page - view.partial.offset; GEM_BUG_ON(n >= view.partial.size); - io = i915_vma_pin_iomap(vma); + io = i915_vma_pin_iomap_unlocked(vma); i915_vma_unpin(vma); if (IS_ERR(io)) { - pr_err("Failed to iomap
[PATCH v3 3/6] drm/i915/ttm: Move the i915_gem_obj_copy_ttm() function
Move the i915_gem_obj_copy_ttm() function to i915_gem_ttm_move.h. This will help keep a number of functions static when introducing async moves. Signed-off-by: Thomas Hellström --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 47 --- drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 4 -- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c | 63 drivers/gpu/drm/i915/gem/i915_gem_ttm_move.h | 10 ++-- drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c | 1 + 5 files changed, 56 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c index 68cfe6e9ceab..537a81445b90 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1063,50 +1063,3 @@ i915_gem_ttm_system_setup(struct drm_i915_private *i915, intel_memory_region_set_name(mr, "system-ttm"); return mr; } - -/** - * i915_gem_obj_copy_ttm - Copy the contents of one ttm-based gem object to - * another - * @dst: The destination object - * @src: The source object - * @allow_accel: Allow using the blitter. Otherwise TTM memcpy is used. - * @intr: Whether to perform waits interruptible: - * - * Note: The caller is responsible for assuring that the underlying - * TTM objects are populated if needed and locked. - * - * Return: Zero on success. Negative error code on error. If @intr == true, - * then it may return -ERESTARTSYS or -EINTR. - */ -int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, - struct drm_i915_gem_object *src, - bool allow_accel, bool intr) -{ - struct ttm_buffer_object *dst_bo = i915_gem_to_ttm(dst); - struct ttm_buffer_object *src_bo = i915_gem_to_ttm(src); - struct ttm_operation_ctx ctx = { - .interruptible = intr, - }; - struct i915_refct_sgt *dst_rsgt; - int ret; - - assert_object_held(dst); - assert_object_held(src); - - /* -* Sync for now. This will change with async moves. -*/ - ret = ttm_bo_wait_ctx(dst_bo, ); - if (!ret) - ret = ttm_bo_wait_ctx(src_bo, ); - if (ret) - return ret; - - dst_rsgt = i915_ttm_resource_get_st(dst, dst_bo->resource); - __i915_ttm_move(src_bo, false, dst_bo->resource, dst_bo->ttm, - dst_rsgt, allow_accel); - - i915_refct_sgt_put(dst_rsgt); - - return 0; -} diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h index 074a7c08ff31..82cdabb542be 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.h @@ -49,10 +49,6 @@ int __i915_gem_ttm_object_init(struct intel_memory_region *mem, resource_size_t page_size, unsigned int flags); -int i915_gem_obj_copy_ttm(struct drm_i915_gem_object *dst, - struct drm_i915_gem_object *src, - bool allow_accel, bool intr); - /* Internal I915 TTM declarations and definitions below. */ #define I915_PL_LMEM0 TTM_PL_PRIV diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c index ef22d4ed66ad..f35b386c56ca 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c @@ -378,18 +378,10 @@ i915_ttm_memcpy_work_arm(struct i915_ttm_memcpy_work *work, return >fence; } -/** - * __i915_ttm_move - helper to perform TTM moves or clears. - * @bo: The source buffer object. - * @clear: Whether this is a clear operation. - * @dst_mem: The destination ttm resource. - * @dst_ttm: The destination ttm page vector. - * @dst_rsgt: The destination refcounted sg-list. - * @allow_accel: Whether to allow acceleration. - */ -void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear, -struct ttm_resource *dst_mem, struct ttm_tt *dst_ttm, -struct i915_refct_sgt *dst_rsgt, bool allow_accel) +static void __i915_ttm_move(struct ttm_buffer_object *bo, bool clear, + struct ttm_resource *dst_mem, + struct ttm_tt *dst_ttm, + struct i915_refct_sgt *dst_rsgt, bool allow_accel) { struct i915_ttm_memcpy_work *copy_work = NULL; struct i915_ttm_memcpy_arg _arg, *arg = &_arg; @@ -521,3 +513,50 @@ int i915_ttm_move(struct ttm_buffer_object *bo, bool evict, i915_ttm_adjust_gem_after_move(obj); return 0; } + +/** + * i915_gem_obj_copy_ttm - Copy the contents of one ttm-based gem object to + * another + * @dst: The destination object + * @src: The source object + * @allow_accel: Allow using the blitter. Otherwise TTM memcpy is used. + * @intr: Whether to perform waits interruptible: + * + * Note: The caller is responsible for assuring that the underlying + * TTM objects are populated if
[PATCH v3 1/6] drm/i915: Add functions to set/get moving fence
From: Maarten Lankhorst We want to get rid of i915_vma tracking to simplify the code and lifetimes. Add a way to set/put the moving fence, in preparation for removing the tracking. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 37 ++ drivers/gpu/drm/i915/gem/i915_gem_object.h | 9 ++ 2 files changed, 46 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index 591ee3cb7275..ec4313836597 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -33,6 +33,7 @@ #include "i915_gem_object.h" #include "i915_memcpy.h" #include "i915_trace.h" +#include "i915_gem_ttm.h" static struct kmem_cache *slab_objects; @@ -726,6 +727,42 @@ static const struct drm_gem_object_funcs i915_gem_object_funcs = { .export = i915_gem_prime_export, }; +struct dma_fence * +i915_gem_object_get_moving_fence(struct drm_i915_gem_object *obj) +{ + return dma_fence_get(i915_gem_to_ttm(obj)->moving); +} + +void i915_gem_object_set_moving_fence(struct drm_i915_gem_object *obj, + struct dma_fence *fence) +{ + dma_fence_put(i915_gem_to_ttm(obj)->moving); + + i915_gem_to_ttm(obj)->moving = dma_fence_get(fence); +} + +int i915_gem_object_wait_moving_fence(struct drm_i915_gem_object *obj, + bool intr) +{ + struct dma_fence *fence = i915_gem_to_ttm(obj)->moving; + int ret; + + assert_object_held(obj); + if (!fence) + return 0; + + ret = dma_fence_wait(fence, intr); + if (ret) + return ret; + + if (fence->error) + return fence->error; + + i915_gem_to_ttm(obj)->moving = NULL; + dma_fence_put(fence); + return 0; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/huge_gem_object.c" #include "selftests/huge_pages.c" diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 133963b46135..36bf3e2e602f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -517,6 +517,15 @@ i915_gem_object_finish_access(struct drm_i915_gem_object *obj) i915_gem_object_unpin_pages(obj); } +struct dma_fence * +i915_gem_object_get_moving_fence(struct drm_i915_gem_object *obj); + +void i915_gem_object_set_moving_fence(struct drm_i915_gem_object *obj, + struct dma_fence *fence); + +int i915_gem_object_wait_moving_fence(struct drm_i915_gem_object *obj, + bool intr); + void i915_gem_object_set_cache_coherency(struct drm_i915_gem_object *obj, unsigned int cache_level); bool i915_gem_object_can_bypass_llc(struct drm_i915_gem_object *obj); -- 2.31.1
[PATCH v3 0/6] drm/i915/ttm: Async migration
This patch series deals with async migration and async vram management. It still leaves an important part out, which is async unbinding which will reduce latency further, at least when trying to migrate already active objects. Patches 1/6 and 2/6 deal with accessing and waiting for the TTM moving fence from i915 GEM. Patch 3 is pure code reorganization, no functional change. Patch 4 breaks a refcounting loop involving the TTM moving fence. Patch 5 uses TTM to implement the ttm move() callback async, it also introduces a utility to collect dependencies and turn them into a single dma_fence, which is needed for the intel_migrate code. This also affects the gem object migrate code so. Patch 6 makes the object copy utility async as well, mainly for future users since the only current user, suspend backup and restore, typically will want to sync anyway. v2: - Fix a couple of SPARSE warnings. v3: - Fix a NULL pointer dereference. Maarten Lankhorst (2): drm/i915: Add functions to set/get moving fence drm/i915: Add support for asynchronous moving fence waiting Thomas Hellström (4): drm/i915/ttm: Move the i915_gem_obj_copy_ttm() function drm/i915/ttm: Break refcounting loops at device region unref time drm/i915/ttm: Implement asynchronous TTM moves drm/i915/ttm: Update i915_gem_obj_copy_ttm() to be asynchronous drivers/gpu/drm/i915/display/intel_fbdev.c| 7 +- drivers/gpu/drm/i915/display/intel_overlay.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_object.c| 37 ++ drivers/gpu/drm/i915/gem/i915_gem_object.h| 9 + drivers/gpu/drm/i915/gem/i915_gem_pages.c | 6 + drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 58 +-- drivers/gpu/drm/i915/gem/i915_gem_ttm.h | 6 +- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.c | 396 -- drivers/gpu/drm/i915/gem/i915_gem_ttm_move.h | 10 +- drivers/gpu/drm/i915/gem/i915_gem_ttm_pm.c| 3 + drivers/gpu/drm/i915/gem/i915_gem_wait.c | 4 +- .../i915/gem/selftests/i915_gem_coherency.c | 4 +- .../drm/i915/gem/selftests/i915_gem_mman.c| 22 +- drivers/gpu/drm/i915/gt/intel_region_lmem.c | 1 + drivers/gpu/drm/i915/i915_vma.c | 39 +- drivers/gpu/drm/i915/i915_vma.h | 3 + drivers/gpu/drm/i915/intel_memory_region.c| 5 +- drivers/gpu/drm/i915/intel_memory_region.h| 1 + drivers/gpu/drm/i915/intel_region_ttm.c | 28 ++ drivers/gpu/drm/i915/intel_region_ttm.h | 2 + drivers/gpu/drm/i915/selftests/i915_vma.c | 4 +- 21 files changed, 538 insertions(+), 109 deletions(-) -- 2.31.1
Re: [PATCH v10 08/10] dyndbg: add print-to-tracefs, selftest with it - RFC
On Thu, Nov 11, 2021 at 03:02:04PM -0700, Jim Cromie wrote: > Sean Paul proposed, in: > https://patchwork.freedesktop.org/series/78133/ > drm/trace: Mirror DRM debug logs to tracefs > > His patchset's objective is to be able to independently steer some of > the drm.debug stream to an alternate tracing destination, by splitting > drm_debug_enabled() into syslog & trace flavors, and enabling them > separately. 2 advantages were identified: > > 1- syslog is heavyweight, tracefs is much lighter > 2- separate selection of enabled categories means less traffic > > Dynamic-Debug can do 2nd exceedingly well: > > A- all work is behind jump-label's NOOP, zero off cost. > B- exact site selectivity, precisely the useful traffic. >can tailor enabled set interactively, at shell. > > Since the tracefs interface is effective for drm (the threads suggest > so), adding that interface to dynamic-debug has real potential for > everyone including drm. > > if CONFIG_TRACING: > > Grab Sean's trace_init/cleanup code, use it to provide tracefs > available by default to all pr_debugs. This will likely need some > further per-module treatment; perhaps something reflecting hierarchy > of module,file,function,line, maybe with a tuned flattening. > > endif CONFIG_TRACING > > Add a new +T flag to enable tracing, independent of +p, and add and > use 3 macros: dyndbg_site_is_enabled/logging/tracing(), to encapsulate > the flag checks. Existing code treats T like other flags. I posted a patchset a while ago to do something very similar, but that got stalled for some reason and I unfortunately didn't follow it up: https://lore.kernel.org/lkml/20200825153338.17061-1-vincent.whitchu...@axis.com/ A key difference between that patchset and this patch (besides that small fact that I used +x instead of +T) was that my patchset allowed the dyndbg trace to be emitted to the main buffer and did not force them to be in an instance-specific buffer. That feature is quite important at least for my use case since I often use dyndbg combined with function tracing, and the latter doesn't work on non-main instances according to Documentation/trace/ftrace.rst. For example, here's a random example of a bootargs from one of my recent debugging sessions: trace_event=printk:* ftrace_filter=_mmc*,mmc*,sd*,dw_mci*,mci* ftrace=function trace_buf_size=20M dyndbg="file drivers/mmc/* +x"
[Bug 215003] apple_gmux fails to initialize and iGPU unclaimed on MacBook Pro 16" 2019
https://bugzilla.kernel.org/show_bug.cgi?id=215003 --- Comment #7 from Lukas Wunner (lu...@wunner.de) --- The gpu-switch utility I've linked to above has macOS and Windows versions. You could try using it from one of those OSes to switch to the iGPU on next boot, then boot into Linux. Perhaps you could add a few debug printk's to find out which runtime services call causes the crash. In summary, there are two issues here: The EFI issue which prevents you from switching to the iGPU on Linux, and the GMUX incompatibility. You may want to open a separate bug for the former and assign it to the "EFI" Product so that Ard Biesheuvel and others can take a look. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.
[Bug 215003] apple_gmux fails to initialize and iGPU unclaimed on MacBook Pro 16" 2019
https://bugzilla.kernel.org/show_bug.cgi?id=215003 --- Comment #6 from Xiaolei Yu (dreifachst...@gmail.com) --- (In reply to Lukas Wunner from comment #5) > Hm, why are runtime services disabled? Are you using "noefi" or > "efi=noruntime" on the command line or is this perhaps an RT kernel? Could > you attach full dmesg output? > EFI runtime service is disabled after a firmware page fault during boot. I pasted the trace in #4. -- You may reply to this email to add a comment. You are receiving this mail because: You are watching the assignee of the bug.