diff options
| author | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:03:44 +1000 |
|---|---|---|
| committer | Dave Airlie <airlied@redhat.com> | 2026-01-16 11:04:03 +1000 |
| commit | 37b812b7fdc2f1c7cb9e22c888776be7347097b0 (patch) | |
| tree | a7584e45073dbf7f8da5d1a44835fbcc50b2ca52 /drivers/gpu | |
| parent | 83dc0ba2755296b5e5882e044c80973b7c3fce9e (diff) | |
| parent | b36178488d479e9a53bbef2b01280378b5586e60 (diff) | |
Merge tag 'drm-misc-next-2026-01-15' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 6.20:
Core Changes:
- atomic: Introduce Gamma/Degamma LUT size check
- gem: Fix a leak in drm_gem_get_unmapped_area
- gpuvm: API sanitation for Rust bindings
- panic: Few corner-cases fixes
Driver Changes:
- Replace system workqueue with percpu equivalent
- amdxdna: Update message buffer allocation requirements, Update
firmware version check
- imagination: Add AM62P support
- ivpu: Implement warm boot flow
- rockchip: Get rid of atomic_check fixups, Add Rockchip RK3506 Support
- rocket: Cleanups
- bridge:
- dw-hdmi-qp: Add support for HPD-less setups
- panel:
- mantix: Various power management related improvements
- new panels: Innolux G150XGE-L05,
- dma-buf:
- cma: Call clear_page instead of memset
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260115-lilac-dragon-of-opposition-ac0a30@houat
Diffstat (limited to 'drivers/gpu')
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); } |
