summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-01-16 11:03:44 +1000
committerDave Airlie <airlied@redhat.com>2026-01-16 11:04:03 +1000
commit37b812b7fdc2f1c7cb9e22c888776be7347097b0 (patch)
treea7584e45073dbf7f8da5d1a44835fbcc50b2ca52
parent83dc0ba2755296b5e5882e044c80973b7c3fce9e (diff)
parentb36178488d479e9a53bbef2b01280378b5586e60 (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
-rw-r--r--Documentation/devicetree/bindings/display/panel/panel-simple.yaml6
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip,dw-mipi-dsi.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml6
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml1
-rw-r--r--Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml14
-rw-r--r--Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml2
-rw-r--r--MAINTAINERS11
-rw-r--r--drivers/accel/amdxdna/aie2_error.c10
-rw-r--r--drivers/accel/amdxdna/aie2_message.c33
-rw-r--r--drivers/accel/amdxdna/aie2_pci.c36
-rw-r--r--drivers/accel/amdxdna/aie2_pci.h10
-rw-r--r--drivers/accel/amdxdna/amdxdna_pci_drv.c2
-rw-r--r--drivers/accel/amdxdna/npu1_regs.c6
-rw-r--r--drivers/accel/amdxdna/npu4_regs.c11
-rw-r--r--drivers/accel/amdxdna/npu5_regs.c2
-rw-r--r--drivers/accel/amdxdna/npu6_regs.c2
-rw-r--r--drivers/accel/ivpu/ivpu_debugfs.c4
-rw-r--r--drivers/accel/ivpu/ivpu_drv.c4
-rw-r--r--drivers/accel/ivpu/ivpu_fw.c13
-rw-r--r--drivers/accel/ivpu/ivpu_fw.h9
-rw-r--r--drivers/accel/ivpu/ivpu_hw_40xx_reg.h6
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.c74
-rw-r--r--drivers/accel/ivpu/ivpu_hw_ip.h1
-rw-r--r--drivers/accel/ivpu/ivpu_pm.c13
-rw-r--r--drivers/accel/ivpu/ivpu_pm.h1
-rw-r--r--drivers/accel/rocket/rocket_core.c7
-rw-r--r--drivers/accel/rocket/rocket_drv.c30
-rw-r--r--drivers/crypto/tegra/tegra-se-main.c4
-rw-r--r--drivers/dma-buf/heaps/cma_heap.c2
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c18
-rw-r--r--drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c34
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c32
-rw-r--r--drivers/gpu/drm/drm_gem.c11
-rw-r--r--drivers/gpu/drm/drm_gpuvm.c26
-rw-r--r--drivers/gpu/drm/drm_mode_object.c25
-rw-r--r--drivers/gpu/drm/drm_panic.c11
-rw-r--r--drivers/gpu/drm/drm_property.c11
-rw-r--r--drivers/gpu/drm/imagination/pvr_vm.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_uvmm.c2
-rw-r--r--drivers/gpu/drm/panel/panel-himax-hx83102.c12
-rw-r--r--drivers/gpu/drm/panel/panel-ilitek-ili9882t.c147
-rw-r--r--drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c4
-rw-r--r--drivers/gpu/drm/panel/panel-mantix-mlaf057we51.c35
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c29
-rw-r--r--drivers/gpu/drm/panfrost/panfrost_mmu.c40
-rw-r--r--drivers/gpu/drm/panthor/panthor_hw.c36
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig4
-rw-r--r--drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c20
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop2.c137
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.c57
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_vop_reg.h14
-rw-r--r--drivers/gpu/drm/tegra/drm.c4
-rw-r--r--drivers/gpu/drm/tegra/dsi.c6
-rw-r--r--drivers/gpu/drm/xe/xe_vm.c4
-rw-r--r--drivers/gpu/host1x/bus.c67
-rw-r--r--drivers/staging/media/tegra-video/video.c4
-rw-r--r--include/drm/drm_gpuvm.h12
-rw-r--r--include/drm/drm_mode_object.h3
-rw-r--r--include/drm/drm_property.h1
-rw-r--r--include/linux/host1x.h2
-rw-r--r--include/uapi/drm/rocket_accel.h98
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;
};