Loading drivers/gpu/drm/msm/dba_bridge.c +74 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "drm_edid.h" #include "sde_kms.h" #include "dba_bridge.h" #include "sde/sde_recovery_manager.h" #undef pr_fmt #define pr_fmt(fmt) "dba_bridge:[%s] " fmt, __func__ Loading @@ -36,6 +37,7 @@ * @num_of_input_lanes: Number of input lanes in case of DSI/LVDS * @pluggable: If it's pluggable * @panel_count: Number of panels attached to this display * @client_info: bridge chip specific information for recovery manager */ struct dba_bridge { struct drm_bridge base; Loading @@ -52,12 +54,17 @@ struct dba_bridge { bool pluggable; u32 panel_count; bool cont_splash_enabled; struct recovery_client_info client_info; }; #define to_dba_bridge(x) container_of((x), struct dba_bridge, base) static int _dba_bridge_recovery_callback(int err_code, struct recovery_client_info *client_info); static void _dba_bridge_cb(void *data, enum msm_dba_callback_event event) { struct dba_bridge *d_bridge = data; int chip_err; if (!d_bridge) { SDE_ERROR("Invalid data\n"); Loading @@ -73,6 +80,12 @@ static void _dba_bridge_cb(void *data, enum msm_dba_callback_event event) case MSM_DBA_CB_HPD_DISCONNECT: DRM_DEBUG("HPD DISCONNECT\n"); break; case MSM_DBA_CB_DDC_I2C_ERROR: case MSM_DBA_CB_DDC_TIMEOUT: DRM_DEBUG("DDC FAILURE\n"); chip_err = DBA_BRIDGE_CRITICAL_ERR + d_bridge->id; sde_recovery_set_events(chip_err); break; default: DRM_DEBUG("event:%d is not supported\n", event); break; Loading @@ -83,6 +96,7 @@ static int _dba_bridge_attach(struct drm_bridge *bridge) { struct dba_bridge *d_bridge = to_dba_bridge(bridge); struct msm_dba_reg_info info; struct recovery_client_info *client_info = &d_bridge->client_info; int ret = 0; if (!bridge) { Loading Loading @@ -115,6 +129,25 @@ static int _dba_bridge_attach(struct drm_bridge *bridge) goto error; } snprintf(client_info->name, MAX_REC_NAME_LEN, "%s_%d", d_bridge->chip_name, d_bridge->id); client_info->recovery_cb = _dba_bridge_recovery_callback; /* Identify individual chip by different error codes */ client_info->err_supported[0].reported_err_code = DBA_BRIDGE_CRITICAL_ERR + d_bridge->id; client_info->err_supported[0].pre_err_code = 0; client_info->err_supported[0].post_err_code = 0; client_info->no_of_err = 1; /* bridge chip context */ client_info->pdata = d_bridge; ret = sde_recovery_client_register(client_info); if (ret) SDE_ERROR("%s recovery mgr register failed %d\n", __func__, ret); DRM_INFO("client:%s bridge:[%s:%d] attached\n", d_bridge->client_name, d_bridge->chip_name, d_bridge->id); Loading Loading @@ -242,6 +275,44 @@ static void _dba_bridge_post_disable(struct drm_bridge *bridge) } } static int _dba_bridge_recovery_callback(int err_code, struct recovery_client_info *client_info) { int rc = 0; struct dba_bridge *d_bridge; if (!client_info) { SDE_ERROR("Invalid client info\n"); rc = -EINVAL; return rc; } d_bridge = client_info->pdata; err_code = err_code - d_bridge->id; switch (err_code) { case DBA_BRIDGE_CRITICAL_ERR: SDE_DEBUG("%s critical bridge chip error\n", __func__); /* Power OFF */ _dba_bridge_disable(&d_bridge->base); _dba_bridge_post_disable(&d_bridge->base); /* settle power rails */ msleep(100); /* Power On */ _dba_bridge_pre_enable(&d_bridge->base); _dba_bridge_enable(&d_bridge->base); break; default: SDE_ERROR("%s error %d undefined\n", __func__, err_code); } return rc; } static void _dba_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) Loading Loading @@ -372,6 +443,9 @@ void dba_bridge_cleanup(struct drm_bridge *bridge) if (!bridge) return; sde_recovery_client_unregister(d_bridge->client_info.handle); d_bridge->client_info.handle = NULL; if (IS_ENABLED(CONFIG_MSM_DBA)) { if (!IS_ERR_OR_NULL(d_bridge->dba_ctx)) msm_dba_deregister_client(d_bridge->dba_ctx); Loading drivers/gpu/drm/msm/msm_mmu.h +4 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,8 @@ static inline void msm_mmu_disable(struct msm_mmu *mmu) int __init msm_smmu_driver_init(void); void __exit msm_smmu_driver_cleanup(void); /* register custom fault handler for a specific domain */ void msm_smmu_register_fault_handler(struct msm_mmu *mmu, iommu_fault_handler_t handler); #endif /* __MSM_MMU_H__ */ drivers/gpu/drm/msm/msm_smmu.c +12 −0 Original line number Diff line number Diff line Loading @@ -335,6 +335,18 @@ static struct device *msm_smmu_device_create(struct device *dev, return &pdev->dev; } void msm_smmu_register_fault_handler(struct msm_mmu *mmu, iommu_fault_handler_t handler) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); if (client) iommu_set_fault_handler(client->mmu_mapping->domain, handler, client->dev); } struct msm_mmu *msm_smmu_new(struct device *dev, enum msm_mmu_domain_type domain) { Loading drivers/gpu/drm/msm/sde/sde_kms.c +20 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ static struct recovery_client_info info = { .recovery_cb = sde_kms_recovery_callback, .err_supported[0] = {SDE_UNDERRUN, 0, 0}, .err_supported[1] = {SDE_VSYNC_MISS, 0, 0}, .no_of_err = 2, .err_supported[2] = {SDE_SMMU_FAULT, 0, 0}, .no_of_err = 3, .handle = NULL, .pdata = NULL, }; Loading Loading @@ -1140,6 +1141,18 @@ static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms) return 0; } static int sde_smmu_fault_handler(struct iommu_domain *iommu, struct device *dev, unsigned long iova, int flags, void *arg) { dev_info(dev, "%s: iova=0x%08lx, flags=0x%x, iommu=%pK\n", __func__, iova, flags, iommu); sde_recovery_set_events(SDE_SMMU_FAULT); return 0; } static int _sde_kms_mmu_init(struct sde_kms *sde_kms) { struct msm_mmu *mmu; Loading @@ -1158,6 +1171,8 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) continue; } msm_smmu_register_fault_handler(mmu, sde_smmu_fault_handler); /* Attaching smmu means IOMMU HW starts to work immediately. * However, display HW in LK is still accessing memory * while the memory map is not done yet. Loading Loading @@ -1523,6 +1538,10 @@ static int sde_kms_recovery_callback(int err_code, pr_debug("%s [SDE_VSYNC_MISS] trigger soft reset\n", __func__); break; case SDE_SMMU_FAULT: pr_debug("%s [SDE_SMMU_FAULT] trigger soft reset\n", __func__); break; default: pr_err("%s error %d undefined\n", __func__, err_code); Loading drivers/gpu/drm/msm/sde/sde_recovery_manager.h +7 −1 Original line number Diff line number Diff line Loading @@ -29,11 +29,17 @@ #define MAX_REC_NAME_LEN (16) #define MAX_REC_UEVENT_LEN (64) #define MAX_REC_ERR_SUPPORT (2) #define MAX_REC_ERR_SUPPORT (3) /* MSM Recovery Manager Error Code */ #define SDE_SMMU_FAULT 111 #define SDE_UNDERRUN 222 #define SDE_VSYNC_MISS 333 /* * instance id of bridge chip is added to make error code * unique to individual bridge chip instance */ #define DBA_BRIDGE_CRITICAL_ERR 444 /** * struct recovery_mgr_info - Recovery manager information Loading Loading
drivers/gpu/drm/msm/dba_bridge.c +74 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "drm_edid.h" #include "sde_kms.h" #include "dba_bridge.h" #include "sde/sde_recovery_manager.h" #undef pr_fmt #define pr_fmt(fmt) "dba_bridge:[%s] " fmt, __func__ Loading @@ -36,6 +37,7 @@ * @num_of_input_lanes: Number of input lanes in case of DSI/LVDS * @pluggable: If it's pluggable * @panel_count: Number of panels attached to this display * @client_info: bridge chip specific information for recovery manager */ struct dba_bridge { struct drm_bridge base; Loading @@ -52,12 +54,17 @@ struct dba_bridge { bool pluggable; u32 panel_count; bool cont_splash_enabled; struct recovery_client_info client_info; }; #define to_dba_bridge(x) container_of((x), struct dba_bridge, base) static int _dba_bridge_recovery_callback(int err_code, struct recovery_client_info *client_info); static void _dba_bridge_cb(void *data, enum msm_dba_callback_event event) { struct dba_bridge *d_bridge = data; int chip_err; if (!d_bridge) { SDE_ERROR("Invalid data\n"); Loading @@ -73,6 +80,12 @@ static void _dba_bridge_cb(void *data, enum msm_dba_callback_event event) case MSM_DBA_CB_HPD_DISCONNECT: DRM_DEBUG("HPD DISCONNECT\n"); break; case MSM_DBA_CB_DDC_I2C_ERROR: case MSM_DBA_CB_DDC_TIMEOUT: DRM_DEBUG("DDC FAILURE\n"); chip_err = DBA_BRIDGE_CRITICAL_ERR + d_bridge->id; sde_recovery_set_events(chip_err); break; default: DRM_DEBUG("event:%d is not supported\n", event); break; Loading @@ -83,6 +96,7 @@ static int _dba_bridge_attach(struct drm_bridge *bridge) { struct dba_bridge *d_bridge = to_dba_bridge(bridge); struct msm_dba_reg_info info; struct recovery_client_info *client_info = &d_bridge->client_info; int ret = 0; if (!bridge) { Loading Loading @@ -115,6 +129,25 @@ static int _dba_bridge_attach(struct drm_bridge *bridge) goto error; } snprintf(client_info->name, MAX_REC_NAME_LEN, "%s_%d", d_bridge->chip_name, d_bridge->id); client_info->recovery_cb = _dba_bridge_recovery_callback; /* Identify individual chip by different error codes */ client_info->err_supported[0].reported_err_code = DBA_BRIDGE_CRITICAL_ERR + d_bridge->id; client_info->err_supported[0].pre_err_code = 0; client_info->err_supported[0].post_err_code = 0; client_info->no_of_err = 1; /* bridge chip context */ client_info->pdata = d_bridge; ret = sde_recovery_client_register(client_info); if (ret) SDE_ERROR("%s recovery mgr register failed %d\n", __func__, ret); DRM_INFO("client:%s bridge:[%s:%d] attached\n", d_bridge->client_name, d_bridge->chip_name, d_bridge->id); Loading Loading @@ -242,6 +275,44 @@ static void _dba_bridge_post_disable(struct drm_bridge *bridge) } } static int _dba_bridge_recovery_callback(int err_code, struct recovery_client_info *client_info) { int rc = 0; struct dba_bridge *d_bridge; if (!client_info) { SDE_ERROR("Invalid client info\n"); rc = -EINVAL; return rc; } d_bridge = client_info->pdata; err_code = err_code - d_bridge->id; switch (err_code) { case DBA_BRIDGE_CRITICAL_ERR: SDE_DEBUG("%s critical bridge chip error\n", __func__); /* Power OFF */ _dba_bridge_disable(&d_bridge->base); _dba_bridge_post_disable(&d_bridge->base); /* settle power rails */ msleep(100); /* Power On */ _dba_bridge_pre_enable(&d_bridge->base); _dba_bridge_enable(&d_bridge->base); break; default: SDE_ERROR("%s error %d undefined\n", __func__, err_code); } return rc; } static void _dba_bridge_mode_set(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) Loading Loading @@ -372,6 +443,9 @@ void dba_bridge_cleanup(struct drm_bridge *bridge) if (!bridge) return; sde_recovery_client_unregister(d_bridge->client_info.handle); d_bridge->client_info.handle = NULL; if (IS_ENABLED(CONFIG_MSM_DBA)) { if (!IS_ERR_OR_NULL(d_bridge->dba_ctx)) msm_dba_deregister_client(d_bridge->dba_ctx); Loading
drivers/gpu/drm/msm/msm_mmu.h +4 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,8 @@ static inline void msm_mmu_disable(struct msm_mmu *mmu) int __init msm_smmu_driver_init(void); void __exit msm_smmu_driver_cleanup(void); /* register custom fault handler for a specific domain */ void msm_smmu_register_fault_handler(struct msm_mmu *mmu, iommu_fault_handler_t handler); #endif /* __MSM_MMU_H__ */
drivers/gpu/drm/msm/msm_smmu.c +12 −0 Original line number Diff line number Diff line Loading @@ -335,6 +335,18 @@ static struct device *msm_smmu_device_create(struct device *dev, return &pdev->dev; } void msm_smmu_register_fault_handler(struct msm_mmu *mmu, iommu_fault_handler_t handler) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct msm_smmu_client *client = msm_smmu_to_client(smmu); if (client) iommu_set_fault_handler(client->mmu_mapping->domain, handler, client->dev); } struct msm_mmu *msm_smmu_new(struct device *dev, enum msm_mmu_domain_type domain) { Loading
drivers/gpu/drm/msm/sde/sde_kms.c +20 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,8 @@ static struct recovery_client_info info = { .recovery_cb = sde_kms_recovery_callback, .err_supported[0] = {SDE_UNDERRUN, 0, 0}, .err_supported[1] = {SDE_VSYNC_MISS, 0, 0}, .no_of_err = 2, .err_supported[2] = {SDE_SMMU_FAULT, 0, 0}, .no_of_err = 3, .handle = NULL, .pdata = NULL, }; Loading Loading @@ -1140,6 +1141,18 @@ static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms) return 0; } static int sde_smmu_fault_handler(struct iommu_domain *iommu, struct device *dev, unsigned long iova, int flags, void *arg) { dev_info(dev, "%s: iova=0x%08lx, flags=0x%x, iommu=%pK\n", __func__, iova, flags, iommu); sde_recovery_set_events(SDE_SMMU_FAULT); return 0; } static int _sde_kms_mmu_init(struct sde_kms *sde_kms) { struct msm_mmu *mmu; Loading @@ -1158,6 +1171,8 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) continue; } msm_smmu_register_fault_handler(mmu, sde_smmu_fault_handler); /* Attaching smmu means IOMMU HW starts to work immediately. * However, display HW in LK is still accessing memory * while the memory map is not done yet. Loading Loading @@ -1523,6 +1538,10 @@ static int sde_kms_recovery_callback(int err_code, pr_debug("%s [SDE_VSYNC_MISS] trigger soft reset\n", __func__); break; case SDE_SMMU_FAULT: pr_debug("%s [SDE_SMMU_FAULT] trigger soft reset\n", __func__); break; default: pr_err("%s error %d undefined\n", __func__, err_code); Loading
drivers/gpu/drm/msm/sde/sde_recovery_manager.h +7 −1 Original line number Diff line number Diff line Loading @@ -29,11 +29,17 @@ #define MAX_REC_NAME_LEN (16) #define MAX_REC_UEVENT_LEN (64) #define MAX_REC_ERR_SUPPORT (2) #define MAX_REC_ERR_SUPPORT (3) /* MSM Recovery Manager Error Code */ #define SDE_SMMU_FAULT 111 #define SDE_UNDERRUN 222 #define SDE_VSYNC_MISS 333 /* * instance id of bridge chip is added to make error code * unique to individual bridge chip instance */ #define DBA_BRIDGE_CRITICAL_ERR 444 /** * struct recovery_mgr_info - Recovery manager information Loading