summaryrefslogtreecommitdiff
path: root/drivers/gpu
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 /drivers/gpu
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
Diffstat (limited to 'drivers/gpu')
-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
30 files changed, 578 insertions, 220 deletions
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);
}