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

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

Merge "fg-memif: update IMA error handling and clear sequence"

parents c05ea068 bc17be09
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -342,6 +342,8 @@ extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len);
extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len);
extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len);
extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val);
extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val);
extern int fg_ima_init(struct fg_chip *chip);
extern int fg_ima_init(struct fg_chip *chip);
extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts);
extern int fg_clear_dma_errors_if_any(struct fg_chip *chip);
extern int fg_debugfs_create(struct fg_chip *chip);
extern int fg_debugfs_create(struct fg_chip *chip);
extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len);
extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len);
extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos);
extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos);
+156 −37
Original line number Original line Diff line number Diff line
@@ -64,44 +64,90 @@ static int fg_config_access_mode(struct fg_chip *chip, bool access, bool burst)


static int fg_run_iacs_clear_sequence(struct fg_chip *chip)
static int fg_run_iacs_clear_sequence(struct fg_chip *chip)
{
{
	u8 tmp;
	u8 val, hw_sts, exp_sts;
	int rc;
	int rc, tries = 250;


	/*
	/*
	 * Values to write for running IACS clear sequence comes from
	 * Values to write for running IACS clear sequence comes from
	 * hardware documentation.
	 * hardware documentation.
	 */
	 */
	rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT,
	rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip),
				IACS_CLR_BIT);
			IACS_CLR_BIT | STATIC_CLK_EN_BIT,
			IACS_CLR_BIT | STATIC_CLK_EN_BIT);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip),
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip),
			rc);
			rc);
		return rc;
		return rc;
	}
	}


	tmp = 0x4;
	rc = fg_config_access_mode(chip, FG_READ, false);
	rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &tmp, 1);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_ADDR_LSB(chip),
		pr_err("failed to write to 0x%04x, rc=%d\n",
			rc);
			MEM_IF_IMA_CTL(chip), rc);
		return rc;
		return rc;
	}
	}


	tmp = 0x0;
	rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip),
	rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &tmp, 1);
				MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT,
				MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_WR_DATA3(chip),
		pr_err("failed to set ima_req_access bit rc=%d\n", rc);
			rc);
		return rc;
	}

	/* Delay for the clock to reach FG */
	usleep_range(35, 40);

	while (1) {
		val = 0;
		rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &val, 1);
		if (rc < 0) {
			pr_err("failed to write 0x%04x, rc=%d\n",
				MEM_IF_ADDR_MSB(chip), rc);
			return rc;
			return rc;
		}
		}


	rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &tmp, 1);
		val = 0;
		rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &val, 1);
		if (rc < 0) {
		if (rc < 0) {
		pr_err("failed to read 0x%04x, rc=%d\n", MEM_IF_RD_DATA3(chip),
			pr_err("failed to write 0x%04x, rc=%d\n",
			rc);
				MEM_IF_WR_DATA3(chip), rc);
			return rc;
			return rc;
		}
		}


		rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &val, 1);
		if (rc < 0) {
			pr_err("failed to read 0x%04x, rc=%d\n",
				MEM_IF_RD_DATA3(chip), rc);
			return rc;
		}

		/* Delay for IMA hardware to clear */
		usleep_range(35, 40);

		rc = fg_read(chip, MEM_IF_IMA_HW_STS(chip), &hw_sts, 1);
		if (rc < 0) {
			pr_err("failed to read ima_hw_sts rc=%d\n", rc);
			return rc;
		}

		if (hw_sts != 0)
			continue;

		rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1);
		if (rc < 0) {
			pr_err("failed to read ima_exp_sts rc=%d\n", rc);
			return rc;
		}

		if (exp_sts == 0 || !(--tries))
			break;
	}

	if (!tries)
		pr_err("Failed to clear the error? hw_sts: %x exp_sts: %d\n",
			hw_sts, exp_sts);

	rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0);
	rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip),
		pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip),
@@ -109,22 +155,54 @@ static int fg_run_iacs_clear_sequence(struct fg_chip *chip)
		return rc;
		return rc;
	}
	}


	udelay(5);

	rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip),
				MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, 0);
	if (rc < 0) {
		pr_err("failed to write to 0x%04x, rc=%d\n",
			MEM_IF_MEM_INTF_CFG(chip), rc);
		return rc;
	}

	/* Delay before next transaction is attempted */
	usleep_range(35, 40);
	fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n");
	fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n");
	return rc;
	return rc;
}
}


static int fg_check_for_ima_errors(struct fg_chip *chip)
int fg_clear_dma_errors_if_any(struct fg_chip *chip)
{
{
	int rc = 0;
	int rc;
	u8 err_sts, exp_sts = 0, hw_sts = 0;
	u8 dma_sts;


	rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1);
	rc = fg_read(chip, MEM_IF_DMA_STS(chip), &dma_sts, 1);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to read ima_err_sts rc=%d\n", rc);
		pr_err("failed to read addr=0x%04x, rc=%d\n",
			MEM_IF_DMA_STS(chip), rc);
		return rc;
	}
	fg_dbg(chip, FG_STATUS, "dma_sts: %x\n", dma_sts);

	if (dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT)) {
		rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip),
				DMA_CLEAR_LOG_BIT, DMA_CLEAR_LOG_BIT);
		if (rc < 0) {
			pr_err("failed to write addr=0x%04x, rc=%d\n",
				MEM_IF_DMA_CTL(chip), rc);
			return rc;
			return rc;
		}
		}
	}

	return 0;
}

int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts)
{
	int rc = 0;
	u8 err_sts, exp_sts = 0, hw_sts = 0;
	bool run_err_clr_seq = false;


	if (err_sts & (ADDR_STBL_ERR_BIT | WR_ACS_ERR_BIT | RD_ACS_ERR_BIT)) {
	rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1);
	rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1);
	if (rc < 0) {
	if (rc < 0) {
		pr_err("failed to read ima_exp_sts rc=%d\n", rc);
		pr_err("failed to read ima_exp_sts rc=%d\n", rc);
@@ -137,9 +215,36 @@ static int fg_check_for_ima_errors(struct fg_chip *chip)
		return rc;
		return rc;
	}
	}


		pr_err("ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n",
	rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1);
	if (rc < 0) {
		pr_err("failed to read ima_err_sts rc=%d\n", rc);
		return rc;
	}

	fg_dbg(chip, FG_STATUS, "ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n",
		err_sts, exp_sts, hw_sts);
		err_sts, exp_sts, hw_sts);


	if (check_hw_sts) {
		/*
		 * Lower nibble should be equal to upper nibble before SRAM
		 * transactions begins from SW side. If they are unequal, then
		 * the error clear sequence should be run irrespective of IMA
		 * exception errors.
		 */
		if ((hw_sts & 0x0F) != hw_sts >> 4) {
			pr_err("IMA HW not in correct state, hw_sts=%x\n",
				hw_sts);
			run_err_clr_seq = true;
		}
	}

	if (exp_sts & (IACS_ERR_BIT | XCT_TYPE_ERR_BIT | DATA_RD_ERR_BIT |
		DATA_WR_ERR_BIT | ADDR_BURST_WRAP_BIT | ADDR_STABLE_ERR_BIT)) {
		pr_err("IMA exception bit set, exp_sts=%x\n", exp_sts);
		run_err_clr_seq = true;
	}

	if (run_err_clr_seq) {
		/* clear the error */
		/* clear the error */
		rc = fg_run_iacs_clear_sequence(chip);
		rc = fg_run_iacs_clear_sequence(chip);
		if (rc < 0) {
		if (rc < 0) {
@@ -156,7 +261,7 @@ static int fg_check_for_ima_errors(struct fg_chip *chip)


static int fg_check_iacs_ready(struct fg_chip *chip)
static int fg_check_iacs_ready(struct fg_chip *chip)
{
{
	int rc = 0, timeout = 250;
	int rc = 0, tries = 250;
	u8 ima_opr_sts = 0;
	u8 ima_opr_sts = 0;


	/*
	/*
@@ -176,17 +281,17 @@ static int fg_check_iacs_ready(struct fg_chip *chip)
		if (ima_opr_sts & IACS_RDY_BIT)
		if (ima_opr_sts & IACS_RDY_BIT)
			break;
			break;


		if (!(--timeout))
		if (!(--tries))
			break;
			break;


		/* delay for iacs_ready to be asserted */
		/* delay for iacs_ready to be asserted */
		usleep_range(5000, 7000);
		usleep_range(5000, 7000);
	}
	}


	if (!timeout) {
	if (!tries) {
		pr_err("IACS_RDY not set\n");
		pr_err("IACS_RDY not set\n");

		/* check for error condition */
		rc = fg_check_for_ima_errors(chip);
		rc = fg_clear_ima_errors_if_any(chip, false);
		if (rc < 0) {
		if (rc < 0) {
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			return rc;
			return rc;
@@ -250,7 +355,7 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address,
		}
		}


		/* check for error condition */
		/* check for error condition */
		rc = fg_check_for_ima_errors(chip);
		rc = fg_clear_ima_errors_if_any(chip, false);
		if (rc < 0) {
		if (rc < 0) {
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			return rc;
			return rc;
@@ -296,7 +401,7 @@ static int __fg_interleaved_mem_read(struct fg_chip *chip, u16 address,
		offset = 0;
		offset = 0;


		/* check for error condition */
		/* check for error condition */
		rc = fg_check_for_ima_errors(chip);
		rc = fg_clear_ima_errors_if_any(chip, false);
		if (rc < 0) {
		if (rc < 0) {
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			pr_err("Failed to check for ima errors rc=%d\n", rc);
			return rc;
			return rc;
@@ -581,5 +686,19 @@ int fg_ima_init(struct fg_chip *chip)
		return rc;
		return rc;
	}
	}


	/* Clear DMA errors if any before clearing IMA errors */
	rc = fg_clear_dma_errors_if_any(chip);
	if (rc < 0) {
		pr_err("Error in checking DMA errors rc:%d\n", rc);
		return rc;
	}

	/* Clear IMA errors if any before SRAM transactions can begin */
	rc = fg_clear_ima_errors_if_any(chip, true);
	if (rc < 0 && rc != -EAGAIN) {
		pr_err("Error in checking IMA errors rc:%d\n", rc);
		return rc;
	}

	return 0;
	return 0;
}
}
+22 −0
Original line number Original line Diff line number Diff line
@@ -258,6 +258,7 @@
#define ESR_REQ_CTL_EN_BIT			BIT(0)
#define ESR_REQ_CTL_EN_BIT			BIT(0)


/* FG_MEM_IF register and bit definitions */
/* FG_MEM_IF register and bit definitions */
#define MEM_IF_INT_RT_STS(chip)			((chip->mem_if_base) + 0x10)
#define MEM_IF_MEM_INTF_CFG(chip)		((chip->mem_if_base) + 0x50)
#define MEM_IF_MEM_INTF_CFG(chip)		((chip->mem_if_base) + 0x50)
#define MEM_IF_IMA_CTL(chip)			((chip->mem_if_base) + 0x51)
#define MEM_IF_IMA_CTL(chip)			((chip->mem_if_base) + 0x51)
#define MEM_IF_IMA_CFG(chip)			((chip->mem_if_base) + 0x52)
#define MEM_IF_IMA_CFG(chip)			((chip->mem_if_base) + 0x52)
@@ -273,6 +274,11 @@
#define MEM_IF_WR_DATA3(chip)			((chip->mem_if_base) + 0x66)
#define MEM_IF_WR_DATA3(chip)			((chip->mem_if_base) + 0x66)
#define MEM_IF_RD_DATA0(chip)			((chip->mem_if_base) + 0x67)
#define MEM_IF_RD_DATA0(chip)			((chip->mem_if_base) + 0x67)
#define MEM_IF_RD_DATA3(chip)			((chip->mem_if_base) + 0x6A)
#define MEM_IF_RD_DATA3(chip)			((chip->mem_if_base) + 0x6A)
#define MEM_IF_DMA_STS(chip)			((chip->mem_if_base) + 0x70)
#define MEM_IF_DMA_CTL(chip)			((chip->mem_if_base) + 0x71)

/* MEM_IF_INT_RT_STS */
#define MEM_XCP_BIT				BIT(1)


/* MEM_IF_MEM_INTF_CFG */
/* MEM_IF_MEM_INTF_CFG */
#define MEM_ACCESS_REQ_BIT			BIT(7)
#define MEM_ACCESS_REQ_BIT			BIT(7)
@@ -286,10 +292,19 @@
/* MEM_IF_IMA_CFG */
/* MEM_IF_IMA_CFG */
#define IACS_CLR_BIT				BIT(2)
#define IACS_CLR_BIT				BIT(2)
#define IACS_INTR_SRC_SLCT_BIT			BIT(3)
#define IACS_INTR_SRC_SLCT_BIT			BIT(3)
#define STATIC_CLK_EN_BIT			BIT(4)


/* MEM_IF_IMA_OPR_STS */
/* MEM_IF_IMA_OPR_STS */
#define IACS_RDY_BIT				BIT(1)
#define IACS_RDY_BIT				BIT(1)


/* MEM_IF_IMA_EXP_STS */
#define IACS_ERR_BIT				BIT(0)
#define XCT_TYPE_ERR_BIT			BIT(1)
#define DATA_RD_ERR_BIT				BIT(3)
#define DATA_WR_ERR_BIT				BIT(4)
#define ADDR_BURST_WRAP_BIT			BIT(5)
#define ADDR_STABLE_ERR_BIT			BIT(7)

/* MEM_IF_IMA_ERR_STS */
/* MEM_IF_IMA_ERR_STS */
#define ADDR_STBL_ERR_BIT			BIT(7)
#define ADDR_STBL_ERR_BIT			BIT(7)
#define WR_ACS_ERR_BIT				BIT(6)
#define WR_ACS_ERR_BIT				BIT(6)
@@ -297,4 +312,11 @@


/* MEM_IF_FG_BEAT_COUNT */
/* MEM_IF_FG_BEAT_COUNT */
#define BEAT_COUNT_MASK				GENMASK(3, 0)
#define BEAT_COUNT_MASK				GENMASK(3, 0)

/* MEM_IF_DMA_STS */
#define DMA_WRITE_ERROR_BIT			BIT(1)
#define DMA_READ_ERROR_BIT			BIT(2)

/* MEM_IF_DMA_CTL */
#define DMA_CLEAR_LOG_BIT			BIT(0)
#endif
#endif
+32 −1
Original line number Original line Diff line number Diff line
@@ -2267,6 +2267,37 @@ static int fg_memif_init(struct fg_chip *chip)


/* INTERRUPT HANDLERS STAY HERE */
/* INTERRUPT HANDLERS STAY HERE */


static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
{
	struct fg_chip *chip = data;
	u8 status;
	int rc;

	rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
	if (rc < 0) {
		pr_err("failed to read addr=0x%04x, rc=%d\n",
			MEM_IF_INT_RT_STS(chip), rc);
		return IRQ_HANDLED;
	}

	fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
	if (status & MEM_XCP_BIT) {
		rc = fg_clear_dma_errors_if_any(chip);
		if (rc < 0) {
			pr_err("Error in clearing DMA error, rc=%d\n", rc);
			return IRQ_HANDLED;
		}

		mutex_lock(&chip->sram_rw_lock);
		rc = fg_clear_ima_errors_if_any(chip, true);
		if (rc < 0 && rc != -EAGAIN)
			pr_err("Error in checking IMA errors rc:%d\n", rc);
		mutex_unlock(&chip->sram_rw_lock);
	}

	return IRQ_HANDLED;
}

static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data)
{
{
	struct fg_chip *chip = data;
	struct fg_chip *chip = data;
@@ -2483,7 +2514,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
	},
	},
	[MEM_XCP_IRQ] = {
	[MEM_XCP_IRQ] = {
		.name		= "mem-xcp",
		.name		= "mem-xcp",
		.handler	= fg_dummy_irq_handler,
		.handler	= fg_mem_xcp_irq_handler,
	},
	},
	[IMA_RDY_IRQ] = {
	[IMA_RDY_IRQ] = {
		.name		= "ima-rdy",
		.name		= "ima-rdy",