[U-Boot] [PATCH 1/6] arm: socfpga: scan: Clean up scan_chain_engine_is_idle()

Rework this function so it's clear that it is only polling for certain bits to be cleared. Add kerneldoc. Fix it's return value to be either 0 on success and -ETIMEDOUT on error and propagate this through the scan manager code.
Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/include/mach/scan_manager.h | 9 ---- arch/arm/mach-socfpga/scan_manager.c | 53 +++++++++++++++-------- 2 files changed, 34 insertions(+), 28 deletions(-)
diff --git a/arch/arm/mach-socfpga/include/mach/scan_manager.h b/arch/arm/mach-socfpga/include/mach/scan_manager.h index 94ad50b..ddf8790 100644 --- a/arch/arm/mach-socfpga/include/mach/scan_manager.h +++ b/arch/arm/mach-socfpga/include/mach/scan_manager.h @@ -59,15 +59,6 @@ struct socfpga_scan_manager { /* Position of second command byte for TDI_TDO packet */ #define TDI_TDO_HEADER_SECOND_BYTE_SHIFT 8
-/* - * Maximum polling loop to wait for IO scan chain engine - * becomes idle to prevent infinite loop - */ -#define SCAN_MAX_DELAY 100 - -#define SCANMGR_STAT_ACTIVE_GET(x) (((x) & 0x80000000) >> 31) -#define SCANMGR_STAT_WFIFOCNT_GET(x) (((x) & 0x70000000) >> 28) - int scan_mgr_configure_iocsr(void); int iocsr_get_config_table(const unsigned int chain_id, const unsigned long **table, diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c index ec0c630..db47f4f 100644 --- a/arch/arm/mach-socfpga/scan_manager.c +++ b/arch/arm/mach-socfpga/scan_manager.c @@ -5,10 +5,22 @@ */
#include <common.h> +#include <errno.h> #include <asm/io.h> #include <asm/arch/freeze_controller.h> #include <asm/arch/scan_manager.h>
+/* + * Maximum polling loop to wait for IO scan chain engine becomes idle + * to prevent infinite loop. It is important that this is NOT changed + * to delay using timer functions, since at the time this function is + * called, timer might not yet be inited. + */ +#define SCANMGR_MAX_DELAY 100 + +#define SCANMGR_STAT_ACTIVE (1 << 31) +#define SCANMGR_STAT_WFIFOCNT_MASK 0x70000000 + DECLARE_GLOBAL_DATA_PTR;
static const struct socfpga_scan_manager *scan_manager_base = @@ -16,26 +28,26 @@ static const struct socfpga_scan_manager *scan_manager_base = static const struct socfpga_freeze_controller *freeze_controller_base = (void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
-/* +/** + * scan_chain_engine_is_idle() - Check if the JTAG scan chain is idle + * @max_iter: Maximum number of iterations to wait for idle + * * Function to check IO scan chain engine status and wait if the engine is * is active. Poll the IO scan chain engine till maximum iteration reached. */ -static inline uint32_t scan_chain_engine_is_idle(uint32_t max_iter) +static u32 scan_chain_engine_is_idle(uint32_t max_iter) { - uint32_t scanmgr_status; - - scanmgr_status = readl(&scan_manager_base->stat); + const u32 mask = SCANMGR_STAT_ACTIVE | SCANMGR_STAT_WFIFOCNT_MASK; + u32 status;
- /* Poll the engine until the scan engine is inactive */ - while (SCANMGR_STAT_ACTIVE_GET(scanmgr_status) || - (SCANMGR_STAT_WFIFOCNT_GET(scanmgr_status) > 0)) { - max_iter--; - if (max_iter > 0) - scanmgr_status = readl(&scan_manager_base->stat); - else + /* Poll the engine until the scan engine is inactive. */ + do { + status = readl(&scan_manager_base->stat); + if (!(status & mask)) return 0; - } - return 1; + } while (max_iter--); + + return -ETIMEDOUT; }
/** @@ -70,8 +82,9 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) * Check if the scan chain engine is inactive and the * WFIFO is empty before enabling the IO scan chain */ - if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY)) - return 1; + ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); + if (ret) + return ret;
/* * Enable IO Scan chain based on scan chain id @@ -114,7 +127,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) * Check if the scan chain engine has completed the * IO scan chain data shifting */ - if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY)) + ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); + if (ret) goto error; }
@@ -185,7 +199,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) * Check if the scan chain engine has completed the * IO scan chain data shifting */ - if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY)) + ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); + if (ret) goto error; }
@@ -196,7 +211,7 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) error: /* Disable IO Scan chain when error detected */ clrbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id); - return 1; + return ret; }
int scan_mgr_configure_iocsr(void)

Introduce generic function for accessing the JTAG scan chains in the SCC manager. Make use of this function throughout the SCC manager to replace the ad-hoc writes to registers and make the code less cryptic.
Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/scan_manager.c | 104 +++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 41 deletions(-)
diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c index db47f4f..962e3bd 100644 --- a/arch/arm/mach-socfpga/scan_manager.c +++ b/arch/arm/mach-socfpga/scan_manager.c @@ -50,13 +50,57 @@ static u32 scan_chain_engine_is_idle(uint32_t max_iter) return -ETIMEDOUT; }
+#define JTAG_BP_INSN (1 << 0) +#define JTAG_BP_TMS (1 << 1) +#define JTAG_BP_PAYLOAD (1 << 2) +#define JTAG_BP_2BYTE (1 << 3) +#define JTAG_BP_4BYTE (1 << 4) + +/** + * scan_mgr_jtag_io() - Access the JTAG chain + * @flags: Control flags, used to configure the action on the JTAG + * @iarg: Instruction argument + * @parg: Payload argument or data + * + * Perform I/O on the JTAG chain + */ +static void scan_mgr_jtag_io(const u32 flags, const u8 iarg, const u32 parg) +{ + u32 data = parg; + + if (flags & JTAG_BP_INSN) { /* JTAG instruction */ + /* + * The SCC JTAG register is LSB first, so make + * space for the instruction at the LSB. + */ + data <<= 8; + if (flags & JTAG_BP_TMS) { + data |= (0 << 7); /* TMS instruction. */ + data |= iarg & 0x3f; /* TMS arg is 6 bits. */ + if (flags & JTAG_BP_PAYLOAD) + data |= (1 << 6); + } else { + data |= (1 << 7); /* TDI/TDO instruction. */ + data |= iarg & 0xf; /* TDI/TDO arg is 4 bits. */ + if (flags & JTAG_BP_PAYLOAD) + data |= (1 << 4); + } + } + + if (flags & JTAG_BP_4BYTE) + writel(data, &scan_manager_base->fifo_quad_byte); + else if (flags & JTAG_BP_2BYTE) + writel(data & 0xffff, &scan_manager_base->fifo_double_byte); + else + writel(data & 0xff, &scan_manager_base->fifo_single_byte); +} + /** * scan_mgr_io_scan_chain_prg() - Program HPS IO Scan Chain * @io_scan_chain_id: IO scan chain ID */ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) { - uint16_t tdi_tdo_header; uint32_t io_program_iter; uint32_t io_scan_chain_data_residual; uint32_t residual; @@ -101,27 +145,17 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) io_scan_chain_data_residual = io_scan_chain_len_in_bits & IO_SCAN_CHAIN_128BIT_MASK;
- /* Construct TDI_TDO packet for 128-bit IO scan chain (2 bytes) */ - tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE | - (TDI_TDO_MAX_PAYLOAD << TDI_TDO_HEADER_SECOND_BYTE_SHIFT); - /* Program IO scan chain in 128-bit iteration */ for (i = 0; i < io_program_iter; i++) { - /* write TDI_TDO packet header to scan manager */ - writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte); - - /* calculate array index. Multiply by 4 as write 4 x 32bits */ - index = i * 4; + /* Write TDI_TDO packet header for 128-bit IO scan chain */ + scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, + TDI_TDO_MAX_PAYLOAD);
/* write 4 successive 32-bit IO scan chain data into WFIFO */ - writel(iocsr_scan_chain[index], - &scan_manager_base->fifo_quad_byte); - writel(iocsr_scan_chain[index + 1], - &scan_manager_base->fifo_quad_byte); - writel(iocsr_scan_chain[index + 2], - &scan_manager_base->fifo_quad_byte); - writel(iocsr_scan_chain[index + 3], - &scan_manager_base->fifo_quad_byte); + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]);
/* * Check if the scan chain engine has completed the @@ -132,9 +166,6 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) goto error; }
- /* Calculate array index for final TDI_TDO packet */ - index = io_program_iter * 4; - /* Final TDI_TDO packet if any */ if (io_scan_chain_data_residual) { /* @@ -145,29 +176,21 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) IO_SCAN_CHAIN_32BIT_SHIFT;
/* - * Construct TDI_TDO packet for remaining IO - * scan chain (2 bytes) + * Program the last part of IO scan chain write TDI_TDO + * packet header (2 bytes) to scan manager. */ - tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE | - ((io_scan_chain_data_residual - 1) << - TDI_TDO_HEADER_SECOND_BYTE_SHIFT); - - /* - * Program the last part of IO scan chain write TDI_TDO packet - * header (2 bytes) to scan manager - */ - writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte); + scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, + io_scan_chain_data_residual - 1);
for (i = 0; i < io_program_iter; i++) { /* * write remaining scan chain data into scan * manager WFIFO with 4 bytes write - */ - writel(iocsr_scan_chain[index + i], - &scan_manager_base->fifo_quad_byte); + */ + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, + iocsr_scan_chain[index++]); }
- index += io_program_iter; residual = io_scan_chain_data_residual & IO_SCAN_CHAIN_32BIT_MASK;
@@ -176,8 +199,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) * write the last 4B scan chain data * into scan manager WFIFO */ - writel(iocsr_scan_chain[index], - &scan_manager_base->fifo_quad_byte); + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, + iocsr_scan_chain[index]); } else { /* * write the remaining 1 - 3 bytes scan chain @@ -189,9 +212,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) * glitch) */ for (i = 0; i < residual; i += 8) { - writel(((iocsr_scan_chain[index] >> i) - & IO_SCAN_CHAIN_BYTE_MASK), - &scan_manager_base->fifo_single_byte); + scan_mgr_jtag_io(0, 0x0, + iocsr_scan_chain[index] >> i); } }

On 8/3/15 9:22 AM, Marek Vasut wrote:
Introduce generic function for accessing the JTAG scan chains in the SCC manager. Make use of this function throughout the SCC manager to replace the ad-hoc writes to registers and make the code less cryptic.
Signed-off-by: Marek Vasut marex@denx.de
arch/arm/mach-socfpga/scan_manager.c | 104 +++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 41 deletions(-)
Acked-by: Dinh Nguyen dinguyen@opensource.altera.com
Thanks, Dinh

Clean up the horrible macros present in the scan_manager.h . Firstly, the function scan_mgr_io_scan_chain_prg() is static, yet all the macros are used only within it, thus there is no point in having them in the header file. Moreover, the macros are just making the code much less readable, so remove them instead.
Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/include/mach/scan_manager.h | 42 -------------------- arch/arm/mach-socfpga/scan_manager.c | 47 ++++++++--------------- 2 files changed, 17 insertions(+), 72 deletions(-)
diff --git a/arch/arm/mach-socfpga/include/mach/scan_manager.h b/arch/arm/mach-socfpga/include/mach/scan_manager.h index ddf8790..3b55e37 100644 --- a/arch/arm/mach-socfpga/include/mach/scan_manager.h +++ b/arch/arm/mach-socfpga/include/mach/scan_manager.h @@ -17,48 +17,6 @@ struct socfpga_scan_manager { u32 fifo_quad_byte; };
-/* - * Shift count to get number of IO scan chain data in granularity - * of 128-bit ( N / 128 ) - */ -#define IO_SCAN_CHAIN_128BIT_SHIFT 7 - -/* - * Mask to get residual IO scan chain data in - * granularity of 128-bit ( N mod 128 ) - */ -#define IO_SCAN_CHAIN_128BIT_MASK 0x7F - -/* - * Shift count to get number of IO scan chain - * data in granularity of 32-bit ( N / 32 ) - */ -#define IO_SCAN_CHAIN_32BIT_SHIFT 5 - -/* - * Mask to get residual IO scan chain data in - * granularity of 32-bit ( N mod 32 ) - */ -#define IO_SCAN_CHAIN_32BIT_MASK 0x1F - -/* Byte mask */ -#define IO_SCAN_CHAIN_BYTE_MASK 0xFF - -/* 24-bits (3 bytes) IO scan chain payload definition */ -#define IO_SCAN_CHAIN_PAYLOAD_24BIT 24 - -/* - * Maximum length of TDI_TDO packet payload is 128 bits, - * represented by (length - 1) in TDI_TDO header - */ -#define TDI_TDO_MAX_PAYLOAD 127 - -/* TDI_TDO packet header for IO scan chain program */ -#define TDI_TDO_HEADER_FIRST_BYTE 0x80 - -/* Position of second command byte for TDI_TDO packet */ -#define TDI_TDO_HEADER_SECOND_BYTE_SHIFT 8 - int scan_mgr_configure_iocsr(void); int iocsr_get_config_table(const unsigned int chain_id, const unsigned long **table, diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c index 962e3bd..1f24e51 100644 --- a/arch/arm/mach-socfpga/scan_manager.c +++ b/arch/arm/mach-socfpga/scan_manager.c @@ -18,6 +18,12 @@ */ #define SCANMGR_MAX_DELAY 100
+/* + * Maximum length of TDI_TDO packet payload is 128 bits, + * represented by (length - 1) in TDI_TDO header. + */ +#define TDI_TDO_MAX_PAYLOAD 127 + #define SCANMGR_STAT_ACTIVE (1 << 31) #define SCANMGR_STAT_WFIFOCNT_MASK 0x70000000
@@ -101,13 +107,10 @@ static void scan_mgr_jtag_io(const u32 flags, const u8 iarg, const u32 parg) */ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) { - uint32_t io_program_iter; - uint32_t io_scan_chain_data_residual; - uint32_t residual; - uint32_t i, ret; - uint32_t index = 0; - uint32_t io_scan_chain_len_in_bits; + u32 residual; + u32 io_scan_chain_len_in_bits; const unsigned long *iocsr_scan_chain; + int i, ret, index = 0;
ret = iocsr_get_config_table(io_scan_chain_id, &iocsr_scan_chain, &io_scan_chain_len_in_bits); @@ -136,17 +139,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) */ setbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
- /* - * Calculate number of iteration needed for full 128-bit (4 x32-bits) - * bits shifting. Each TDI_TDO packet can shift in maximum 128-bits - */ - io_program_iter = io_scan_chain_len_in_bits >> - IO_SCAN_CHAIN_128BIT_SHIFT; - io_scan_chain_data_residual = io_scan_chain_len_in_bits & - IO_SCAN_CHAIN_128BIT_MASK; - /* Program IO scan chain in 128-bit iteration */ - for (i = 0; i < io_program_iter; i++) { + for (i = 0; i < io_scan_chain_len_in_bits / 128; i++) { /* Write TDI_TDO packet header for 128-bit IO scan chain */ scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, TDI_TDO_MAX_PAYLOAD); @@ -166,23 +160,18 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) goto error; }
- /* Final TDI_TDO packet if any */ - if (io_scan_chain_data_residual) { - /* - * Calculate number of quad bytes FIFO write - * needed for the final TDI_TDO packet - */ - io_program_iter = io_scan_chain_data_residual >> - IO_SCAN_CHAIN_32BIT_SHIFT; + residual = io_scan_chain_len_in_bits % 128;
+ /* Final TDI_TDO packet (if chain length is not aligned to 128 bits) */ + if (residual) { /* * Program the last part of IO scan chain write TDI_TDO * packet header (2 bytes) to scan manager. */ scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, - io_scan_chain_data_residual - 1); + residual - 1);
- for (i = 0; i < io_program_iter; i++) { + for (i = 0; i < residual / 32; i++) { /* * write remaining scan chain data into scan * manager WFIFO with 4 bytes write @@ -191,10 +180,8 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) iocsr_scan_chain[index++]); }
- residual = io_scan_chain_data_residual & - IO_SCAN_CHAIN_32BIT_MASK; - - if (IO_SCAN_CHAIN_PAYLOAD_24BIT < residual) { + residual = io_scan_chain_len_in_bits % 32; + if (residual > 24) { /* * write the last 4B scan chain data * into scan manager WFIFO

On 8/3/15 9:22 AM, Marek Vasut wrote:
Clean up the horrible macros present in the scan_manager.h . Firstly, the function scan_mgr_io_scan_chain_prg() is static, yet all the macros are used only within it, thus there is no point in having them in the header file. Moreover, the macros are just making the code much less readable, so remove them instead.
Signed-off-by: Marek Vasut marex@denx.de
arch/arm/mach-socfpga/include/mach/scan_manager.h | 42 -------------------- arch/arm/mach-socfpga/scan_manager.c | 47 ++++++++--------------- 2 files changed, 17 insertions(+), 72 deletions(-)
Acked-by: Dinh Nguyen dinguyen@opensource.altera.com
Thanks, Dinh

Factor out the code which sends JTAG instruction followed by data into separate function to tidy the code up a little.
Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/scan_manager.c | 113 +++++++++++++---------------------- 1 file changed, 42 insertions(+), 71 deletions(-)
diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c index 1f24e51..4f2c4b5 100644 --- a/arch/arm/mach-socfpga/scan_manager.c +++ b/arch/arm/mach-socfpga/scan_manager.c @@ -102,15 +102,46 @@ static void scan_mgr_jtag_io(const u32 flags, const u8 iarg, const u32 parg) }
/** + * scan_mgr_jtag_insn_data() - Send JTAG instruction and data + * @iarg: Instruction argument + * @data: Associated data + * @dlen: Length of data in bits + * + * This function is used when programming the IO chains to submit the + * instruction followed by variable length payload. + */ +static int +scan_mgr_jtag_insn_data(const u8 iarg, const unsigned long *data, + const unsigned int dlen) +{ + int i, j; + + scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, iarg, dlen - 1); + + /* 32 bits or more remain */ + for (i = 0; i < dlen / 32; i++) + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, data[i]); + + if ((dlen % 32) > 24) { /* 31...24 bits remain */ + scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, data[i]); + } else if (dlen % 32) { /* 24...1 bit remain */ + for (j = 0; j < dlen % 32; j += 8) + scan_mgr_jtag_io(0, 0x0, data[i] >> j); + } + + return scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); +} + +/** * scan_mgr_io_scan_chain_prg() - Program HPS IO Scan Chain * @io_scan_chain_id: IO scan chain ID */ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) { - u32 residual; u32 io_scan_chain_len_in_bits; const unsigned long *iocsr_scan_chain; - int i, ret, index = 0; + unsigned int rem, idx = 0; + int ret;
ret = iocsr_get_config_table(io_scan_chain_id, &iocsr_scan_chain, &io_scan_chain_len_in_bits); @@ -139,78 +170,18 @@ static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id) */ setbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
- /* Program IO scan chain in 128-bit iteration */ - for (i = 0; i < io_scan_chain_len_in_bits / 128; i++) { - /* Write TDI_TDO packet header for 128-bit IO scan chain */ - scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, - TDI_TDO_MAX_PAYLOAD); + /* Program IO scan chain. */ + while (io_scan_chain_len_in_bits) { + if (io_scan_chain_len_in_bits > 128) + rem = 128; + else + rem = io_scan_chain_len_in_bits;
- /* write 4 successive 32-bit IO scan chain data into WFIFO */ - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, iocsr_scan_chain[index++]); - - /* - * Check if the scan chain engine has completed the - * IO scan chain data shifting - */ - ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); - if (ret) - goto error; - } - - residual = io_scan_chain_len_in_bits % 128; - - /* Final TDI_TDO packet (if chain length is not aligned to 128 bits) */ - if (residual) { - /* - * Program the last part of IO scan chain write TDI_TDO - * packet header (2 bytes) to scan manager. - */ - scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, 0x0, - residual - 1); - - for (i = 0; i < residual / 32; i++) { - /* - * write remaining scan chain data into scan - * manager WFIFO with 4 bytes write - */ - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, - iocsr_scan_chain[index++]); - } - - residual = io_scan_chain_len_in_bits % 32; - if (residual > 24) { - /* - * write the last 4B scan chain data - * into scan manager WFIFO - */ - scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, - iocsr_scan_chain[index]); - } else { - /* - * write the remaining 1 - 3 bytes scan chain - * data into scan manager WFIFO byte by byte - * to prevent JTAG engine shifting unused data - * from the FIFO and mistaken the data as a - * valid command (even though unused bits are - * set to 0, but just to prevent hardware - * glitch) - */ - for (i = 0; i < residual; i += 8) { - scan_mgr_jtag_io(0, 0x0, - iocsr_scan_chain[index] >> i); - } - } - - /* - * Check if the scan chain engine has completed the - * IO scan chain data shifting - */ - ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY); + ret = scan_mgr_jtag_insn_data(0x0, &iocsr_scan_chain[idx], rem); if (ret) goto error; + io_scan_chain_len_in_bits -= rem; + idx += 4; }
/* Disable IO Scan chain when configuration done*/

On 8/3/15 9:22 AM, Marek Vasut wrote:
Factor out the code which sends JTAG instruction followed by data into separate function to tidy the code up a little.
Signed-off-by: Marek Vasut marex@denx.de
arch/arm/mach-socfpga/scan_manager.c | 113 +++++++++++++---------------------- 1 file changed, 42 insertions(+), 71 deletions(-)
Acked-by: Dinh Nguyen dinguyen@opensource.altera.com
Thanks, Dinh

From: Dinh Nguyen dinguyen@opensource.altera.com
Add code to get the FPGA type for Altera's SoCFPGA family of FPGA. The code uses the scan manager to send jtag pulses that will return the FPGA ID.
Signed-off-by: Dinh Nguyen dinguyen@opensource.altera.com Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/include/mach/scan_manager.h | 1 + arch/arm/mach-socfpga/scan_manager.c | 55 +++++++++++++++++++++++ 2 files changed, 56 insertions(+)
diff --git a/arch/arm/mach-socfpga/include/mach/scan_manager.h b/arch/arm/mach-socfpga/include/mach/scan_manager.h index 3b55e37..5ca6843 100644 --- a/arch/arm/mach-socfpga/include/mach/scan_manager.h +++ b/arch/arm/mach-socfpga/include/mach/scan_manager.h @@ -18,6 +18,7 @@ struct socfpga_scan_manager { };
int scan_mgr_configure_iocsr(void); +u32 scan_mgr_get_fpga_id(void); int iocsr_get_config_table(const unsigned int chain_id, const unsigned long **table, unsigned int *table_len); diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c index 4f2c4b5..d78e91d 100644 --- a/arch/arm/mach-socfpga/scan_manager.c +++ b/arch/arm/mach-socfpga/scan_manager.c @@ -9,6 +9,7 @@ #include <asm/io.h> #include <asm/arch/freeze_controller.h> #include <asm/arch/scan_manager.h> +#include <asm/arch/system_manager.h>
/* * Maximum polling loop to wait for IO scan chain engine becomes idle @@ -33,6 +34,8 @@ static const struct socfpga_scan_manager *scan_manager_base = (void *)(SOCFPGA_SCANMGR_ADDRESS); static const struct socfpga_freeze_controller *freeze_controller_base = (void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS); +static struct socfpga_system_manager *sys_mgr_base = + (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
/** * scan_chain_engine_is_idle() - Check if the JTAG scan chain is idle @@ -205,3 +208,55 @@ int scan_mgr_configure_iocsr(void) status |= scan_mgr_io_scan_chain_prg(3); return status; } + +/** + * scan_mgr_get_fpga_id() - Obtain FPGA JTAG ID + * + * This function obtains JTAG ID from the FPGA TAP controller. + */ +u32 scan_mgr_get_fpga_id(void) +{ + const unsigned long data = 0; + u32 id = 0xffffffff; + int ret; + + /* Enable HPS to talk to JTAG in the FPGA through the System Manager */ + writel(0x1, &sys_mgr_base->scanmgrgrp_ctrl); + + /* Enable port 7 */ + writel(0x80, &scan_manager_base->en); + /* write to CSW to make s2f_ntrst reset */ + writel(0x02, &scan_manager_base->stat); + + /* Add a pause */ + mdelay(1); + + /* write 0x00 to CSW to clear the s2f_ntrst */ + writel(0, &scan_manager_base->stat); + + /* + * Go to Test-Logic-Reset state. + * This sets TAP controller into IDCODE mode. + */ + scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_TMS, 0x1f | (1 << 5), 0x0); + + /* Go to Run-Test/Idle -> DR-Scan -> Capture-DR -> Shift-DR state. */ + scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_TMS, 0x02 | (1 << 4), 0x0); + + /* + * Push 4 bytes of data through TDI->DR->TDO. + * + * Length of TDI data is 32bits (length - 1) and they are only + * zeroes as we care only for TDO data. + */ + ret = scan_mgr_jtag_insn_data(0x4, &data, 32); + /* Read 32 bit from captured JTAG data. */ + if (!ret) + id = readl(&scan_manager_base->fifo_quad_byte); + + /* Disable all port */ + writel(0, &scan_manager_base->en); + writel(0, &sys_mgr_base->scanmgrgrp_ctrl); + + return id; +}

From: Dinh Nguyen dinguyen@opensource.altera.com
Add code which uses the new functions for obtaining FPGA ID from the scan manager. This new code prints the FPGA model attached to the SoCFPGA during boot and sets environment variable "fpgatype", which can be used to determine the FPGA model in U-Boot scripts.
Signed-off-by: Dinh Nguyen dinguyen@opensource.altera.com Signed-off-by: Marek Vasut marex@denx.de --- arch/arm/mach-socfpga/Makefile | 4 +-- arch/arm/mach-socfpga/misc.c | 63 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index 7524ef9..8a745c9 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -8,5 +8,5 @@ #
obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o \ - fpga_manager.o -obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o + fpga_manager.o scan_manager.o +obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o diff --git a/arch/arm/mach-socfpga/misc.c b/arch/arm/mach-socfpga/misc.c index 9d34cd3..0940cc5 100644 --- a/arch/arm/mach-socfpga/misc.c +++ b/arch/arm/mach-socfpga/misc.c @@ -6,6 +6,7 @@
#include <common.h> #include <asm/io.h> +#include <errno.h> #include <fdtdec.h> #include <libfdt.h> #include <altera.h> @@ -13,6 +14,7 @@ #include <netdev.h> #include <watchdog.h> #include <asm/arch/reset_manager.h> +#include <asm/arch/scan_manager.h> #include <asm/arch/system_manager.h> #include <asm/arch/dwmmc.h> #include <asm/arch/nic301.h> @@ -141,6 +143,63 @@ struct { { "qspi", "QSPI Flash (3.0V)", }, };
+static const struct { + const u16 pn; + const char *name; + const char *var; +} const socfpga_fpga_model[] = { + /* Cyclone V E */ + { 0x2b15, "Cyclone V, E/A2", "cv_e_a2" }, + { 0x2b05, "Cyclone V, E/A4", "cv_e_a4" }, + { 0x2b22, "Cyclone V, E/A5", "cv_e_a5" }, + { 0x2b13, "Cyclone V, E/A7", "cv_e_a7" }, + { 0x2b14, "Cyclone V, E/A9", "cv_e_a9" }, + /* Cyclone V GX/GT */ + { 0x2b01, "Cyclone V, GX/C3", "cv_gx_c3" }, + { 0x2b12, "Cyclone V, GX/C4", "cv_gx_c4" }, + { 0x2b02, "Cyclone V, GX/C5 or GT/D5", "cv_gx_c5" }, + { 0x2b03, "Cyclone V, GX/C7 or GT/D7", "cv_gx_c7" }, + { 0x2b04, "Cyclone V, GX/C9 or GT/D9", "cv_gx_c9" }, + /* Cyclone V SE/SX/ST */ + { 0x2d11, "Cyclone V, SE/A2 or SX/C2", "cv_se_a2" }, + { 0x2d01, "Cyclone V, SE/A4 or SX/C4", "cv_se_a4" }, + { 0x2d12, "Cyclone V, SE/A5 or SX/C5 or ST/D5", "cv_se_a5" }, + { 0x2d02, "Cyclone V, SE/A6 or SX/C6 or ST/D6", "cv_se_a6" }, + /* Arria V */ + { 0x2d03, "Arria V, D5", "av_d5" }, +}; + +static int socfpga_fpga_id(const bool print_id) +{ + const u32 altera_mi = 0x6e; + const u32 id = scan_mgr_get_fpga_id(); + + const u32 lsb = id & 0x00000001; + const u32 mi = (id >> 1) & 0x000007ff; + const u32 pn = (id >> 12) & 0x0000ffff; + const u32 version = (id >> 28) & 0x0000000f; + int i; + + if ((mi != altera_mi) || (lsb != 1)) { + printf("FPGA: Not Altera chip ID\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(socfpga_fpga_model); i++) + if (pn == socfpga_fpga_model[i].pn) + break; + + if (i == ARRAY_SIZE(socfpga_fpga_model)) { + printf("FPGA: Unknown Altera chip, ID 0x%08x\n", id); + return -EINVAL; + } + + if (print_id) + printf("FPGA: Altera %s, version 0x%01x\n", + socfpga_fpga_model[i].name, version); + return i; +} + /* * Print CPU information */ @@ -149,6 +208,7 @@ int print_cpuinfo(void) { const u32 bsel = readl(&sysmgr_regs->bootinfo) & 0x7; puts("CPU: Altera SoCFPGA Platform\n"); + socfpga_fpga_id(1); printf("BOOT: %s\n", bsel_str[bsel].name); return 0; } @@ -158,7 +218,10 @@ int print_cpuinfo(void) int arch_misc_init(void) { const u32 bsel = readl(&sysmgr_regs->bootinfo) & 0x7; + const int fpga_id = socfpga_fpga_id(0); setenv("bootmode", bsel_str[bsel].mode); + if (fpga_id >= 0) + setenv("fpgatype", socfpga_fpga_model[fpga_id].var); return 0; } #endif

On Monday, August 03, 2015 at 04:22:08 PM, Marek Vasut wrote:
Rework this function so it's clear that it is only polling for certain bits to be cleared. Add kerneldoc. Fix it's return value to be either 0 on success and -ETIMEDOUT on error and propagate this through the scan manager code.
Signed-off-by: Marek Vasut marex@denx.de
Hi Dinh,
in case you missed this small patchset :-)
Best regards, Marek Vasut

On 8/3/15 9:22 AM, Marek Vasut wrote:
Rework this function so it's clear that it is only polling for certain bits to be cleared. Add kerneldoc. Fix it's return value to be either 0 on success and -ETIMEDOUT on error and propagate this through the scan manager code.
Signed-off-by: Marek Vasut marex@denx.de
arch/arm/mach-socfpga/include/mach/scan_manager.h | 9 ---- arch/arm/mach-socfpga/scan_manager.c | 53 +++++++++++++++-------- 2 files changed, 34 insertions(+), 28 deletions(-)
[...]
@@ -16,26 +28,26 @@ static const struct socfpga_scan_manager *scan_manager_base = static const struct socfpga_freeze_controller *freeze_controller_base = (void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
-/* +/**
- scan_chain_engine_is_idle() - Check if the JTAG scan chain is idle
- @max_iter: Maximum number of iterations to wait for idle
*/
- Function to check IO scan chain engine status and wait if the engine is
- is active. Poll the IO scan chain engine till maximum iteration reached.
-static inline uint32_t scan_chain_engine_is_idle(uint32_t max_iter) +static u32 scan_chain_engine_is_idle(uint32_t max_iter)
Should you go ahead and change this to u32?
Only comment, otherwise:
Acked-by: Dinh Nguyen dinguyen@opensource.altera.com
Thanks, Dinh

On Friday, August 07, 2015 at 10:26:04 PM, Dinh Nguyen wrote:
On 8/3/15 9:22 AM, Marek Vasut wrote:
Rework this function so it's clear that it is only polling for certain bits to be cleared. Add kerneldoc. Fix it's return value to be either 0 on success and -ETIMEDOUT on error and propagate this through the scan manager code.
Signed-off-by: Marek Vasut marex@denx.de
arch/arm/mach-socfpga/include/mach/scan_manager.h | 9 ---- arch/arm/mach-socfpga/scan_manager.c | 53 +++++++++++++++-------- 2 files changed, 34 insertions(+), 28 deletions(-)
[...]
@@ -16,26 +28,26 @@ static const struct socfpga_scan_manager *scan_manager_base =
static const struct socfpga_freeze_controller *freeze_controller_base =
(void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
-/* +/**
- scan_chain_engine_is_idle() - Check if the JTAG scan chain is idle
- @max_iter: Maximum number of iterations to wait for idle
Function to check IO scan chain engine status and wait if the engine
is * is active. Poll the IO scan chain engine till maximum iteration reached. */
-static inline uint32_t scan_chain_engine_is_idle(uint32_t max_iter) +static u32 scan_chain_engine_is_idle(uint32_t max_iter)
Should you go ahead and change this to u32?
Only comment, otherwise:
Ah nice, thanks! Fixed :)
Acked-by: Dinh Nguyen dinguyen@opensource.altera.com
Thanks, Dinh
Best regards, Marek Vasut

On Monday, August 03, 2015 at 04:22:08 PM, Marek Vasut wrote:
Rework this function so it's clear that it is only polling for certain bits to be cleared. Add kerneldoc. Fix it's return value to be either 0 on success and -ETIMEDOUT on error and propagate this through the scan manager code.
Signed-off-by: Marek Vasut marex@denx.de
Whole series applied to u-boot-socfpga/master .
Best regards, Marek Vasut
participants (2)
-
Dinh Nguyen
-
Marek Vasut