Re: [PATCH v4] drm/radeon/radeon_kms: Fix a NULL pointer dereference in radeon_driver_open_kms()
Am 01.12.21 um 04:22 schrieb Zhou Qingyang: In radeon_driver_open_kms(), radeon_vm_bo_add() is assigned to vm->ib_bo_va and passes and used in radeon_vm_bo_set_addr(). In radeon_vm_bo_set_addr(), there is a dereference of vm->ib_bo_va, which could lead to a NULL pointer dereference on failure of radeon_vm_bo_add(). Fix this bug by adding a check of vm->ib_bo_va. This bug was found by a static analyzer. The analysis employs differential checking to identify inconsistent security operations (e.g., checks or kfrees) between two code paths and confirms that the inconsistent operations are not recovered in the current function or the callers, so they constitute bugs. Note that, as a bug found by static analysis, it can be a false positive or hard to trigger. Multiple researchers have cross-reviewed the bug. Builds with CONFIG_DRM_RADEON=m show no new warnings, and our static analyzer no longer warns about this code. Fixes: cc9e67e3d700 ("drm/radeon: fix VM IB handling") Reported-by: kernel test robot Signed-off-by: Zhou Qingyang --- Changes in v2: - Initialize the variables to silence warning What warning do you get? Double checking the code that shouldn't be necessary and is usually rather frowned upon. Thanks, Christian. Changes in v3: - Fix the bug that good case will also be freed - Improve code style Changes in v2: - Improve the error handling into goto style drivers/gpu/drm/radeon/radeon_kms.c | 37 - 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 482fb0ae6cb5..9d0f840286a1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -648,7 +648,9 @@ void radeon_driver_lastclose_kms(struct drm_device *dev) int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; - int r; + struct radeon_fpriv *fpriv = NULL; + struct radeon_vm *vm = NULL; + int r = 0; file_priv->driver_priv = NULL; @@ -660,8 +662,6 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) /* new gpu have virtual address space support */ if (rdev->family >= CHIP_CAYMAN) { - struct radeon_fpriv *fpriv; - struct radeon_vm *vm; fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); if (unlikely(!fpriv)) { @@ -672,35 +672,38 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) if (rdev->accel_working) { vm = &fpriv->vm; r = radeon_vm_init(rdev, vm); - if (r) { - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_fpriv; r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); - if (r) { - radeon_vm_fini(rdev, vm); - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_vm_fini; /* map the ib pool buffer read only into * virtual address space */ vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); + if (!vm->ib_bo_va) { + r = -ENOMEM; + goto out_vm_fini; + } + r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); - if (r) { - radeon_vm_fini(rdev, vm); - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_vm_fini; } file_priv->driver_priv = fpriv; } +out_vm_fini: + if (r) + radeon_vm_fini(rdev, vm); +out_fpriv: + if (r) + kfree(fpriv); out_suspend: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev);
Re: [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes
Am 30.11.21 um 20:27 schrieb Thomas Hellström: On 11/30/21 19:12, Thomas Hellström wrote: On Tue, 2021-11-30 at 16:02 +0100, Christian König wrote: Am 30.11.21 um 15:35 schrieb Thomas Hellström: On Tue, 2021-11-30 at 14:26 +0100, Christian König wrote: Am 30.11.21 um 13:56 schrieb Thomas Hellström: On 11/30/21 13:42, Christian König wrote: Am 30.11.21 um 13:31 schrieb Thomas Hellström: [SNIP] Other than that, I didn't investigate the nesting fails enough to say I can accurately review this. :) Basically the problem is that within enable_signaling() which is called with the dma_fence lock held, we take the dma_fence lock of another fence. If that other fence is a dma_fence_array, or a dma_fence_chain which in turn tries to lock a dma_fence_array we hit a splat. Yeah, I already thought that you constructed something like that. You get the splat because what you do here is illegal, you can't mix dma_fence_array and dma_fence_chain like this or you can end up in a stack corruption. Hmm. Ok, so what is the stack corruption, is it that the enable_signaling() will end up with endless recursion? If so, wouldn't it be more usable we break that recursion chain and allow a more general use? The problem is that this is not easily possible for dma_fence_array containers. Just imagine that you drop the last reference to the containing fences during dma_fence_array destruction if any of the contained fences is another container you can easily run into recursion and with that stack corruption. Indeed, that would require some deeper surgery. That's one of the major reasons I came up with the dma_fence_chain container. This one you can chain any number of elements together without running into any recursion. Also what are the mixing rules between these? Never use a dma-fence-chain as one of the array fences and never use a dma-fence-array as a dma-fence-chain fence? You can't add any other container to a dma_fence_array, neither other dma_fence_array instances nor dma_fence_chain instances. IIRC at least technically a dma_fence_chain can contain a dma_fence_array if you absolutely need that, but Daniel, Jason and I already had the same discussion a while back and came to the conclusion to avoid that as well if possible. Yes, this is actually the use-case. But what I can't easily guarantee is that that dma_fence_chain isn't fed into a dma_fence_array somewhere else. How do you typically avoid that? Meanwhile I guess I need to take a different approach in the driver to avoid this altogether. Jason and I came up with a deep dive iterator for his use case, but I think we don't want to use that any more after my dma_resv rework. In other words when you need to create a new dma_fence_array you flatten out the existing construct which is at worst case dma_fence_chain->dma_fence_array->dma_fence. Ok, Are there any cross-driver contract here, Like every driver using a dma_fence_array need to check for dma_fence_chain and flatten like above? So far we only discussed that on the mailing list but haven't made any documentation for that. /Thomas Oh, and a follow up question: If there was a way to break the recursion on final put() (using the same basic approach as patch 2 in this series uses to break recursion in enable_signaling()), so that none of these containers did require any special treatment, would it be worth pursuing? I guess it might be possible by having the callbacks drop the references rather than the loop in the final put. + a couple of changes in code iterating over the fence pointers. That won't really help, you just move the recursion from the final put into the callback. What could be possible is to use an work item for any possible operation, e.g. enabling, signaling and destruction. But in the last discussion everybody agreed that it is better to just flatten out the array. Christian. /Thomas Regards, Christian. /Thomas Regards, Christian. /Thomas Regards, Christian. But I'll update the commit message with a typical splat. /Thomas
Re: [PATCH v3] drm/radeon/radeon_kms: Fix a NULL pointer dereference in radeon_driver_open_kms()
Am 30.11.21 um 16:57 schrieb Zhou Qingyang: In radeon_driver_open_kms(), radeon_vm_bo_add() is assigned to vm->ib_bo_va and passes and used in radeon_vm_bo_set_addr(). In radeon_vm_bo_set_addr(), there is a dereference of vm->ib_bo_va, which could lead to a NULL pointer dereference on failure of radeon_vm_bo_add(). Fix this bug by adding a check of vm->ib_bo_va. This bug was found by a static analyzer. The analysis employs differential checking to identify inconsistent security operations (e.g., checks or kfrees) between two code paths and confirms that the inconsistent operations are not recovered in the current function or the callers, so they constitute bugs. Note that, as a bug found by static analysis, it can be a false positive or hard to trigger. Multiple researchers have cross-reviewed the bug. Builds with CONFIG_DRM_RADEON=m show no new warnings, and our static analyzer no longer warns about this code. Fixes: cc9e67e3d700 ("drm/radeon: fix VM IB handling") Signed-off-by: Zhou Qingyang Reviewed-by: Christian König --- Changes in v3: - Fix the bug that good case will also be freed - Improve code style Changes in v2: - Improve the error handling into goto style drivers/gpu/drm/radeon/radeon_kms.c | 35 - 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 482fb0ae6cb5..439f4d1fdd65 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -648,6 +648,8 @@ void radeon_driver_lastclose_kms(struct drm_device *dev) int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) { struct radeon_device *rdev = dev->dev_private; + struct radeon_fpriv *fpriv; + struct radeon_vm *vm; int r; file_priv->driver_priv = NULL; @@ -660,8 +662,6 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) /* new gpu have virtual address space support */ if (rdev->family >= CHIP_CAYMAN) { - struct radeon_fpriv *fpriv; - struct radeon_vm *vm; fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); if (unlikely(!fpriv)) { @@ -672,35 +672,38 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) if (rdev->accel_working) { vm = &fpriv->vm; r = radeon_vm_init(rdev, vm); - if (r) { - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_fpriv; r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); - if (r) { - radeon_vm_fini(rdev, vm); - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_vm_fini; /* map the ib pool buffer read only into * virtual address space */ vm->ib_bo_va = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo); + if (!vm->ib_bo_va) { + r = -ENOMEM; + goto out_vm_fini; + } + r = radeon_vm_bo_set_addr(rdev, vm->ib_bo_va, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); - if (r) { - radeon_vm_fini(rdev, vm); - kfree(fpriv); - goto out_suspend; - } + if (r) + goto out_vm_fini; } file_priv->driver_priv = fpriv; } +out_vm_fini: + if (r) + radeon_vm_fini(rdev, vm); +out_fpriv: + if (r) + kfree(fpriv); out_suspend: pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev);
Re: [PATCH v2 1/2] drm/msm: Allocate msm_drm_private early and pass it as driver data
Hi AngeloGioacchino, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on drm/drm-next] [also build test WARNING on next-20211130] [cannot apply to v5.16-rc3] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/AngeloGioacchino-Del-Regno/drm-msm-Fix-dsi-bridge-probe/20211130-221304 base: git://anongit.freedesktop.org/drm/drm drm-next config: csky-randconfig-c004-20211128 (https://download.01.org/0day-ci/archive/20211201/202112011405.wn79h7q3-...@intel.com/config) compiler: csky-linux-gcc (GCC) 11.2.0 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot cocci warnings: (new ones prefixed by >>) >> drivers/gpu/drm/msm/msm_drv.c:412:1-6: WARNING: invalid free of devm_ >> allocated data vim +412 drivers/gpu/drm/msm/msm_drv.c 2aa31767259722 Sean Paul 2019-05-24 384 98659487b845c0 Abhinav Kumar 2021-04-16 385 msm_disp_snapshot_destroy(ddev); 98659487b845c0 Abhinav Kumar 2021-04-16 386 2b669875332fbd Archit Taneja 2016-05-02 387 drm_mode_config_cleanup(ddev); c8afe684c95cd1 Rob Clark 2013-06-26 388 2b669875332fbd Archit Taneja 2016-05-02 389 pm_runtime_get_sync(dev); f026e431cf8611 Thomas Zimmermann 2021-08-03 390 msm_irq_uninstall(ddev); 2b669875332fbd Archit Taneja 2016-05-02 391 pm_runtime_put_sync(dev); c8afe684c95cd1 Rob Clark 2013-06-26 392 16976085a114ae Archit Taneja 2016-11-03 393 if (kms && kms->funcs) c8afe684c95cd1 Rob Clark 2013-06-26 394 kms->funcs->destroy(kms); c8afe684c95cd1 Rob Clark 2013-06-26 395 871d812aa43e63 Rob Clark 2013-11-16 396 if (priv->vram.paddr) { 00085f1efa387a Krzysztof Kozlowski 2016-08-03 397 unsigned long attrs = DMA_ATTR_NO_KERNEL_MAPPING; 871d812aa43e63 Rob Clark 2013-11-16 398 drm_mm_takedown(&priv->vram.mm); 2b669875332fbd Archit Taneja 2016-05-02 399 dma_free_attrs(dev, priv->vram.size, NULL, 00085f1efa387a Krzysztof Kozlowski 2016-08-03 400 priv->vram.paddr, attrs); 871d812aa43e63 Rob Clark 2013-11-16 401 } 871d812aa43e63 Rob Clark 2013-11-16 402 2b669875332fbd Archit Taneja 2016-05-02 403 component_unbind_all(dev, ddev); 060530f1ea6740 Rob Clark 2014-03-03 404 bc3220be22577e Rajesh Yadav2018-06-21 405 if (mdss && mdss->funcs) bc3220be22577e Rajesh Yadav2018-06-21 406 mdss->funcs->destroy(ddev); 0a6030d224d3a4 Archit Taneja 2016-05-08 407 2b669875332fbd Archit Taneja 2016-05-02 408 ddev->dev_private = NULL; 4d8dc2dfae2c48 Thomas Zimmermann 2018-09-26 409 drm_dev_put(ddev); c8afe684c95cd1 Rob Clark 2013-06-26 410 2aa31767259722 Sean Paul 2019-05-24 411 destroy_workqueue(priv->wq); c8afe684c95cd1 Rob Clark 2013-06-26 @412 kfree(priv); c8afe684c95cd1 Rob Clark 2013-06-26 413 c8afe684c95cd1 Rob Clark 2013-06-26 414 return 0; c8afe684c95cd1 Rob Clark 2013-06-26 415 } c8afe684c95cd1 Rob Clark 2013-06-26 416 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org
Re: [PATCH] drm: rcar-du: add modifiers support
Hi Daniel-san, On 2021/11/30 22:20, Daniel Stone wrote: On Tue, 30 Nov 2021 at 08:44, Esaki Tomohito wrote: On 2021/11/18 23:05, Laurent Pinchart wrote: On Thu, Nov 18, 2021 at 01:02:11PM +, Daniel Stone wrote: Laurent's concern is that the DRM core should handle this rather than open-coding in every driver, which I agree with. Some drivers (e.g. radeon, maybe legacy NV?) do not support modifiers, and _also_ do magic inference of the actual layout of the underlying buffer. However, these drivers are legacy and we do not accept any new addition of inferring layout without modifiers. I think the best way forward here is: - add a new mode_config.cannot_support_modifiers flag, and enable this in radeon (plus any other drivers in the same boat) Is there an easy way to identify the drivers that need this ? Should I find a driver that has not use drm_plane_funcs? I don't think there's a good way to systematically audit it. The only two I know are radeon (i.e. pre-amdgpu) and nouveau (pre-nv50), both of which pass no modifiers to drm_universal_plane_init(), but do have magic back channels to communicate tiling information. If anyone knows of any others, well, I guess we'll find out. :) Thanks for the information. I checked the driver code with the tiling keyword, and it seems that these are the only two drivers that require cannot_support_modifiers. I will start creating patches for these two drivers first. -- Best Regards Tomohito Esaki
[PATCH v3 2/2] drm: rcar-du: Add R-Car DSI driver
From: LUU HOAI The driver supports the MIPI DSI/CSI-2 TX encoder found in the R-Car V3U SoC. It currently supports DSI mode only. Signed-off-by: LUU HOAI Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Tested-by: Kieran Bingham Acked-by: Sam Ravnborg --- Changes since v2: - Support probing of child DSI devices - Use devm_drm_of_get_bridge() helper Changes since v1: - Use U suffix for unsigned constants - Fix indentation in Makefile - Select DRM_MIPI_DSI - Report correct fout frequency in debug message - Move dsi_setup_info.err to local variable --- drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 817 +++ drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h | 172 4 files changed, 997 insertions(+) create mode 100644 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index 3e588ddba245..1675df21d91f 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -45,6 +45,13 @@ config DRM_RCAR_LVDS select OF_FLATTREE select OF_OVERLAY +config DRM_RCAR_MIPI_DSI + tristate "R-Car DU MIPI DSI Encoder Support" + depends on DRM && DRM_BRIDGE && OF + select DRM_MIPI_DSI + help + Enable support for the R-Car Display Unit embedded MIPI DSI encoders. + config DRM_RCAR_VSP bool "R-Car DU VSP Compositor Support" if ARM default y if ARM64 diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 4d1187ccc3e5..286bc81b3e7c 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_DRM_RCAR_CMM)+= rcar_cmm.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o obj-$(CONFIG_DRM_RCAR_LVDS)+= rcar_lvds.o +obj-$(CONFIG_DRM_RCAR_MIPI_DSI)+= rcar_mipi_dsi.o # 'remote-endpoint' is fixed up at run-time DTC_FLAGS_rcar_du_of_lvds_r8a7790 += -Wno-graph_endpoint diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c new file mode 100644 index ..fcaec3308d68 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c @@ -0,0 +1,817 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rcar_mipi_dsi.c -- R-Car MIPI DSI Encoder + * + * Copyright (C) 2020 Renesas Electronics Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rcar_mipi_dsi_regs.h" + +struct rcar_mipi_dsi { + struct device *dev; + const struct rcar_mipi_dsi_device_info *info; + struct reset_control *rstc; + + struct mipi_dsi_host host; + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct drm_connector connector; + + void __iomem *mmio; + struct { + struct clk *mod; + struct clk *pll; + struct clk *dsi; + } clocks; + + struct drm_display_mode display_mode; + enum mipi_dsi_pixel_format format; + unsigned int num_data_lanes; + unsigned int lanes; +}; + +static inline struct rcar_mipi_dsi * +bridge_to_rcar_mipi_dsi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct rcar_mipi_dsi, bridge); +} + +static inline struct rcar_mipi_dsi * +host_to_rcar_mipi_dsi(struct mipi_dsi_host *host) +{ + return container_of(host, struct rcar_mipi_dsi, host); +} + +static const u32 phtw[] = { + 0x01020114, 0x01600115, /* General testing */ + 0x01030116, 0x0102011d, /* General testing */ + 0x011101a4, 0x018601a4, /* 1Gbps testing */ + 0x014201a0, 0x010001a3, /* 1Gbps testing */ + 0x0101011f, /* 1Gbps testing */ +}; + +static const u32 phtw2[] = { + 0x010c0130, 0x010c0140, /* General testing */ + 0x010c0150, 0x010c0180, /* General testing */ + 0x010c0190, + 0x010a0160, 0x010a0170, + 0x01800164, 0x01800174, /* 1Gbps testing */ +}; + +static const u32 hsfreqrange_table[][2] = { + { 8000U, 0x00 }, { 9000U, 0x10 }, { 1U, 0x20 }, + { 11000U, 0x30 }, { 12000U, 0x01 }, { 13000U, 0x11 }, + { 14000U, 0x21 }, { 15000U, 0x31 }, { 16000U, 0x02 }, + { 17000U, 0x12 }, { 18000U, 0x22 }, { 19000U, 0x32 }, + { 20500U, 0x03 }, { 22000U, 0x13 }, { 23500U, 0x23 }, + { 25000U, 0x33 }, { 27500U, 0x04 }, { 3U, 0x14 }, + { 32500U, 0x25 }, { 35000U, 0x35 }, { 4U, 0x05 }, + { 45000U, 0x16 }, { 5U, 0x26 }, { 55000U, 0x37 }, +
[PATCH v3 1/2] dt-bindings: display: bridge: Add binding for R-Car MIPI DSI/CSI-2 TX
The R-Car MIPI DSI/CSI-2 TX is embedded in the Renesas R-Car V3U SoC. It can operate in either DSI or CSI-2 mode, with up to four data lanes. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Acked-by: Sam Ravnborg Reviewed-by: Rob Herring Reviewed-by: Geert Uytterhoeven --- .../display/bridge/renesas,dsi-csi2-tx.yaml | 118 ++ MAINTAINERS | 1 + 2 files changed, 119 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml b/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml new file mode 100644 index ..afeeb967393d --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/renesas,dsi-csi2-tx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas R-Car MIPI DSI/CSI-2 Encoder + +maintainers: + - Laurent Pinchart + +description: | + This binding describes the MIPI DSI/CSI-2 encoder embedded in the Renesas + R-Car V3U SoC. The encoder can operate in either DSI or CSI-2 mode, with up + to four data lanes. + +properties: + compatible: +enum: + - renesas,r8a779a0-dsi-csi2-tx# for V3U + + reg: +maxItems: 1 + + clocks: +items: + - description: Functional clock + - description: DSI (and CSI-2) functional clock + - description: PLL reference clock + + clock-names: +items: + - const: fck + - const: dsi + - const: pll + + power-domains: +maxItems: 1 + + resets: +maxItems: 1 + + ports: +$ref: /schemas/graph.yaml#/properties/ports + +properties: + port@0: +$ref: /schemas/graph.yaml#/properties/port +description: Parallel input port + + port@1: +$ref: /schemas/graph.yaml#/$defs/port-base +unevaluatedProperties: false +description: DSI/CSI-2 output port + +properties: + endpoint: +$ref: /schemas/media/video-interfaces.yaml# +unevaluatedProperties: false + +properties: + data-lanes: +minItems: 1 +maxItems: 4 + +required: + - data-lanes + +required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - power-domains + - resets + - ports + +additionalProperties: false + +examples: + - | +#include +#include + +dsi0: dsi-encoder@fed8 { +compatible = "renesas,r8a779a0-dsi-csi2-tx"; +reg = <0xfed8 0x1>; +power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; +clocks = <&cpg CPG_MOD 415>, + <&cpg CPG_CORE R8A779A0_CLK_DSI>, + <&cpg CPG_CORE R8A779A0_CLK_CP>; +clock-names = "fck", "dsi", "pll"; +resets = <&cpg 415>; + +ports { +#address-cells = <1>; +#size-cells = <0>; + +port@0 { +reg = <0>; +dsi0_in: endpoint { +remote-endpoint = <&du_out_dsi0>; +}; +}; + +port@1 { +reg = <1>; +dsi0_out: endpoint { +data-lanes = <1 2>; +remote-endpoint = <&sn65dsi86_in>; +}; +}; +}; +}; +... diff --git a/MAINTAINERS b/MAINTAINERS index 53b859d10de6..caf359403a97 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6413,6 +6413,7 @@ L:dri-devel@lists.freedesktop.org L: linux-renesas-...@vger.kernel.org S: Supported T: git git://linuxtv.org/pinchartl/media drm/du/next +F: Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml F: Documentation/devicetree/bindings/display/renesas,du.yaml -- Regards, Laurent Pinchart
[PATCH v3 0/2] R-Car DU: Add DSI encoder driver for V3U
Hello, This patch series adds a driver for the DSI encoder found in the R-Car V3U SoC, which is the first SoC in the family that supports DSI. The driver is based on an implementation from the BSP written by Luu Hoai, with lots of further rework. If anyone is interested in the history, a broken down v1 is available from [1]. The driver has been successfully tested on the Falcon board, which connects an SN65DSI86 to the output of the DSI encoder. Further patches are needed for the ti-sn65dsi86 driver to enable usage in plain DP (non-eDP) mode, as the Falcon board has a mini-DP connector wired to the output of the SN65DSI86. This is work in progress (see [2]). [1] https://lore.kernel.org/linux-renesas-soc/189c7a07-29cd-39f4-1dec-56aa94c11...@ideasonboard.com/T/#mafbe130386cbc8326f85cad46860813516ef4a80 [2] https://lore.kernel.org/linux-renesas-soc/20210322030128.2283-1-laurent.pinchart+rene...@ideasonboard.com/ LUU HOAI (1): drm: rcar-du: Add R-Car DSI driver Laurent Pinchart (1): dt-bindings: display: bridge: Add binding for R-Car MIPI DSI/CSI-2 TX .../display/bridge/renesas,dsi-csi2-tx.yaml | 118 +++ MAINTAINERS | 1 + drivers/gpu/drm/rcar-du/Kconfig | 7 + drivers/gpu/drm/rcar-du/Makefile | 1 + drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 817 ++ drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h | 172 6 files changed, 1116 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/renesas,dsi-csi2-tx.yaml create mode 100644 drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c create mode 100644 drivers/gpu/drm/rcar-du/rcar_mipi_dsi_regs.h base-commit: c18c889bb5e014e144716044991112f16833 -- Regards, Laurent Pinchart
Re: [PATCH v2 2/2] drm: rcar-du: mipi-dsi: Use devm_drm_of_get_bridge helper
Hi Kieran, On Tue, Nov 30, 2021 at 04:52:19PM +, Kieran Bingham wrote: > Quoting Kieran Bingham (2021-11-30 16:25:13) > > Instead of open coding the calls for > > drm_of_find_panel_or_bridge() > > devm_drm_panel_bridge_add() > > > > use the devm_drm_of_get_bridge() helper directly. > > > > Signed-off-by: Kieran Bingham > > --- > > v2: > > - New patch > > > > drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 19 --- > > 1 file changed, 4 insertions(+), 15 deletions(-) > > > > diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > > b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > > index 0a9f197ef62c..1dfe20d3d0f2 100644 > > --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > > +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > > @@ -637,7 +637,7 @@ static int rcar_mipi_dsi_host_attach(struct > > mipi_dsi_host *host, > > struct mipi_dsi_device *device) > > { > > struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); > > - struct drm_panel *panel; > > + struct device *dev = dsi->dev; > > int ret; > > > > if (device->lanes > dsi->num_data_lanes) > > @@ -646,20 +646,9 @@ static int rcar_mipi_dsi_host_attach(struct > > mipi_dsi_host *host, > > dsi->lanes = device->lanes; > > dsi->format = device->format; > > > > - ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel, > > - &dsi->next_bridge); > > - if (ret) { > > - dev_err_probe(dsi->dev, ret, "could not find next > > bridge\n"); > > - return ret; > > - } > > - > > - if (!dsi->next_bridge) { > > - dsi->next_bridge = devm_drm_panel_bridge_add(dsi->dev, > > panel); > > - if (IS_ERR(dsi->next_bridge)) { > > - dev_err(dsi->dev, "failed to create panel > > bridge\n"); > > - return PTR_ERR(dsi->next_bridge); > > - } > > - } > > + dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); > > + if (IS_ERR(dsi->next_bridge)) > > + return PTR_ERR(dsi->next_bridge); > > I did make a change here to make this: > > dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); > if (IS_ERR(dsi->next_bridge)) { > dev_err(dev, "failed to get next bridge\n"); > return PTR_ERR(dsi->next_bridge); > } > > But it seems I got out of sequence and saved out the wrong patch ;-( > > If you think it's better with the error print, please add it while > squashing, or if you really need, I can send an updated patch and > retest. I think an error message is useful, yes. I'll add it manually. > > > > /* Initialize the DRM bridge. */ > > dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; -- Regards, Laurent Pinchart
Re: [PATCH v2 1/2] drm: rcar-du: mipi-dsi: Support bridge probe ordering
Hi Kieran, Thank you for the patch. On Tue, Nov 30, 2021 at 04:25:12PM +, Kieran Bingham wrote: > The bridge probe ordering for DSI devices has been clarified and further > documented in I've read the document and :-) > To support connecting with the SN65DSI86 device after commit c3b75d4734cb > ("drm/bridge: sn65dsi86: Register and attach our DSI device at probe"), > update to the new probe ordering to remove a perpetual -EPROBE_DEFER > loop between the two devices. > > Signed-off-by: Kieran Bingham > > --- > v2 > - Remove now unused panel variable from rcar_mipi_dsi_probe() > > drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 49 + > 1 file changed, 26 insertions(+), 23 deletions(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > index 50e922328fed..0a9f197ef62c 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > @@ -637,6 +637,8 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host > *host, > struct mipi_dsi_device *device) > { > struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); > + struct drm_panel *panel; > + int ret; > > if (device->lanes > dsi->num_data_lanes) > return -EINVAL; > @@ -644,12 +646,36 @@ static int rcar_mipi_dsi_host_attach(struct > mipi_dsi_host *host, > dsi->lanes = device->lanes; > dsi->format = device->format; > > + ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel, > + &dsi->next_bridge); > + if (ret) { > + dev_err_probe(dsi->dev, ret, "could not find next bridge\n"); dev_err_probe() should only be used in probe(), and this function isn't guaranteed to be called at probe time only. This isn't a big deal as the next patch fixes this, and both will be squashed. Furthermore, rcar_mipi_dsi_host_attach() should only be called when the DSI device gets registered, which should happen after it registers its bridge, so I don't think we can see a probe deferral here. Other than that the patch looks fine, I'll squash it with the DSI driver. > + return ret; > + } > + > + if (!dsi->next_bridge) { > + dsi->next_bridge = devm_drm_panel_bridge_add(dsi->dev, panel); > + if (IS_ERR(dsi->next_bridge)) { > + dev_err(dsi->dev, "failed to create panel bridge\n"); > + return PTR_ERR(dsi->next_bridge); > + } > + } > + > + /* Initialize the DRM bridge. */ > + dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; > + dsi->bridge.of_node = dsi->dev->of_node; > + drm_bridge_add(&dsi->bridge); > + > return 0; > } > > static int rcar_mipi_dsi_host_detach(struct mipi_dsi_host *host, > struct mipi_dsi_device *device) > { > + struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); > + > + drm_bridge_remove(&dsi->bridge); > + > return 0; > } > > @@ -731,7 +757,6 @@ static int rcar_mipi_dsi_get_clocks(struct rcar_mipi_dsi > *dsi) > static int rcar_mipi_dsi_probe(struct platform_device *pdev) > { > struct rcar_mipi_dsi *dsi; > - struct drm_panel *panel; > struct resource *mem; > int ret; > > @@ -764,21 +789,6 @@ static int rcar_mipi_dsi_probe(struct platform_device > *pdev) > return PTR_ERR(dsi->rstc); > } > > - ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel, > - &dsi->next_bridge); > - if (ret) { > - dev_err_probe(dsi->dev, ret, "could not find next bridge\n"); > - return ret; > - } > - > - if (!dsi->next_bridge) { > - dsi->next_bridge = devm_drm_panel_bridge_add(dsi->dev, panel); > - if (IS_ERR(dsi->next_bridge)) { > - dev_err(dsi->dev, "failed to create panel bridge\n"); > - return PTR_ERR(dsi->next_bridge); > - } > - } > - > /* Initialize the DSI host. */ > dsi->host.dev = dsi->dev; > dsi->host.ops = &rcar_mipi_dsi_host_ops; > @@ -786,11 +796,6 @@ static int rcar_mipi_dsi_probe(struct platform_device > *pdev) > if (ret < 0) > return ret; > > - /* Initialize the DRM bridge. */ > - dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; > - dsi->bridge.of_node = dsi->dev->of_node; > - drm_bridge_add(&dsi->bridge); > - > return 0; > } > > @@ -798,8 +803,6 @@ static int rcar_mipi_dsi_remove(struct platform_device > *pdev) > { > struct rcar_mipi_dsi *dsi = platform_get_drvdata(pdev); > > - drm_bridge_remove(&dsi->bridge); > - > mipi_dsi_host_unregister(&dsi->host); > > return 0; -- Regards, Laurent Pinchart
Re: [PATCH] drm/msm/dpu: fix exception in error path
On Thu 25 Nov 12:01 CST 2021, Dmitry Baryshkov wrote: > In case of DPU probe failure, prevent the following NULL pointer > exception: > > [3.976112] Unable to handle kernel NULL pointer dereference at virtual > address 0030 > [3.984983] Mem abort info: > [3.987800] ESR = 0x9604 > [3.990891] EC = 0x25: DABT (current EL), IL = 32 bits > [3.996251] SET = 0, FnV = 0 > [3.996254] EA = 0, S1PTW = 0 > [3.996257] FSC = 0x04: level 0 translation fault > [3.996260] Data abort info: > [3.996262] ISV = 0, ISS = 0x0004 > [4.005229] CM = 0, WnR = 0 > [4.028893] [0030] user address but active_mm is swapper > [4.035305] Internal error: Oops: 9604 [#1] SMP > [4.040223] Modules linked in: > [4.043317] CPU: 1 PID: 50 Comm: kworker/u16:2 Not tainted > 5.16.0-rc1-00036-g6d4bafcbb015-dirty #166 > [4.052518] Hardware name: Thundercomm Dragonboard 845c (DT) > [4.058224] Workqueue: events_unbound deferred_probe_work_func > [4.064105] pstate: 6045 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) > [4.071124] pc : dpu_core_irq_uninstall+0x28/0x100 > [4.075960] lr : dpu_core_irq_uninstall+0x24/0x100 > [4.080793] sp : 80001057b990 > [4.084138] x29: 80001057b990 x28: 7653c0a41c00 x27: > 7653c0926480 > [4.091330] x26: b90d5d262ad0 x25: 7653c4b2e980 x24: > 7653c0046080 > [4.098520] x23: 7653c099a810 x22: 7653c5a65800 x21: > 7653c5a65080 > [4.105711] x20: 7653c5a65800 x19: 7653c0046080 x18: > 0034 > [4.112902] x17: 0038 x16: 0005 x15: > 000c > [4.120095] x14: 024c x13: 7653c2f90358 x12: > > [4.127287] x11: 7653c2f903b0 x10: 09c0 x9 : > 80001057b180 > [4.134477] x8 : 80001057b404 x7 : x6 : > 7653c5a5f190 > [4.141669] x5 : 80001057b890 x4 : x3 : > 7653c5a5f0f4 > [4.148859] x2 : 7653c2f5 x1 : x0 : > > [4.156052] Call trace: > [4.158525] dpu_core_irq_uninstall+0x28/0x100 > [4.163004] dpu_irq_uninstall+0x10/0x20 > [4.166963] msm_drm_uninit.isra.0+0xe0/0x1b0 > [4.171353] msm_drm_bind+0x278/0x5f0 > [4.175043] try_to_bring_up_master+0x164/0x1d0 > [4.179610] __component_add+0xa0/0x170 > [4.183482] component_add+0x14/0x20 > [4.187086] dsi_dev_probe+0x1c/0x30 > [4.190691] platform_probe+0x68/0xe0 > [4.194382] really_probe.part.0+0x9c/0x30c > [4.198601] __driver_probe_device+0x98/0x144 > [4.202990] driver_probe_device+0x44/0x15c > [4.207208] __device_attach_driver+0xb4/0x120 > [4.211685] bus_for_each_drv+0x78/0xd0 > [4.215549] __device_attach+0xdc/0x184 > [4.219412] device_initial_probe+0x14/0x20 > [4.223630] bus_probe_device+0x9c/0xa4 > [4.227503] deferred_probe_work_func+0x88/0xc0 > [4.232075] process_one_work+0x1e8/0x380 > [4.236126] worker_thread+0x280/0x520 > [4.239902] kthread+0x168/0x174 > [4.243166] ret_from_fork+0x10/0x20 > [4.246778] Code: f9442400 91004000 940188b9 f9430660 (b9403001) > [4.252925] ---[ end trace b470a50cd7b5e606 ]--- > > Signed-off-by: Dmitry Baryshkov > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c > b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c > index d2b6dca487e3..fc1b6c47c93d 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c > @@ -575,6 +575,9 @@ void dpu_core_irq_uninstall(struct dpu_kms *dpu_kms) > { > int i; > > + if (!dpu_kms->hw_intr) > + return; I would rather see that we fix msm_drm_init() to nicely unroll things in a more granular fashion instead of handle all types of errors with the big hammer that msm_drm_uninit() provides. Regards, Bjorn > + > pm_runtime_get_sync(&dpu_kms->pdev->dev); > for (i = 0; i < dpu_kms->hw_intr->total_irqs; i++) > if (!list_empty(&dpu_kms->hw_intr->irq_cb_tbl[i])) > -- > 2.33.0 >
[PATCH] drm/exynos: drop the use of label from exynos_dsi_register_te_irq
Dropped the use of 'out' label from exynos_dsi_register_te_irq function because the label isn't needed. This patch returns an error in each error case directly not going to 'out' label. With this patch build warning[1] is also fixed, which was reported by kernel test robot [1] https://www.spinics.net/lists/dri-devel/msg323803.html Reported-by: kernel test robot Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index b0b1acb7e712..32a36572b894 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1338,7 +1338,7 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi, if (IS_ERR(dsi->te_gpio)) { dev_err(dsi->dev, "gpio request failed with %ld\n", PTR_ERR(dsi->te_gpio)); - goto out; + return PTR_ERR(dsi->te_gpio); } te_gpio_irq = gpiod_to_irq(dsi->te_gpio); @@ -1348,11 +1348,10 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi, if (ret) { dev_err(dsi->dev, "request interrupt failed with %d\n", ret); gpiod_put(dsi->te_gpio); - goto out; + return ret; } -out: - return ret; + return 0; } static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) -- 2.25.1
Re: [Intel-gfx] [PATCH v5] drm/i915: Re-use i915 macros for checking PTEs
On Thu, Nov 18, 2021 at 12:54:32PM -0800, Michael Cheng wrote: Certain gen8 ppgtt/gtt functions are using _PAGE_RW and _PAGE_PRESENT to check bits 0 and 1 for PTEs. These macros are defined per architectures, and some architectures do not have these defined (like arm64). This patch replaces these two macros with their i915 equivalent implementation. Signed-off-by: Michael Cheng Reviewed-by: Lucas De Marchi thanks Lucas De Marchi
Re: [PATCH v4 2/2] drm/i915: Use to_root_gt() to refer to the root tile
On Wed, Dec 01, 2021 at 12:41:08AM +0200, Andi Shyti wrote: Hi Lucas, fist of all thanks for taking a look at this, I was eagerly waiting for reviewers. On Tue, Nov 30, 2021 at 01:07:30PM -0800, Lucas De Marchi wrote: On Sun, Nov 28, 2021 at 01:09:26PM +0200, Andi Shyti wrote: > Starting from a patch from Matt to_root_gt() returns the > reference to the root tile in order to abstract the root tile > from th callers. > > Being the root tile identified as tile '0', embed the id in the > name so that i915->gt becomes i915->gt0. > > The renaming has been mostly done with the following command and > some manual fixes. > > sed -i -e sed -i 's/\&i915\->gt\./\&to_root_gt(i915)\->/g' \ >-e sed -i 's/\&dev_priv\->gt\./\&to_root_gt(dev_priv)\->/g' \ >-e 's/\&dev_priv\->gt/to_root_gt(dev_priv)/g' \ >-e 's/\&i915\->gt/to_root_gt(i915)/g' \ >-e 's/dev_priv\->gt\./to_root_gt(dev_priv)\->/g' \ >-e 's/i915\->gt\./to_root_gt(i915)\->/g' \ >`find drivers/gpu/drm/i915/ -name *.[ch]` > > Two small changes have been added to this commit: > > 1. intel_reset_gpu() in intel_display.c retreives the gt from >to_scanout_gt() > 2. in set_scheduler_caps() the gt is taken from the engine and >not from i915. Ideally the non-automatic changes should be in separate patches, before the ones that can be done by automation. Because then it becomes easier to apply the final result without conflicts. OK This is quite a big diff to merge in one go. Looking at the pending patches from Michal however I see he had similar changes, split in sensible chunks.. Could you split your version like that? at least gt/gem and display would be good to have separate. Or sync with Michal on how to proceed with these versions Here are his patches: drm/i915: Remove i915->ggtt drm/i915: Use to_gt() helper for GGTT accesses drm/i915: Use to_gt() helper drm/i915/gvt: Use to_gt() helper drm/i915/gem: Use to_gt() helper drm/i915/gt: Use to_gt() helper drm/i915/display: Use to_gt() helper drm/i915: Introduce to_gt() helper I understand... will follow this approach. This first patch also removed the `struct intel_gt *gt = to_gt(pool)`, that would otherwise be a leftover in drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c One difference from Michal patch is that I am not using the wrapper to_gt(...) but to_root_gt(...) which was introduced by Matt. To me sounds more meaningful as it specifies that we are really looking for the root tile and not any tile. yes, I think it makes sense, too. Michal, any comment? I think you also had other plans to get the root gt by another helper... ? Lucas De Marchi
Re: [PATCH v4 1/2] drm/i915: Store backpointer to GT in uncore
Hi, ping! (Lucas?) > We now support a per-gt uncore, yet we're not able to infer which GT > we're operating upon. Let's store a backpointer for now. > > Signed-off-by: Michał Winiarski > Signed-off-by: Matt Roper > Reviewed-by: Andi Shyti > Signed-off-by: Andi Shyti can we merge this, meanwhile? Andi
[PATCH v16 39/40] 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 0ac6cb315e8d..96d1c5688248 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 = <&tegra_car TEGRA30_CLK_HOST1X>; clock-names = "host1x"; - resets = <&tegra_car 28>; - reset-names = "host1x"; + resets = <&tegra_car 28>, <&mc TEGRA30_MC_RESET_HC>; + reset-names = "host1x", "mc"; iommus = <&mc TEGRA_SWGROUP_HC>; power-domains = <&pd_heg>; operating-points-v2 = <&host1x_dvfs_opp_table>; @@ -190,8 +190,8 @@ gr2d@5414 { reg = <0x5414 0x0004>; interrupts = ; clocks = <&tegra_car TEGRA30_CLK_GR2D>; - resets = <&tegra_car 21>; - reset-names = "2d"; + resets = <&tegra_car 21>, <&mc TEGRA30_MC_RESET_2D>; + reset-names = "2d", "mc"; power-domains = <&pd_heg>; operating-points-v2 = <&gr2d_dvfs_opp_table>; @@ -205,8 +205,10 @@ gr3d@5418 { <&tegra_car TEGRA30_CLK_GR3D2>; clock-names = "3d", "3d2"; resets = <&tegra_car 24>, -<&tegra_car 98>; - reset-names = "3d", "3d2"; +<&tegra_car 98>, +<&mc TEGRA30_MC_RESET_3D>, +<&mc TEGRA30_MC_RESET_3D2>; + reset-names = "3d", "3d2", "mc", "mc2"; power-domains = <&pd_3d0>, <&pd_3d1>; power-domain-names = "3d0", "3d1"; operating-points-v2 = <&gr3d_dvfs_opp_table>; -- 2.33.1
[PATCH v16 20/40] 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(&pdev->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 = &tegra_gmi_pm, }, }; module_platform_driver(tegra_gmi_driver); -- 2.33.1
[PATCH v16 18/40] drm/tegra: Consolidate runtime PM management of older UAPI codepath
Move runtime PM management of older UAPI code paths into the common place. This removes boilerplate code from client drivers. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/drm.c | 11 ++- drivers/gpu/drm/tegra/gr2d.c | 10 +- drivers/gpu/drm/tegra/gr3d.c | 10 +- drivers/gpu/drm/tegra/nvdec.c | 14 +- drivers/gpu/drm/tegra/vic.c | 12 +--- 5 files changed, 14 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 2e7da2a7505d..dc04ce329be3 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -116,6 +117,7 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) static void tegra_drm_context_free(struct tegra_drm_context *context) { context->client->ops->close_channel(context); + pm_runtime_put(context->client->base.dev); kfree(context); } @@ -427,13 +429,20 @@ static int tegra_client_open(struct tegra_drm_file *fpriv, { int err; + err = pm_runtime_resume_and_get(client->base.dev); + if (err) + return err; + err = client->ops->open_channel(client, context); - if (err < 0) + if (err < 0) { + pm_runtime_put(client->base.dev); return err; + } err = idr_alloc(&fpriv->legacy_contexts, context, 1, 0, GFP_KERNEL); if (err < 0) { client->ops->close_channel(context); + pm_runtime_put(client->base.dev); return err; } diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 2382def93923..e3bb4c99ed39 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -127,17 +127,10 @@ 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) { - pm_runtime_put(client->base.dev); + if (!context->channel) return -ENOMEM; - } return 0; } @@ -145,7 +138,6 @@ 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) diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 032d71365494..a1fd3113ea96 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -136,17 +136,10 @@ 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) { - pm_runtime_put(client->base.dev); + if (!context->channel) return -ENOMEM; - } return 0; } @@ -154,7 +147,6 @@ 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) diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c index 15f036e09e5c..79e1e88203cf 100644 --- a/drivers/gpu/drm/tegra/nvdec.c +++ b/drivers/gpu/drm/tegra/nvdec.c @@ -291,29 +291,17 @@ static int nvdec_open_channel(struct tegra_drm_client *client, struct tegra_drm_context *context) { struct nvdec *nvdec = to_nvdec(client); - int err; - - err = pm_runtime_get_sync(nvdec->dev); - if (err < 0) { - pm_runtime_put(nvdec->dev); - return err; - } context->channel = host1x_channel_get(nvdec->channel); - if (!context->channel) { - pm_runtime_put(nvdec->dev); + if (!context->channel) return -ENOMEM; - } return 0; } static void nvdec_close_channel(struct tegra_drm_context *context) { - struct nvdec *nvdec = to_nvdec(context->client); - host1x_channel_put(context->channel); - pm_runtime_put(nvdec->dev); } static const struct tegra_drm_client_ops nvdec_ops = { diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c index 9622ca96c539..7886740bcbf2 100644 --
[PATCH v16 14/40] 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..032d71365494 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(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(&pdev->dev, sizeof(*gr3d), GFP_KERNEL); - if (!gr3d) - return -ENOMEM; - - gr3d->soc = of_device_get_match_data(&pdev->dev); + /* +* Tegra20 device-tree doesn't specify 3d clock name and there is only +* one clock for Tegra20. Teg
[PATCH v16 32/40] 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 v16 22/40] 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(&pdev->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(&pdev->dev); if (rc) goto err_rst_get; + pm_runtime_enable(&pdev->dev); + rc = pm_runtime_resume_and_get(&pdev->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(&pdev->dev); +err_pm_get: + pm_runtime_disable(&pdev->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(&pdev->dev); + pm_runtime_force_suspend(&pdev->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) {
[PATCH v16 17/40] 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 | 16 ++-- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c index 1ba4d539da06..6d6dd8c35475 100644 --- a/drivers/gpu/drm/tegra/submit.c +++ b/drivers/gpu/drm/tegra/submit.c @@ -504,10 +504,8 @@ 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_mark_last_busy(client->base.dev); - pm_runtime_put_autosuspend(client->base.dev); - } + pm_runtime_mark_last_busy(client->base.dev); + pm_runtime_put_autosuspend(client->base.dev); } int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data, @@ -591,12 +589,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 v16 37/40] 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 861ac96bd806..f9d64360222b 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi @@ -966,6 +966,7 @@ pmc@7000e400 { nvidia,core-pwr-off-time = <0>; nvidia,core-power-req-active-high; nvidia,sys-clock-req-active-high; + core-supply = <&vdd_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 = <&core_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 = <&vdd_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 = <&vdd_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 = <&vddctrl_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-
[PATCH v16 25/40] 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 = <&vde_pool>; /* IRAM region */ - interrupts = , /* Sync token interrupt */ -, /* BSE-V interrupt */ -; /* SXE interrupt */ - interrupt-names = "sync-token", "bsev", "sxe"; - clocks = <&tegra_car TEGRA20_CLK_VDE>; - reset-names = "vde", "mc"; - resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; - iommus = <&mc 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 0x10
[PATCH v16 16/40] 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(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, 500); - pm_runtime_use_autosuspend(&pdev->dev); - return 0; exit_falcon: @@ -436,11 +446,6 @@ static int nvdec_remove(struct platform_device *pdev) return err; } - if (pm_runtime_enabled(&pdev->dev)) - pm_runtime_disable(&pdev->dev); - else - nvdec_runtime_suspend(&pdev->dev); - falcon_exit(&nvdec->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 v16 19/40] 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(&pdev->dev); if (!soc) { dev_err(&pdev->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(&pdev->dev, "failed to enable clock: %d\n", err); + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (err) + return err; + + pm_runtime_enable(&pdev->dev); + err = pm_runtime_resume_and_get(&pdev->dev); + if (err) return err; - } if (device_property_present(&pdev->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(&pdev->dev); + pm_runtime_force_suspend(&pdev->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(&pdev->dev); + pm_runtime_force_suspend(&pdev->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 = &tegra_usb_pm, }, .probe = tegra_usb_probe, .remove = tegra_usb_remove, -- 2.33.1
[PATCH v16 36/40] 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 = <&vdd_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 = <&vdd_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 = <&vdd_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 = <&core_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 v16 38/40] 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 = <&tegra_car TEGRA20_CLK_HOST1X>; clock-names = "host1x"; - resets = <&tegra_car 28>; - reset-names = "host1x"; + resets = <&tegra_car 28>, <&mc TEGRA20_MC_RESET_HC>; + reset-names = "host1x", "mc"; power-domains = <&pd_core>; operating-points-v2 = <&host1x_dvfs_opp_table>; @@ -98,8 +98,8 @@ gr2d@5414 { reg = <0x5414 0x0004>; interrupts = ; clocks = <&tegra_car TEGRA20_CLK_GR2D>; - resets = <&tegra_car 21>; - reset-names = "2d"; + resets = <&tegra_car 21>, <&mc TEGRA20_MC_RESET_2D>; + reset-names = "2d", "mc"; power-domains = <&pd_core>; operating-points-v2 = <&gr2d_dvfs_opp_table>; }; @@ -108,8 +108,8 @@ gr3d@5418 { compatible = "nvidia,tegra20-gr3d"; reg = <0x5418 0x0004>; clocks = <&tegra_car TEGRA20_CLK_GR3D>; - resets = <&tegra_car 24>; - reset-names = "3d"; + resets = <&tegra_car 24>, <&mc TEGRA20_MC_RESET_3D>; + reset-names = "3d", "mc"; power-domains = <&pd_3d>; operating-points-v2 = <&gr3d_dvfs_opp_table>; }; -- 2.33.1
[PATCH v16 21/40] 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(&pdev->dev); + if (ret) + return ret; + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->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(&pdev->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(&pdev->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(&pdev->dev, "pwmchip_add() failed: %d\n", ret); reset_control_assert(pwm->rst); - return ret; + goto put_pm; } + pm_runtime_put(&pdev->dev); + return 0; +put_pm: + pm_runtime_put_sync_suspend(&pdev->dev); + pm_runtime_force_suspend(&pdev->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(&pdev->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
[PATCH v16 13/40] 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..2382def93923 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(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 = &pdev->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 v16 34/40] 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 { }; &emc_icc_dvfs_opp_table { - /delete-node/ opp@12,1100; + /delete-node/ opp-12-1100; }; &emc_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 { }; &emc_icc_dvfs_opp_table { - /delete-node/ opp@12,1100; + /delete-node/ opp-12-1100; }; &emc_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 { }; &emc_icc_dvfs_opp_table { - /delete-node/ opp@92400,1100; - /delete-node/ opp@12,1100; + /delete-node/ opp-92400-1100; + /delete-node/ opp-12-1100; }; &emc_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 { }; &emc_icc_dvfs_opp_table { - /delete-node/ opp@92400,1100; - /delete-node/ opp@12,1100; + /delete-node/ opp-92400-1100; + /delete-node/ opp-12-1100; }; &emc_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 { +
[PATCH v16 35/40] 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 v16 27/40] 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(&pdev->dev)) - tegra_vde_runtime_resume(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); } static __maybe_unused int tegra_vde_pm_suspend(struct device *dev) -- 2.33.1
[PATCH v16 33/40] 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 v16 31/40] 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 v16 28/40] 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(&pdev->dev, "fuse"); + if (IS_ERR(fuse->rst)) { + err = PTR_ERR(fuse->rst); + dev_err(&pdev->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(&pdev->dev); + if (err) + goto restore; + + err = reset_control_reset(fuse->rst); + pm_runtime_put(&pdev->dev); + + if (err < 0) { + dev_err(&pdev->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 v16 29/40] 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(&pdev->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(&pdev->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(&pdev->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 = &pdev->dev; - pm_runtime_enable(&pdev->dev); + err = devm_pm_runtime_enable(&pdev->dev); + if (err) + return err; if (fuse->soc->probe) { err = fuse->soc->probe(fuse); if (err < 0) - goto restore; + return err; } memset(&nvmem, 0, sizeof(nvmem)); @@ -241,7 +251,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->nvmem); dev_err(&pdev->dev, "failed to register NVMEM device: %d\n", err); - goto restore; + return err; } fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse"); @@ -249,7 +259,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->rst); dev_err(&pdev->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(&pdev->dev); if (err) - goto restore; + return err; err = reset_control_reset(fuse->rst); pm_runtime_put(&pdev->dev); if (err < 0) { dev_err(&pdev->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(&pdev->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
[PATCH v16 23/40] 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 = &pdev->dev; + platform_set_drvdata(pdev, ctrl); nand_controller_init(&ctrl->controller); ctrl->controller.ops = &tegra_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(&pdev->dev); + if (err) + return err; + + /* +* This driver doesn't support active power management yet, +* so we will simply keep device resumed. +*/ + pm_runtime_enable(&pdev->dev); + err = pm_runtime_resume_and_get(&pdev->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(&pdev->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 = &tegra_nand_pm, }, .probe = tegra_nand_probe, .remove = tegra_nand_remove, -- 2.33.1
[PATCH v16 40/40] 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 = <&pd_mpe>; operating-points-v2 = <&mpe_dvfs_opp_table>; + status = "disabled"; }; vi@5408 { @@ -70,6 +71,7 @@ vi@5408 { reset-names = "vi"; power-domains = <&pd_venc>; operating-points-v2 = <&vi_dvfs_opp_table>; + status = "disabled"; }; epp@540c { @@ -81,6 +83,7 @@ epp@540c { reset-names = "epp"; power-domains = <&pd_core>; operating-points-v2 = <&epp_dvfs_opp_table>; + status = "disabled"; }; isp@5410 { @@ -91,6 +94,7 @@ isp@5410 { resets = <&tegra_car 23>; reset-names = "isp"; power-domains = <&pd_venc>; + status = "disabled"; }; gr2d@5414 { diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 96d1c5688248..c8b22ec30ef0 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -145,6 +145,8 @@ mpe@5404 { operating-points-v2 = <&mpe_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_MPE>; + + status = "disabled"; }; vi@5408 { @@ -158,6 +160,8 @@ vi@5408 { operating-points-v2 = <&vi_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_VI>; + + status = "disabled"; }; epp@540c { @@ -171,6 +175,8 @@ epp@540c { operating-points-v2 = <&epp_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_EPP>; + + status = "disabled"; }; isp@5410 { @@ -183,6 +189,8 @@ isp@5410 { power-domains = <&pd_venc>; iommus = <&mc TEGRA_SWGROUP_ISP>; + + status = "disabled"; }; gr2d@5414 { -- 2.33.1
[PATCH v16 30/40] 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 = tegra20_
[PATCH v16 26/40] 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 = <&rst 61>, <&mem 13>; iommus = <&mem 15>; + operating-points-v2 = <&dvfs_opp_table>; + power-domains = <&domain>; }; -- 2.33.1
[PATCH v16 15/40] 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(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - err = vic_runtime_resume(&pdev->dev); - if (err < 0) - goto unregister_client; - } - pm_runtime_set_autosuspend_delay(&pdev->dev, 500); - pm_runtime_use_autosuspend(&pdev->dev); - return 0; -unregister_client: - host1x_client_unregister(&vic->client.base); exit_falcon: falcon_exit(&vic->falcon); @@ -513,11 +516,6 @@ static int vic_remove(struct platform_device *pdev) return err; } - if (pm_runtime_enabled(&pdev->dev)) - pm_runtime_disable(&pdev->dev); - else - vic_runtime_suspend(&pdev->dev); - falcon_exit(&vic->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 v16 24/40] 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(&pdev->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 v16 12/40] 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(&pdev->dev); + + err = devm_pm_runtime_enable(&pdev->dev); + if (err) + return err; + + err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); + if (err) + return err; INIT_LIST_HEAD(&hdmi->client.list); hdmi->client.ops = &hdmi_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(&pdev->dev); - err = host1x_client_unregister(&hdmi->client); if (err < 0) { dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", -- 2.33.1
[PATCH v16 10/40] 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. Cc: Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/submit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/submit.c b/drivers/gpu/drm/tegra/submit.c index c32698404e36..1ba4d539da06 100644 --- a/drivers/gpu/drm/tegra/submit.c +++ b/drivers/gpu/drm/tegra/submit.c @@ -504,8 +504,10 @@ static void release_job(struct host1x_job *job) kfree(job_data->used_mappings); kfree(job_data); - if (pm_runtime_enabled(client->base.dev)) + if (pm_runtime_enabled(client->base.dev)) { + pm_runtime_mark_last_busy(client->base.dev); pm_runtime_put_autosuspend(client->base.dev); + } } int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data, -- 2.33.1
[PATCH v16 07/40] 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 v16 03/40] 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 v16 11/40] 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, &rate); + + /* +* 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, &rate); + + 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(&dc->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, &opp_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 v16 09/40] 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, &channel->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 v16 02/40] 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, &opp_params); + if (err != -ENODEV) + return err; + + return 0; +} + #endif /* __SOC_TEGRA_COMMON_H__ */ -- 2.33.1
[PATCH v16 08/40] 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(&ch->cdma.lock); mutex_lock(&debug_lock); @@ -64,6 +70,8 @@ static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) mutex_unlock(&debug_lock); mutex_unlock(&ch->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 = &info->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(&pdev->dev, "host1x"); - if (IS_ERR(host->rst)) { - err = PTR_ERR(host->rst); - dev_err(&pdev->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(&pdev->dev, "failed to enable clock\n"); - goto free_channels; - } - - err = reset_control_deassert(host->rst); - if (err < 0) { - dev_err(&pdev->dev, "failed to deassert reset: %d\n", err); - goto unprepare_disable; - } - err = host1x_syncpt_init(host); if (err) { dev_err
[PATCH v16 04/40] 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 = <&opp_table>; +clocks = <&tegra_car TEGRA20_CLK_SCLK>; +power-domains = <&domain>; +}; }; usb-controller@c5004000 { -- 2.33.1
[PATCH v16 06/40] 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 v16 05/40] 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, &rate); + 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
[PATCH v16 01/40] 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 v16 00/40] 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: v16: - Replaced redundant "context->client" with "client" in gr2d/3d RPM patches, which was spotted by Michał Mirosław in v15. - Added new patch that consolidates the RPM management of older UAPI code path. - Added stable tag to "submit: Add missing pm_runtime_mark_last_busy()" patch and reordered it such that it could be backported without merge conflicts. 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
[PATCH v2 4/4] drm/tegra: Use dev_err_probe()
Replace dev_printk() with a generic dev_err_probe() helper which silences noisy error messages about deferred probe and makes easy to debug failing deferred probe by printing notification about the failure to KMSG in the end of kernel booting process and by adding failing device and the reason of deferred probe to devices_deferred of debugfs. This was proven to be useful in the case of eDP driver regression by immediately showing why display driver was failing when user asked for help, otherwise it would've been much more difficult to debug such problems on a third party device that doesn't have developer setup. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/dc.c | 13 +++-- drivers/gpu/drm/tegra/hdmi.c | 34 +- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 7ea3c045a6f7..f7370d28816f 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -3236,16 +3236,9 @@ static int tegra_dc_probe(struct platform_device *pdev) return -ENXIO; err = tegra_dc_rgb_probe(dc); - if (err < 0 && err != -ENODEV) { - const char *level = KERN_ERR; - - if (err == -EPROBE_DEFER) - level = KERN_DEBUG; - - dev_printk(level, dc->dev, "failed to probe RGB output: %d\n", - err); - return err; - } + if (err < 0 && err != -ENODEV) + return dev_err_probe(&pdev->dev, err, +"failed to probe RGB output\n"); platform_set_drvdata(pdev, dc); pm_runtime_enable(&pdev->dev); diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 9a87d351a828..3242baddc5e7 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1638,7 +1638,6 @@ static irqreturn_t tegra_hdmi_irq(int irq, void *data) static int tegra_hdmi_probe(struct platform_device *pdev) { - const char *level = KERN_ERR; struct tegra_hdmi *hdmi; struct resource *regs; int err; @@ -1678,36 +1677,21 @@ static int tegra_hdmi_probe(struct platform_device *pdev) hdmi->hdmi = devm_regulator_get(&pdev->dev, "hdmi"); err = PTR_ERR_OR_ZERO(hdmi->hdmi); - if (err) { - if (err == -EPROBE_DEFER) - level = KERN_DEBUG; - - dev_printk(level, &pdev->dev, - "failed to get HDMI regulator: %d\n", err); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, +"failed to get HDMI regulator\n"); hdmi->pll = devm_regulator_get(&pdev->dev, "pll"); err = PTR_ERR_OR_ZERO(hdmi->pll); - if (err) { - if (err == -EPROBE_DEFER) - level = KERN_DEBUG; - - dev_printk(level, &pdev->dev, - "failed to get PLL regulator: %d\n", err); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, +"failed to get PLL regulator\n"); hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); err = PTR_ERR_OR_ZERO(hdmi->vdd); - if (err) { - if (err == -EPROBE_DEFER) - level = KERN_DEBUG; - - dev_printk(level, &pdev->dev, - "failed to get VDD regulator: %d\n", err); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, +"failed to get VDD regulator\n"); hdmi->output.dev = &pdev->dev; -- 2.33.1
[PATCH v2 1/4] gpu/host1x: Add init/deinit callbacks to host1x driver framework
Add init/deinit callbacks to host1x driver framework which allow to perform early pre-initialization required by Tegra DRM driver. Cc: # 5.13+ Signed-off-by: Dmitry Osipenko --- drivers/gpu/host1x/bus.c | 15 +++ include/linux/host1x.h | 4 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 0d81eede1217..25d688e5c742 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -479,8 +479,18 @@ static int host1x_device_add(struct host1x *host1x, device->dev.dma_parms = &device->dma_parms; dma_set_max_seg_size(&device->dev, UINT_MAX); + if (driver->init) { + err = driver->init(device); + if (err < 0) { + kfree(device); + return err; + } + } + err = host1x_device_parse_dt(device, driver); if (err < 0) { + if (driver->deinit) + driver->deinit(device); kfree(device); return err; } @@ -512,11 +522,16 @@ static int host1x_device_add(struct host1x *host1x, static void host1x_device_del(struct host1x *host1x, struct host1x_device *device) { + struct host1x_driver *driver = device->driver; + if (device->registered) { device->registered = false; device_del(&device->dev); } + if (driver->deinit) + driver->deinit(device); + put_device(&device->dev); } diff --git a/include/linux/host1x.h b/include/linux/host1x.h index e8dc5bc41f79..5e5ba33af4ae 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -346,6 +346,8 @@ struct host1x_device; * @driver: core driver * @subdevs: table of OF device IDs matching subdevices for this driver * @list: list node for the driver + * @init: called when the host1x logical driver is registered + * @deinit: called when the host1x logical driver is unregistered * @probe: called when the host1x logical device is probed * @remove: called when the host1x logical device is removed * @shutdown: called when the host1x logical device is shut down @@ -356,6 +358,8 @@ struct host1x_driver { const struct of_device_id *subdevs; struct list_head list; + int (*init)(struct host1x_device *device); + void (*deinit)(struct host1x_device *device); int (*probe)(struct host1x_device *device); int (*remove)(struct host1x_device *device); void (*shutdown)(struct host1x_device *device); -- 2.33.1
[PATCH v2 3/4] drm/tegra: dpaux: Restore DP AUX DDC registration order
Restore DP AUX I2C DDC registration order by moving registration to DP AUX driver probe phase. This fixes broken display panel driver of Acer Chromebook CB5-311 that fails to probe starting with v5.13 kernel when DP AUX registration order was changed to prevent accessing uninitialized aux->drm_dev. Tegra SOR driver is never probed now using the new registration order because tegra-output always fails with -EPROBE_DEFER due to missing display panel that requires DP AUX DDC to be registered first. The offending commit made DDC to be registered after SOR's output, which can't ever happen. Use new tegra_drm_device() helper that allows to set aux->drm_dev during DP AUX probe, restoring the DCC registration order and reviving display panel. Cc: # 5.13+ Fixes: 39c17ae60ea9 ("drm/tegra: Don't register DP AUX channels before connectors") Reported-by: Thomas Graichen # T124 Nyan Big Tested-by: Thomas Graichen # T124 Nyan Big Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/dpaux.c | 26 +- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 1f96e416fa08..148d3c00dd8e 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -530,9 +530,12 @@ static int tegra_dpaux_probe(struct platform_device *pdev) disable_irq(dpaux->irq); dpaux->aux.transfer = tegra_dpaux_transfer; + dpaux->aux.drm_dev = tegra_drm_device(); dpaux->aux.dev = &pdev->dev; - drm_dp_aux_init(&dpaux->aux); + err = drm_dp_aux_register(&dpaux->aux); + if (err < 0) + goto put_pm; /* * Assume that by default the DPAUX/I2C pads will be used for HDMI, @@ -544,7 +547,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) */ err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C); if (err < 0) - return err; + goto dp_aux_unreg; #ifdef CONFIG_GENERIC_PINCONF dpaux->desc.name = dev_name(&pdev->dev); @@ -557,7 +560,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); if (IS_ERR(dpaux->pinctrl)) { dev_err(&pdev->dev, "failed to register pincontrol\n"); - return PTR_ERR(dpaux->pinctrl); + err = PTR_ERR(dpaux->pinctrl); + goto dp_aux_unreg; } #endif /* enable and clear all interrupts */ @@ -571,6 +575,14 @@ static int tegra_dpaux_probe(struct platform_device *pdev) mutex_unlock(&dpaux_lock); return 0; + +dp_aux_unreg: + drm_dp_aux_unregister(&dpaux->aux); +put_pm: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return err; } static int tegra_dpaux_remove(struct platform_device *pdev) @@ -579,6 +591,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev) cancel_work_sync(&dpaux->work); + drm_dp_aux_unregister(&dpaux->aux); + /* make sure pads are powered down when not in use */ tegra_dpaux_pad_power_down(dpaux); @@ -717,11 +731,6 @@ int drm_dp_aux_attach(struct drm_dp_aux *aux, struct tegra_output *output) unsigned long timeout; int err; - aux->drm_dev = output->connector.dev; - err = drm_dp_aux_register(aux); - if (err < 0) - return err; - output->connector.polled = DRM_CONNECTOR_POLL_HPD; dpaux->output = output; @@ -759,7 +768,6 @@ int drm_dp_aux_detach(struct drm_dp_aux *aux) unsigned long timeout; int err; - drm_dp_aux_unregister(aux); disable_irq(dpaux->irq); if (dpaux->output->panel) { -- 2.33.1
[PATCH v2 2/4] drm/tegra: Create DRM device early
DRM sub-drivers need to access DRM device early during first stage of drivers' probing. Use new host1x init/deinit callbacks to create DRM device early and destroy late. Cc: # 5.13+ Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/drm.c | 46 ++--- drivers/gpu/drm/tegra/drm.h | 2 ++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index e9de91a4e7e8..e9cbcaf6e017 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1133,21 +1133,42 @@ static bool host1x_drm_wants_iommu(struct host1x_device *dev) return domain != NULL; } -static int host1x_drm_probe(struct host1x_device *dev) +static struct drm_device *terga_drm_dev; + +struct drm_device *tegra_drm_device(void) { - struct tegra_drm *tegra; - struct drm_device *drm; - int err; + return terga_drm_dev; +} - drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev); +static int host1x_drm_dev_init(struct host1x_device *dev) +{ + struct drm_device *drm = drm_dev_alloc(&tegra_drm_driver, &dev->dev); if (IS_ERR(drm)) return PTR_ERR(drm); + dev_set_drvdata(&dev->dev, drm); + terga_drm_dev = drm; + + return 0; +} + +static void host1x_drm_dev_deinit(struct host1x_device *dev) +{ + struct drm_device *drm = dev_get_drvdata(&dev->dev); + + terga_drm_dev = NULL; + drm_dev_put(drm); +} + +static int host1x_drm_probe(struct host1x_device *dev) +{ + struct drm_device *drm = dev_get_drvdata(&dev->dev); + struct tegra_drm *tegra; + int err; + tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); - if (!tegra) { - err = -ENOMEM; - goto put; - } + if (!tegra) + return -ENOMEM; if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) { tegra->domain = iommu_domain_alloc(&platform_bus_type); @@ -1164,7 +1185,6 @@ static int host1x_drm_probe(struct host1x_device *dev) mutex_init(&tegra->clients_lock); INIT_LIST_HEAD(&tegra->clients); - dev_set_drvdata(&dev->dev, drm); drm->dev_private = tegra; tegra->drm = drm; @@ -1285,8 +1305,7 @@ static int host1x_drm_probe(struct host1x_device *dev) iommu_domain_free(tegra->domain); free: kfree(tegra); -put: - drm_dev_put(drm); + return err; } @@ -1319,7 +1338,6 @@ static int host1x_drm_remove(struct host1x_device *dev) } kfree(tegra); - drm_dev_put(drm); return 0; } @@ -1391,6 +1409,8 @@ static struct host1x_driver host1x_drm_driver = { .probe = host1x_drm_probe, .remove = host1x_drm_remove, .subdevs = host1x_drm_subdevs, + .init = host1x_drm_dev_init, + .deinit = host1x_drm_dev_deinit, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index fc0a19554eac..8b7c9508070f 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -121,6 +121,8 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, int host1x_client_iommu_attach(struct host1x_client *client); void host1x_client_iommu_detach(struct host1x_client *client); +struct drm_device *tegra_drm_device(void); + int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); int tegra_drm_exit(struct tegra_drm *tegra); -- 2.33.1
[PATCH v2 0/4] Restore Tegra DRM on Nyan Big Chromebook
This patchset restores regressed SOR driver probing on Nyan Chromebook. Changelog: v2: - Changed host1x and Tegra DRM drivers such that DRM device is registered early now. This removes the need to change DRM core. - Introduced dev_err_probe() patch again. Previously Thierry rejected it, saying that he likes his variant more, but I kept that patch in grate kernel and it happened to be very handy to have because I instantly identified the problem in the DP AUX driver with it, which would've been much more difficult to do otherwise. Please apply it this time. Dmitry Osipenko (4): gpu/host1x: Add init/deinit callbacks to host1x driver framework drm/tegra: Create DRM device early drm/tegra: dpaux: Restore DP AUX DDC registration order drm/tegra: Use dev_err_probe() drivers/gpu/drm/tegra/dc.c| 13 +++--- drivers/gpu/drm/tegra/dpaux.c | 26 +--- drivers/gpu/drm/tegra/drm.c | 46 +-- drivers/gpu/drm/tegra/drm.h | 2 ++ drivers/gpu/drm/tegra/hdmi.c | 34 +++--- drivers/gpu/host1x/bus.c | 15 include/linux/host1x.h| 4 +++ 7 files changed, 83 insertions(+), 57 deletions(-) -- 2.33.1
Re: [PATCH v4 2/2] drm/i915: Use to_root_gt() to refer to the root tile
Hi Lucas, fist of all thanks for taking a look at this, I was eagerly waiting for reviewers. On Tue, Nov 30, 2021 at 01:07:30PM -0800, Lucas De Marchi wrote: > On Sun, Nov 28, 2021 at 01:09:26PM +0200, Andi Shyti wrote: > > Starting from a patch from Matt to_root_gt() returns the > > reference to the root tile in order to abstract the root tile > > from th callers. > > > > Being the root tile identified as tile '0', embed the id in the > > name so that i915->gt becomes i915->gt0. > > > > The renaming has been mostly done with the following command and > > some manual fixes. > > > > sed -i -e sed -i 's/\&i915\->gt\./\&to_root_gt(i915)\->/g' \ > > -e sed -i 's/\&dev_priv\->gt\./\&to_root_gt(dev_priv)\->/g' \ > > -e 's/\&dev_priv\->gt/to_root_gt(dev_priv)/g' \ > > -e 's/\&i915\->gt/to_root_gt(i915)/g' \ > > -e 's/dev_priv\->gt\./to_root_gt(dev_priv)\->/g' \ > > -e 's/i915\->gt\./to_root_gt(i915)\->/g' \ > > `find drivers/gpu/drm/i915/ -name *.[ch]` > > > > Two small changes have been added to this commit: > > > > 1. intel_reset_gpu() in intel_display.c retreives the gt from > >to_scanout_gt() > > 2. in set_scheduler_caps() the gt is taken from the engine and > >not from i915. > > Ideally the non-automatic changes should be in separate patches, before > the ones that can be done by automation. Because then it becomes easier > to apply the final result without conflicts. OK > This is quite a big diff to merge in one go. Looking at the pending > patches from Michal however I see he had similar changes, split in > sensible chunks.. Could you split your version like that? at least > gt/gem and display would be good to have separate. Or sync with Michal > on how to proceed with these versions Here are his patches: > > drm/i915: Remove i915->ggtt > drm/i915: Use to_gt() helper for GGTT accesses > drm/i915: Use to_gt() helper > drm/i915/gvt: Use to_gt() helper > drm/i915/gem: Use to_gt() helper > drm/i915/gt: Use to_gt() helper > drm/i915/display: Use to_gt() helper > drm/i915: Introduce to_gt() helper I understand... will follow this approach. > This first patch also removed the `struct intel_gt *gt = to_gt(pool)`, > that would otherwise be a leftover in > drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c One difference from Michal patch is that I am not using the wrapper to_gt(...) but to_root_gt(...) which was introduced by Matt. To me sounds more meaningful as it specifies that we are really looking for the root tile and not any tile. Thanks again, Andi
[PATCH v3] drm/i915/dp: Perform 30ms delay after source OUI write
While working on supporting the Intel HDR backlight interface, I noticed that there's a couple of laptops that will very rarely manage to boot up without detecting Intel HDR backlight support - even though it's supported on the system. One example of such a laptop is the Lenovo P17 1st generation. Following some investigation Ville Syrjälä did through the docs they have available to them, they discovered that there's actually supposed to be a 30ms wait after writing the source OUI before we begin setting up the rest of the backlight interface. This seems to be correct, as adding this 30ms delay seems to have completely fixed the probing issues I was previously seeing. So - let's start performing a 30ms wait after writing the OUI, which we do in a manner similar to how we keep track of PPS delays (e.g. record the timestamp of the OUI write, and then wait for however many ms are left since that timestamp right before we interact with the backlight) in order to avoid waiting any longer then we need to. As well, this also avoids us performing this delay on systems where we don't end up using the HDR backlight interface. V3: * Move last_oui_write into intel_dp V2: * Move panel delays into intel_pps Signed-off-by: Lyude Paul Reviewed-by: Jani Nikula Fixes: 4a8d79901d5b ("drm/i915/dp: Enable Intel's HDR backlight interface (only SDR for now)") Cc: Ville Syrjälä Cc: # v5.12+ --- drivers/gpu/drm/i915/display/intel_display_types.h| 3 +++ drivers/gpu/drm/i915/display/intel_dp.c | 11 +++ drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c | 5 + 4 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index ea1e8a6e10b0..b9c967837872 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1653,6 +1653,9 @@ struct intel_dp { struct intel_dp_pcon_frl frl; struct intel_psr psr; + + /* When we last wrote the OUI for eDP */ + unsigned long last_oui_write; }; enum lspcon_vendor { diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0a424bf69396..5a8206298691 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -2010,6 +2011,16 @@ intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful) if (drm_dp_dpcd_write(&intel_dp->aux, DP_SOURCE_OUI, oui, sizeof(oui)) < 0) drm_err(&i915->drm, "Failed to write source OUI\n"); + + intel_dp->last_oui_write = jiffies; +} + +void intel_dp_wait_source_oui(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + + drm_dbg_kms(&i915->drm, "Performing OUI wait\n"); + wait_remaining_ms_from_jiffies(intel_dp->last_oui_write, 30); } /* If the device supports it, try to set the power state appropriately */ diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index ce229026dc91..b64145a3869a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -119,4 +119,6 @@ void intel_dp_pcon_dsc_configure(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); void intel_dp_phy_test(struct intel_encoder *encoder); +void intel_dp_wait_source_oui(struct intel_dp *intel_dp); + #endif /* __INTEL_DP_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 8b9c925c4c16..62c112daacf2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -36,6 +36,7 @@ #include "intel_backlight.h" #include "intel_display_types.h" +#include "intel_dp.h" #include "intel_dp_aux_backlight.h" /* TODO: @@ -106,6 +107,8 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) int ret; u8 tcon_cap[4]; + intel_dp_wait_source_oui(intel_dp); + ret = drm_dp_dpcd_read(aux, INTEL_EDP_HDR_TCON_CAP0, tcon_cap, sizeof(tcon_cap)); if (ret != sizeof(tcon_cap)) return false; @@ -204,6 +207,8 @@ intel_dp_aux_hdr_enable_backlight(const struct intel_crtc_state *crtc_state, int ret; u8 old_ctrl, ctrl; + intel_dp_wait_source_oui(intel_dp); + ret = drm_dp_dpcd_readb(&intel_dp->aux, INTEL_EDP_HDR_GETSET_CTRL_PARAMS, &old_ctrl); if (ret != 1) { drm_err(&i915->drm, "Failed to read current backlight control mode: %d\n", ret); -- 2.33.1
[PATCH v10 5/8] MIPS: DTS: jz4780: Account for Synopsys HDMI driver and LCD controllers
From: Paul Boddie A specialisation of the generic Synopsys HDMI driver is employed for JZ4780 HDMI support. This requires a new driver, plus device tree and configuration modifications. Here we add jz4780 device tree setup. Signed-off-by: Paul Boddie Signed-off-by: H. Nikolaus Schaller --- arch/mips/boot/dts/ingenic/jz4780.dtsi | 40 ++ 1 file changed, 40 insertions(+) diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi index b0a4e2e019c36..3f9ea47a10cd2 100644 --- a/arch/mips/boot/dts/ingenic/jz4780.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi @@ -444,6 +444,46 @@ i2c4: i2c@10054000 { status = "disabled"; }; + hdmi: hdmi@1018 { + compatible = "ingenic,jz4780-dw-hdmi"; + reg = <0x1018 0x8000>; + reg-io-width = <4>; + + clocks = <&cgu JZ4780_CLK_AHB0>, <&cgu JZ4780_CLK_HDMI>; + clock-names = "iahb", "isfr"; + + interrupt-parent = <&intc>; + interrupts = <3>; + + status = "disabled"; + }; + + lcdc0: lcdc0@1305 { + compatible = "ingenic,jz4780-lcd"; + reg = <0x1305 0x1800>; + + clocks = <&cgu JZ4780_CLK_TVE>, <&cgu JZ4780_CLK_LCD0PIXCLK>; + clock-names = "lcd", "lcd_pclk"; + + interrupt-parent = <&intc>; + interrupts = <31>; + + status = "disabled"; + }; + + lcdc1: lcdc1@130a { + compatible = "ingenic,jz4780-lcd"; + reg = <0x130a 0x1800>; + + clocks = <&cgu JZ4780_CLK_TVE>, <&cgu JZ4780_CLK_LCD1PIXCLK>; + clock-names = "lcd", "lcd_pclk"; + + interrupt-parent = <&intc>; + interrupts = <23>; + + status = "disabled"; + }; + nemc: nemc@1341 { compatible = "ingenic,jz4780-nemc", "simple-mfd"; reg = <0x1341 0x1>; -- 2.33.0
[PATCH v10 8/8] [RFC] MIPS: DTS: Ingenic: adjust register size to available registers
After getting the regmap size from the device tree we should reduce the ranges to the really available registers. This allows to read only existing registers from the debug fs and makes the regmap check out-of-bounds access. For the jz4780 we have done this already. Suggested-for: Paul Cercueil Signed-off-by: H. Nikolaus Schaller --- arch/mips/boot/dts/ingenic/jz4725b.dtsi | 2 +- arch/mips/boot/dts/ingenic/jz4740.dtsi | 2 +- arch/mips/boot/dts/ingenic/jz4770.dtsi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/boot/dts/ingenic/jz4725b.dtsi b/arch/mips/boot/dts/ingenic/jz4725b.dtsi index 0c6a5a4266f43..e9e48022f6316 100644 --- a/arch/mips/boot/dts/ingenic/jz4725b.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4725b.dtsi @@ -321,7 +321,7 @@ udc: usb@1304 { lcd: lcd-controller@1305 { compatible = "ingenic,jz4725b-lcd"; - reg = <0x1305 0x1000>; + reg = <0x1305 0x130>; /* tbc */ interrupt-parent = <&intc>; interrupts = <31>; diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi index 772542e1f266a..7f76cba03a089 100644 --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi @@ -323,7 +323,7 @@ udc: usb@1304 { lcd: lcd-controller@1305 { compatible = "ingenic,jz4740-lcd"; - reg = <0x1305 0x1000>; + reg = <0x1305 0x60>; /* LCDCMD1+4 */ interrupt-parent = <&intc>; interrupts = <30>; diff --git a/arch/mips/boot/dts/ingenic/jz4770.dtsi b/arch/mips/boot/dts/ingenic/jz4770.dtsi index dfe74328ae5dc..bda0a3a86ed5f 100644 --- a/arch/mips/boot/dts/ingenic/jz4770.dtsi +++ b/arch/mips/boot/dts/ingenic/jz4770.dtsi @@ -399,7 +399,7 @@ gpu: gpu@1304 { lcd: lcd-controller@1305 { compatible = "ingenic,jz4770-lcd"; - reg = <0x1305 0x300>; + reg = <0x1305 0x130>; /* tbc */ interrupt-parent = <&intc>; interrupts = <31>; -- 2.33.0
[PATCH v10 3/8] dt-bindings: display: Add ingenic, jz4780-dw-hdmi DT Schema
From: Sam Ravnborg Add DT bindings for the hdmi driver for the Ingenic JZ4780 SoC. Based on .txt binding from Zubair Lutfullah Kakakhel We also add generic ddc-i2c-bus to synopsys,dw-hdmi.yaml Signed-off-by: Sam Ravnborg Signed-off-by: H. Nikolaus Schaller Cc: Rob Herring Cc: devicet...@vger.kernel.org --- .../display/bridge/ingenic,jz4780-hdmi.yaml | 76 +++ .../display/bridge/synopsys,dw-hdmi.yaml | 3 + 2 files changed, 79 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml new file mode 100644 index 0..5f372bdea0f0d --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ingenic,jz4780-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bindings for Ingenic JZ4780 HDMI Transmitter + +maintainers: + - H. Nikolaus Schaller + +description: | + The HDMI Transmitter in the Ingenic JZ4780 is a Synopsys DesignWare HDMI 1.4 + TX controller IP with accompanying PHY IP. + +allOf: + - $ref: synopsys,dw-hdmi.yaml# + +properties: + compatible: +const: ingenic,jz4780-dw-hdmi + + reg-io-width: +const: 4 + + clocks: +maxItems: 2 + + hdmi-5v-supply: +description: Optional regulator to provide +5V at the connector + + ports: +$ref: /schemas/graph.yaml#/properties/ports + +required: + - compatible + - clocks + - clock-names + - ports + - reg-io-width + +unevaluatedProperties: false + +examples: + - | +#include + +hdmi: hdmi@1018 { +compatible = "ingenic,jz4780-dw-hdmi"; +reg = <0x1018 0x8000>; +reg-io-width = <4>; +ddc-i2c-bus = <&i2c4>; +interrupt-parent = <&intc>; +interrupts = <3>; +clocks = <&cgu JZ4780_CLK_AHB0>, <&cgu JZ4780_CLK_HDMI>; +clock-names = "iahb", "isfr"; + +ports { +#address-cells = <1>; +#size-cells = <0>; +hdmi_in: port@0 { +reg = <0>; +dw_hdmi_in: endpoint { +remote-endpoint = <&jz4780_lcd_out>; +}; +}; +hdmi_out: port@1 { +reg = <1>; +dw_hdmi_out: endpoint { +remote-endpoint = <&hdmi_con>; +}; +}; +}; +}; + +... diff --git a/Documentation/devicetree/bindings/display/bridge/synopsys,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/bridge/synopsys,dw-hdmi.yaml index 9be44a682e67a..9cbeabaee0968 100644 --- a/Documentation/devicetree/bindings/display/bridge/synopsys,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/bridge/synopsys,dw-hdmi.yaml @@ -50,6 +50,9 @@ properties: interrupts: maxItems: 1 + ddc-i2c-bus: +description: An I2C interface if the internal DDC I2C driver is not to be used + additionalProperties: true ... -- 2.33.0
[PATCH v10 2/8] drm/ingenic: Add support for JZ4780 and HDMI output
From: Paul Boddie Add support for the LCD controller present on JZ4780 SoCs. This SoC uses 8-byte descriptors which extend the current 4-byte descriptors used for other Ingenic SoCs. Tested on MIPS Creator CI20 board. Signed-off-by: Paul Boddie Signed-off-by: Ezequiel Garcia Signed-off-by: H. Nikolaus Schaller --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 53 +++ drivers/gpu/drm/ingenic/ingenic-drm.h | 38 2 files changed, 91 insertions(+) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 0bb590c3910d9..34089bc6e0fcd 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -6,6 +6,7 @@ #include "ingenic-drm.h" +#include #include #include #include @@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc { u32 addr; u32 id; u32 cmd; + /* extended hw descriptor for jz4780 */ + u32 offsize; + u32 pagewidth; + u32 cpos; + u32 dessize; } __aligned(16); struct ingenic_dma_hwdescs { @@ -60,6 +66,7 @@ struct jz_soc_info { bool needs_dev_clk; bool has_osd; bool map_noncoherent; + bool use_extended_hwdesc; unsigned int max_width, max_height; const u32 *formats_f0, *formats_f1; unsigned int num_formats_f0, num_formats_f1; @@ -446,6 +453,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; + if (plane == &priv->f0) + return -EINVAL; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) @@ -662,6 +672,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); hwdesc->next = dma_hwdesc_addr(priv, next_id); + if (priv->soc_info->use_extended_hwdesc) { + hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; + + /* Extended 8-byte descriptor */ + hwdesc->cpos = 0; + hwdesc->offsize = 0; + hwdesc->pagewidth = 0; + + switch (newstate->fb->format->format) { + case DRM_FORMAT_XRGB1555: + hwdesc->cpos |= JZ_LCD_CPOS_RGB555; + fallthrough; + case DRM_FORMAT_RGB565: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; + break; + case DRM_FORMAT_XRGB: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; + break; + } + hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << +JZ_LCD_CPOS_COEFFICIENT_OFFSET); + hwdesc->dessize = + (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) | + FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | + FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); + } + if (drm_atomic_crtc_needs_modeset(crtc_state)) { fourcc = newstate->fb->format->format; @@ -693,6 +730,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; } + if (priv->soc_info->use_extended_hwdesc) + cfg |= JZ_LCD_CFG_DESCRIPTOR_8; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; if (mode->flags & DRM_MODE_FLAG_NVSYNC) @@ -1468,10 +1508,23 @@ static const struct jz_soc_info jz4770_soc_info = { .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), }; +static const struct jz_soc_info jz4780_soc_info = { + .needs_dev_clk = true, + .has_osd = true, + .use_extended_hwdesc = true, + .max_width = 4096, + .max_height = 2048, + .formats_f1 = jz4770_formats_f1, + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), + .formats_f0 = jz4770_formats_f0, + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), +}; + static const struct of_device_id ingenic_drm_of_match[] = { { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, + { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.h b/drivers/gpu/drm/ingenic/ingenic-drm.h index 22654ac1dde1c..cb1d09b625881 100644
[PATCH v10 7/8] MIPS: defconfig: CI20: configure for DRM_DW_HDMI_JZ4780
Enable CONFIG options as modules. Signed-off-by: Ezequiel Garcia Signed-off-by: H. Nikolaus Schaller --- arch/mips/configs/ci20_defconfig | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig index ab7ebb0668340..cc69b215854ea 100644 --- a/arch/mips/configs/ci20_defconfig +++ b/arch/mips/configs/ci20_defconfig @@ -98,7 +98,13 @@ CONFIG_RC_DEVICES=y CONFIG_IR_GPIO_CIR=m CONFIG_IR_GPIO_TX=m CONFIG_MEDIA_SUPPORT=m +CONFIG_DRM=m +CONFIG_DRM_INGENIC=m +CONFIG_DRM_INGENIC_DW_HDMI=m +CONFIG_DRM_DISPLAY_CONNECTOR=m # CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y +CONFIG_FRAMEBUFFER_CONSOLE=y # CONFIG_HID is not set CONFIG_USB=y CONFIG_USB_STORAGE=y -- 2.33.0
[PATCH v10 6/8] MIPS: DTS: CI20: Add DT nodes for HDMI setup
From: Paul Boddie We need to hook up * HDMI connector * HDMI power regulator * JZ4780_CLK_HDMI @ 27 MHz * DDC pinmux * HDMI and LCDC endpoint connections Signed-off-by: Paul Boddie Signed-off-by: H. Nikolaus Schaller --- arch/mips/boot/dts/ingenic/ci20.dts | 72 - 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts index b249a4f0f6b62..3e336b3dbb109 100644 --- a/arch/mips/boot/dts/ingenic/ci20.dts +++ b/arch/mips/boot/dts/ingenic/ci20.dts @@ -78,6 +78,18 @@ eth0_power: fixedregulator@0 { enable-active-high; }; + hdmi_out: connector { + compatible = "hdmi-connector"; + label = "HDMI OUT"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&dw_hdmi_out>; + }; + }; + }; + ir: ir { compatible = "gpio-ir-receiver"; gpios = <&gpe 3 GPIO_ACTIVE_LOW>; @@ -102,6 +114,17 @@ otg_power: fixedregulator@2 { gpio = <&gpf 14 GPIO_ACTIVE_LOW>; enable-active-high; }; + + hdmi_power: fixedregulator@3 { + compatible = "regulator-fixed"; + + regulator-name = "hdmi_power"; + regulator-min-microvolt = <500>; + regulator-max-microvolt = <500>; + + gpio = <&gpa 25 0>; + enable-active-high; + }; }; &ext { @@ -114,11 +137,12 @@ &cgu { * precision. */ assigned-clocks = <&cgu JZ4780_CLK_OTGPHY>, <&cgu JZ4780_CLK_RTC>, - <&cgu JZ4780_CLK_SSIPLL>, <&cgu JZ4780_CLK_SSI>; + <&cgu JZ4780_CLK_SSIPLL>, <&cgu JZ4780_CLK_SSI>, + <&cgu JZ4780_CLK_HDMI>; assigned-clock-parents = <0>, <&cgu JZ4780_CLK_RTCLK>, <&cgu JZ4780_CLK_MPLL>, <&cgu JZ4780_CLK_SSIPLL>; - assigned-clock-rates = <4800>, <0>, <5400>; + assigned-clock-rates = <4800>, <0>, <5400>, <0>, <2700>; }; &tcu { @@ -509,6 +533,12 @@ pins_i2c4: i2c4 { bias-disable; }; + pins_hdmi_ddc: hdmi_ddc { + function = "hdmi-ddc"; + groups = "hdmi-ddc"; + bias-disable; + }; + pins_nemc: nemc { function = "nemc"; groups = "nemc-data", "nemc-cle-ale", "nemc-rd-we", "nemc-frd-fwe"; @@ -539,3 +569,41 @@ pins_mmc1: mmc1 { bias-disable; }; }; + +&hdmi { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pins_hdmi_ddc>; + + hdmi-5v-supply = <&hdmi_power>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dw_hdmi_in: endpoint { + remote-endpoint = <&lcd_out>; + }; + }; + + port@1 { + reg = <1>; + dw_hdmi_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; +}; + +&lcdc0 { + status = "okay"; + + port { + lcd_out: endpoint { + remote-endpoint = <&dw_hdmi_in>; + }; + }; +}; -- 2.33.0
[PATCH v10 4/8] drm/ingenic: Add dw-hdmi driver for jz4780
From: Paul Boddie A specialisation of the generic Synopsys HDMI driver is employed for JZ4780 HDMI support. This requires a new driver, plus device tree and configuration modifications. Here we add Kconfig DRM_INGENIC_DW_HDMI, Makefile and driver code. Signed-off-by: Paul Boddie Signed-off-by: Ezequiel Garcia Signed-off-by: H. Nikolaus Schaller --- drivers/gpu/drm/ingenic/Kconfig | 9 ++ drivers/gpu/drm/ingenic/Makefile | 1 + drivers/gpu/drm/ingenic/ingenic-dw-hdmi.c | 138 ++ 3 files changed, 148 insertions(+) create mode 100644 drivers/gpu/drm/ingenic/ingenic-dw-hdmi.c diff --git a/drivers/gpu/drm/ingenic/Kconfig b/drivers/gpu/drm/ingenic/Kconfig index 3b57f8be007c4..4efc709d77b0a 100644 --- a/drivers/gpu/drm/ingenic/Kconfig +++ b/drivers/gpu/drm/ingenic/Kconfig @@ -25,4 +25,13 @@ config DRM_INGENIC_IPU The Image Processing Unit (IPU) will appear as a second primary plane. +config DRM_INGENIC_DW_HDMI + tristate "Ingenic specific support for Synopsys DW HDMI" + depends on MACH_JZ4780 + select DRM_DW_HDMI + help + Choose this option to enable Synopsys DesignWare HDMI based driver. + If you want to enable HDMI on Ingenic JZ4780 based SoC, you should + select this option.. + endif diff --git a/drivers/gpu/drm/ingenic/Makefile b/drivers/gpu/drm/ingenic/Makefile index d313326bdddbb..f10cc1c5a5f22 100644 --- a/drivers/gpu/drm/ingenic/Makefile +++ b/drivers/gpu/drm/ingenic/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_DRM_INGENIC) += ingenic-drm.o ingenic-drm-y = ingenic-drm-drv.o ingenic-drm-$(CONFIG_DRM_INGENIC_IPU) += ingenic-ipu.o +obj-$(CONFIG_DRM_INGENIC_DW_HDMI) += ingenic-dw-hdmi.o diff --git a/drivers/gpu/drm/ingenic/ingenic-dw-hdmi.c b/drivers/gpu/drm/ingenic/ingenic-dw-hdmi.c new file mode 100644 index 0..199e39c227d29 --- /dev/null +++ b/drivers/gpu/drm/ingenic/ingenic-dw-hdmi.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * Copyright (C) 2019, 2020 Paul Boddie + * + * Derived from dw_hdmi-imx.c with i.MX portions removed. + * Probe and remove operations derived from rcar_dw_hdmi.c. + */ + +#include +#include +#include + +#include +#include +#include + +static const struct dw_hdmi_mpll_config ingenic_mpll_cfg[] = { + { 4525, { { 0x01e0, 0x }, { 0x21e1, 0x }, { 0x41e2, 0x } } }, + { 9250, { { 0x0140, 0x0005 }, { 0x2141, 0x0005 }, { 0x4142, 0x0005 } } }, + { 14850, { { 0x00a0, 0x000a }, { 0x20a1, 0x000a }, { 0x40a2, 0x000a } } }, + { 21600, { { 0x00a0, 0x000a }, { 0x2001, 0x000f }, { 0x4002, 0x000f } } }, + { ~0UL, { { 0x, 0x }, { 0x, 0x }, { 0x, 0x } } } +}; + +static const struct dw_hdmi_curr_ctrl ingenic_cur_ctr[] = { + /*pixelclk bpp8bpp10 bpp12 */ + { 5400, { 0x091c, 0x091c, 0x06dc } }, + { 5840, { 0x091c, 0x06dc, 0x06dc } }, + { 7200, { 0x06dc, 0x06dc, 0x091c } }, + { 7425, { 0x06dc, 0x0b5c, 0x091c } }, + { 11880, { 0x091c, 0x091c, 0x06dc } }, + { 21600, { 0x06dc, 0x0b5c, 0x091c } }, + { ~0UL, { 0x, 0x, 0x } }, +}; + +/* + * Resistance term 133Ohm Cfg + * PREEMP config 0.00 + * TX/CK level 10 + */ +static const struct dw_hdmi_phy_config ingenic_phy_config[] = { + /*pixelclk symbol term vlev */ + { 21600, 0x800d, 0x0005, 0x01ad}, + { ~0UL, 0x, 0x, 0x} +}; + +static enum drm_mode_status +ingenic_dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + /* FIXME: Hardware is capable of 270MHz, but setup data is missing. */ + if (mode->clock > 216000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static struct dw_hdmi_plat_data ingenic_dw_hdmi_plat_data = { + .mpll_cfg = ingenic_mpll_cfg, + .cur_ctr= ingenic_cur_ctr, + .phy_config = ingenic_phy_config, + .mode_valid = ingenic_dw_hdmi_mode_valid, + .output_port= 1, +}; + +static const struct of_device_id ingenic_dw_hdmi_dt_ids[] = { + { .compatible = "ingenic,jz4780-dw-hdmi" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ingenic_dw_hdmi_dt_ids); + +static void ingenic_dw_hdmi_cleanup(void *data) +{ + struct dw_hdmi *hdmi = (struct dw_hdmi *)data; + + dw_hdmi_remove(hdmi); +} + +static void ingenic_dw_hdmi_disable_regulator(void *data) +{ + struct regulator *regulator = (struct regulator *)data; + + regulator_disable(regulator); +} + +static int ingenic_dw_hdmi_probe(struct platform_device *pdev) +{ + struct dw_hdmi *hdmi; + struct regulator *regulator; + int ret; + + hdmi = dw_
[PATCH v10 0/8] MIPS: JZ4780 and CI20 HDMI
PATCH V10 2021-11-30 22:26:41: - patch 3/8: fix $id and $ref paths (found by r...@kernel.org) PATCH V9 2021-11-24 22:29:14: - patch 6/8: remove optional <0> for assigned-clocks and unintentionally included "unwedge" setup (found by p...@crapouillou.net) - patch 4/8: some cosmetics make regulator enable/disable only if not NULL (found by p...@crapouillou.net) simplify/fix error handling and driver cleanup on remove (proposed by p...@crapouillou.net) - patch 3/8: fix #include path in example (found by p...@crapouillou.net) fix missing "i" in unevaluatedProperties (found by r...@kernel.org) fix 4 spaces indentation for required: property (found by r...@kernel.org) PATCH V8 2021-11-23 19:14:00: - fix a bad editing result from patch 2/8 (found by p...@crapouillou.net) PATCH V7 2021-11-23 18:46:23: - changed gpio polarity of hdmi_power to 0 (suggested by p...@crapouillou.net) - fixed LCD1 irq number (bug found by p...@crapouillou.net) - removed "- 4" for calculating max_register (suggested by p...@crapouillou.net) - use unevaluatedPropertes instead of additionalProperties (suggested by r...@kernel.org) - moved and renamed ingenic,jz4780-hdmi.yaml (suggested by r...@kernel.org) - adjusted assigned-clocks changes to upstream which added some for SSI (by h...@goldelico.com) - rebased and tested with v5.16-rc2 + patch set drm/ingenic by p...@crapouillou.net (by h...@goldelico.com) PATCH V6 2021-11-10 20:43:33: - changed CONFIG_DRM_INGENIC_DW_HDMI to "m" (by h...@goldelico.com) - made ingenic-dw-hdmi an independent platform driver which can be compiled as module and removed error patch fixes for IPU (suggested by p...@crapouillou.net) - moved assigned-clocks from jz4780.dtsi to ci20.dts (suggested by p...@crapouillou.net) - fixed reg property in jz4780.dtsi to cover all registers incl. gamma and vee (by h...@goldelico.com) - added a base patch to calculate regmap size from DTS reg property (requested by p...@crapouillou.net) - restored resetting all bits except one in LCDOSDC (requested by p...@crapouillou.net) - clarified setting of cpos (suggested by p...@crapouillou.net) - moved bindings definition for ddc-i2c-bus (suggested by p...@crapouillou.net) - simplified mask definitions for JZ_LCD_DESSIZE (requested by p...@crapouillou.net) - removed setting alpha premultiplication (suggested by p...@crapouillou.net) - removed some comments (suggested by p...@crapouillou.net) PATCH V5 2021-10-05 14:28:44: - dropped mode_fixup and timings support in dw-hdmi as it is no longer needed in this V5 (by h...@goldelico.com) - dropped "drm/ingenic: add some jz4780 specific features" (stimulated by p...@crapouillou.net) - fixed typo in commit subject: "synopsis" -> "synopsys" (by h...@goldelico.com) - swapped clocks in jz4780.dtsi to match synopsys,dw-hdmi.yaml (by h...@goldelico.com) - improved, simplified, fixed, dtbschecked ingenic-jz4780-hdmi.yaml and made dependent of bridge/synopsys,dw-hdmi.yaml (based on suggestions by max...@cerno.tech) - fixed binding vs. driver&DTS use of hdmi-5v regulator (suggested by max...@cerno.tech) - dropped "drm/bridge: synopsis: Fix to properly handle HPD" - was a no longer needed workaround for a previous version (suggested by max...@cerno.tech) PATCH V4 2021-09-27 18:44:38: - fix setting output_port = 1 (issue found by p...@crapouillou.net) - ci20.dts: convert to use hdmi-connector (by h...@goldelico.com) - add a hdmi-regulator to control +5V power (by h...@goldelico.com) - added a fix to dw-hdmi to call drm_kms_helper_hotplug_event on plugin event detection (by h...@goldelico.com) - always allocate extended descriptor but initialize only for jz4780 (by h...@goldelico.com) - updated to work on top of "[PATCH v3 0/6] drm/ingenic: Various improvements v3" (by p...@crapouillou.net) - rebased to v5.13-rc3 PATCH V3 2021-08-08 07:10:50: This series adds HDMI support for JZ4780 and CI20 board (and fixes one IPU related issue in registration error path) - [patch 1/8] switched from mode_fixup to atomic_check (suggested by robert.f...@linaro.org) - the call to the dw-hdmi specialization is still called mode_fixup - [patch 3/8] diverse fixes for ingenic-drm-drv (suggested by p...@crapouillou.net) - factor out some non-HDMI features of the jz4780 into a separate patch - multiple fixes around max height - do not change regmap config but a copy on stack - define some constants - factor out fixing of drm_init error path for IPU into separate patch - use FIELD_PREP() - [patch 8/8] conversion to component framework dropped (suggested by laurent.pinch...@ideasonboard.com and p...@crapouillou.net) PATCH V2 2021-08-05 16:08:05: - code and commit messages revisited for checkpatch warnings - rebased on v5.14-rc4 - include (failed, hence RFC 8/8) attempt to convert to component framework (was suggested by Paul Cercueil a while ago) This series adds HDMI support for JZ4780 and CI20 board H. Nikolaus Schaller
[PATCH v10 1/8] drm/ingenic: prepare ingenic drm for later addition of JZ4780
This changes the way the regmap is allocated to prepare for the later addition of the JZ4780 which has more registers and bits than the others. Therefore we make the regmap as big as the reg property in the device tree tells. Suggested-by: Paul Cercueil Signed-off-by: H. Nikolaus Schaller --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 462bc0f35f1bf..0bb590c3910d9 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -173,7 +173,6 @@ static const struct regmap_config ingenic_drm_regmap_config = { .val_bits = 32, .reg_stride = 4, - .max_register = JZ_REG_LCD_SIZE1, .writeable_reg = ingenic_drm_writeable_reg, }; @@ -1011,6 +1010,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) struct ingenic_drm_bridge *ib; struct drm_device *drm; void __iomem *base; + struct resource *res; + struct regmap_config regmap_config; long parent_rate; unsigned int i, clone_mask = 0; int ret, irq; @@ -1056,14 +1057,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; - base = devm_platform_ioremap_resource(pdev, 0); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) { dev_err(dev, "Failed to get memory resource\n"); return PTR_ERR(base); } + regmap_config = ingenic_drm_regmap_config; + regmap_config.max_register = res->end - res->start; priv->map = devm_regmap_init_mmio(dev, base, - &ingenic_drm_regmap_config); + ®map_config); if (IS_ERR(priv->map)) { dev_err(dev, "Failed to create regmap\n"); return PTR_ERR(priv->map); -- 2.33.0
Re: [PATCH v4 2/2] drm/i915: Use to_root_gt() to refer to the root tile
On Sun, Nov 28, 2021 at 01:09:26PM +0200, Andi Shyti wrote: Starting from a patch from Matt to_root_gt() returns the reference to the root tile in order to abstract the root tile from th callers. Being the root tile identified as tile '0', embed the id in the name so that i915->gt becomes i915->gt0. The renaming has been mostly done with the following command and some manual fixes. sed -i -e sed -i 's/\&i915\->gt\./\&to_root_gt(i915)\->/g' \ -e sed -i 's/\&dev_priv\->gt\./\&to_root_gt(dev_priv)\->/g' \ -e 's/\&dev_priv\->gt/to_root_gt(dev_priv)/g' \ -e 's/\&i915\->gt/to_root_gt(i915)/g' \ -e 's/dev_priv\->gt\./to_root_gt(dev_priv)\->/g' \ -e 's/i915\->gt\./to_root_gt(i915)\->/g' \ `find drivers/gpu/drm/i915/ -name *.[ch]` Two small changes have been added to this commit: 1. intel_reset_gpu() in intel_display.c retreives the gt from to_scanout_gt() 2. in set_scheduler_caps() the gt is taken from the engine and not from i915. Ideally the non-automatic changes should be in separate patches, before the ones that can be done by automation. Because then it becomes easier to apply the final result without conflicts. This is quite a big diff to merge in one go. Looking at the pending patches from Michal however I see he had similar changes, split in sensible chunks.. Could you split your version like that? at least gt/gem and display would be good to have separate. Or sync with Michal on how to proceed with these versions Here are his patches: drm/i915: Remove i915->ggtt drm/i915: Use to_gt() helper for GGTT accesses drm/i915: Use to_gt() helper drm/i915/gvt: Use to_gt() helper drm/i915/gem: Use to_gt() helper drm/i915/gt: Use to_gt() helper drm/i915/display: Use to_gt() helper drm/i915: Introduce to_gt() helper This first patch also removed the `struct intel_gt *gt = to_gt(pool)`, that would otherwise be a leftover in drivers/gpu/drm/i915/gt/intel_gt_buffer_pool.c thanks Lucas De Marchi
Re: [PATCH 1/6] Documentation/gpu: Reorganize DC documentation
> On 2021-11-30 10:48 a.m., Harry Wentland wrote: > > On 2021-11-30 10:46, Rodrigo Siqueira Jordao wrote: > >> > >> > >> On 2021-11-29 7:06 a.m., Jani Nikula wrote: > >>> On Fri, 26 Nov 2021, Daniel Vetter wrote: > On Thu, Nov 25, 2021 at 10:38:25AM -0500, Rodrigo Siqueira > wrote: > > Display core documentation is not well organized, and it is > > hard to find > > information due to the lack of sections. This commit > > reorganizes the > > documentation layout, and it is preparation work for future > > changes. > > > > Signed-off-by: Rodrigo Siqueira > > --- > > Documentation/gpu/amdgpu-dc.rst | 74 > > --- > > .../gpu/amdgpu-dc/amdgpu-dc-debug.rst | 4 + > > Documentation/gpu/amdgpu-dc/amdgpu-dc.rst | 29 > > Documentation/gpu/amdgpu-dc/amdgpu-dm.rst | 42 > > +++ > > Documentation/gpu/drivers.rst | 2 +- > > 5 files changed, 76 insertions(+), 75 deletions(-) > > delete mode 100644 Documentation/gpu/amdgpu-dc.rst > > create mode 100644 > > Documentation/gpu/amdgpu-dc/amdgpu-dc-debug.rst > > create mode 100644 Documentation/gpu/amdgpu-dc/amdgpu-dc.rst > > create mode 100644 Documentation/gpu/amdgpu-dc/amdgpu-dm.rst > > > > diff --git a/Documentation/gpu/amdgpu-dc.rst > > b/Documentation/gpu/amdgpu-dc.rst > > deleted file mode 100644 > > index f7ff7e1309de.. > > --- a/Documentation/gpu/amdgpu-dc.rst > > +++ /dev/null > > @@ -1,74 +0,0 @@ > > -=== > > -drm/amd/display - Display Core (DC) > > -=== > > - > > -*placeholder - general description of supported platforms, > > what dc is, etc.* > > - > > -Because it is partially shared with other operating systems, > > the Display Core > > -Driver is divided in two pieces. > > - > > -1. **Display Core (DC)** contains the OS-agnostic components. > > Things like > > - hardware programming and resource management are handled > > here. > > -2. **Display Manager (DM)** contains the OS-dependent > > components. Hooks to the > > - amdgpu base driver and DRM are implemented here. > > - > > -It doesn't help that the entire package is frequently referred > > to as DC. But > > -with the context in mind, it should be clear. > > - > > -When CONFIG_DRM_AMD_DC is enabled, DC will be initialized by > > default for > > -supported ASICs. To force disable, set `amdgpu.dc=0` on kernel > > command line. > > -Likewise, to force enable on unsupported ASICs, set > > `amdgpu.dc=1`. > > - > > -To determine if DC is loaded, search dmesg for the following > > entry: > > - > > -``Display Core initialized with `` > > - > > -AMDgpu Display Manager > > -== > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :doc: overview > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h > > - :internal: > > - > > -Lifecycle > > -- > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :doc: DM Lifecycle > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :functions: dm_hw_init dm_hw_fini > > - > > -Interrupts > > --- > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c > > - :doc: overview > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c > > - :internal: > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :functions: register_hpd_handlers dm_crtc_high_irq > > dm_pflip_high_irq > > - > > -Atomic Implementation > > -- > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :doc: atomic > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :functions: amdgpu_dm_atomic_check > > amdgpu_dm_atomic_commit_tail > > - > > -Display Core > > - > > - > > -**WIP** > > - > > -FreeSync Video > > --- > > - > > -.. kernel-doc:: > > drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c > > - :doc: FreeSync Video > > diff --git a/Documentation/gpu/amdgpu-dc/amdgpu-dc-debug.rst > > b/Documentation/gpu/amdgpu-dc/amdgpu-dc-debug.rst > > new file mode 100644 > > index ..bbb8c3fc8eee > > --- /dev/null > > +++ b/Documentation/gpu/amdgpu-dc/amdgpu-dc-debug.rst > > @@ -0,0 +1,4 @@ > > +Display Core Debug tools
Re: [PATCH v2 1/2] drm/input_helper: Add new input-handling helper
Hi Pekka, On Fri, Nov 19, 2021 at 12:38:41PM +0200, Pekka Paalanen wrote: > On Thu, 18 Nov 2021 17:46:10 -0800 > Brian Norris wrote: > > On Thu, Nov 18, 2021 at 12:39:28PM +0200, Pekka Paalanen wrote: > > > On Wed, 17 Nov 2021 14:48:40 -0800 > > > Brian Norris wrote: > > > If KMS gets a pageflip or modeset in no time after an input event, then > > > what's the gain. OTOH, if the display server is locking on to vblank, > > > there might be a delay worth avoiding. But then, is it worth > > > short-circuiting the wake-up in kernel vs. adding a new ioctl that > > > userspace could hit to start the warming up process? > > > > Rob responded to the first part to some extent (there is definitely gain > > to be had). > > > > To the last part: I wrote a simple debugfs hook to allow user space to > > force a PSR exit, and then a simple user space program to read input > > events and smash that debugfs file whenever it sees one. Testing in the > > same scenarios, this appears to lose less than 100 microseconds versus > > the in-kernel approach, which is negligible for this use case. (I'm not > > sure about the other use cases.) > > > > So, this is technically doable in user space. > > This is crucial information I would like you to include in some commit > message. I think it is very interesting for the reviewers. Maybe also > copy that in the cover letter. > > In my opinion there is a clear and obvious decision due that > measurement: Add the new ioctl for userspace to hit, do not try to > hardcode or upload the wake-up policy into the kernel. Perhaps. I'll admit, I'm not eager to go write the fd-passing solutions that others are designing on the fly. I'm currently torn on whether I'll just live with this current patch set out-of-tree (or, y'all can decide that a simple, 99% working solution is better than no solution), because it's simple; or possibly figuring out how to utilize such an ioctl cleanly within our display manager. I'm not super hopeful on the latter. IOW, I'm approximately in line with Doug's thoughts: https://lore.kernel.org/all/CAD=FV=XARhZoj+0p-doxcbC=4K+NuMc=ur6wqg6kwk-mkpk...@mail.gmail.com/ But then, we're obviously biased. > > I can't speak to the ease of _actually_ integrating this into even our > > own Chrome display manager, but I highly doubt it will get integrated > > into others. I'd posit this should weigh into the relative worth, but > > otherwise can't really give you an answer there. > > I think such a thing would be very simple to add to any display server. > They already have hooks for things like resetting idle timeout timers on > any relevant input event. > > > I'd also note, software-directed PSR is so far designed to be completely > > opaque to user space. There's no way to disable it; no way to know it's > > active; and no way to know anything about the parameters it's computing > > (like average entry/exit delay). Would you suggest a whole set of new > > IOCTLs for this? > > Just one ioctl on the DRM device: "Hey, wake up!". Because that's what > your patch does in-kernel, right? Well, we'd at least want something to advertise that the feature does something ("is supported") I think, otherwise we're just asking user space to do useless work. > If there are use case specific parameters, then how did you intend to > allow adjusting those in your proposal? Another commenter mentioned the latency tradeoff -- it's possible that there are panels/eDP-links that resume fast enough that one doesn't care to use this ioctl. For an in-kernel solution, one has all the data available and could use hardware information to make decisions, if needed. For a user space solution, we won't have any of that, and we'd have to work to expose that information. I suppose we could ignore that problem and only expose a minimal UAPI until we need something more, but it feels like exposing a UAPI for something is a critical point where one should make sure it's reasonably descriptive and useful. > > > How do you know userspace is using this input device at all? If > > > userspace is not using the input device, then DRM should not be opening > > > it either, as it must have no effect on anything. > > > > > > If you open an input device that userspace does not use, you also cause > > > a power consumption regression, because now the input device itself is > > > active and possibly flooding the kernel with events (e.g. an > > > accelerometer). > > > > Well, I don't think accelerometers show up as input devices, but I > > suppose your point could apply to actual input devices. > > My understanding is that accelerometers are evdev (input) devices, > especially when used as input e.g. for controlling games. I'm not aware > of any other interface for it. I'm not familiar with game-controlling accelerometers, but many types of accelerometers are serviced by drivers/iio/. And even if they register as input devices, do they match the ID list in this patch? > Even audio sockets are input
Re: linux-next: manual merge of the drm tree with the drm-misc-fixes tree
Hi Maxime, On Tue, 30 Nov 2021 09:58:31 +0100 Maxime Ripard wrote: > > Unfortunately the merge resolution isn't entirely correct :/ > > There's multiple conflicts between those two branches on that file, but > things went wrong between 16e101051f32 and 0c980a006d3f > > The first one changes the logic a bit for the clk_set_min_rate argument, > and the second moves the clk_set_min_rate around. > > However, the merge resolution reintroduced the initial clk_set_min_rate > call line (line 373), without changing the logic of the proper call site > (line 396). > > This is the patch to fix the resolution: > > -- >8 -- > --- a/drivers/gpu/drm/vc4/vc4_kms.c 2021-11-30 08:56:28.748524275 +0100 > +++ b/drivers/gpu/drm/vc4/vc4_kms.c 2021-11-29 15:46:11.692151678 +0100 > @@ -365,14 +365,6 @@ > vc4_hvs_mask_underrun(dev, vc4_crtc_state->assigned_channel); > } > > - if (vc4->hvs->hvs5) { > - unsigned long core_rate = max_t(unsigned long, > - 5, > - new_hvs_state->core_clock_rate); > - > - clk_set_min_rate(hvs->core_clk, core_rate); > - } > - > for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) { > struct drm_crtc_commit *commit; > int ret; > @@ -392,8 +384,13 @@ > old_hvs_state->fifo_state[channel].pending_commit = NULL; > } > > - if (vc4->hvs->hvs5) > - clk_set_min_rate(hvs->core_clk, 5); > + if (vc4->hvs->hvs5) { > + unsigned long core_rate = max_t(unsigned long, > + 5, > + new_hvs_state->core_clock_rate); > + > + clk_set_min_rate(hvs->core_clk, core_rate); > + } > > drm_atomic_helper_commit_modeset_disables(dev, state); > -- >8 -- Thanks, I have fixed that up in my resolution. -- Cheers, Stephen Rothwell pgpCdjHVzzrwX.pgp Description: OpenPGP digital signature
Re: [PATCH v2] drm/i915/dp: Perform 30ms delay after source OUI write
On Tue, 2021-11-30 at 12:36 +0200, Jani Nikula wrote: > On Mon, 29 Nov 2021, Lyude Paul wrote: > > While working on supporting the Intel HDR backlight interface, I noticed > > that there's a couple of laptops that will very rarely manage to boot up > > without detecting Intel HDR backlight support - even though it's supported > > on the system. One example of such a laptop is the Lenovo P17 1st > > generation. > > > > Following some investigation Ville Syrjälä did through the docs they have > > available to them, they discovered that there's actually supposed to be a > > 30ms wait after writing the source OUI before we begin setting up the rest > > of the backlight interface. > > > > This seems to be correct, as adding this 30ms delay seems to have > > completely fixed the probing issues I was previously seeing. So - let's > > start performing a 30ms wait after writing the OUI, which we do in a > > manner > > similar to how we keep track of PPS delays (e.g. record the timestamp of > > the OUI write, and then wait for however many ms are left since that > > timestamp right before we interact with the backlight) in order to avoid > > waiting any longer then we need to. As well, this also avoids us > > performing > > this delay on systems where we don't end up using the HDR backlight > > interface. > > > > V2: > > * Move panel delays into intel_pps > > > > Signed-off-by: Lyude Paul > > Fixes: 4a8d79901d5b ("drm/i915/dp: Enable Intel's HDR backlight interface > > (only SDR for now)") > > Cc: Ville Syrjälä > > Cc: # v5.12+ > > --- > > drivers/gpu/drm/i915/display/intel_display_types.h | 4 > > drivers/gpu/drm/i915/display/intel_dp.c | 11 +++ > > drivers/gpu/drm/i915/display/intel_dp.h | 2 ++ > > drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c | 5 + > > 4 files changed, 22 insertions(+) > > > > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h > > b/drivers/gpu/drm/i915/display/intel_display_types.h > > index ea1e8a6e10b0..ad64f9caa7ff 100644 > > --- a/drivers/gpu/drm/i915/display/intel_display_types.h > > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h > > @@ -1485,6 +1485,7 @@ struct intel_pps { > > bool want_panel_vdd; > > unsigned long last_power_on; > > unsigned long last_backlight_off; > > + unsigned long last_oui_write; > > ktime_t panel_power_off_time; > > intel_wakeref_t vdd_wakeref; > > > > @@ -1653,6 +1654,9 @@ struct intel_dp { > > struct intel_dp_pcon_frl frl; > > > > struct intel_psr psr; > > + > > + /* When we last wrote the OUI for eDP */ > > + unsigned long last_oui_write; > > Now you're adding last_oui_write to both intel_pps and intel_dp, forgot > to git add? ;) Yep :P, will send out a different version in a bit > > I guess I'd add this to intel_dp only, because it's not strictly about > PPS. I just wanted the mechanism to be similar to that. > > > }; > > > > enum lspcon_vendor { > > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c > > b/drivers/gpu/drm/i915/display/intel_dp.c > > index 0a424bf69396..45318891ba07 100644 > > --- a/drivers/gpu/drm/i915/display/intel_dp.c > > +++ b/drivers/gpu/drm/i915/display/intel_dp.c > > @@ -29,6 +29,7 @@ > > #include > > #include > > #include > > +#include > > #include > > > > #include > > @@ -2010,6 +2011,16 @@ intel_edp_init_source_oui(struct intel_dp > > *intel_dp, bool careful) > > > > if (drm_dp_dpcd_write(&intel_dp->aux, DP_SOURCE_OUI, oui, > > sizeof(oui)) < 0) > > drm_err(&i915->drm, "Failed to write source OUI\n"); > > + > > + intel_dp->pps.last_oui_write = jiffies; > > Set to intel_dp->last_oui_write. > > With those fixes, > > Reviewed-by: Jani Nikula > > > > +} > > + > > +void intel_dp_wait_source_oui(struct intel_dp *intel_dp) > > +{ > > + struct drm_i915_private *i915 = dp_to_i915(intel_dp); > > + > > + drm_dbg_kms(&i915->drm, "Performing OUI wait\n"); > > + wait_remaining_ms_from_jiffies(intel_dp->last_oui_write, 30); > > } > > > > /* If the device supports it, try to set the power state appropriately */ > > diff --git a/drivers/gpu/drm/i915/display/intel_dp.h > > b/drivers/gpu/drm/i915/display/intel_dp.h > > index ce229026dc91..b64145a3869a 100644 > > --- a/drivers/gpu/drm/i915/display/intel_dp.h > > +++ b/drivers/gpu/drm/i915/display/intel_dp.h > > @@ -119,4 +119,6 @@ void intel_dp_pcon_dsc_configure(struct intel_dp > > *intel_dp, > > const struct intel_crtc_state > > *crtc_state); > > void intel_dp_phy_test(struct intel_encoder *encoder); > > > > +void intel_dp_wait_source_oui(struct intel_dp *intel_dp); > > + > > #endif /* __INTEL_DP_H__ */ > > diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c > > b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c > > index 8b9c925c4c16..62c112daacf2 100644 > > --- a/drivers/gpu/drm/i915/display/in
Re: [PATCH] staging: fbtft: add spi_device_id table
On 30.11.2021 09:16, Geert Uytterhoeven wrote: > Hi Heiner, > > On Mon, Nov 29, 2021 at 10:12 PM Heiner Kallweit wrote: >> After 5fa6863ba692 ("spi: Check we have a spi_device_id for each DT >> compatible") we need the following to make the SPI core happy. >> >> Works for me with a SH1106-based OLED display. >> >> Signed-off-by: Heiner Kallweit > > Thanks for your patch! > >> --- a/drivers/staging/fbtft/fbtft.h >> +++ b/drivers/staging/fbtft/fbtft.h >> @@ -307,12 +307,19 @@ static const struct of_device_id dt_ids[] = { >> \ >>\ >> MODULE_DEVICE_TABLE(of, dt_ids); \ >>\ >> +static const struct spi_device_id spi_ids[] = {\ >> + { .name = _compatible }, \ > > Shouldn't this be the part of _compatible after the "," prefix? > You're right. I was fooled by a new bug in SPI core that made the warning suddenly disappear: https://patchwork.kernel.org/project/spi-devel-general/patch/44b2ad71-dc4b-801c-237f-9c233f675...@gmail.com/ >> + {},\ >> +}; \ >> + \ >> +MODULE_DEVICE_TABLE(spi, spi_ids);\ >>\ >> static struct spi_driver fbtft_driver_spi_driver = { \ >> .driver = {\ >> .name = _name, \ >> .of_match_table = dt_ids, \ >> }, \ >> + .id_table = spi_ids, \ >> .probe = fbtft_driver_probe_spi, \ >> .remove = fbtft_driver_remove_spi, \ >> }; \ > > Gr{oetje,eeting}s, > > Geert > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- > ge...@linux-m68k.org > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like > that. > -- Linus Torvalds >
Re: [PATCH 6/6] Documentation/gpu: Add DC glossary
- Mail original - > De: "Rodrigo Siqueira Jordao" > À: ydir...@free.fr, "Rodrigo Siqueira" , "Christian > König" , > "Alex Deucher" > Cc: "Harry Wentland" , "Linux Doc Mailing List" > , "Mark Yacoub" > , "Michel Dänzer" , "Bas > Nieuwenhuizen" , > "Roman Li" , "amd-gfx list" > , "Roman Gilg" , > "Marek Olšák" , "Pekka Paalanen" , > "Aurabindo Pillai" > , "nicholas choi" , "Maling > list - DRI developers" > , "Simon Ser" , "Alex > Deucher" , "Sean > Paul" , "Qingqing Zhuo" , > "Bhawanpreet Lakha" > , "Nicholas Kazlauskas" > > Envoyé: Mardi 30 Novembre 2021 16:53:55 > Objet: Re: [PATCH 6/6] Documentation/gpu: Add DC glossary > > > > On 2021-11-29 3:48 p.m., ydir...@free.fr wrote: > > Hi Rodrigo, > > > > That will really be helpful! > > > > I know drawing the line is a difficult problem (and can even make > > things > > harder when searching), but maybe it would make sense to keep > > generic > > acronyms not specific to amdgpu in a separate list. I bet a number > > of > > them would be useful in the scope of other drm drivers (e.g. CRTC, > > DCC, > > MST), and some are not restricted to the drm subsystem at all (e.g. > > FEC, > > LUT), but still have value as not necessarily easy to look up. > > > > Maybe "DC glossary" should just be "Glossary", since quite some > > entries > > help to read adm/amdgpu/ too. Which brings me to the result of my > > recent > > searches as suggested entries: > > > > KIQ (Kernel Interface Queue), MQD (memory queue descriptor), HQD > > (hardware > > queue descriptor), EOP (still no clue :) > > > > Maybe some more specific ones just to be spelled out in clear where > > they > > are used ? KCQ (compute queue?), KGQ (gfx queue?) > > > > More suggestions inlined. > > > > Best regards, > > > > Hi all, > > I'll address all the highlighted problems in the V2. Thanks a lot for > all the feedback. > > Yann, > For the generic acronyms, how about keeping it in this patch for now? > After it gets merged, I can prepare a new documentation patch that > creates a glossary for DRM where I move the generic acronyms to the > DRM > documentation. I prefer this approach to keep the improvement small > and > manageable. Sure, especially as the Right Solution(tm) is not necessarily obvious :) One thing I thought about is that a context could be specified together with terms. Like "BPP (graphics)", "FEC (CS)", "DMCUB (amdgpu)". Well, "CS" may not be a good choice but you get the idea: that would keep all terms together and keep it easy for the reader. That way it could be easily be generalized at some point by just moving it to a generic kernel level - provided the solution suits the doc community at large. Best regards, -- Yann
Re: [PATCH v1 1/2] dt-bindings: sharp, lq101r1sx01: Add compatible for LQ101R1SX03
30.11.2021 18:54, Dmitry Osipenko пишет: > 30.11.2021 00:32, Rob Herring пишет: >> On Sun, Nov 14, 2021 at 11:07:16PM +0300, Dmitry Osipenko wrote: >>> From: Anton Bambura >>> >>> LQ101R1SX03 is compatible with LQ101R1SX01, document it. >> >> Then sounds like '"sharp,lq101r1sx03", "sharp,lq101r1sx01"' would be the >> appropriate compatible value. Do that, and you don't need a driver >> change. > > Apparently you're right. The "sharp,lq101r1sx03" should be a slightly > improved revision of "sharp,lq101r1sx01". I see now that LQ101R1SX03 is > sold as a spare part panel for ASUS TF701T, hence these panels should be > entirely compatible with each other. > I mixed up the panel model which TF701T uses. I compared datasheets of both panel variants. These panel have differences in the pins configuration. Hence panels seems aren't compatible in terms of hardware integration, although the difference is small. They should be compatible from software perspective.
Re: [PATCH v4] drm/i915: Use per device iommu check
On Fri, Nov 26, 2021 at 02:14:24PM +, Tvrtko Ursulin wrote: From: Tvrtko Ursulin With both integrated and discrete Intel GPUs in a system, the current global check of intel_iommu_gfx_mapped, as done from intel_vtd_active() may not be completely accurate. In this patch we add i915 parameter to intel_vtd_active() in order to prepare it for multiple GPUs and we also change the check away from Intel specific intel_iommu_gfx_mapped (global exported by the Intel IOMMU driver) to probing the presence of IOMMU on a specific device using device_iommu_mapped(). This will return true both for IOMMU pass-through and address translation modes which matches the current behaviour. If in the future we wanted to distinguish between these two modes we could either use iommu_get_domain_for_dev() and check for __IOMMU_DOMAIN_PAGING bit indicating address translation, or ask for a new API to be exported from the IOMMU core code. v2: * Check for dmar translation specifically, not just iommu domain. (Baolu) v3: * Go back to plain "any domain" check for now, rewrite commit message. v4: * Use device_iommu_mapped. (Robin, Baolu) Signed-off-by: Tvrtko Ursulin Cc: Lu Baolu Cc: Lucas De Marchi Cc: Robin Murphy Acked-by: Robin Murphy Reviewed-by: Lu Baolu this last version looks pretty clean. Also, for patches touching gem / gt we should Cc dri-devel. I'm leaving the patch below for reference and Cc'ing it. Small nit below, but can be ignored. --- drivers/gpu/drm/i915/display/intel_bw.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- drivers/gpu/drm/i915/display/intel_fbc.c | 2 +- drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 2 +- drivers/gpu/drm/i915/gem/i915_gemfs.c| 2 +- drivers/gpu/drm/i915/gt/intel_ggtt.c | 4 ++-- drivers/gpu/drm/i915/i915_debugfs.c | 1 + drivers/gpu/drm/i915/i915_driver.c | 7 +++ drivers/gpu/drm/i915/i915_drv.h | 13 +++-- drivers/gpu/drm/i915/i915_gpu_error.c| 5 + drivers/gpu/drm/i915/intel_device_info.c | 14 +- drivers/gpu/drm/i915/intel_pm.c | 2 +- 12 files changed, 25 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index abec394f6869..2da4aacc956b 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -634,7 +634,7 @@ static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, for_each_pipe(dev_priv, pipe) data_rate += bw_state->data_rate[pipe]; - if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active()) + if (DISPLAY_VER(dev_priv) >= 13 && intel_vtd_active(dev_priv)) data_rate = data_rate * 105 / 100; return data_rate; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index b2d51cd79d6c..1ef77ba7f645 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -1293,7 +1293,7 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); - return crtc_state->uapi.async_flip && intel_vtd_active() && + return crtc_state->uapi.async_flip && intel_vtd_active(i915) && (DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915)); } diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index d0c34bc3af6c..614e8697c068 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -1677,7 +1677,7 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *i915) static bool need_fbc_vtd_wa(struct drm_i915_private *i915) { /* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */ - if (intel_vtd_active() && + if (intel_vtd_active(i915) && (IS_SKYLAKE(i915) || IS_BROXTON(i915))) { drm_info(&i915->drm, "Disabling framebuffer compression (FBC) to prevent screen flicker with VT-d enabled\n"); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 80680395bb3b..bce03d74a0b4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -399,7 +399,7 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) return 0; } - if (intel_vtd_active() && GRAPHICS_VER(i915) < 8) { + if (intel_vtd_active(i915) && GRAPHICS_VER(i915) < 8) { drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "DMAR active"); diff --git a/drivers/gpu/drm/i915/gem/i915_gemfs.c b/drivers/gpu/drm/i915/gem/i915_gemfs.c index dbdbdc344d87..11cd66d183e6 100644 --- a/drivers/gpu/drm/i915/gem/i9
Re: [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes
On 11/30/21 19:12, Thomas Hellström wrote: On Tue, 2021-11-30 at 16:02 +0100, Christian König wrote: Am 30.11.21 um 15:35 schrieb Thomas Hellström: On Tue, 2021-11-30 at 14:26 +0100, Christian König wrote: Am 30.11.21 um 13:56 schrieb Thomas Hellström: On 11/30/21 13:42, Christian König wrote: Am 30.11.21 um 13:31 schrieb Thomas Hellström: [SNIP] Other than that, I didn't investigate the nesting fails enough to say I can accurately review this. :) Basically the problem is that within enable_signaling() which is called with the dma_fence lock held, we take the dma_fence lock of another fence. If that other fence is a dma_fence_array, or a dma_fence_chain which in turn tries to lock a dma_fence_array we hit a splat. Yeah, I already thought that you constructed something like that. You get the splat because what you do here is illegal, you can't mix dma_fence_array and dma_fence_chain like this or you can end up in a stack corruption. Hmm. Ok, so what is the stack corruption, is it that the enable_signaling() will end up with endless recursion? If so, wouldn't it be more usable we break that recursion chain and allow a more general use? The problem is that this is not easily possible for dma_fence_array containers. Just imagine that you drop the last reference to the containing fences during dma_fence_array destruction if any of the contained fences is another container you can easily run into recursion and with that stack corruption. Indeed, that would require some deeper surgery. That's one of the major reasons I came up with the dma_fence_chain container. This one you can chain any number of elements together without running into any recursion. Also what are the mixing rules between these? Never use a dma-fence-chain as one of the array fences and never use a dma-fence-array as a dma-fence-chain fence? You can't add any other container to a dma_fence_array, neither other dma_fence_array instances nor dma_fence_chain instances. IIRC at least technically a dma_fence_chain can contain a dma_fence_array if you absolutely need that, but Daniel, Jason and I already had the same discussion a while back and came to the conclusion to avoid that as well if possible. Yes, this is actually the use-case. But what I can't easily guarantee is that that dma_fence_chain isn't fed into a dma_fence_array somewhere else. How do you typically avoid that? Meanwhile I guess I need to take a different approach in the driver to avoid this altogether. Jason and I came up with a deep dive iterator for his use case, but I think we don't want to use that any more after my dma_resv rework. In other words when you need to create a new dma_fence_array you flatten out the existing construct which is at worst case dma_fence_chain->dma_fence_array->dma_fence. Ok, Are there any cross-driver contract here, Like every driver using a dma_fence_array need to check for dma_fence_chain and flatten like above? /Thomas Oh, and a follow up question: If there was a way to break the recursion on final put() (using the same basic approach as patch 2 in this series uses to break recursion in enable_signaling()), so that none of these containers did require any special treatment, would it be worth pursuing? I guess it might be possible by having the callbacks drop the references rather than the loop in the final put. + a couple of changes in code iterating over the fence pointers. /Thomas Regards, Christian. /Thomas Regards, Christian. /Thomas Regards, Christian. But I'll update the commit message with a typical splat. /Thomas
Re: [Intel-gfx] [PATCH v2 00/16] drm/i915: Remove short term pins from execbuf.
On 30/11/2021 11:17, Maarten Lankhorst wrote: On 30-11-2021 09:54, Tvrtko Ursulin wrote: Hi, On 29/11/2021 13:47, Maarten Lankhorst wrote: New version of the series, with feedback from previous series added. If there was a cover letter sent for this work in the past could you please keep attaching it? Or if there wasn't, could you please write one? I am worried about two things. First is that we need to have a high level overview of the rules/design changes documented so third party people have any hope of getting code right after this lands. (Where we are, where we are going, how we will get there, how far did we get and when we will get to the end.) Second is that when parts of the series land piecemeal (Which they have in this right, right?), it gets very hard to write up a maintainer level changelog. The preparation part is to ensure we always hold vma->obj->resv when unbinding. The first preparation series ensured vma->obj always existed. This was not the case for mock gtt and gen6 aliasing gtt. This allowed us to remove all the special handling for those uncommon cases, and actually enforce we can always take that lock. This part is merged. Sounds good. But also mention the high level motivation for why we always want to hold vma->obj->resv when unbinding in the introduction as well. Patch 2-11 in this series adds the vma->obj->resv to eviction and shrinker. Those are the only parts where we don't take the lock yet. After that, we always hold the lock when required, and we can start requiring the obj-> resv lock when unbinding. This is completed in patch 15. With that fixed, removing short term pins can be done, because for unbind we now always take obj->resv, so holding obj->resv during execbuf submission is sufficient, and all short term pinning can be removed. I'd also like the cover letter to contain a high level description on _why_ is removing short term pins needed or beneficial. What was the flow and object lifetimes so far, and what it will be going forward etc. We only pin temporarily when calling i915_gem_evict_vm in execbuf, which could also be handled in theory by just marking all objects as unpinned. As a bonus, using TTM for delayed eviction on all objects becomes easy, just need to get rid of i915_active in i915_vma, as it keeps the object refcount alive. Remainder is removing refcount to i915_vma, to make it a real Sounds on the right track with maybe a bit more text so the readers can easily understand it on the higher level. But in any case, even on the mundane process level, we need to have cover letters for any non trivial work was the conclusion since some time ago. Here you go! I hope it explains the reasoning. It is on the right track. I think just needs to be expanded a bit with high level direction and plan, pointing out where in the grand scheme this series is. And then don't forget to add the improved text as cover letter when sending next time please. Regards, Tvrtko
Re: [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes
On Tue, 2021-11-30 at 16:02 +0100, Christian König wrote: > Am 30.11.21 um 15:35 schrieb Thomas Hellström: > > On Tue, 2021-11-30 at 14:26 +0100, Christian König wrote: > > > Am 30.11.21 um 13:56 schrieb Thomas Hellström: > > > > On 11/30/21 13:42, Christian König wrote: > > > > > Am 30.11.21 um 13:31 schrieb Thomas Hellström: > > > > > > [SNIP] > > > > > > > Other than that, I didn't investigate the nesting fails > > > > > > > enough to > > > > > > > say I can accurately review this. :) > > > > > > Basically the problem is that within enable_signaling() > > > > > > which > > > > > > is > > > > > > called with the dma_fence lock held, we take the dma_fence > > > > > > lock > > > > > > of > > > > > > another fence. If that other fence is a dma_fence_array, or > > > > > > a > > > > > > dma_fence_chain which in turn tries to lock a > > > > > > dma_fence_array > > > > > > we hit > > > > > > a splat. > > > > > Yeah, I already thought that you constructed something like > > > > > that. > > > > > > > > > > You get the splat because what you do here is illegal, you > > > > > can't > > > > > mix > > > > > dma_fence_array and dma_fence_chain like this or you can end > > > > > up > > > > > in a > > > > > stack corruption. > > > > Hmm. Ok, so what is the stack corruption, is it that the > > > > enable_signaling() will end up with endless recursion? If so, > > > > wouldn't > > > > it be more usable we break that recursion chain and allow a > > > > more > > > > general use? > > > The problem is that this is not easily possible for > > > dma_fence_array > > > containers. Just imagine that you drop the last reference to the > > > containing fences during dma_fence_array destruction if any of > > > the > > > contained fences is another container you can easily run into > > > recursion > > > and with that stack corruption. > > Indeed, that would require some deeper surgery. > > > > > That's one of the major reasons I came up with the > > > dma_fence_chain > > > container. This one you can chain any number of elements together > > > without running into any recursion. > > > > > > > Also what are the mixing rules between these? Never use a > > > > dma-fence-chain as one of the array fences and never use a > > > > dma-fence-array as a dma-fence-chain fence? > > > You can't add any other container to a dma_fence_array, neither > > > other > > > dma_fence_array instances nor dma_fence_chain instances. > > > > > > IIRC at least technically a dma_fence_chain can contain a > > > dma_fence_array if you absolutely need that, but Daniel, Jason > > > and I > > > already had the same discussion a while back and came to the > > > conclusion > > > to avoid that as well if possible. > > Yes, this is actually the use-case. But what I can't easily > > guarantee > > is that that dma_fence_chain isn't fed into a dma_fence_array > > somewhere > > else. How do you typically avoid that? > > > > Meanwhile I guess I need to take a different approach in the driver > > to > > avoid this altogether. > > Jason and I came up with a deep dive iterator for his use case, but I > think we don't want to use that any more after my dma_resv rework. > > In other words when you need to create a new dma_fence_array you > flatten > out the existing construct which is at worst case > dma_fence_chain->dma_fence_array->dma_fence. Ok, Are there any cross-driver contract here, Like every driver using a dma_fence_array need to check for dma_fence_chain and flatten like above? /Thomas > > Regards, > Christian. > > > > > /Thomas > > > > > > > Regards, > > > Christian. > > > > > > > /Thomas > > > > > > > > > > > > > > > > > > > > > Regards, > > > > > Christian. > > > > > > > > > > > But I'll update the commit message with a typical splat. > > > > > > > > > > > > /Thomas > > >
Re: [PATCH 1/3] drm/simpledrm: Bind to OF framebuffers in /chosen
On Tue, Nov 30, 2021 at 12:45 AM Javier Martinez Canillas wrote: > > > > > > > > > Simpledrm is just a driver, but this is platform setup code. Why is this > > > > code located here and not under arch/ or drivers/firmware/? > > > > > > Agreed. Creating platform devices is something for platform code and > not really a DRM driver. > > > > > I know that other drivers do similar things, it doesn't seem to belong > > > > here. > > > > > Yeah, the simplefb driver does this but that seems like something that > should be changed. > > > > This definitely doesn't belong in either of those, since it is not arch- > > > or firmware-specific. It is implementing support for the standard > > > simple-framebuffer OF binding, which specifies that it must be located > > > within the /chosen node (and thus the default OF setup code won't do the > > > matching for you); this applies to all OF platforms [1] > > > > > > Adding Rob; do you think this should move from simplefb/simpledrm to > > > common OF code? (where?) > > > > of_platform_default_populate_init() should work. > > That should work but I still wonder if it is the correct place to add > this logic. It is because that is where most of the other devices are created unless the bus handles it. > I think that instead it could be done in the sysfb_create_simplefb() > function [0], which already creates the "simple-framebuffer" device > for x86 legacy BIOS and x86/arm64/riscv EFI so it makes sense to do > the same for OF. That way the simplefb platform device registration > code could also be dropped from the driver and users would just need > to enable CONFIG_SYSFB and CONFIG_SYSFB_SIMPLEFB to have the same. Doesn't look like that would share anything with anything else (BIOS/EFI/ACPI). Rob
Re: [PATCH v9 3/8] dt-bindings: display: Add ingenic,jz4780-dw-hdmi DT Schema
On Tue, Nov 30, 2021 at 11:03 AM H. Nikolaus Schaller wrote: > > Hi Rob, > > > Am 25.11.2021 um 22:26 schrieb Rob Herring : > > > > On Wed, 24 Nov 2021 22:29:09 +0100, H. Nikolaus Schaller wrote: > >> From: Sam Ravnborg > >> > >> Add DT bindings for the hdmi driver for the Ingenic JZ4780 SoC. > >> Based on .txt binding from Zubair Lutfullah Kakakhel > >> > >> We also add generic ddc-i2c-bus to synopsys,dw-hdmi.yaml > >> > >> Signed-off-by: Sam Ravnborg > >> Signed-off-by: H. Nikolaus Schaller > >> Cc: Rob Herring > >> Cc: devicet...@vger.kernel.org > >> --- > >> .../display/bridge/ingenic,jz4780-hdmi.yaml | 76 +++ > >> .../display/bridge/synopsys,dw-hdmi.yaml | 3 + > >> 2 files changed, 79 insertions(+) > >> create mode 100644 > >> Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml > >> > > > > My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' > > on your patch (DT_CHECKER_FLAGS is new in v5.13): > > > > yamllint warnings/errors: > > > > dtschema/dtc warnings/errors: > > Unknown file referenced: [Errno 2] No such file or directory: > > '/usr/local/lib/python3.8/dist-packages/dtschema/schemas/bridge/bridge/synopsys,dw-hdmi.yaml' > > I wasn't able to fix that. > > If I change > > allOf: > - - $ref: bridge/synopsys,dw-hdmi.yaml# > + - $ref: synopsys,dw-hdmi.yaml# That is correct. > > then make dt_binding_check still reports: > > Unknown file referenced: [Errno 2] No such file or directory: > '/Users/hns/Library/Python/3.7/lib/python/site-packages/dtschema/schemas/bridge/synopsys,dw-hdmi.yaml' The $id is wrong: $id: http://devicetree.org/schemas/bridge/ingenic,jz4780-hdmi.yaml# The path should be: http://devicetree.org/schemas/display/bridge/ingenic,jz4780-hdmi.yaml# Rob
Re: [PATCH] drm/komeda: Fix an undefined behavior bug in komeda_plane_add()
Hi Zhou, On Tue, Nov 30, 2021 at 10:23:01PM +0800, Zhou Qingyang wrote: > In komeda_plane_add(), komeda_get_layer_fourcc_list() is assigned to > formats and used in drm_universal_plane_init(). > drm_universal_plane_init() passes formats to > __drm_universal_plane_init(). __drm_universal_plane_init() further > passes formats to memcpy() as src parameter, which could lead to an > undefined behavior bug on failure of komeda_get_layer_fourcc_list(). > > Fix this bug by adding a check of formats. > > This bug was found by a static analyzer. The analysis employs > differential checking to identify inconsistent security operations > (e.g., checks or kfrees) between two code paths and confirms that the > inconsistent operations are not recovered in the current function or > the callers, so they constitute bugs. > > Note that, as a bug found by static analysis, it can be a false > positive or hard to trigger. Multiple researchers have cross-reviewed > the bug. If multiple researchers have cross-reviewed the bug how many have reviewed the fix? I'm asking because there is a problem with the fix > > Builds with CONFIG_DRM_KOMEDA=m show no new warnings, > and our static analyzer no longer warns about this code. > > Fixes: 61f1c4a8ab75 ("drm/komeda: Attach komeda_dev to DRM-KMS") > Signed-off-by: Zhou Qingyang > --- > drivers/gpu/drm/arm/display/komeda/komeda_plane.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c > b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c > index d63d83800a8a..dd3f17e970dd 100644 > --- a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c > @@ -265,6 +265,10 @@ static int komeda_plane_add(struct komeda_kms_dev *kms, > > formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl, > layer->layer_type, &n_formats); > + if (!formats) { > + err = -ENOMEM; > + goto cleanup; If you go to cleanup here it is too early, as the plane variable has not been initialised by the drm_universal_plane_init(), so komeda_plane_destroy() will crash. The correct fix here is to free the kplane allocation and then return -ENOMEM. > + } > > err = drm_universal_plane_init(&kms->base, plane, > get_possible_crtcs(kms, c->pipeline), > -- > 2.25.1 > Best regards, Liviu -- | I would like to | | fix the world, | | but they're not | | giving me the | \ source code! / --- ¯\_(ツ)_/¯
[PATCH v3 0/2] Fix mediatek-drm suspend and resume issue
Change in v3: - fix return typo: modify -NOEDV to -ENODEV. - add missing complete function in ddp_cmdq_cb. Change in v2: - rollback adding cmdq_mbox_flush in cmdq_suspend and add blocking config mode for mtk_drm_crtc_atomic_disable. - add return error when device_link_add fail. - change the first parameter of device_link_add from dev to priv->dev. jason-jh.lin (2): drm/mediatek: add blocking config mode for crtc disable flow drm/mediatek: add devlink to cmdq dev drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 31 - 1 file changed, 30 insertions(+), 1 deletion(-) -- 2.18.0
[PATCH v3 1/2] drm/mediatek: add blocking config mode for crtc disable flow
mtk_drm_crtc_atomic_disable will send an async cmd to cmdq driver, so it may not finish when cmdq_suspend is called sometimes. Change async cmd to blocking cmd for mtk_drm_crtc_atomic_disable to make sure the lastest cmd is done before cmdq_suspend. Signed-off-by: jason-jh.lin --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 17 - 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 62529a954b62..6ca96802fd77 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -56,6 +56,8 @@ struct mtk_drm_crtc { struct cmdq_pkt cmdq_handle; u32 cmdq_event; u32 cmdq_vblank_cnt; + boolblocking_config; + struct completion cmplt; #endif struct device *mmsys_dev; @@ -314,6 +316,9 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) } mtk_crtc->cmdq_vblank_cnt = 0; + + if (mtk_crtc->blocking_config) + complete(&mtk_crtc->cmplt); } #endif @@ -584,8 +589,16 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, */ mtk_crtc->cmdq_vblank_cnt = 3; + if (mtk_crtc->blocking_config) + init_completion(&mtk_crtc->cmplt); + mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + + if (mtk_crtc->blocking_config) { + wait_for_completion(&mtk_crtc->cmplt); + mtk_crtc->blocking_config = false; + } } #endif mtk_crtc->config_updating = false; @@ -698,7 +711,9 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, plane_state->pending.config = true; } mtk_crtc->pending_planes = true; - +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + mtk_crtc->blocking_config = true; +#endif mtk_drm_crtc_update_config(mtk_crtc, false); /* Wait for planes to be disabled */ drm_crtc_wait_one_vblank(crtc); -- 2.18.0
[PATCH v3 2/2] drm/mediatek: add devlink to cmdq dev
Add devlink to cmdq to make sure the order of suspend and resume is correct. Signed-off-by: jason-jh.lin --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 6ca96802fd77..88b57a20f26d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -61,6 +61,7 @@ struct mtk_drm_crtc { #endif struct device *mmsys_dev; + struct device *drm_dev; struct mtk_mutex*mutex; unsigned intddp_comp_nr; struct mtk_ddp_comp **ddp_comp; @@ -160,6 +161,7 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); if (mtk_crtc->cmdq_client.chan) { + device_link_remove(mtk_crtc->drm_dev, mtk_crtc->cmdq_client.chan->mbox->dev); mbox_free_channel(mtk_crtc->cmdq_client.chan); mtk_crtc->cmdq_client.chan = NULL; } @@ -908,6 +910,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, return -ENOMEM; mtk_crtc->mmsys_dev = priv->mmsys_dev; + mtk_crtc->drm_dev = priv->dev; mtk_crtc->ddp_comp_nr = path_len; mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr, sizeof(*mtk_crtc->ddp_comp), @@ -975,6 +978,17 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, } if (mtk_crtc->cmdq_client.chan) { + struct device_link *link; + + /* add devlink to cmdq dev to make sure suspend/resume order is correct */ + link = device_link_add(priv->dev, mtk_crtc->cmdq_client.chan->mbox->dev, + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); + if (!link) { + dev_err(priv->dev, "Unable to link dev=%s\n", + dev_name(mtk_crtc->cmdq_client.chan->mbox->dev)); + return -ENODEV; + } + ret = of_property_read_u32_index(priv->mutex_node, "mediatek,gce-events", i, -- 2.18.0
Re: [PATCH] drm/amdkfd: Fix a wild pointer dereference in svm_range_add()
Am 2021-11-30 um 11:51 a.m. schrieb philip yang: > > > On 2021-11-30 6:26 a.m., Zhou Qingyang wrote: >> In svm_range_add(), the return value of svm_range_new() is assigned >> to prange and &prange->insert_list is used in list_add(). There is a >> a dereference of &prange->insert_list in list_add(), which could lead >> to a wild pointer dereference on failure of vm_range_new() if >> CONFIG_DEBUG_LIST is unset in .config file. >> >> Fix this bug by adding a check of prange. >> >> This bug was found by a static analyzer. The analysis employs >> differential checking to identify inconsistent security operations >> (e.g., checks or kfrees) between two code paths and confirms that the >> inconsistent operations are not recovered in the current function or >> the callers, so they constitute bugs. >> >> Note that, as a bug found by static analysis, it can be a false >> positive or hard to trigger. Multiple researchers have cross-reviewed >> the bug. >> >> Builds with CONFIG_DRM_AMDGPU=m, CONFIG_HSA_AMD=y, and >> CONFIG_HSA_AMD_SVM=y show no new warnings, and our static analyzer no >> longer warns about this code. >> >> Fixes: 42de677f7999 ("drm/amdkfd: register svm range") >> Signed-off-by: Zhou Qingyang > Reviewed-by: Philip Yang The patch looks good to me. It's an obvious bug and definitely not a false positive. The patch description is a bit verbose. Is this auto-generated output from the static checker? It could be replaced with something more concise. Especially the comment about this possibly being a false positive should not be in the final submission. Regards, Felix >> --- >> drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 3 +++ >> 1 file changed, 3 insertions(+) >> >> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> index 58b89b53ebe6..e40c2211901d 100644 >> --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c >> @@ -2940,6 +2940,9 @@ svm_range_add(struct kfd_process *p, uint64_t start, >> uint64_t size, >> >> if (left) { >> prange = svm_range_new(svms, last - left + 1, last); >> +if (!prange) >> +return -ENOMEM; >> + >> list_add(&prange->insert_list, insert_list); >> list_add(&prange->update_list, update_list); >> }
[PATCH v2 2/2] drm/mediatek: add devlink to cmdq dev
Add devlink to cmdq to make sure the order of suspend and resume is correct. Signed-off-by: jason-jh.lin --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index e886d299813c..98486f99043e 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -61,6 +61,7 @@ struct mtk_drm_crtc { #endif struct device *mmsys_dev; + struct device *drm_dev; struct mtk_mutex*mutex; unsigned intddp_comp_nr; struct mtk_ddp_comp **ddp_comp; @@ -160,6 +161,7 @@ static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); if (mtk_crtc->cmdq_client.chan) { + device_link_remove(mtk_crtc->drm_dev, mtk_crtc->cmdq_client.chan->mbox->dev); mbox_free_channel(mtk_crtc->cmdq_client.chan); mtk_crtc->cmdq_client.chan = NULL; } @@ -905,6 +907,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, return -ENOMEM; mtk_crtc->mmsys_dev = priv->mmsys_dev; + mtk_crtc->drm_dev = priv->dev; mtk_crtc->ddp_comp_nr = path_len; mtk_crtc->ddp_comp = devm_kmalloc_array(dev, mtk_crtc->ddp_comp_nr, sizeof(*mtk_crtc->ddp_comp), @@ -972,6 +975,17 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, } if (mtk_crtc->cmdq_client.chan) { + struct device_link *link; + + /* add devlink to cmdq dev to make sure suspend/resume order is correct */ + link = device_link_add(priv->dev, mtk_crtc->cmdq_client.chan->mbox->dev, + DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS); + if (!link) { + dev_err(priv->dev, "Unable to link dev=%s\n", + dev_name(mtk_crtc->cmdq_client.chan->mbox->dev)); + return -NODEV; + } + ret = of_property_read_u32_index(priv->mutex_node, "mediatek,gce-events", i, -- 2.18.0
[PATCH v2 0/2] Fix mediatek-drm suspend and resume issue
Change in v2: - rollback adding cmdq_mbox_flush in cmdq_suspend and add blocking config mode for mtk_drm_crtc_atomic_disable. - add return error when device_link_add fail. - change the first parameter of device_link_add from dev to priv->dev. jason-jh.lin (2): drm/mediatek: add blocking config mode for crtc disable flow drm/mediatek: add devlink to cmdq dev drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 28 - 1 file changed, 27 insertions(+), 1 deletion(-) -- 2.18.0
[PATCH v2 1/2] drm/mediatek: add blocking config mode for crtc disable flow
mtk_drm_crtc_atomic_disable will send an async cmd to cmdq driver, so it may not finish when cmdq_suspend is called sometimes. Change async cmd to blocking cmd for mtk_drm_crtc_atomic_disable to make sure the lastest cmd is done before cmdq_suspend. Signed-off-by: jason-jh.lin --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 14 +- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 62529a954b62..e886d299813c 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -56,6 +56,8 @@ struct mtk_drm_crtc { struct cmdq_pkt cmdq_handle; u32 cmdq_event; u32 cmdq_vblank_cnt; + boolblocking_config; + struct completion cmplt; #endif struct device *mmsys_dev; @@ -584,8 +586,16 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, */ mtk_crtc->cmdq_vblank_cnt = 3; + if (mtk_crtc->blocking_config) + init_completion(&mtk_crtc->cmplt); + mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + + if (mtk_crtc->blocking_config) { + wait_for_completion(&mtk_crtc->cmplt); + mtk_crtc->blocking_config = false; + } } #endif mtk_crtc->config_updating = false; @@ -698,7 +708,9 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, plane_state->pending.config = true; } mtk_crtc->pending_planes = true; - +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + mtk_crtc->blocking_config = true; +#endif mtk_drm_crtc_update_config(mtk_crtc, false); /* Wait for planes to be disabled */ drm_crtc_wait_one_vblank(crtc); -- 2.18.0
Re: [PATCH v9 3/8] dt-bindings: display: Add ingenic,jz4780-dw-hdmi DT Schema
Hi Rob, > Am 25.11.2021 um 22:26 schrieb Rob Herring : > > On Wed, 24 Nov 2021 22:29:09 +0100, H. Nikolaus Schaller wrote: >> From: Sam Ravnborg >> >> Add DT bindings for the hdmi driver for the Ingenic JZ4780 SoC. >> Based on .txt binding from Zubair Lutfullah Kakakhel >> >> We also add generic ddc-i2c-bus to synopsys,dw-hdmi.yaml >> >> Signed-off-by: Sam Ravnborg >> Signed-off-by: H. Nikolaus Schaller >> Cc: Rob Herring >> Cc: devicet...@vger.kernel.org >> --- >> .../display/bridge/ingenic,jz4780-hdmi.yaml | 76 +++ >> .../display/bridge/synopsys,dw-hdmi.yaml | 3 + >> 2 files changed, 79 insertions(+) >> create mode 100644 >> Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.yaml >> > > My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' > on your patch (DT_CHECKER_FLAGS is new in v5.13): > > yamllint warnings/errors: > > dtschema/dtc warnings/errors: > Unknown file referenced: [Errno 2] No such file or directory: > '/usr/local/lib/python3.8/dist-packages/dtschema/schemas/bridge/bridge/synopsys,dw-hdmi.yaml' I wasn't able to fix that. If I change allOf: - - $ref: bridge/synopsys,dw-hdmi.yaml# + - $ref: synopsys,dw-hdmi.yaml# then make dt_binding_check still reports: Unknown file referenced: [Errno 2] No such file or directory: '/Users/hns/Library/Python/3.7/lib/python/site-packages/dtschema/schemas/bridge/synopsys,dw-hdmi.yaml' BR and thanks, Nikolaus Schaller > xargs: dt-doc-validate: exited with status 255; aborting > make[1]: *** Deleting file > 'Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.example.dt.yaml' > Unknown file referenced: [Errno 2] No such file or directory: > '/usr/local/lib/python3.8/dist-packages/dtschema/schemas/bridge/bridge/synopsys,dw-hdmi.yaml' > make[1]: *** [scripts/Makefile.lib:373: > Documentation/devicetree/bindings/display/bridge/ingenic,jz4780-hdmi.example.dt.yaml] > Error 255 > make[1]: *** Waiting for unfinished jobs > make: *** [Makefile:1413: dt_binding_check] Error 2 > > doc reference errors (make refcheckdocs): > > See https://patchwork.ozlabs.org/patch/1559375 > > This check can fail if there are any dependencies. The base for a patch > series is generally the most recent rc1. > > If you already ran 'make dt_binding_check' and didn't see the above > error(s), then make sure 'yamllint' is installed and dt-schema is up to > date: > > pip3 install dtschema --upgrade > > Please check and re-submit. >
Re: [PATCH v2 2/2] drm: rcar-du: mipi-dsi: Use devm_drm_of_get_bridge helper
Hi Laurent, Quoting Kieran Bingham (2021-11-30 16:25:13) > Instead of open coding the calls for > drm_of_find_panel_or_bridge() > devm_drm_panel_bridge_add() > > use the devm_drm_of_get_bridge() helper directly. > > Signed-off-by: Kieran Bingham > --- > v2: > - New patch > > drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 19 --- > 1 file changed, 4 insertions(+), 15 deletions(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > index 0a9f197ef62c..1dfe20d3d0f2 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c > @@ -637,7 +637,7 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host > *host, > struct mipi_dsi_device *device) > { > struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); > - struct drm_panel *panel; > + struct device *dev = dsi->dev; > int ret; > > if (device->lanes > dsi->num_data_lanes) > @@ -646,20 +646,9 @@ static int rcar_mipi_dsi_host_attach(struct > mipi_dsi_host *host, > dsi->lanes = device->lanes; > dsi->format = device->format; > > - ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel, > - &dsi->next_bridge); > - if (ret) { > - dev_err_probe(dsi->dev, ret, "could not find next bridge\n"); > - return ret; > - } > - > - if (!dsi->next_bridge) { > - dsi->next_bridge = devm_drm_panel_bridge_add(dsi->dev, panel); > - if (IS_ERR(dsi->next_bridge)) { > - dev_err(dsi->dev, "failed to create panel bridge\n"); > - return PTR_ERR(dsi->next_bridge); > - } > - } > + dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); > + if (IS_ERR(dsi->next_bridge)) > + return PTR_ERR(dsi->next_bridge); I did make a change here to make this: dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); if (IS_ERR(dsi->next_bridge)) { dev_err(dev, "failed to get next bridge\n"); return PTR_ERR(dsi->next_bridge); } But it seems I got out of sequence and saved out the wrong patch ;-( If you think it's better with the error print, please add it while squashing, or if you really need, I can send an updated patch and retest. -- Kieran > > /* Initialize the DRM bridge. */ > dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; > -- > 2.30.2 >
Re: [PATCH] drm/amdkfd: Fix a wild pointer dereference in svm_range_add()
On 2021-11-30 6:26 a.m., Zhou Qingyang wrote: In svm_range_add(), the return value of svm_range_new() is assigned to prange and &prange->insert_list is used in list_add(). There is a a dereference of &prange->insert_list in list_add(), which could lead to a wild pointer dereference on failure of vm_range_new() if CONFIG_DEBUG_LIST is unset in .config file. Fix this bug by adding a check of prange. This bug was found by a static analyzer. The analysis employs differential checking to identify inconsistent security operations (e.g., checks or kfrees) between two code paths and confirms that the inconsistent operations are not recovered in the current function or the callers, so they constitute bugs. Note that, as a bug found by static analysis, it can be a false positive or hard to trigger. Multiple researchers have cross-reviewed the bug. Builds with CONFIG_DRM_AMDGPU=m, CONFIG_HSA_AMD=y, and CONFIG_HSA_AMD_SVM=y show no new warnings, and our static analyzer no longer warns about this code. Fixes: 42de677f7999 ("drm/amdkfd: register svm range") Signed-off-by: Zhou Qingyang Reviewed-by: Philip Yang --- drivers/gpu/drm/amd/amdkfd/kfd_svm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 58b89b53ebe6..e40c2211901d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -2940,6 +2940,9 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size, if (left) { prange = svm_range_new(svms, last - left + 1, last); + if (!prange) + return -ENOMEM; + list_add(&prange->insert_list, insert_list); list_add(&prange->update_list, update_list); }
Re: [PATCH v7 0/9] drm/omap: Add virtual-planes support
Hi Tomi, On 17/11/2021 15:19, Neil Armstrong wrote: > This patchset is the follow-up the v4 patchset from Benoit Parrot at [1]. > > This patch series adds virtual-plane support to omapdrm driver to allow the > use > of display wider than 2048 pixels. > > In order to do so we introduce the concept of hw_overlay which can then be > dynamically allocated to a plane. When the requested output width exceed what > be supported by one overlay a second is then allocated if possible to handle > display wider then 2048. > > This series replaces an earlier series which was DT based and using statically > allocated resources. > > This implementation is inspired from the work done in msm/disp/mdp5 > driver. > > Changes since v6 at [3]: > - Patch 1: Added comment for drm_atomic_helper_check_plane_state, added > Reviewed-by > - Patch 2: added Reviewed-by > - Patch 3: added Reviewed-by > - Patch 4: added Reviewed-by > - Patch 5: added Reviewed-by > - Patch 6: No changes > - Patch 7: No changes > - Patch 8: Reformatted omap_plane_atomic_print_state() output for overlays > - Patch 9: Added a comment of the utility of the local > omap_atomic_update_normalize_zpos() + atomic_print_state() reformat > > Changes since v5 at [2]: > - Patch 1: renamed width/height_fp to max_width/height > - Patch 2: no changes > - Patch 3: removed possible_crtcs stuff, > added cleanup on failure to allocate, > removed name in omap_plane struct & plane_id_to_name in omap_plane.c, > switched all omap_plane->name to plane->name or omap_plane->id > - Patch 4: aligned omap_plane_atomic_duplicate_state the the crtc style > - Patch 5: removed glob_obj_lock & reformated global state declaration in > omap_drv.h > - Patch 6: moved drm_atomic_helper_check_plane_state() from atomic_check() in > separate commit, > removed zpos change, updated debug messages to be useful, > renamed omap_overlay_disable() to omap_overlay_update_state(), > added useful comments for omap_overlay_assign() & > omap_overlay_update_state(), > simplified omap_overlay_assign() & omap_overlay_update_state() for > actual use-cases, > refactored omap_plane_atomic_check() changes to be cleaner & simpler > - Patch 7: no changes (except possible_crtcs print removal) > - Patch 8: Reformated omap_plane_atomic_check() & omap_overlay_assign() > changes to match previous patches layout > > Changes since v4 at [1]: > - rebased on v5.15-rc2 > - adapted to drm_atomic_get_new/old_plane_state() > - tested on Beagle-x15 > - checked for non-regression on Beagle-x15 > - removed unused "state" variable in omap_global_state > > [1] https://lore.kernel.org/all/20181012201703.29065-1-bpar...@ti.com/ > [2] > https://lore.kernel.org/all/20210923070701.145377-1-narmstr...@baylibre.com/ > [3] > https://lore.kernel.org/all/20211018142842.2511200-1-narmstr...@baylibre.com > > Benoit Parrot (8): > drm/omap: Add ability to check if requested plane modes can be > supported > drm/omap: Add ovl checking funcs to dispc_ops > drm/omap: introduce omap_hw_overlay > drm/omap: omap_plane: subclass drm_plane_state > drm/omap: Add global state as a private atomic object > drm/omap: dynamically assign hw overlays to planes > drm/omap: add plane_atomic_print_state support > drm/omap: Add a 'right overlay' to plane state > > Neil Armstrong (1): > drm/omap: add sanity plane state check > > drivers/gpu/drm/omapdrm/Makefile | 1 + > drivers/gpu/drm/omapdrm/dss/dispc.c| 31 ++- > drivers/gpu/drm/omapdrm/dss/dss.h | 5 + > drivers/gpu/drm/omapdrm/omap_drv.c | 196 +- > drivers/gpu/drm/omapdrm/omap_drv.h | 24 ++ > drivers/gpu/drm/omapdrm/omap_fb.c | 33 ++- > drivers/gpu/drm/omapdrm/omap_fb.h | 4 +- > drivers/gpu/drm/omapdrm/omap_overlay.c | 212 +++ > drivers/gpu/drm/omapdrm/omap_overlay.h | 35 +++ > drivers/gpu/drm/omapdrm/omap_plane.c | 349 + > drivers/gpu/drm/omapdrm/omap_plane.h | 1 + > 11 files changed, 832 insertions(+), 59 deletions(-) > create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.c > create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.h > > > base-commit: 49c39ec4670a8f045729e3717af2e1a74caf89a5 > Gentle ping, Neil
Re: [PATCH] drm/i915: Don't disable interrupts and pretend a lock as been acquired in __timeline_mark_lock().
On 2021-11-19 17:04:00 [+0100], Daniel Vetter wrote: > Yeah if we can simplify this with reverts then I'm all for this. > > Acked-by: Daniel Vetter > > I've asked drm/i915 maintainers to check&merge. Thanks. Should I repost my queue (excluding this one) or should wait until this one has been taken care? > -Daniel Sebastian
[PATCH v2 2/2] drm: rcar-du: mipi-dsi: Use devm_drm_of_get_bridge helper
Instead of open coding the calls for drm_of_find_panel_or_bridge() devm_drm_panel_bridge_add() use the devm_drm_of_get_bridge() helper directly. Signed-off-by: Kieran Bingham --- v2: - New patch drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c | 19 --- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c index 0a9f197ef62c..1dfe20d3d0f2 100644 --- a/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c +++ b/drivers/gpu/drm/rcar-du/rcar_mipi_dsi.c @@ -637,7 +637,7 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct rcar_mipi_dsi *dsi = host_to_rcar_mipi_dsi(host); - struct drm_panel *panel; + struct device *dev = dsi->dev; int ret; if (device->lanes > dsi->num_data_lanes) @@ -646,20 +646,9 @@ static int rcar_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->lanes = device->lanes; dsi->format = device->format; - ret = drm_of_find_panel_or_bridge(dsi->dev->of_node, 1, 0, &panel, - &dsi->next_bridge); - if (ret) { - dev_err_probe(dsi->dev, ret, "could not find next bridge\n"); - return ret; - } - - if (!dsi->next_bridge) { - dsi->next_bridge = devm_drm_panel_bridge_add(dsi->dev, panel); - if (IS_ERR(dsi->next_bridge)) { - dev_err(dsi->dev, "failed to create panel bridge\n"); - return PTR_ERR(dsi->next_bridge); - } - } + dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + if (IS_ERR(dsi->next_bridge)) + return PTR_ERR(dsi->next_bridge); /* Initialize the DRM bridge. */ dsi->bridge.funcs = &rcar_mipi_dsi_bridge_ops; -- 2.30.2