summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVatsal Bucha <vbucha@codeaurora.org>2020-07-13 02:30:04 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2020-07-26 03:33:23 -0700
commitad9d364285b1b3363909a325545b720b02794122 (patch)
tree12477bb0aaeae247275911ffac421823dc6baf4d
parentead188cb70dac01923cda368996955fa7a17038d (diff)
downloadmsm-extra-ad9d364285b1b3363909a325545b720b02794122.tar.gz
soc: swr-mstr: Avoid overflow during swr fifo read/write
Avoid swr fifo overflow by checking no. of outstanding commands in fifo and comparing with fifo depth before every read/write. If no. of commands is equal to fifo depth then give some delay and retry. If no of outstanding commands are still equal to fifo depth then flush fifo and try writing/reading from fifo again. Change-Id: Ifd986c7affb70a61f8a90e4960a2779273a7d4d2 Signed-off-by: Vatsal Bucha <vbucha@codeaurora.org>
-rw-r--r--soc/swr-mstr-ctrl.c72
-rw-r--r--soc/swr-mstr-ctrl.h2
2 files changed, 74 insertions, 0 deletions
diff --git a/soc/swr-mstr-ctrl.c b/soc/swr-mstr-ctrl.c
index beaaa26f..623f70e6 100644
--- a/soc/swr-mstr-ctrl.c
+++ b/soc/swr-mstr-ctrl.c
@@ -56,6 +56,8 @@
#define SWRM_COL_02 02
#define SWRM_COL_16 16
+#define SWR_OVERFLOW_RETRY_COUNT 30
+
/* pm runtime auto suspend timer in msecs */
static int auto_suspend_timer = SWR_AUTO_SUSPEND_DELAY * 1000;
module_param(auto_suspend_timer, int, 0664);
@@ -84,6 +86,11 @@ enum {
LPASS_AUDIO_CORE,
};
+enum {
+ SWRM_WR_CHECK_AVAIL,
+ SWRM_RD_CHECK_AVAIL,
+};
+
#define TRUE 1
#define FALSE 0
@@ -743,6 +750,54 @@ static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
return val;
}
+static void swrm_wait_for_fifo_avail(struct swr_mstr_ctrl *swrm, int swrm_rd_wr)
+{
+ u32 fifo_outstanding_cmd;
+ u8 fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
+
+ if (swrm_rd_wr) {
+ /* Check for fifo underflow during read */
+ /* Check no of outstanding commands in fifo before read */
+ fifo_outstanding_cmd = ((swr_master_read(swrm,
+ SWRM_CMD_FIFO_STATUS) & 0x001F0000) >> 16);
+ if (fifo_outstanding_cmd == 0) {
+ while (fifo_retry_count) {
+ usleep_range(500, 510);
+ fifo_outstanding_cmd =
+ ((swr_master_read (swrm,
+ SWRM_CMD_FIFO_STATUS) & 0x001F0000)
+ >> 16);
+ fifo_retry_count--;
+ if (fifo_outstanding_cmd > 0)
+ break;
+ }
+ }
+ if (fifo_outstanding_cmd == 0)
+ dev_err_ratelimited(swrm->dev,
+ "%s err read underflow\n", __func__);
+ } else {
+ /* Check for fifo overflow during write */
+ /* Check no of outstanding commands in fifo before write */
+ fifo_outstanding_cmd = ((swr_master_read(swrm,
+ SWRM_CMD_FIFO_STATUS) & 0x00001F00)
+ >> 8);
+ if (fifo_outstanding_cmd == swrm->wr_fifo_depth) {
+ while (fifo_retry_count) {
+ usleep_range(500, 510);
+ fifo_outstanding_cmd =
+ ((swr_master_read(swrm, SWRM_CMD_FIFO_STATUS)
+ & 0x00001F00) >> 8);
+ fifo_retry_count--;
+ if (fifo_outstanding_cmd < swrm->wr_fifo_depth)
+ break;
+ }
+ }
+ if (fifo_outstanding_cmd == swrm->wr_fifo_depth)
+ dev_err_ratelimited(swrm->dev,
+ "%s err write overflow\n", __func__);
+ }
+}
+
static int swrm_cmd_fifo_rd_cmd(struct swr_mstr_ctrl *swrm, int *cmd_data,
u8 dev_addr, u8 cmd_id, u16 reg_addr,
u32 len)
@@ -756,12 +811,19 @@ static int swrm_cmd_fifo_rd_cmd(struct swr_mstr_ctrl *swrm, int *cmd_data,
/* skip delay if read is handled in platform driver */
swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
} else {
+ /*
+ * Check for outstanding cmd wrt. write fifo depth to avoid
+ * overflow as read will also increase write fifo cnt.
+ */
+ swrm_wait_for_fifo_avail(swrm, SWRM_WR_CHECK_AVAIL);
/* wait for FIFO RD to complete to avoid overflow */
usleep_range(100, 105);
swr_master_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
/* wait for FIFO RD CMD complete to avoid overflow */
usleep_range(250, 255);
}
+ /* Check if slave responds properly after FIFO RD is complete */
+ swrm_wait_for_fifo_avail(swrm, SWRM_RD_CHECK_AVAIL);
retry_read:
*cmd_data = swr_master_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR);
dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x, rcmd_id: 0x%x, \
@@ -808,6 +870,11 @@ static int swrm_cmd_fifo_wr_cmd(struct swr_mstr_ctrl *swrm, u8 cmd_data,
dev_dbg(swrm->dev, "%s: reg: 0x%x, cmd_id: 0x%x,wcmd_id: 0x%x, \
dev_num: 0x%x, cmd_data: 0x%x\n", __func__,
reg_addr, cmd_id, swrm->wcmd_id,dev_addr, cmd_data);
+ /*
+ * Check for outstanding cmd wrt. write fifo depth to avoid
+ * overflow.
+ */
+ swrm_wait_for_fifo_avail(swrm, SWRM_WR_CHECK_AVAIL);
swr_master_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
/*
* wait for FIFO WR command to complete to avoid overflow
@@ -2785,6 +2852,11 @@ static int swrm_probe(struct platform_device *pdev)
if (pdev->dev.of_node)
of_register_swr_devices(&swrm->master);
+ swrm->rd_fifo_depth = ((swr_master_read(swrm, SWRM_COMP_PARAMS)
+ & SWRM_COMP_PARAMS_RD_FIFO_DEPTH) >> 15);
+ swrm->wr_fifo_depth = ((swr_master_read(swrm, SWRM_COMP_PARAMS)
+ & SWRM_COMP_PARAMS_WR_FIFO_DEPTH) >> 10);
+
#ifdef CONFIG_DEBUG_FS
swrm->debugfs_swrm_dent = debugfs_create_dir(dev_name(&pdev->dev), 0);
if (!IS_ERR(swrm->debugfs_swrm_dent)) {
diff --git a/soc/swr-mstr-ctrl.h b/soc/swr-mstr-ctrl.h
index 8d384412..51b35386 100644
--- a/soc/swr-mstr-ctrl.h
+++ b/soc/swr-mstr-ctrl.h
@@ -182,6 +182,8 @@ struct swr_mstr_ctrl {
int aud_core_clk_en;
int clk_src;
u32 disable_div2_clk_switch;
+ u32 rd_fifo_depth;
+ u32 wr_fifo_depth;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_swrm_dent;
struct dentry *debugfs_peek;