Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e72dda7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/sde: bridge chip error and smmu fault handling for recovery"

parents 3cf955ea faa4206f
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -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__
@@ -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;
@@ -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");
@@ -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;
@@ -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) {
@@ -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);

@@ -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)
@@ -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);
+4 −0
Original line number Diff line number Diff line
@@ -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__ */
+12 −0
Original line number Diff line number Diff line
@@ -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)
{
+20 −1
Original line number Diff line number Diff line
@@ -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,
};
@@ -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;
@@ -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.
@@ -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);

+7 −1
Original line number Diff line number Diff line
@@ -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