diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:03:44 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:04:03 +1000 |
| commit | 37b812b7fdc2f1c7cb9e22c888776be7347097b0 (patch) | |
| tree | a7584e45073dbf7f8da5d1a44835fbcc50b2ca52 | |
| parent | 83dc0ba2755296b5e5882e044c80973b7c3fce9e (diff) | |
| parent | b36178488d479e9a53bbef2b01280378b5586e60 (diff) | |
Merge tag 'drm-misc-next-2026-01-15' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 6.20:
Core Changes:
- atomic: Introduce Gamma/Degamma LUT size check
- gem: Fix a leak in drm_gem_get_unmapped_area
- gpuvm: API sanitation for Rust bindings
- panic: Few corner-cases fixes
Driver Changes:
- Replace system workqueue with percpu equivalent
- amdxdna: Update message buffer allocation requirements, Update
firmware version check
- imagination: Add AM62P support
- ivpu: Implement warm boot flow
- rockchip: Get rid of atomic_check fixups, Add Rockchip RK3506 Support
- rocket: Cleanups
- bridge:
- dw-hdmi-qp: Add support for HPD-less setups
- panel:
- mantix: Various power management related improvements
- new panels: Innolux G150XGE-L05,
- dma-buf:
- cma: Call clear_page instead of memset
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260115-lilac-dragon-of-opposition-ac0a30@houat
65 files changed, 870 insertions, 370 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index fc244fbb5a54..868edb04989a 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -178,6 +178,8 @@ properties: - innolux,g121x1-l03 # Innolux Corporation 12.1" G121XCE-L01 XGA (1024x768) TFT LCD panel - innolux,g121xce-l01 + # InnoLux 15.0" G150XGE-L05 XGA (1024x768) TFT LCD panel + - innolux,g150xge-l05 # InnoLux 15.6" FHD (1920x1080) TFT LCD panel - innolux,g156hce-l01 # InnoLux 13.3" FHD (1920x1080) TFT LCD panel @@ -349,7 +351,9 @@ if: properties: compatible: contains: - const: innolux,g101ice-l01 + enum: + - innolux,g101ice-l01 + - yes-optoelectronics,ytc700tlag-05-201c then: properties: data-mapping: false diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml index 632b48bfabb9..b968f2de93f7 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml @@ -19,6 +19,7 @@ properties: - rockchip,rk3288-mipi-dsi - rockchip,rk3368-mipi-dsi - rockchip,rk3399-mipi-dsi + - rockchip,rk3506-mipi-dsi - rockchip,rk3568-mipi-dsi - rockchip,rv1126-mipi-dsi - const: snps,dw-mipi-dsi @@ -75,6 +76,7 @@ allOf: - rockchip,px30-mipi-dsi - rockchip,rk3128-mipi-dsi - rockchip,rk3368-mipi-dsi + - rockchip,rk3506-mipi-dsi - rockchip,rk3568-mipi-dsi - rockchip,rv1126-mipi-dsi diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml index d649808c59da..70ac6751bdba 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml @@ -69,6 +69,12 @@ properties: - const: main - const: hpd + no-hpd: + type: boolean + description: + The HPD pin is not present or used for another purpose, and the EDID + must be polled instead to determine if a device is attached. + phys: maxItems: 1 description: The HDMI/eDP PHY diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml index 8b5f58103dda..fdf4b1109da2 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml @@ -31,6 +31,7 @@ properties: - rockchip,rk3368-vop - rockchip,rk3399-vop-big - rockchip,rk3399-vop-lit + - rockchip,rk3506-vop - rockchip,rv1126-vop reg: diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml index bee9faf1d3f8..8eccd4338a2b 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml @@ -51,6 +51,14 @@ properties: - stacks - const: stacks + nvmem-cells: + items: + - description: bitmask of functional shader cores + + nvmem-cell-names: + items: + - const: shader-present + mali-supply: true operating-points-v2: true @@ -108,6 +116,8 @@ allOf: properties: clocks: minItems: 3 + nvmem-cells: false + nvmem-cell-names: false power-domains: maxItems: 1 power-domain-names: false @@ -133,6 +143,8 @@ allOf: - const: core - const: stacks required: + - nvmem-cells + - nvmem-cell-names - power-domains examples: @@ -179,6 +191,8 @@ examples: <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH 0>, <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH 0>; interrupt-names = "job", "mmu", "gpu"; + nvmem-cells = <&shader_present>; + nvmem-cell-names = "shader-present"; power-domains = <&gpufreq>; }; diff --git a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml index 86ef68985317..a1f54dbae3f3 100644 --- a/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml +++ b/Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml @@ -40,6 +40,7 @@ properties: - const: img,img-rogue - items: - enum: + - ti,am62p-gpu - ti,j721s2-gpu - const: img,img-bxs-4-64 - const: img,img-rogue @@ -100,6 +101,7 @@ allOf: contains: enum: - ti,am62-gpu + - ti,am62p-gpu - ti,j721s2-gpu then: properties: diff --git a/MAINTAINERS b/MAINTAINERS index e405c257f62b..c8c77f388e87 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8780,6 +8780,17 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/ttm/ F: include/drm/ttm/ +DRM BUDDY ALLOCATOR +M: Matthew Auld <matthew.auld@intel.com> +M: Arun Pravin <arunpravin.paneerselvam@amd.com> +R: Christian Koenig <christian.koenig@amd.com> +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: drivers/gpu/drm/drm_buddy.c +F: drivers/gpu/drm/tests/drm_buddy_test.c +F: include/drm/drm_buddy.h + DRM AUTOMATED TESTING M: Helen Koike <helen.fornazier@gmail.com> M: Vignesh Raman <vignesh.raman@collabora.com> diff --git a/drivers/accel/amdxdna/aie2_error.c b/drivers/accel/amdxdna/aie2_error.c index d452008ec4f4..5e82df2b7cf6 100644 --- a/drivers/accel/amdxdna/aie2_error.c +++ b/drivers/accel/amdxdna/aie2_error.c @@ -338,8 +338,7 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) destroy_workqueue(events->wq); mutex_lock(&xdna->dev_lock); - dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, - events->addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); kfree(events); } @@ -355,8 +354,8 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) if (!events) return -ENOMEM; - events->buf = dma_alloc_noncoherent(xdna->ddev.dev, total_size, &events->addr, - DMA_FROM_DEVICE, GFP_KERNEL); + events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr); + if (!events->buf) { ret = -ENOMEM; goto free_events; @@ -396,8 +395,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) free_wq: destroy_workqueue(events->wq); free_buf: - dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, - events->addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr); free_events: kfree(events); return ret; diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c index 051f4ceaabae..99215328505e 100644 --- a/drivers/accel/amdxdna/aie2_message.c +++ b/drivers/accel/amdxdna/aie2_message.c @@ -55,6 +55,22 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev, return ret; } +void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, + dma_addr_t *dma_addr) +{ + struct amdxdna_dev *xdna = ndev->xdna; + int order; + + *size = max(*size, SZ_8K); + order = get_order(*size); + if (order > MAX_PAGE_ORDER) + return NULL; + *size = PAGE_SIZE << order; + + return dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr, + DMA_FROM_DEVICE, GFP_KERNEL); +} + int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev) { DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND); @@ -346,14 +362,13 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, { DECLARE_AIE2_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS); struct amdxdna_dev *xdna = ndev->xdna; + u32 buf_sz = size, aie_bitmap = 0; struct amdxdna_client *client; dma_addr_t dma_addr; - u32 aie_bitmap = 0; u8 *buff_addr; int ret; - buff_addr = dma_alloc_noncoherent(xdna->ddev.dev, size, &dma_addr, - DMA_FROM_DEVICE, GFP_KERNEL); + buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (!buff_addr) return -ENOMEM; @@ -363,7 +378,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, *cols_filled = 0; req.dump_buff_addr = dma_addr; - req.dump_buff_size = size; + req.dump_buff_size = buf_sz; req.num_cols = hweight32(aie_bitmap); req.aie_bitmap = aie_bitmap; @@ -391,7 +406,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, *cols_filled = aie_bitmap; fail: - dma_free_noncoherent(xdna->ddev.dev, size, buff_addr, dma_addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, buf_sz, buff_addr, dma_addr); return ret; } @@ -402,19 +417,19 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, DECLARE_AIE2_MSG(get_telemetry, MSG_OP_GET_TELEMETRY); struct amdxdna_dev *xdna = ndev->xdna; dma_addr_t dma_addr; + u32 buf_sz = size; u8 *addr; int ret; if (header->type >= MAX_TELEMETRY_TYPE) return -EINVAL; - addr = dma_alloc_noncoherent(xdna->ddev.dev, size, &dma_addr, - DMA_FROM_DEVICE, GFP_KERNEL); + addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr); if (!addr) return -ENOMEM; req.buf_addr = dma_addr; - req.buf_size = size; + req.buf_size = buf_sz; req.type = header->type; drm_clflush_virt_range(addr, size); /* device can access */ @@ -440,7 +455,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev, header->minor = resp.minor; free_buf: - dma_free_noncoherent(xdna->ddev.dev, size, addr, dma_addr, DMA_FROM_DEVICE); + aie2_free_msg_buffer(ndev, buf_sz, addr, dma_addr); return ret; } diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index ec1c3ad57d49..f70ccf0f3c01 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -57,41 +57,23 @@ struct mgmt_mbox_chann_info { static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 fw_minor) { const struct aie2_fw_feature_tbl *feature; - struct amdxdna_dev *xdna = ndev->xdna; - - /* - * The driver supported mailbox behavior is defined by - * ndev->priv->protocol_major and protocol_minor. - * - * When protocol_major and fw_major are different, it means driver - * and firmware are incompatible. - */ - if (ndev->priv->protocol_major != fw_major) { - XDNA_ERR(xdna, "Incompatible firmware protocol major %d minor %d", - fw_major, fw_minor); - return -EINVAL; - } + bool found = false; - /* - * When protocol_minor is greater then fw_minor, that means driver - * relies on operation the installed firmware does not support. - */ - if (ndev->priv->protocol_minor > fw_minor) { - XDNA_ERR(xdna, "Firmware minor version smaller than supported"); - return -EINVAL; - } - - for (feature = ndev->priv->fw_feature_tbl; feature && feature->min_minor; - feature++) { + for (feature = ndev->priv->fw_feature_tbl; feature->major; feature++) { + if (feature->major != fw_major) + continue; if (fw_minor < feature->min_minor) continue; if (feature->max_minor > 0 && fw_minor > feature->max_minor) continue; - set_bit(feature->feature, &ndev->feature_mask); + ndev->feature_mask |= feature->features; + + /* firmware version matches one of the driver support entry */ + found = true; } - return 0; + return found ? 0 : -EOPNOTSUPP; } static void aie2_dump_chann_info_debug(struct amdxdna_dev_hdl *ndev) diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h index a929fa98a121..b20a3661078c 100644 --- a/drivers/accel/amdxdna/aie2_pci.h +++ b/drivers/accel/amdxdna/aie2_pci.h @@ -237,7 +237,8 @@ enum aie2_fw_feature { }; struct aie2_fw_feature_tbl { - enum aie2_fw_feature feature; + u64 features; + u32 major; u32 max_minor; u32 min_minor; }; @@ -246,8 +247,6 @@ struct aie2_fw_feature_tbl { struct amdxdna_dev_priv { const char *fw_path; - u64 protocol_major; - u64 protocol_minor; const struct rt_config *rt_config; const struct dpm_clk_freq *dpm_clk_tbl; const struct aie2_fw_feature_tbl *fw_feature_tbl; @@ -336,6 +335,11 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int (*notify_cb)(void *, void __iomem *, size_t)); int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, int (*notify_cb)(void *, void __iomem *, size_t)); +void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size, + dma_addr_t *dma_addr); +#define aie2_free_msg_buffer(ndev, size, buff_addr, dma_addr) \ + dma_free_noncoherent((ndev)->xdna->ddev.dev, size, buff_addr, \ + dma_addr, DMA_FROM_DEVICE) /* aie2_hwctx.c */ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx); diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 7d59764d7869..45f5c12fc67f 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -275,7 +275,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) fs_reclaim_release(GFP_KERNEL); } - xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", 0); + xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); if (!xdna->notifier_wq) return -ENOMEM; diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c index ebc6e2802297..6f36a27b5a02 100644 --- a/drivers/accel/amdxdna/npu1_regs.c +++ b/drivers/accel/amdxdna/npu1_regs.c @@ -6,6 +6,7 @@ #include <drm/amdxdna_accel.h> #include <drm/drm_device.h> #include <drm/gpu_scheduler.h> +#include <linux/bits.h> #include <linux/sizes.h> #include "aie2_pci.h" @@ -65,14 +66,13 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = { }; static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = { - { .feature = AIE2_NPU_COMMAND, .min_minor = 8 }, + { .major = 5, .min_minor = 7 }, + { .features = BIT_U64(AIE2_NPU_COMMAND), .min_minor = 8 }, { 0 } }; static const struct amdxdna_dev_priv npu1_dev_priv = { .fw_path = "amdnpu/1502_00/npu.sbin", - .protocol_major = 0x5, - .protocol_minor = 0x7, .rt_config = npu1_default_rt_cfg, .dpm_clk_tbl = npu1_dpm_clk_table, .fw_feature_tbl = npu1_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu4_regs.c b/drivers/accel/amdxdna/npu4_regs.c index a62234fd266d..a8d6f76dde5f 100644 --- a/drivers/accel/amdxdna/npu4_regs.c +++ b/drivers/accel/amdxdna/npu4_regs.c @@ -6,6 +6,7 @@ #include <drm/amdxdna_accel.h> #include <drm/drm_device.h> #include <drm/gpu_scheduler.h> +#include <linux/bits.h> #include <linux/sizes.h> #include "aie2_pci.h" @@ -88,16 +89,16 @@ const struct dpm_clk_freq npu4_dpm_clk_table[] = { }; const struct aie2_fw_feature_tbl npu4_fw_feature_table[] = { - { .feature = AIE2_NPU_COMMAND, .min_minor = 15 }, - { .feature = AIE2_PREEMPT, .min_minor = 12 }, - { .feature = AIE2_TEMPORAL_ONLY, .min_minor = 12 }, + { .major = 6, .min_minor = 12 }, + { .features = BIT_U64(AIE2_NPU_COMMAND), .major = 6, .min_minor = 15 }, + { .features = BIT_U64(AIE2_PREEMPT), .major = 6, .min_minor = 12 }, + { .features = BIT_U64(AIE2_TEMPORAL_ONLY), .major = 6, .min_minor = 12 }, + { .features = GENMASK_ULL(AIE2_TEMPORAL_ONLY, AIE2_NPU_COMMAND), .major = 7 }, { 0 } }; static const struct amdxdna_dev_priv npu4_dev_priv = { .fw_path = "amdnpu/17f0_10/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu5_regs.c b/drivers/accel/amdxdna/npu5_regs.c index 131080652ef0..c0a35cfd886c 100644 --- a/drivers/accel/amdxdna/npu5_regs.c +++ b/drivers/accel/amdxdna/npu5_regs.c @@ -64,8 +64,6 @@ static const struct amdxdna_dev_priv npu5_dev_priv = { .fw_path = "amdnpu/17f0_11/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/amdxdna/npu6_regs.c b/drivers/accel/amdxdna/npu6_regs.c index 1f71285655b2..1fb07df99186 100644 --- a/drivers/accel/amdxdna/npu6_regs.c +++ b/drivers/accel/amdxdna/npu6_regs.c @@ -64,8 +64,6 @@ static const struct amdxdna_dev_priv npu6_dev_priv = { .fw_path = "amdnpu/17f0_10/npu.sbin", - .protocol_major = 0x6, - .protocol_minor = 12, .rt_config = npu4_default_rt_cfg, .dpm_clk_tbl = npu4_dpm_clk_table, .fw_feature_tbl = npu4_fw_feature_table, diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 3bd85ee6c26b..a09f54fc4302 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -20,6 +20,7 @@ #include "ivpu_hw.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +#include "vpu_boot_api.h" static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) { @@ -96,7 +97,8 @@ static int last_bootmode_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = seq_to_ivpu(s); - seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); + seq_printf(s, "%s\n", (vdev->fw->last_boot_mode == VPU_BOOT_TYPE_WARMBOOT) ? + "warm boot" : "cold boot"); return 0; } diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 3d6fccdefdd6..8ffda57459df 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -384,6 +384,7 @@ int ivpu_boot(struct ivpu_device *vdev) drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem_bp)); + vdev->fw->last_boot_mode = vdev->fw->next_boot_mode; ret = ivpu_hw_boot_fw(vdev); if (ret) { @@ -396,13 +397,12 @@ int ivpu_boot(struct ivpu_device *vdev) ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); goto err_diagnose_failure; } - ivpu_hw_irq_clear(vdev); enable_irq(vdev->irq); ivpu_hw_irq_enable(vdev); ivpu_ipc_enable(vdev); - if (ivpu_fw_is_cold_boot(vdev)) { + if (!ivpu_fw_is_warm_boot(vdev)) { ret = ivpu_pm_dct_init(vdev); if (ret) goto err_disable_ipc; diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 48386d2cddbb..107f8ad31050 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -300,9 +300,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->image_load_offset = image_load_addr - runtime_addr; fw->image_size = image_size; fw->shave_nn_size = PAGE_ALIGN(fw_hdr->shave_nn_fw_size); - fw->cold_boot_entry_point = fw_hdr->entry_point; - fw->entry_point = fw->cold_boot_entry_point; fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL); fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; @@ -338,7 +336,7 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->image_load_offset, fw->image_size); ivpu_dbg(vdev, FW_BOOT, "Read-only section: address 0x%llx, size %u\n", fw->read_only_addr, fw->read_only_size); - ivpu_dbg(vdev, FW_BOOT, "FW entry point: 0x%llx\n", fw->entry_point); + ivpu_dbg(vdev, FW_BOOT, "FW cold boot entry point: 0x%llx\n", fw->cold_boot_entry_point); ivpu_dbg(vdev, FW_BOOT, "SHAVE NN size: %u\n", fw->shave_nn_size); return 0; @@ -616,6 +614,7 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->power_profile); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_uses_ecc_mca_signal = 0x%x\n", boot_params->vpu_uses_ecc_mca_signal); + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type); } void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params) @@ -623,7 +622,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params struct ivpu_bo *ipc_mem_rx = vdev->ipc->mem_rx; /* In case of warm boot only update variable params */ - if (!ivpu_fw_is_cold_boot(vdev)) { + if (ivpu_fw_is_warm_boot(vdev)) { boot_params->d0i3_residency_time_us = ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; @@ -635,16 +634,16 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->d0i3_entry_vpu_ts); ivpu_dbg(vdev, FW_BOOT, "boot_params.system_time_us = %llu\n", boot_params->system_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.boot_type = 0x%x\n", boot_params->boot_type); boot_params->save_restore_ret_address = 0; - vdev->pm->is_warmboot = true; + boot_params->boot_type = VPU_BOOT_TYPE_WARMBOOT; wmb(); /* Flush WC buffers after writing save_restore_ret_address */ return; } memset(boot_params, 0, sizeof(*boot_params)); - vdev->pm->is_warmboot = false; - + boot_params->boot_type = VPU_BOOT_TYPE_COLDBOOT; boot_params->magic = VPU_BOOT_PARAMS_MAGIC; boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 00945892b55e..d3c410912c9c 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -6,6 +6,7 @@ #ifndef __IVPU_FW_H__ #define __IVPU_FW_H__ +#include "vpu_boot_api.h" #include "vpu_jsm_api.h" #define FW_VERSION_HEADER_SIZE SZ_4K @@ -34,8 +35,10 @@ struct ivpu_fw_info { u64 image_load_offset; u32 image_size; u32 shave_nn_size; - u64 entry_point; /* Cold or warm boot entry point for next boot */ + u64 warm_boot_entry_point; u64 cold_boot_entry_point; + u8 last_boot_mode; + u8 next_boot_mode; u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; @@ -54,9 +57,9 @@ void ivpu_fw_fini(struct ivpu_device *vdev); void ivpu_fw_load(struct ivpu_device *vdev); void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params *boot_params); -static inline bool ivpu_fw_is_cold_boot(struct ivpu_device *vdev) +static inline bool ivpu_fw_is_warm_boot(struct ivpu_device *vdev) { - return vdev->fw->entry_point == vdev->fw->cold_boot_entry_point; + return vdev->fw->next_boot_mode == VPU_BOOT_TYPE_WARMBOOT; } static inline u32 ivpu_fw_preempt_buf_size(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h index fc0ee8d637f9..421242acb184 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h @@ -121,6 +121,12 @@ #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0) +#define VPU_40XX_HOST_SS_AON_RETENTION0 0x0003000cu +#define VPU_40XX_HOST_SS_AON_RETENTION1 0x00030010u +#define VPU_40XX_HOST_SS_AON_RETENTION2 0x00030014u +#define VPU_40XX_HOST_SS_AON_RETENTION3 0x00030018u +#define VPU_40XX_HOST_SS_AON_RETENTION4 0x0003001cu + #define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u #define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0) #define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1) diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c index 06aa1e7dc50b..959984c54341 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.c +++ b/drivers/accel/ivpu/ivpu_hw_ip.c @@ -5,6 +5,7 @@ #include "ivpu_drv.h" #include "ivpu_fw.h" +#include "ivpu_gem.h" #include "ivpu_hw.h" #include "ivpu_hw_37xx_reg.h" #include "ivpu_hw_40xx_reg.h" @@ -816,6 +817,14 @@ void ivpu_hw_ip_tbu_mmu_enable(struct ivpu_device *vdev) return ivpu_hw_ip_tbu_mmu_enable_40xx(vdev); } +static inline u64 get_entry_point_addr(struct ivpu_device *vdev) +{ + if (ivpu_fw_is_warm_boot(vdev)) + return vdev->fw->warm_boot_entry_point; + else + return vdev->fw->cold_boot_entry_point; +} + static int soc_cpu_boot_37xx(struct ivpu_device *vdev) { u32 val; @@ -832,15 +841,12 @@ static int soc_cpu_boot_37xx(struct ivpu_device *vdev) val = REG_CLR_FLD(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, IRQI_RESUME0, val); REGV_WR32(VPU_37XX_CPU_SS_MSSCPU_CPR_LEON_RT_VEC, val); - val = vdev->fw->entry_point >> 9; + val = get_entry_point_addr(vdev) >> 9; REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val); val = REG_SET_FLD(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, DONE, val); REGV_WR32(VPU_37XX_HOST_SS_LOADING_ADDRESS_LO, val); - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", - vdev->fw->entry_point == vdev->fw->cold_boot_entry_point ? "cold boot" : "resume"); - return 0; } @@ -894,46 +900,68 @@ static int soc_cpu_drive_40xx(struct ivpu_device *vdev, bool enable) return ret; } -static int soc_cpu_enable(struct ivpu_device *vdev) +static void soc_cpu_set_entry_point_40xx(struct ivpu_device *vdev, u64 entry_point) { - if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_60XX) - return 0; + u64 val64; + u32 val; + + val64 = entry_point; + val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1; + REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64); - return soc_cpu_drive_40xx(vdev, true); + val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO); + val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val); + REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val); } static int soc_cpu_boot_40xx(struct ivpu_device *vdev) { int ret; - u32 val; - u64 val64; - ret = soc_cpu_enable(vdev); + ret = soc_cpu_drive_40xx(vdev, true); if (ret) { ivpu_err(vdev, "Failed to enable SOC CPU: %d\n", ret); return ret; } - val64 = vdev->fw->entry_point; - val64 <<= ffs(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO_IMAGE_LOCATION_MASK) - 1; - REGV_WR64(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val64); + soc_cpu_set_entry_point_40xx(vdev, get_entry_point_addr(vdev)); - val = REGV_RD32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO); - val = REG_SET_FLD(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, DONE, val); - REGV_WR32(VPU_40XX_HOST_SS_VERIFICATION_ADDRESS_LO, val); + return 0; +} - ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", - ivpu_fw_is_cold_boot(vdev) ? "cold boot" : "resume"); +static int soc_cpu_boot_60xx(struct ivpu_device *vdev) +{ + REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr); + soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point); return 0; } int ivpu_hw_ip_soc_cpu_boot(struct ivpu_device *vdev) { - if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) - return soc_cpu_boot_37xx(vdev); - else - return soc_cpu_boot_40xx(vdev); + int ret; + + switch (ivpu_hw_ip_gen(vdev)) { + case IVPU_HW_IP_37XX: + ret = soc_cpu_boot_37xx(vdev); + break; + + case IVPU_HW_IP_40XX: + case IVPU_HW_IP_50XX: + ret = soc_cpu_boot_40xx(vdev); + break; + + default: + ret = soc_cpu_boot_60xx(vdev); + } + + if (ret) + return ret; + + ivpu_dbg(vdev, PM, "Booting firmware, mode: %s\n", + ivpu_fw_is_warm_boot(vdev) ? "warm boot" : "cold boot"); + + return 0; } static void wdt_disable_37xx(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_hw_ip.h b/drivers/accel/ivpu/ivpu_hw_ip.h index 5b1b391aa577..dbbcdd10a5f8 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.h +++ b/drivers/accel/ivpu/ivpu_hw_ip.h @@ -29,7 +29,6 @@ u32 ivpu_hw_ip_ipc_rx_addr_get(struct ivpu_device *vdev); void ivpu_hw_ip_ipc_tx_set(struct ivpu_device *vdev, u32 vpu_addr); void ivpu_hw_ip_irq_enable(struct ivpu_device *vdev); void ivpu_hw_ip_irq_disable(struct ivpu_device *vdev); -void ivpu_hw_ip_diagnose_failure(struct ivpu_device *vdev); void ivpu_hw_ip_fabric_req_override_enable_50xx(struct ivpu_device *vdev); void ivpu_hw_ip_fabric_req_override_disable_50xx(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 480c075d87f6..d20144a21e09 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -47,8 +47,10 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev) ivpu_ipc_reset(vdev); ivpu_fw_log_reset(vdev); ivpu_fw_load(vdev); - fw->entry_point = fw->cold_boot_entry_point; fw->last_heartbeat = 0; + + ivpu_dbg(vdev, FW_BOOT, "Cold boot entry point 0x%llx", vdev->fw->cold_boot_entry_point); + fw->next_boot_mode = VPU_BOOT_TYPE_COLDBOOT; } static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev) @@ -56,13 +58,14 @@ static void ivpu_pm_prepare_warm_boot(struct ivpu_device *vdev) struct ivpu_fw_info *fw = vdev->fw; struct vpu_boot_params *bp = ivpu_bo_vaddr(fw->mem_bp); - if (!bp->save_restore_ret_address) { + fw->warm_boot_entry_point = bp->save_restore_ret_address; + if (!fw->warm_boot_entry_point) { ivpu_pm_prepare_cold_boot(vdev); return; } - ivpu_dbg(vdev, FW_BOOT, "Save/restore entry point %llx", bp->save_restore_ret_address); - fw->entry_point = bp->save_restore_ret_address; + ivpu_dbg(vdev, FW_BOOT, "Warm boot entry point 0x%llx", fw->warm_boot_entry_point); + fw->next_boot_mode = VPU_BOOT_TYPE_WARMBOOT; } static int ivpu_suspend(struct ivpu_device *vdev) @@ -110,7 +113,7 @@ err_power_down: ivpu_hw_power_down(vdev); pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); - if (!ivpu_fw_is_cold_boot(vdev)) { + if (ivpu_fw_is_warm_boot(vdev)) { ivpu_pm_prepare_cold_boot(vdev); goto retry; } else { diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index a2aa7a27f32e..00f2a01e3df6 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -18,7 +18,6 @@ struct ivpu_pm_info { struct rw_semaphore reset_lock; atomic_t reset_counter; atomic_t reset_pending; - bool is_warmboot; u8 dct_active_percent; }; diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c index abe7719c1db4..b3b2fa9ba645 100644 --- a/drivers/accel/rocket/rocket_core.c +++ b/drivers/accel/rocket/rocket_core.c @@ -59,8 +59,11 @@ int rocket_core_init(struct rocket_core *core) core->iommu_group = iommu_group_get(dev); err = rocket_job_init(core); - if (err) + if (err) { + iommu_group_put(core->iommu_group); + core->iommu_group = NULL; return err; + } pm_runtime_use_autosuspend(dev); @@ -76,7 +79,7 @@ int rocket_core_init(struct rocket_core *core) err = pm_runtime_resume_and_get(dev); if (err) { - rocket_job_fini(core); + rocket_core_fini(core); return err; } diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c index 5c0b63f0a8f0..e4cb2efeb55a 100644 --- a/drivers/accel/rocket/rocket_drv.c +++ b/drivers/accel/rocket/rocket_drv.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include "rocket_device.h" #include "rocket_drv.h" #include "rocket_gem.h" #include "rocket_job.h" @@ -158,6 +159,8 @@ static const struct drm_driver rocket_drm_driver = { static int rocket_probe(struct platform_device *pdev) { + int ret; + if (rdev == NULL) { /* First core probing, initialize DRM device. */ rdev = rocket_device_init(drm_dev, &rocket_drm_driver); @@ -177,20 +180,31 @@ static int rocket_probe(struct platform_device *pdev) rdev->num_cores++; - return rocket_core_init(&rdev->cores[core]); + ret = rocket_core_init(&rdev->cores[core]); + if (ret) { + rdev->num_cores--; + + if (rdev->num_cores == 0) { + rocket_device_fini(rdev); + rdev = NULL; + } + } + + return ret; } +static int find_core_for_dev(struct device *dev); + static void rocket_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + int core = find_core_for_dev(dev); - for (unsigned int core = 0; core < rdev->num_cores; core++) { - if (rdev->cores[core].dev == dev) { - rocket_core_fini(&rdev->cores[core]); - rdev->num_cores--; - break; - } - } + if (core < 0) + return; + + rocket_core_fini(&rdev->cores[core]); + rdev->num_cores--; if (rdev->num_cores == 0) { /* Last core removed, deinitialize DRM device. */ diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c index 7237f14eaf5a..4e7115b247e7 100644 --- a/drivers/crypto/tegra/tegra-se-main.c +++ b/drivers/crypto/tegra/tegra-se-main.c @@ -401,11 +401,9 @@ static int tegra_se_host1x_probe(struct host1x_device *dev) return host1x_device_init(dev); } -static int tegra_se_host1x_remove(struct host1x_device *dev) +static void tegra_se_host1x_remove(struct host1x_device *dev) { host1x_device_exit(dev); - - return 0; } static struct host1x_driver tegra_se_host1x_driver = { diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 42f88193eab9..49cc45fb42dd 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -331,7 +331,7 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, while (nr_clear_pages > 0) { void *vaddr = kmap_local_page(page); - memset(vaddr, 0, PAGE_SIZE); + clear_page(vaddr); kunmap_local(vaddr); /* * Avoid wasting time zeroing memory if the process diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index 2e3ee78999d9..8c5912b59e19 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -1676,8 +1676,8 @@ dm_atomic_plane_set_property(struct drm_plane *plane, if (property == adev->mode_info.plane_degamma_lut_property) { ret = drm_property_replace_blob_from_id(plane->dev, &dm_plane_state->degamma_lut, - val, -1, - sizeof(struct drm_color_lut), + val, + -1, -1, sizeof(struct drm_color_lut), &replaced); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; @@ -1695,15 +1695,15 @@ dm_atomic_plane_set_property(struct drm_plane *plane, ret = drm_property_replace_blob_from_id(plane->dev, &dm_plane_state->ctm, val, - sizeof(struct drm_color_ctm_3x4), -1, + -1, sizeof(struct drm_color_ctm_3x4), -1, &replaced); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; } else if (property == adev->mode_info.plane_shaper_lut_property) { ret = drm_property_replace_blob_from_id(plane->dev, &dm_plane_state->shaper_lut, - val, -1, - sizeof(struct drm_color_lut), + val, + -1, -1, sizeof(struct drm_color_lut), &replaced); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; @@ -1715,16 +1715,16 @@ dm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == adev->mode_info.plane_lut3d_property) { ret = drm_property_replace_blob_from_id(plane->dev, &dm_plane_state->lut3d, - val, -1, - sizeof(struct drm_color_lut), + val, + -1, -1, sizeof(struct drm_color_lut), &replaced); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; } else if (property == adev->mode_info.plane_blend_lut_property) { ret = drm_property_replace_blob_from_id(plane->dev, &dm_plane_state->blend_lut, - val, -1, - sizeof(struct drm_color_lut), + val, + -1, -1, sizeof(struct drm_color_lut), &replaced); dm_plane_state->base.color_mgmt_changed |= replaced; return ret; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index fe4c026280f0..0c7ad06aaca4 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -165,6 +165,7 @@ struct dw_hdmi_qp { struct regmap *regm; unsigned long tmds_char_rate; + bool no_hpd; }; static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, @@ -555,14 +556,22 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); if (!stat) { - dev_err(hdmi->dev, "i2c read timed out\n"); + if (hdmi->no_hpd) + dev_dbg_ratelimited(hdmi->dev, + "i2c read timed out\n"); + else + dev_err(hdmi->dev, "i2c read timed out\n"); dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); return -EAGAIN; } /* Check for error condition on the bus */ if (i2c->stat & I2CM_NACK_RCVD_IRQ) { - dev_err(hdmi->dev, "i2c read error\n"); + if (hdmi->no_hpd) + dev_dbg_ratelimited(hdmi->dev, + "i2c read error\n"); + else + dev_err(hdmi->dev, "i2c read error\n"); dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); return -EIO; } @@ -900,6 +909,15 @@ static enum drm_connector_status dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) { struct dw_hdmi_qp *hdmi = bridge->driver_private; + const struct drm_edid *drm_edid; + + if (hdmi->no_hpd) { + drm_edid = drm_edid_read_ddc(connector, bridge->ddc); + if (drm_edid) + return connector_status_connected; + else + return connector_status_disconnected; + } return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); } @@ -925,6 +943,11 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge, { struct dw_hdmi_qp *hdmi = bridge->driver_private; + /* + * TODO: when hdmi->no_hpd is 1 we must not support modes that + * require scrambling, including every mode with a clock above + * HDMI14_MAX_TMDSCLK. + */ if (rate > HDMI14_MAX_TMDSCLK) { dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate); return MODE_CLOCK_HIGH; @@ -1277,12 +1300,15 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, if (ret) return ERR_PTR(ret); + hdmi->no_hpd = device_property_read_bool(dev, "no-hpd"); + hdmi->bridge.driver_private = hdmi; hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HDMI | - DRM_BRIDGE_OP_HDMI_AUDIO | - DRM_BRIDGE_OP_HPD; + DRM_BRIDGE_OP_HDMI_AUDIO; + if (!hdmi->no_hpd) + hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD; hdmi->bridge.of_node = pdev->dev.of_node; hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; hdmi->bridge.vendor = "Synopsys"; diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 7320db4b8489..dc013a22bf26 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -413,10 +413,19 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, } else if (property == config->prop_vrr_enabled) { state->vrr_enabled = val; } else if (property == config->degamma_lut_property) { + const size_t elem_size = sizeof(struct drm_color_lut); + u64 lut_size; + + ret = drm_object_immutable_property_get_value(&crtc->base, + config->degamma_lut_size_property, + &lut_size); + if (ret) + return ret; + ret = drm_property_replace_blob_from_id(dev, &state->degamma_lut, val, - -1, sizeof(struct drm_color_lut), + elem_size * lut_size, -1, elem_size, &replaced); state->color_mgmt_changed |= replaced; return ret; @@ -424,15 +433,24 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, ret = drm_property_replace_blob_from_id(dev, &state->ctm, val, - sizeof(struct drm_color_ctm), -1, + -1, sizeof(struct drm_color_ctm), -1, &replaced); state->color_mgmt_changed |= replaced; return ret; } else if (property == config->gamma_lut_property) { + const size_t elem_size = sizeof(struct drm_color_lut); + u64 lut_size; + + ret = drm_object_immutable_property_get_value(&crtc->base, + config->gamma_lut_size_property, + &lut_size); + if (ret) + return ret; + ret = drm_property_replace_blob_from_id(dev, &state->gamma_lut, val, - -1, sizeof(struct drm_color_lut), + elem_size * lut_size, -1, elem_size, &replaced); state->color_mgmt_changed |= replaced; return ret; @@ -587,8 +605,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, ret = drm_property_replace_blob_from_id(dev, &state->fb_damage_clips, val, - -1, - sizeof(struct drm_mode_rect), + -1, -1, sizeof(struct drm_mode_rect), &replaced); return ret; } else if (property == plane->scaling_filter_property) { @@ -717,8 +734,7 @@ static int drm_atomic_color_set_data_property(struct drm_colorop *colorop, return drm_property_replace_blob_from_id(colorop->dev, &state->data, val, - size, - elem_size, + -1, size, elem_size, &replaced); } @@ -876,7 +892,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, ret = drm_property_replace_blob_from_id(dev, &state->hdr_output_metadata, val, - sizeof(struct hdr_output_metadata), -1, + -1, sizeof(struct hdr_output_metadata), -1, &replaced); return ret; } else if (property == config->aspect_ratio_property) { diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 127fbebcf175..7ff6b7bbeb73 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -1302,12 +1302,13 @@ unsigned long drm_gem_get_unmapped_area(struct file *filp, unsigned long uaddr, unsigned long ret; obj = drm_gem_object_lookup_at_offset(filp, pgoff, len >> PAGE_SHIFT); - if (IS_ERR(obj) || !obj->filp || !obj->filp->f_op->get_unmapped_area) - return mm_get_unmapped_area(filp, uaddr, len, 0, - flags); + if (IS_ERR(obj)) + obj = NULL; - ret = obj->filp->f_op->get_unmapped_area(obj->filp, uaddr, len, 0, - flags); + if (!obj || !obj->filp || !obj->filp->f_op->get_unmapped_area) + ret = mm_get_unmapped_area(filp, uaddr, len, 0, flags); + else + ret = obj->filp->f_op->get_unmapped_area(obj->filp, uaddr, len, 0, flags); drm_gem_object_put(obj); diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 8a06d296561d..c75b4877ab92 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1815,8 +1815,8 @@ drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, EXPORT_SYMBOL_GPL(drm_gpuvm_bo_find); /** - * drm_gpuvm_bo_obtain() - obtains an instance of the &drm_gpuvm_bo for the - * given &drm_gpuvm and &drm_gem_object + * drm_gpuvm_bo_obtain_locked() - obtains an instance of the &drm_gpuvm_bo for + * the given &drm_gpuvm and &drm_gem_object * @gpuvm: The &drm_gpuvm the @obj is mapped in. * @obj: The &drm_gem_object being mapped in the @gpuvm. * @@ -1825,16 +1825,26 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_find); * count of the &drm_gpuvm_bo accordingly. If not found, allocates a new * &drm_gpuvm_bo. * + * Requires the lock for the GEMs gpuva list. + * * A new &drm_gpuvm_bo is added to the GEMs gpuva list. * * Returns: a pointer to the &drm_gpuvm_bo on success, an ERR_PTR on failure */ struct drm_gpuvm_bo * -drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, - struct drm_gem_object *obj) +drm_gpuvm_bo_obtain_locked(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) { struct drm_gpuvm_bo *vm_bo; + /* + * In immediate mode this would require the caller to hold the GEMs + * gpuva mutex, but it's not okay to allocate while holding that lock, + * and this method allocates. Immediate mode drivers should use + * drm_gpuvm_bo_obtain_prealloc() instead. + */ + drm_WARN_ON(gpuvm->drm, drm_gpuvm_immediate_mode(gpuvm)); + vm_bo = drm_gpuvm_bo_find(gpuvm, obj); if (vm_bo) return vm_bo; @@ -1848,7 +1858,7 @@ drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, return vm_bo; } -EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain_locked); /** * drm_gpuvm_bo_obtain_prealloc() - obtains an instance of the &drm_gpuvm_bo @@ -2258,7 +2268,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_interval_empty); void drm_gpuva_map(struct drm_gpuvm *gpuvm, struct drm_gpuva *va, - struct drm_gpuva_op_map *op) + const struct drm_gpuva_op_map *op) { drm_gpuva_init_from_op(va, op); drm_gpuva_insert(gpuvm, va); @@ -2278,7 +2288,7 @@ EXPORT_SYMBOL_GPL(drm_gpuva_map); void drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva *next, - struct drm_gpuva_op_remap *op) + const struct drm_gpuva_op_remap *op) { struct drm_gpuva *va = op->unmap->va; struct drm_gpuvm *gpuvm = va->vm; @@ -2305,7 +2315,7 @@ EXPORT_SYMBOL_GPL(drm_gpuva_remap); * Removes the &drm_gpuva associated with the &drm_gpuva_op_unmap. */ void -drm_gpuva_unmap(struct drm_gpuva_op_unmap *op) +drm_gpuva_unmap(const struct drm_gpuva_op_unmap *op) { drm_gpuva_remove(op->va); } diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index b45d501b10c8..2d943a610b88 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -385,6 +385,31 @@ int drm_object_property_get_default_value(struct drm_mode_object *obj, } EXPORT_SYMBOL(drm_object_property_get_default_value); +/** + * drm_object_immutable_property_get_value - retrieve the value of a property + * @obj: drm mode object to get property value from + * @property: property to retrieve + * @val: storage for the property value + * + * This function retrieves the software state of the given immutable property + * for the given mode object. + * + * This function can be called by both atomic and non-atomic drivers. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_object_immutable_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t *val) +{ + if (drm_WARN_ON(property->dev, !(property->flags & DRM_MODE_PROP_IMMUTABLE))) + return -EINVAL; + + return __drm_object_property_get_prop_value(obj, property, val); +} +EXPORT_SYMBOL(drm_object_immutable_property_get_value); + /* helper for getconnector and getproperties ioctls */ int drm_mode_object_get_properties(struct drm_mode_object *obj, bool atomic, bool plane_color_pipeline, diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index eb7ef17b9c71..d6d3b8d85dea 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -823,7 +823,7 @@ static const char *drm_panic_type_map[] = { [DRM_PANIC_TYPE_KMSG] = "kmsg", [DRM_PANIC_TYPE_USER] = "user", #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) - [DRM_PANIC_TYPE_QR] = "qr", + [DRM_PANIC_TYPE_QR] = "qr_code", #endif }; @@ -855,7 +855,7 @@ static const struct kernel_param_ops drm_panic_ops = { module_param_cb(panic_screen, &drm_panic_ops, NULL, 0644); MODULE_PARM_DESC(panic_screen, #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) - "Choose what will be displayed by drm_panic, 'user', 'kmsg' or 'qr' [default=" + "Choose what will be displayed by drm_panic, 'user', 'kmsg' or 'qr_code' [default=" #else "Choose what will be displayed by drm_panic, 'user' or 'kmsg' [default=" #endif @@ -1072,8 +1072,11 @@ void drm_panic_unregister(struct drm_device *dev) */ void __init drm_panic_init(void) { - if (drm_panic_type == -1) - drm_panic_type_set(CONFIG_DRM_PANIC_SCREEN, NULL); + if (drm_panic_type == -1 && drm_panic_type_set(CONFIG_DRM_PANIC_SCREEN, NULL)) { + pr_warn("Unsupported value for CONFIG_DRM_PANIC_SCREEN ('%s'), falling back to 'user'...\n", + CONFIG_DRM_PANIC_SCREEN); + drm_panic_type = DRM_PANIC_TYPE_USER; + } drm_panic_qr_init(); } diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index 596272149a35..955fa960843b 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -757,6 +757,7 @@ EXPORT_SYMBOL(drm_property_replace_blob); * @dev: DRM device * @blob: a pointer to the member blob to be replaced * @blob_id: the id of the new blob to replace with + * @max_size: the maximum size of the blob property for variable-size blobs * @expected_size: expected size of the blob property * @expected_elem_size: expected size of an element in the blob property * @replaced: if the blob was in fact replaced @@ -771,6 +772,7 @@ EXPORT_SYMBOL(drm_property_replace_blob); int drm_property_replace_blob_from_id(struct drm_device *dev, struct drm_property_blob **blob, uint64_t blob_id, + ssize_t max_size, ssize_t expected_size, ssize_t expected_elem_size, bool *replaced) @@ -785,6 +787,15 @@ int drm_property_replace_blob_from_id(struct drm_device *dev, return -EINVAL; } + if (max_size > 0 && + new_blob->length > max_size) { + drm_dbg_atomic(dev, + "[BLOB:%d] length %zu greater than max %zu\n", + new_blob->base.id, new_blob->length, max_size); + drm_property_blob_put(new_blob); + return -EINVAL; + } + if (expected_size > 0 && new_blob->length != expected_size) { drm_dbg_atomic(dev, diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index 48e52c5561be..9a9ad4e82305 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -256,7 +256,7 @@ pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, bind_op->type = PVR_VM_BIND_TYPE_MAP; dma_resv_lock(obj->resv, NULL); - bind_op->gpuvm_bo = drm_gpuvm_bo_obtain(&vm_ctx->gpuvm_mgr, obj); + bind_op->gpuvm_bo = drm_gpuvm_bo_obtain_locked(&vm_ctx->gpuvm_mgr, obj); dma_resv_unlock(obj->resv); if (IS_ERR(bind_op->gpuvm_bo)) return PTR_ERR(bind_op->gpuvm_bo); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index a4cf31853c50..26dfe3d22e3e 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -60,7 +60,7 @@ struct msm_gem_vm_log_entry { * embedded in any larger driver structure. The GEM object holds a list of * drm_gpuvm_bo, which in turn holds a list of msm_gem_vma. A linked vma * holds a reference to the vm_bo, and drops it when the vma is unlinked. - * So we just need to call drm_gpuvm_bo_obtain() to return a ref to an + * So we just need to call drm_gpuvm_bo_obtain_locked() to return a ref to an * existing vm_bo, or create a new one. Once the vma is linked, the ref * to the vm_bo can be dropped (since the vma is holding one). */ diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 71d5238437eb..71943104ce9f 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -413,7 +413,7 @@ msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj, if (!obj) return &vma->base; - vm_bo = drm_gpuvm_bo_obtain(&vm->base, obj); + vm_bo = drm_gpuvm_bo_obtain_locked(&vm->base, obj); if (IS_ERR(vm_bo)) { ret = PTR_ERR(vm_bo); goto err_va_remove; diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index f10809115c56..0d693760d222 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -1275,7 +1275,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job, return -ENOENT; dma_resv_lock(obj->resv, NULL); - op->vm_bo = drm_gpuvm_bo_obtain(&uvmm->base, obj); + op->vm_bo = drm_gpuvm_bo_obtain_locked(&uvmm->base, obj); dma_resv_unlock(obj->resv); if (IS_ERR(op->vm_bo)) return PTR_ERR(op->vm_bo); diff --git a/drivers/gpu/drm/panel/panel-himax-hx83102.c b/drivers/gpu/drm/panel/panel-himax-hx83102.c index 4c432d207634..1d3bb5dca559 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83102.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83102.c @@ -859,7 +859,7 @@ static int hx83102_unprepare(struct drm_panel *panel) { struct hx83102 *ctx = panel_to_hx83102(panel); - gpiod_set_value(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); usleep_range(1000, 2000); regulator_disable(ctx->avee); regulator_disable(ctx->avdd); @@ -875,7 +875,7 @@ static int hx83102_prepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = ctx->dsi; struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; - gpiod_set_value(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); usleep_range(1000, 1500); dsi_ctx.accum_err = regulator_enable(ctx->pp1800); @@ -899,11 +899,11 @@ static int hx83102_prepare(struct drm_panel *panel) usleep_range(1000, 2000); - gpiod_set_value(ctx->enable_gpio, 1); + gpiod_set_value_cansleep(ctx->enable_gpio, 1); usleep_range(1000, 2000); - gpiod_set_value(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); usleep_range(1000, 2000); - gpiod_set_value(ctx->enable_gpio, 1); + gpiod_set_value_cansleep(ctx->enable_gpio, 1); usleep_range(6000, 10000); dsi_ctx.accum_err = ctx->desc->init(ctx); @@ -917,7 +917,7 @@ static int hx83102_prepare(struct drm_panel *panel) return 0; poweroff: - gpiod_set_value(ctx->enable_gpio, 0); + gpiod_set_value_cansleep(ctx->enable_gpio, 0); regulator_disable(ctx->avee); poweroffavdd: regulator_disable(ctx->avdd); diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c index c52f20863fc7..370424ddfc80 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9882t.c @@ -8,6 +8,8 @@ #include <linux/of.h> #include <linux/regulator/consumer.h> +#include <drm/display/drm_dsc.h> +#include <drm/display/drm_dsc_helper.h> #include <drm/drm_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> @@ -15,6 +17,8 @@ #include <video/mipi_display.h> +#define DSC_BPG_OFFSET(x) ((u8)((x) & DSC_RANGE_BPG_OFFSET_MASK)) + struct ili9882t; /* @@ -23,6 +27,7 @@ struct ili9882t; */ struct panel_desc { const struct drm_display_mode *modes; + const struct drm_dsc_config *dsc; unsigned int bpc; /** @@ -52,6 +57,8 @@ struct ili9882t { struct regulator *avee; struct regulator *avdd; struct gpio_desc *enable_gpio; + + struct drm_dsc_config dsc; }; /* ILI9882-specific commands, add new commands as you decode them */ @@ -68,6 +75,67 @@ struct ili9882t { mipi_dsi_dcs_write_seq_multi(ctx, IL79900A_DCS_SWITCH_PAGE, \ 0x5a, 0xa5, (page)) +static const struct drm_dsc_config tianma_il79900a_dsc = { + .dsc_version_major = 1, + .dsc_version_minor = 2, + .slice_height = 8, + .slice_width = 800, + .slice_count = 2, + .bits_per_component = 8, + .bits_per_pixel = 8 << 4, + .block_pred_enable = true, + .native_420 = false, + .native_422 = false, + .simple_422 = false, + .vbr_enable = false, + .rc_model_size = DSC_RC_MODEL_SIZE_CONST, + .pic_width = 1600, + .pic_height = 2560, + .convert_rgb = 0, + .vbr_enable = 0, + .rc_buf_thresh = {14, 28, 42, 56, 70, 84, 98, 105, 112, 119, 121, 123, 125, 126}, + .rc_model_size = DSC_RC_MODEL_SIZE_CONST, + .rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST, + .rc_tgt_offset_high = DSC_RC_TGT_OFFSET_HI_CONST, + .rc_tgt_offset_low = DSC_RC_TGT_OFFSET_LO_CONST, + .mux_word_size = DSC_MUX_WORD_SIZE_8_10_BPC, + .line_buf_depth = 9, + .first_line_bpg_offset = 12, + .initial_xmit_delay = 512, + .initial_offset = 6144, + .rc_quant_incr_limit0 = 11, + .rc_quant_incr_limit1 = 11, + .nfl_bpg_offset = 1402, + .rc_range_params = { + { 0, 4, DSC_BPG_OFFSET(2)}, + { 0, 4, DSC_BPG_OFFSET(0)}, + { 1, 5, DSC_BPG_OFFSET(0)}, + { 1, 6, DSC_BPG_OFFSET(-2)}, + { 3, 7, DSC_BPG_OFFSET(-4)}, + { 3, 7, DSC_BPG_OFFSET(-6)}, + { 3, 7, DSC_BPG_OFFSET(-8)}, + { 3, 8, DSC_BPG_OFFSET(-8)}, + { 3, 9, DSC_BPG_OFFSET(-8)}, + { 3, 10, DSC_BPG_OFFSET(-10)}, + { 5, 10, DSC_BPG_OFFSET(-10)}, + { 5, 11, DSC_BPG_OFFSET(-12)}, + { 5, 11, DSC_BPG_OFFSET(-12)}, + { 9, 12, DSC_BPG_OFFSET(-12)}, + {12, 13, DSC_BPG_OFFSET(-12)}, + }, + .initial_scale_value = 32, + .slice_chunk_size = 800, + .initial_dec_delay = 657, + .final_offset = 4320, + .scale_increment_interval = 222, + .scale_decrement_interval = 11, + .initial_scale_value = 32, + .nfl_bpg_offset = 3511, + .slice_bpg_offset = 2179, + .flatness_max_qp = 12, + .flatness_min_qp = 3, +}; + static int starry_ili9882t_init(struct ili9882t *ili) { struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi }; @@ -423,22 +491,72 @@ static int starry_ili9882t_init(struct ili9882t *ili) static int tianma_il79900a_init(struct ili9882t *ili) { struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi }; + struct drm_dsc_picture_parameter_set pps; mipi_dsi_usleep_range(&ctx, 5000, 5100); il79900a_switch_page(&ctx, 0x06); mipi_dsi_dcs_write_seq_multi(&ctx, 0x3e, 0x62); + il79900a_switch_page(&ctx, 0x01); + mipi_dsi_dcs_write_seq_multi(&ctx, 0xb0, 0x00); + il79900a_switch_page(&ctx, 0x02); - mipi_dsi_dcs_write_seq_multi(&ctx, 0x1b, 0x20); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x1b, 0x00); mipi_dsi_dcs_write_seq_multi(&ctx, 0x5d, 0x00); mipi_dsi_dcs_write_seq_multi(&ctx, 0x5e, 0x40); + il79900a_switch_page(&ctx, 0x05); + mipi_dsi_dcs_write_seq_multi(&ctx, 0X9e, 0xe9); + il79900a_switch_page(&ctx, 0x07); - mipi_dsi_dcs_write_seq_multi(&ctx, 0X29, 0x00); + mipi_dsi_dcs_write_seq_multi(&ctx, 0X29, 0x01); + + il79900a_switch_page(&ctx, 0x17); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, + 0x00, 0x89, 0x30, 0x80, 0x0a, 0x00, 0x06, 0x40, 0x00, + 0x08, 0x03, 0x20, 0x03, 0x20, 0x02, 0x00, 0x02, 0x91, + 0x00, 0x20, 0x00, 0xde, 0x00, 0x0b, 0x00, 0x0c, 0x0d, + 0xb7, 0x08, 0x83, 0x18, 0x00, 0x10, 0xe0, 0x03, 0x0c, + 0x20, 0x00, 0x06, 0x0b, 0x0b, 0x33, 0x0e, 0x1c, 0x2a, + 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, + 0x7d, 0x7e, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40, 0x09, + 0xbe, 0x19, 0xfc, 0x19, 0xfa, 0x19, 0xf8, 0x1a, 0x38, + 0x1a, 0x78, 0x1a, 0xb6, 0x2a, 0xb6, 0x2a, 0xf4, 0x2a, + 0xf4, 0x4b, 0x34, 0x63, 0x74); il79900a_switch_page(&ctx, 0x06); - mipi_dsi_dcs_write_seq_multi(&ctx, 0x92, 0x22); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x91, 0x45); + + il79900a_switch_page(&ctx, 0x16); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x03, 0x4b); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x04, 0x73); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x05, 0xdf); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x00, 0x01); + + il79900a_switch_page(&ctx, 0x10); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x12, 0x8c); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x14, 0x3c); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x15, 0x3d); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x1d, 0xfc); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x25, 0x9d); + + il79900a_switch_page(&ctx, 0x0e); + mipi_dsi_dcs_write_seq_multi(&ctx, 0xc0, 0x18); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x2a, 0x0e); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x38, 0xcd); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x80, 0x53); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x81, 0x0e); + + il79900a_switch_page(&ctx, 0x1e); + mipi_dsi_dcs_write_seq_multi(&ctx, 0x61, 0x5c); + + drm_dsc_pps_payload_pack(&pps, &tianma_il79900a_dsc); + + mipi_dsi_picture_parameter_set_multi(&ctx, &pps); + + mipi_dsi_compression_mode_ext_multi(&ctx, true, + MIPI_DSI_COMPRESSION_DSC, 1); il79900a_switch_page(&ctx, 0x00); mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); @@ -447,9 +565,9 @@ static int tianma_il79900a_init(struct ili9882t *ili) mipi_dsi_dcs_set_display_on_multi(&ctx); - mipi_dsi_msleep(&ctx, 80); + mipi_dsi_msleep(&ctx, 20); - return 0; + return ctx.accum_err; }; static inline struct ili9882t *to_ili9882t(struct drm_panel *panel) @@ -569,15 +687,15 @@ static const struct drm_display_mode starry_ili9882t_default_mode = { }; static const struct drm_display_mode tianma_il79900a_default_mode = { - .clock = 264355, + .clock = 543850, .hdisplay = 1600, .hsync_start = 1600 + 20, - .hsync_end = 1600 + 20 + 4, - .htotal = 1600 + 20 + 4 + 20, + .hsync_end = 1600 + 20 + 2, + .htotal = 1600 + 20 + 2 + 20, .vdisplay = 2560, - .vsync_start = 2560 + 82, - .vsync_end = 2560 + 82 + 2, - .vtotal = 2560 + 82 + 2 + 36, + .vsync_start = 2560 + 62, + .vsync_end = 2560 + 62 + 2, + .vtotal = 2560 + 62 + 2 + 136, .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, }; @@ -597,6 +715,7 @@ static const struct panel_desc starry_ili9882t_desc = { static const struct panel_desc tianma_tl121bvms07_desc = { .modes = &tianma_il79900a_default_mode, + .dsc = &tianma_il79900a_dsc, .bpc = 8, .size = { .width_mm = 163, @@ -716,6 +835,12 @@ static int ili9882t_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = desc->mode_flags; ili->desc = desc; ili->dsi = dsi; + + if (desc->dsc) { + ili->dsc = *desc->dsc; + dsi->dsc = &ili->dsc; + } + ret = ili9882t_add(ili); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c index 23462065d726..ea975170faff 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -434,8 +434,10 @@ static void jdi_panel_dsi_remove(struct mipi_dsi_device *dsi) int err; /* only detach from host for the DSI-LINK2 interface */ - if (!jdi) + if (!jdi) { mipi_dsi_detach(dsi); + return; + } err = jdi_panel_disable(&jdi->base); if (err < 0) diff --git a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c index 55664f5d5aa5..13352cb4ad77 100644 --- a/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c +++ b/drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c @@ -53,16 +53,12 @@ static void mantix_init_sequence(struct mipi_dsi_multi_context *dsi_ctx) mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5a); mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_INT_CANCEL, 0x03); - mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5a, 0x03); - mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x80, 0xa9, 0x00); - mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5a, 0x09); - mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00); - mipi_dsi_msleep(dsi_ctx, 20); + mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5a, 0x03); + mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x80, 0xa9, 0x00); /* VCOM */ mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_SPI_FINISH, 0xa5); mipi_dsi_generic_write_seq_multi(dsi_ctx, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2f); - mipi_dsi_msleep(dsi_ctx, 20); } static int mantix_enable(struct drm_panel *panel) @@ -75,14 +71,15 @@ static int mantix_enable(struct drm_panel *panel) if (!dsi_ctx.accum_err) dev_dbg(ctx->dev, "Panel init sequence done\n"); + /* remainder to 120ms (7.3.1 Note 4) */ + mipi_dsi_msleep(&dsi_ctx, 70); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); - mipi_dsi_msleep(&dsi_ctx, 20); + mipi_dsi_msleep(&dsi_ctx, 120); mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); mipi_dsi_usleep_range(&dsi_ctx, 10000, 12000); - mipi_dsi_turn_on_peripheral_multi(&dsi_ctx); - return dsi_ctx.accum_err; } @@ -95,6 +92,9 @@ static int mantix_disable(struct drm_panel *panel) mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + /* T10 */ + mipi_dsi_msleep(&dsi_ctx, 150); + return dsi_ctx.accum_err; } @@ -102,15 +102,16 @@ static int mantix_unprepare(struct drm_panel *panel) { struct mantix *ctx = panel_to_mantix(panel); - gpiod_set_value_cansleep(ctx->tp_rstn_gpio, 1); - usleep_range(5000, 6000); - gpiod_set_value_cansleep(ctx->reset_gpio, 1); - regulator_disable(ctx->avee); regulator_disable(ctx->avdd); /* T11 */ usleep_range(5000, 6000); regulator_disable(ctx->vddi); + + gpiod_set_value_cansleep(ctx->tp_rstn_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + /* T14 */ msleep(50); @@ -147,10 +148,10 @@ static int mantix_prepare(struct drm_panel *panel) return ret; } - /* T3 + T4 + time for voltage to become stable: */ - usleep_range(6000, 7000); - gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(100, 200); gpiod_set_value_cansleep(ctx->tp_rstn_gpio, 0); + usleep_range(100, 200); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); /* T6 */ msleep(50); @@ -258,7 +259,7 @@ static int mantix_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; ctx->avdd = devm_regulator_get(dev, "avdd"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 3acc9f3dac16..c606e5932ca7 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2836,6 +2836,32 @@ static const struct panel_desc innolux_g121xce_l01 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct display_timing innolux_g150xge_l05_timing = { + .pixelclock = { 53350000, 65000000, 80000000 }, + .hactive = { 1024, 1024, 1024 }, + .hfront_porch = { 58, 160, 288 }, + .hback_porch = { 58, 160, 288 }, + .hsync_len = { 1, 1, 1 }, + .vactive = { 768, 768, 768 }, + .vfront_porch = { 6, 19, 216 }, + .vback_porch = { 6, 19, 216 }, + .vsync_len = { 1, 1, 1 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc innolux_g150xge_l05 = { + .timings = &innolux_g150xge_l05_timing, + .num_timings = 1, + .bpc = 8, + .size = { + .width = 304, + .height = 228, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .bus_flags = DRM_BUS_FLAG_DE_HIGH, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing innolux_g156hce_l01_timings = { .pixelclock = { 120000000, 141860000, 150000000 }, .hactive = { 1920, 1920, 1920 }, @@ -5315,6 +5341,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,g121xce-l01", .data = &innolux_g121xce_l01, }, { + .compatible = "innolux,g150xge-l05", + .data = &innolux_g150xge_l05, + }, { .compatible = "innolux,g156hce-l01", .data = &innolux_g156hce_l01, }, { diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index 8f3b7a7b6ad0..50ff30849361 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -587,12 +587,12 @@ out: static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, u64 addr) { - int ret, i; + int ret; struct panfrost_gem_mapping *bomapping; struct panfrost_gem_object *bo; struct address_space *mapping; struct drm_gem_object *obj; - pgoff_t page_offset; + pgoff_t page_offset, nr_pages; struct sg_table *sgt; struct page **pages; @@ -613,6 +613,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, addr &= ~((u64)SZ_2M - 1); page_offset = addr >> PAGE_SHIFT; page_offset -= bomapping->mmnode.start; + nr_pages = bo->base.base.size >> PAGE_SHIFT; obj = &bo->base.base; @@ -626,8 +627,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, goto err_unlock; } - pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT, - sizeof(struct page *), GFP_KERNEL | __GFP_ZERO); + pages = kvmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL | __GFP_ZERO); if (!pages) { kvfree(bo->sgts); bo->sgts = NULL; @@ -649,20 +649,30 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, mapping = bo->base.base.filp->f_mapping; mapping_set_unevictable(mapping); - for (i = page_offset; i < page_offset + NUM_FAULT_PAGES; i++) { - /* Can happen if the last fault only partially filled this - * section of the pages array before failing. In that case - * we skip already filled pages. - */ - if (pages[i]) - continue; + for (pgoff_t pg = page_offset; pg < page_offset + NUM_FAULT_PAGES;) { + bool already_owned = false; + struct folio *folio; - pages[i] = shmem_read_mapping_page(mapping, i); - if (IS_ERR(pages[i])) { - ret = PTR_ERR(pages[i]); - pages[i] = NULL; + folio = shmem_read_folio(mapping, pg); + if (IS_ERR(folio)) { + ret = PTR_ERR(folio); goto err_unlock; } + + pg &= ~(folio_nr_pages(folio) - 1); + for (u32 i = 0; i < folio_nr_pages(folio) && pg < nr_pages; i++) { + if (pages[pg]) + already_owned = true; + + pages[pg++] = folio_page(folio, i); + } + + /* We always fill the page array at a folio granularity so + * there's no valid reason for a folio range to be partially + * populated. + */ + if (drm_WARN_ON(&pfdev->base, already_owned)) + folio_put(folio); } ret = sg_alloc_table_from_pages(sgt, pages + page_offset, diff --git a/drivers/gpu/drm/panthor/panthor_hw.c b/drivers/gpu/drm/panthor/panthor_hw.c index 87ebb7ae42c4..80c521784cd3 100644 --- a/drivers/gpu/drm/panthor/panthor_hw.c +++ b/drivers/gpu/drm/panthor/panthor_hw.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 or MIT /* Copyright 2025 ARM Limited. All rights reserved. */ +#include <linux/nvmem-consumer.h> #include <drm/drm_print.h> #include "panthor_device.h" @@ -109,7 +110,25 @@ static char *get_gpu_model_name(struct panthor_device *ptdev) return "(Unknown Mali GPU)"; } -static void panthor_gpu_info_init(struct panthor_device *ptdev) +static int overload_shader_present(struct panthor_device *ptdev) +{ + u64 contents; + int ret; + + ret = nvmem_cell_read_variable_le_u64(ptdev->base.dev, "shader-present", + &contents); + if (!ret) + ptdev->gpu_info.shader_present = contents; + else if (ret == -ENOENT) + return 0; + else + return dev_err_probe(ptdev->base.dev, ret, + "Failed to read shader-present nvmem cell\n"); + + return 0; +} + +static int panthor_gpu_info_init(struct panthor_device *ptdev) { unsigned int i; @@ -143,13 +162,18 @@ static void panthor_gpu_info_init(struct panthor_device *ptdev) ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT); ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT); } + + return overload_shader_present(ptdev); } -static void panthor_hw_info_init(struct panthor_device *ptdev) +static int panthor_hw_info_init(struct panthor_device *ptdev) { u32 major, minor, status; + int ret; - panthor_gpu_info_init(ptdev); + ret = panthor_gpu_info_init(ptdev); + if (ret) + return ret; major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id); minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id); @@ -172,6 +196,8 @@ static void panthor_hw_info_init(struct panthor_device *ptdev) "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx", ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present, ptdev->gpu_info.tiler_present); + + return 0; } static int panthor_hw_bind_device(struct panthor_device *ptdev) @@ -218,7 +244,5 @@ int panthor_hw_init(struct panthor_device *ptdev) if (ret) return ret; - panthor_hw_info_init(ptdev); - - return 0; + return panthor_hw_info_init(ptdev); } diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 6f068ce1021d..1479b8c4ed40 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_ROCKCHIP tristate "DRM Support for Rockchip" - depends on DRM && ROCKCHIP_IOMMU + depends on DRM + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on ROCKCHIP_IOMMU || !ROCKCHIP_IOMMU depends on OF select DRM_CLIENT_SELECTION select DRM_GEM_DMA_HELPER diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 2dad6b7b61b2..3547d91b25d3 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -198,6 +198,11 @@ #define RK3568_DSI0_TURNDISABLE BIT(2) #define RK3568_DSI0_FORCERXMODE BIT(0) +#define RK3506_SYS_GRF_SOC_CON6 0x0018 +#define RK3506_DSI_FORCETXSTOPMODE (0xf << 4) +#define RK3506_DSI_TURNDISABLE BIT(2) +#define RK3506_DSI_FORCERXMODE BIT(0) + /* * Note these registers do not appear in the datasheet, they are * however present in the BSP driver which is where these values @@ -1661,6 +1666,18 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { { /* sentinel */ } }; +static const struct rockchip_dw_dsi_chip_data rk3506_chip_data[] = { + { + .reg = 0xff640000, + .lanecfg1_grf_reg = RK3506_SYS_GRF_SOC_CON6, + .lanecfg1 = (FIELD_PREP_WM16_CONST(RK3506_DSI_TURNDISABLE, 0) | + FIELD_PREP_WM16_CONST(RK3506_DSI_FORCERXMODE, 0) | + FIELD_PREP_WM16_CONST(RK3506_DSI_FORCETXSTOPMODE, 0)), + .max_data_lanes = 2, + }, + { /* sentinel */ } +}; + static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { { .reg = 0xfe060000, @@ -1712,6 +1729,9 @@ static const struct of_device_id dw_mipi_dsi_rockchip_dt_ids[] = { .compatible = "rockchip,rk3399-mipi-dsi", .data = &rk3399_chip_data, }, { + .compatible = "rockchip,rk3506-mipi-dsi", + .data = &rk3506_chip_data, + }, { .compatible = "rockchip,rk3568-mipi-dsi", .data = &rk3568_chip_data, }, { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index c9fe6aa3e3e3..e91caae7e353 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -289,7 +289,7 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id) val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1); regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val); - mod_delayed_work(system_wq, &hdmi->hpd_work, + mod_delayed_work(system_percpu_wq, &hdmi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0); @@ -332,7 +332,7 @@ static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1); regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); - mod_delayed_work(system_wq, &hdmi->hpd_work, + mod_delayed_work(system_percpu_wq, &hdmi->hpd_work, msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); if (hdmi->port_id) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ad4ab894391a..1b466623b6c7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1771,7 +1771,7 @@ static void vop_handle_vblank(struct vop *vop) spin_unlock(&drm->event_lock); if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) - drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq); + drm_flip_work_commit(&vop->fb_unref_work, system_dfl_wq); } static irqreturn_t vop_isr(int irq, void *data) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 498df0ce4680..a0099e4dd4ea 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -367,59 +367,47 @@ static bool is_yuv_output(u32 bus_format) } } -static bool rockchip_afbc(struct drm_plane *plane, u64 modifier) -{ - int i; - - if (modifier == DRM_FORMAT_MOD_LINEAR) - return false; - - for (i = 0 ; i < plane->modifier_count; i++) - if (plane->modifiers[i] == modifier) - return true; - - return false; -} - static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, u64 modifier) { struct vop2_win *win = to_vop2_win(plane); struct vop2 *vop2 = win->vop2; + int i; + /* No support for implicit modifiers */ if (modifier == DRM_FORMAT_MOD_INVALID) return false; - if (vop2->version == VOP_VERSION_RK3568) { - if (vop2_cluster_window(win)) { - if (modifier == DRM_FORMAT_MOD_LINEAR) { - drm_dbg_kms(vop2->drm, - "Cluster window only supports format with afbc\n"); - return false; - } - } + /* The cluster window on 3568 is AFBC-only */ + if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) && + !drm_is_afbc(modifier)) { + drm_dbg_kms(vop2->drm, + "Cluster window only supports format with afbc\n"); + return false; } - if (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010) { - if (vop2->version == VOP_VERSION_RK3588) { - if (!rockchip_afbc(plane, modifier)) { - drm_dbg_kms(vop2->drm, "Only support 32 bpp format with afbc\n"); - return false; - } - } + /* 10bpc formats on 3588 are AFBC-only */ + if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) && + (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) { + drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n"); + return false; } + /* Linear is otherwise supported everywhere */ if (modifier == DRM_FORMAT_MOD_LINEAR) return true; - if (!rockchip_afbc(plane, modifier)) { - drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n", - modifier); - + /* Not all format+modifier combinations are allowable */ + if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID) return false; + + /* Different windows have different format/modifier support */ + for (i = 0; i < plane->modifier_count; i++) { + if (plane->modifiers[i] == modifier) + return true; } - return vop2_convert_afbc_format(format) >= 0; + return false; } /* @@ -998,6 +986,7 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, struct drm_crtc *crtc = pstate->crtc; struct drm_crtc_state *cstate; struct vop2_video_port *vp; + struct vop2_win *win = to_vop2_win(plane); struct vop2 *vop2; const struct vop2_data *vop2_data; struct drm_rect *dest = &pstate->dst; @@ -1030,7 +1019,8 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, return 0; format = vop2_convert_format(fb->format->format); - if (format < 0) + /* We shouldn't be able to create a fb for an unsupported format */ + if (WARN_ON(format < 0)) return format; /* Co-ordinates have now been clipped */ @@ -1064,6 +1054,32 @@ static int vop2_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } + /* + * This is workaround solution for IC design: + * esmart can't support scale down when src_w % 16 == 1. + */ + if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) { + drm_dbg_kms(vop2->drm, + "Esmart windows cannot downscale odd-width source regions\n"); + return -EINVAL; + } + + if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) { + drm_dbg_kms(vop2->drm, + "AFBC source rectangles must be 4-pixel aligned; is %d\n", + src_w); + return -EINVAL; + } + + if (drm_is_afbc(fb->modifier) && + pstate->rotation & + (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) && + (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) { + drm_dbg_kms(vop2->drm, + "AFBC buffers must be 64-pixel aligned for horizontal rotation or mirroring\n"); + return -EINVAL; + } + return 0; } @@ -1179,7 +1195,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, return; } - afbc_en = rockchip_afbc(plane, fb->modifier); + afbc_en = drm_is_afbc(fb->modifier); offset = (src->x1 >> 16) * fb->format->cpp[0]; @@ -1213,46 +1229,20 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, src_w = drm_rect_width(src) >> 16; src_h = drm_rect_height(src) >> 16; dsp_w = drm_rect_width(dest); - - if (dest->x1 + dsp_w > adjusted_mode->hdisplay) { - drm_dbg_kms(vop2->drm, - "vp%d %s dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", - vp->id, win->data->name, dest->x1, dsp_w, adjusted_mode->hdisplay); - dsp_w = adjusted_mode->hdisplay - dest->x1; - if (dsp_w < 4) - dsp_w = 4; - src_w = dsp_w * src_w / drm_rect_width(dest); - } - dsp_h = drm_rect_height(dest); - if (dest->y1 + dsp_h > adjusted_mode->vdisplay) { - drm_dbg_kms(vop2->drm, - "vp%d %s dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", - vp->id, win->data->name, dest->y1, dsp_h, adjusted_mode->vdisplay); - dsp_h = adjusted_mode->vdisplay - dest->y1; - if (dsp_h < 4) - dsp_h = 4; - src_h = dsp_h * src_h / drm_rect_height(dest); - } - - /* - * This is workaround solution for IC design: - * esmart can't support scale down when src_w % 16 == 1. + /* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for + * us, which keeps our planes bounded within the CRTC active area */ - if (!(win->data->feature & WIN_FEATURE_AFBDC)) { - if (src_w > dsp_w && (src_w & 0xf) == 1) { - drm_dbg_kms(vop2->drm, "vp%d %s act_w[%d] MODE 16 == 1\n", - vp->id, win->data->name, src_w); - src_w -= 1; - } - } + if (WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay) || + WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay) || + WARN_ON(dsp_w < 4) || WARN_ON(dsp_h < 4) || + WARN_ON(src_w < 4) || WARN_ON(src_h < 4)) + return; - if (afbc_en && src_w % 4) { - drm_dbg_kms(vop2->drm, "vp%d %s src_w[%d] not 4 pixel aligned\n", - vp->id, win->data->name, src_w); - src_w = ALIGN_DOWN(src_w, 4); - } + if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier)) + if (WARN_ON(src_w % 4)) + return; act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff); dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); @@ -1297,9 +1287,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, * with WIN_VIR_STRIDE. */ stride = (fb->pitches[0] << 3) / bpp; - if ((stride & 0x3f) && (xmirror || rotate_90 || rotate_270)) - drm_dbg_kms(vop2->drm, "vp%d %s stride[%d] not 64 pixel aligned\n", - vp->id, win->data->name, stride); /* It's for head stride, each head size is 16 byte */ stride = ALIGN(stride, block_w) / block_w * 16; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 219f8c2fa88e..b2f8ebf90968 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -1180,6 +1180,61 @@ static const struct vop_data rk3328_vop = { .max_output = { 4096, 2160 }, }; +static const struct vop_common rk3506_common = { + .standby = VOP_REG_SYNC(RK3506_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(RK3506_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(RK3506_DSP_CTRL2, 0x1, 14), + .dither_down_en = VOP_REG(RK3506_DSP_CTRL2, 0x1, 8), + .dither_down_sel = VOP_REG(RK3506_DSP_CTRL2, 0x1, 7), + .dither_down_mode = VOP_REG(RK3506_DSP_CTRL2, 0x1, 6), + .dsp_lut_en = VOP_REG(RK3506_DSP_CTRL2, 0x1, 5), + .dither_up = VOP_REG(RK3506_DSP_CTRL2, 0x1, 2), + .cfg_done = VOP_REG_SYNC(RK3506_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_output rk3506_output = { + .rgb_en = VOP_REG(RK3506_DSP_CTRL0, 0x1, 0), + .rgb_pin_pol = VOP_REG(RK3506_DSP_CTRL0, 0x7, 2), + .mipi_en = VOP_REG(RK3506_DSP_CTRL0, 0x1, 24), + .mipi_dclk_pol = VOP_REG(RK3506_DSP_CTRL0, 0x1, 25), + .mipi_pin_pol = VOP_REG(RK3506_DSP_CTRL0, 0x7, 26), +}; + +static const struct vop_win_phy rk3506_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .format_modifiers = format_modifiers_win_lite, + .enable = VOP_REG(RK3506_WIN1_CTRL0, 0x1, 0), + .format = VOP_REG(RK3506_WIN1_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(RK3506_WIN1_CTRL0, 0x1, 12), + .channel = VOP_REG(RK3506_WIN1_CTRL1, 0xf, 8), + .yrgb_vir = VOP_REG(RK3506_WIN1_VIR, 0x1fff, 0), + .yrgb_mst = VOP_REG(RK3506_WIN1_MST, 0xffffffff, 0), + .dsp_info = VOP_REG(RK3506_WIN1_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(RK3506_WIN1_DSP_ST, 0xffffffff, 0), + .alpha_en = VOP_REG(RK3506_WIN1_ALPHA_CTRL, 0x1, 0), + .alpha_mode = VOP_REG(RK3506_WIN1_ALPHA_CTRL, 0x1, 1), + .alpha_pre_mul = VOP_REG(RK3506_WIN1_ALPHA_CTRL, 0x1, 2), +}; + +static const struct vop_win_data rk3506_vop_win_data[] = { + { .base = 0x00, .phy = &rk3506_win1_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data rk3506_vop = { + .version = VOP_VERSION(2, 0xe), + .feature = VOP_FEATURE_INTERNAL_RGB, + .intr = &px30_intr, + .common = &rk3506_common, + .modeset = &px30_modeset, + .output = &rk3506_output, + .win = rk3506_vop_win_data, + .win_size = ARRAY_SIZE(rk3506_vop_win_data), + .lut_size = 256, + .max_output = { 1280, 1280 }, +}; + static const struct vop_common rv1126_common = { .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), @@ -1260,6 +1315,8 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &rk3228_vop }, { .compatible = "rockchip,rk3328-vop", .data = &rk3328_vop }, + { .compatible = "rockchip,rk3506-vop", + .data = &rk3506_vop }, { .compatible = "rockchip,rv1126-vop", .data = &rv1126_vop }, {}, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index addf8ca085f6..7805533e88bc 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1033,4 +1033,18 @@ #define RK3066_DSP_LUT_ADDR 0x800 /* rk3066 register definition end */ +/* rk3506 register definition */ +#define RK3506_REG_CFG_DONE 0x00 +#define RK3506_SYS_CTRL2 0x18 +#define RK3506_DSP_CTRL0 0x20 +#define RK3506_DSP_CTRL2 0x28 +#define RK3506_WIN1_CTRL0 0x90 +#define RK3506_WIN1_CTRL1 0x94 +#define RK3506_WIN1_VIR 0x98 +#define RK3506_WIN1_MST 0xa0 +#define RK3506_WIN1_DSP_INFO 0xa4 +#define RK3506_WIN1_DSP_ST 0xa8 +#define RK3506_WIN1_ALPHA_CTRL 0xbc +/* rk3506 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */ diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 1d18d43292dc..f7222819d672 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1301,7 +1301,7 @@ put: return err; } -static int host1x_drm_remove(struct host1x_device *dev) +static void host1x_drm_remove(struct host1x_device *dev) { struct drm_device *drm = dev_get_drvdata(&dev->dev); struct tegra_drm *tegra = drm->dev_private; @@ -1330,8 +1330,6 @@ static int host1x_drm_remove(struct host1x_device *dev) kfree(tegra); drm_dev_put(drm); - - return 0; } static void host1x_drm_shutdown(struct host1x_device *dev) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 175f5f9937b0..8ee96b59fdbc 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1542,11 +1542,9 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) return -EPROBE_DEFER; dsi->slave = platform_get_drvdata(gangster); - - if (!dsi->slave) { - put_device(&gangster->dev); + put_device(&gangster->dev); + if (!dsi->slave) return -EPROBE_DEFER; - } dsi->slave->master = dsi; } diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index a07d8b53de66..02df403a5b28 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1044,7 +1044,7 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm, xe_bo_assert_held(bo); - vm_bo = drm_gpuvm_bo_obtain(vma->gpuva.vm, &bo->ttm.base); + vm_bo = drm_gpuvm_bo_obtain_locked(vma->gpuva.vm, &bo->ttm.base); if (IS_ERR(vm_bo)) { xe_vma_free(vma); return ERR_CAST(vm_bo); @@ -2301,7 +2301,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops, if (err) return ERR_PTR(err); - vm_bo = drm_gpuvm_bo_obtain(&vm->gpuvm, obj); + vm_bo = drm_gpuvm_bo_obtain_locked(&vm->gpuvm, obj); if (IS_ERR(vm_bo)) { xe_bo_unlock(bo); return ERR_CAST(vm_bo); diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 723a80895cd4..e2673bc7cb31 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -346,6 +346,36 @@ static int host1x_device_uevent(const struct device *dev, return 0; } +static int host1x_device_probe(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (driver->probe) + return driver->probe(device); + + return 0; +} + +static void host1x_device_remove(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (driver->remove) + driver->remove(device); +} + +static void host1x_device_shutdown(struct device *dev) +{ + struct host1x_driver *driver = to_host1x_driver(dev->driver); + struct host1x_device *device = to_host1x_device(dev); + + if (dev->driver && driver->shutdown) + driver->shutdown(device); +} + + static const struct dev_pm_ops host1x_device_pm_ops = { .suspend = pm_generic_suspend, .resume = pm_generic_resume, @@ -359,6 +389,9 @@ const struct bus_type host1x_bus_type = { .name = "host1x", .match = host1x_device_match, .uevent = host1x_device_uevent, + .probe = host1x_device_probe, + .remove = host1x_device_remove, + .shutdown = host1x_device_shutdown, .pm = &host1x_device_pm_ops, }; @@ -623,37 +656,6 @@ int host1x_unregister(struct host1x *host1x) return 0; } -static int host1x_device_probe(struct device *dev) -{ - struct host1x_driver *driver = to_host1x_driver(dev->driver); - struct host1x_device *device = to_host1x_device(dev); - - if (driver->probe) - return driver->probe(device); - - return 0; -} - -static int host1x_device_remove(struct device *dev) -{ - struct host1x_driver *driver = to_host1x_driver(dev->driver); - struct host1x_device *device = to_host1x_device(dev); - - if (driver->remove) - return driver->remove(device); - - return 0; -} - -static void host1x_device_shutdown(struct device *dev) -{ - struct host1x_driver *driver = to_host1x_driver(dev->driver); - struct host1x_device *device = to_host1x_device(dev); - - if (driver->shutdown) - driver->shutdown(device); -} - /** * host1x_driver_register_full() - register a host1x driver * @driver: host1x driver @@ -684,9 +686,6 @@ int host1x_driver_register_full(struct host1x_driver *driver, driver->driver.bus = &host1x_bus_type; driver->driver.owner = owner; - driver->driver.probe = host1x_device_probe; - driver->driver.remove = host1x_device_remove; - driver->driver.shutdown = host1x_device_shutdown; return driver_register(&driver->driver); } diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c index 074ad0dc56ca..68783d5ffeb1 100644 --- a/drivers/staging/media/tegra-video/video.c +++ b/drivers/staging/media/tegra-video/video.c @@ -107,7 +107,7 @@ cleanup: return ret; } -static int host1x_video_remove(struct host1x_device *dev) +static void host1x_video_remove(struct host1x_device *dev) { struct tegra_video_device *vid = dev_get_drvdata(&dev->dev); @@ -118,8 +118,6 @@ static int host1x_video_remove(struct host1x_device *dev) /* This calls v4l2_dev release callback on last reference */ v4l2_device_put(&vid->v4l2_dev); - - return 0; } static const struct of_device_id host1x_video_subdevs[] = { diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h index fdfc575b2603..655bd9104ffb 100644 --- a/include/drm/drm_gpuvm.h +++ b/include/drm/drm_gpuvm.h @@ -736,8 +736,8 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj); struct drm_gpuvm_bo * -drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, - struct drm_gem_object *obj); +drm_gpuvm_bo_obtain_locked(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj); struct drm_gpuvm_bo * drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *vm_bo); @@ -1121,7 +1121,7 @@ void drm_gpuva_ops_free(struct drm_gpuvm *gpuvm, struct drm_gpuva_ops *ops); static inline void drm_gpuva_init_from_op(struct drm_gpuva *va, - struct drm_gpuva_op_map *op) + const struct drm_gpuva_op_map *op) { va->va.addr = op->va.addr; va->va.range = op->va.range; @@ -1265,13 +1265,13 @@ int drm_gpuvm_sm_unmap_exec_lock(struct drm_gpuvm *gpuvm, struct drm_exec *exec, void drm_gpuva_map(struct drm_gpuvm *gpuvm, struct drm_gpuva *va, - struct drm_gpuva_op_map *op); + const struct drm_gpuva_op_map *op); void drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva *next, - struct drm_gpuva_op_remap *op); + const struct drm_gpuva_op_remap *op); -void drm_gpuva_unmap(struct drm_gpuva_op_unmap *op); +void drm_gpuva_unmap(const struct drm_gpuva_op_unmap *op); /** * drm_gpuva_op_remap_to_unmap_range() - Helper to get the start and range of diff --git a/include/drm/drm_mode_object.h b/include/drm/drm_mode_object.h index c68edbd126d0..44a0d6f8d01f 100644 --- a/include/drm/drm_mode_object.h +++ b/include/drm/drm_mode_object.h @@ -133,6 +133,9 @@ int drm_object_property_get_value(struct drm_mode_object *obj, int drm_object_property_get_default_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); +int drm_object_immutable_property_get_value(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t *val); void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, diff --git a/include/drm/drm_property.h b/include/drm/drm_property.h index 082f29156b3e..aa49b5a42bb5 100644 --- a/include/drm/drm_property.h +++ b/include/drm/drm_property.h @@ -284,6 +284,7 @@ int drm_property_replace_blob_from_id(struct drm_device *dev, uint64_t blob_id, ssize_t expected_size, ssize_t expected_elem_size, + ssize_t max_size, bool *replaced); int drm_property_replace_global_blob(struct drm_device *dev, struct drm_property_blob **replace, diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 9fa9c30a34e6..5e7a63143a4a 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -380,7 +380,7 @@ struct host1x_driver { struct list_head list; int (*probe)(struct host1x_device *device); - int (*remove)(struct host1x_device *device); + void (*remove)(struct host1x_device *device); void (*shutdown)(struct host1x_device *device); }; diff --git a/include/uapi/drm/rocket_accel.h b/include/uapi/drm/rocket_accel.h index 14b2e12b7c49..d0685e372b79 100644 --- a/include/uapi/drm/rocket_accel.h +++ b/include/uapi/drm/rocket_accel.h @@ -26,20 +26,27 @@ extern "C" { * */ struct drm_rocket_create_bo { - /** Input: Size of the requested BO. */ + /** + * @size: Input: Size of the requested BO. + */ __u32 size; - /** Output: GEM handle for the BO. */ + /** + * @handle: Output: GEM handle for the BO. + */ __u32 handle; /** - * Output: DMA address for the BO in the NPU address space. This address - * is private to the DRM fd and is valid for the lifetime of the GEM - * handle. + * @dma_address: Output: DMA address for the BO in the NPU address + * space. This address is private to the DRM fd and is valid for + * the lifetime of the GEM handle. */ __u64 dma_address; - /** Output: Offset into the drm node to use for subsequent mmap call. */ + /** + * @offset: Output: Offset into the drm node to use for subsequent + * mmap call. + */ __u64 offset; }; @@ -50,13 +57,19 @@ struct drm_rocket_create_bo { * synchronization. */ struct drm_rocket_prep_bo { - /** Input: GEM handle of the buffer object. */ + /** + * @handle: Input: GEM handle of the buffer object. + */ __u32 handle; - /** Reserved, must be zero. */ + /** + * @reserved: Reserved, must be zero. + */ __u32 reserved; - /** Input: Amount of time to wait for NPU jobs. */ + /** + * @timeout_ns: Input: Amount of time to wait for NPU jobs. + */ __s64 timeout_ns; }; @@ -66,10 +79,14 @@ struct drm_rocket_prep_bo { * Synchronize caches for NPU access. */ struct drm_rocket_fini_bo { - /** Input: GEM handle of the buffer object. */ + /** + * @handle: Input: GEM handle of the buffer object. + */ __u32 handle; - /** Reserved, must be zero. */ + /** + * @reserved: Reserved, must be zero. + */ __u32 reserved; }; @@ -79,10 +96,15 @@ struct drm_rocket_fini_bo { * A task is the smallest unit of work that can be run on the NPU. */ struct drm_rocket_task { - /** Input: DMA address to NPU mapping of register command buffer */ + /** + * @regcmd: Input: DMA address to NPU mapping of register command buffer + */ __u32 regcmd; - /** Input: Number of commands in the register command buffer */ + /** + * @regcmd_count: Input: Number of commands in the register command + * buffer + */ __u32 regcmd_count; }; @@ -94,25 +116,44 @@ struct drm_rocket_task { * sequentially on the same core, to benefit from memory residency in SRAM. */ struct drm_rocket_job { - /** Input: Pointer to an array of struct drm_rocket_task. */ + /** + * @tasks: Input: Pointer to an array of struct drm_rocket_task. + */ __u64 tasks; - /** Input: Pointer to a u32 array of the BOs that are read by the job. */ + /** + * @in_bo_handles: Input: Pointer to a u32 array of the BOs that + * are read by the job. + */ __u64 in_bo_handles; - /** Input: Pointer to a u32 array of the BOs that are written to by the job. */ + /** + * @out_bo_handles: Input: Pointer to a u32 array of the BOs that + * are written to by the job. + */ __u64 out_bo_handles; - /** Input: Number of tasks passed in. */ + /** + * @task_count: Input: Number of tasks passed in. + */ __u32 task_count; - /** Input: Size in bytes of the structs in the @tasks field. */ + /** + * @task_struct_size: Input: Size in bytes of the structs in the + * @tasks field. + */ __u32 task_struct_size; - /** Input: Number of input BO handles passed in (size is that times 4). */ + /** + * @in_bo_handle_count: Input: Number of input BO handles passed in + * (size is that times 4). + */ __u32 in_bo_handle_count; - /** Input: Number of output BO handles passed in (size is that times 4). */ + /** + * @out_bo_handle_count: Input: Number of output BO handles passed in + * (size is that times 4). + */ __u32 out_bo_handle_count; }; @@ -122,16 +163,25 @@ struct drm_rocket_job { * The kernel will schedule the execution of these jobs in dependency order. */ struct drm_rocket_submit { - /** Input: Pointer to an array of struct drm_rocket_job. */ + /** + * @jobs: Input: Pointer to an array of struct drm_rocket_job. + */ __u64 jobs; - /** Input: Number of jobs passed in. */ + /** + * @job_count: Input: Number of jobs passed in. + */ __u32 job_count; - /** Input: Size in bytes of the structs in the @jobs field. */ + /** + * @job_struct_size: Input: Size in bytes of the structs in the + * @jobs field. + */ __u32 job_struct_size; - /** Reserved, must be zero. */ + /** + * @reserved: Reserved, must be zero. + */ __u64 reserved; }; |
