summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErnesto Corona <ernesto.corona@intel.com>2021-03-30 18:40:42 +0300
committerJae Hyun Yoo <jae.hyun.yoo@linux.intel.com>2021-10-20 01:10:38 +0300
commit61d615deb0262e3ec5295a1802ffb6915e3d47da (patch)
tree0a2a6bd87e8c147e86bc923afd992f03474dc722
parentb8d5a06c8b7ed23d7398ecd92f76ec19cefb6805 (diff)
downloadlinux-61d615deb0262e3ec5295a1802ffb6915e3d47da.tar.xz
ASD AST26xx Add a delay in SW bitbang operations
Using an overshift test environment where we execute a continuous JTAG R/W operation during hours we discover that in one of million ocurences for AST26xx TDO read occurred before JTAG Master controller reflected real tdo value on ASPEED_JTAG_SW. It was needed to add two delays during the SW xfer process to prevent this issue. We tested several delay options and found that using a read/write to ASPEED_JTAG_PADCTRL1(not used in SW mode) register gives the JTAG Master controller enough time to process the xfer with the lowest performance impact among the delay options. For AST25xx an extra delay was not required. Test: All of the following in SW mode: AST26xx(SPR) ASD Sanity finished successfully. AST26xx(SPR) Overshift test with 4K iterations finished successfully. AST26xx(SPR) jtag_test with 8M iterations finished successfully. AST25xx(ICX) ASD Sanity finished successfully AST25xx(ICX) jtag_test with 8M iterations finished successfully. Signed-off-by: Ernesto Corona <ernesto.corona@intel.com> Change-Id: Idf82632a564495e0a69075c9b842e84d39419612
-rw-r--r--drivers/jtag/jtag-aspeed.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c
index 653fab91f248..aeb6502e5a85 100644
--- a/drivers/jtag/jtag-aspeed.c
+++ b/drivers/jtag/jtag-aspeed.c
@@ -200,7 +200,8 @@ struct aspeed_jtag {
u32 pad_data_zero[ASPEED_JTAG_MAX_PAD_SIZE / 32];
};
-/* Multi generation support is enabled by fops and low level assped function
+/*
+ * Multi generation support is enabled by fops and low level assped function
* mapping using asped_jtag_functions struct as config mechanism.
*/
@@ -216,6 +217,7 @@ struct jtag_low_level_functions {
int (*xfer_hw)(struct aspeed_jtag *aspeed_jtag, struct jtag_xfer *xfer,
u32 *data);
void (*xfer_hw_fifo_delay)(void);
+ void (*xfer_sw_delay)(struct aspeed_jtag *aspeed_jtag);
irqreturn_t (*jtag_interrupt)(s32 this_irq, void *dev_id);
};
@@ -411,6 +413,18 @@ static int aspeed_jtag_mode_set(struct jtag *jtag, struct jtag_mode *jtag_mode)
return 0;
}
+/*
+ * We read and write from an unused JTAG Master controller register in SW
+ * mode to create a delay in xfers.
+ * We found this mechanism better than any udelay or usleep option.
+ */
+static inline void aspeed_jtag_sw_delay_26xx(struct aspeed_jtag *aspeed_jtag)
+{
+ u32 read_reg = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_PADCTRL1);
+
+ aspeed_jtag_write(aspeed_jtag, read_reg, ASPEED_JTAG_PADCTRL1);
+}
+
static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag, u8 tms,
u8 tdi)
{
@@ -423,7 +437,11 @@ static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag, u8 tms,
(tdi * ASPEED_JTAG_SW_MODE_TDIO),
ASPEED_JTAG_SW);
- aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
+ /* Wait until JTAG Master controller finishes the operation */
+ if (aspeed_jtag->llops->xfer_sw_delay)
+ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag);
+ else
+ aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);
/* TCK = 1 */
aspeed_jtag_write(aspeed_jtag,
@@ -432,6 +450,10 @@ static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag, u8 tms,
(tdi * ASPEED_JTAG_SW_MODE_TDIO),
ASPEED_JTAG_SW);
+ /* Wait until JTAG Master controller finishes the operation */
+ if (aspeed_jtag->llops->xfer_sw_delay)
+ aspeed_jtag->llops->xfer_sw_delay(aspeed_jtag);
+
if (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &
ASPEED_JTAG_SW_MODE_TDIO)
tdo = 1;
@@ -1429,6 +1451,7 @@ static const struct jtag_low_level_functions ast25xx_llops = {
.xfer_sw = aspeed_jtag_xfer_sw,
.xfer_hw = aspeed_jtag_xfer_hw,
.xfer_hw_fifo_delay = NULL,
+ .xfer_sw_delay = NULL,
.jtag_interrupt = aspeed_jtag_interrupt
};
@@ -1446,6 +1469,7 @@ static const struct jtag_low_level_functions ast26xx_llops = {
.xfer_sw = aspeed_jtag_xfer_sw,
.xfer_hw = aspeed_jtag_xfer_hw2,
.xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx,
+ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx,
.jtag_interrupt = aspeed_jtag_interrupt_hw2
#else
.master_enable = aspeed_jtag_master,
@@ -1455,6 +1479,7 @@ static const struct jtag_low_level_functions ast26xx_llops = {
.xfer_sw = aspeed_jtag_xfer_sw,
.xfer_hw = aspeed_jtag_xfer_hw,
.xfer_hw_fifo_delay = aspeed_jtag_xfer_hw_fifo_delay_26xx,
+ .xfer_sw_delay = aspeed_jtag_sw_delay_26xx,
.jtag_interrupt = aspeed_jtag_interrupt
#endif
};