[U-Boot] [PATCH v4] socfpga: Adding Scan Manager driver
Michal Simek
monstr at monstr.eu
Fri Feb 21 17:01:05 CET 2014
Hi,
On 02/21/2014 04:26 PM, Chin Liang See wrote:
> Scan Manager driver will be called to configure the IOCSR
> scan chain. This configuration will setup the IO buffer settings
>
> Signed-off-by: Chin Liang See <clsee at altera.com>
> Cc: Dinh Nguyen <dinguyen at altera.com>
> Cc: Wolfgang Denk <wd at denx.de>
> CC: Pavel Machek <pavel at denx.de>
> Cc: Tom Rini <trini at ti.com>
> Cc: Albert Aribaud <albert.u.boot at aribaud.net>
> ---
> Changes for v4
> - avoid code duplication by add goto error
> - include underscore to variables name
> Changes for v3
> - merge the handoff file and driver into single patch
> Changes for v2
> - rebase with latest v2014.01-rc1
> ---
> arch/arm/cpu/armv7/socfpga/Makefile | 2 +-
> arch/arm/cpu/armv7/socfpga/scan_manager.c | 225 +++++++
> arch/arm/cpu/armv7/socfpga/spl.c | 4 +
> arch/arm/include/asm/arch-socfpga/scan_manager.h | 97 +++
> .../include/asm/arch-socfpga/socfpga_base_addrs.h | 1 +
> board/altera/socfpga/iocsr_config.c | 657 ++++++++++++++++++++
> board/altera/socfpga/iocsr_config.h | 17 +
> include/configs/socfpga_cyclone5.h | 1 +
> 8 files changed, 1003 insertions(+), 1 deletion(-)
> create mode 100644 arch/arm/cpu/armv7/socfpga/scan_manager.c
> create mode 100644 arch/arm/include/asm/arch-socfpga/scan_manager.h
> create mode 100644 board/altera/socfpga/iocsr_config.c
> create mode 100644 board/altera/socfpga/iocsr_config.h
>
> diff --git a/arch/arm/cpu/armv7/socfpga/Makefile b/arch/arm/cpu/armv7/socfpga/Makefile
> index 3e84a0c..4edc5d4 100644
> --- a/arch/arm/cpu/armv7/socfpga/Makefile
> +++ b/arch/arm/cpu/armv7/socfpga/Makefile
> @@ -9,4 +9,4 @@
>
> obj-y := lowlevel_init.o
> obj-y += misc.o timer.o reset_manager.o system_manager.o
> -obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o
> +obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o
> diff --git a/arch/arm/cpu/armv7/socfpga/scan_manager.c b/arch/arm/cpu/armv7/socfpga/scan_manager.c
> new file mode 100644
> index 0000000..3ec6c7e
> --- /dev/null
> +++ b/arch/arm/cpu/armv7/socfpga/scan_manager.c
> @@ -0,0 +1,225 @@
> +/*
> + * Copyright (C) 2013 Altera Corporation <www.altera.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +
probably we can use just empty line here.
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/arch/freeze_controller.h>
> +#include <asm/arch/scan_manager.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +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);
> +
> +/*
> + * 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_mgr_io_scan_chain_engine_is_idle(uint32_t max_iter)
> +{
> + uint32_t scanmgr_status;
> +
> + scanmgr_status = readl(&scan_manager_base->stat);
> +
> + /* 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
> + return SCAN_MGR_IO_SCAN_ENGINE_STATUS_ACTIVE;
> + }
> + return SCAN_MGR_IO_SCAN_ENGINE_STATUS_IDLE;
> +}
> +
> +
> +
ditto.
> +/* Program HPS IO Scan Chain */
> +uint32_t scan_mgr_io_scan_chain_prg(
> + uint32_t io_scan_chain_id,
> + uint32_t io_scan_chain_len_in_bits,
> + const uint32_t *iocsr_scan_chain)
> +{
> +
why blanks line here.
> + uint16_t tdi_tdo_header;
> + uint32_t io_program_iter;
> + uint32_t io_scan_chain_data_residual;
> + uint32_t residual;
> + uint32_t i;
> + uint32_t index = 0;
> +
> + /* De-assert reinit if the IO scan chain is intended for HIO */
> + if (3 == io_scan_chain_id)
this 3 is magic
> + clrbits_le32(&freeze_controller_base->hioctrl,
> + SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK);
> +
> + /*
> + * Check if the scan chain engine is inactive and the
> + * WFIFO is empty before enabling the IO scan chain
> + */
> + if (SCAN_MGR_IO_SCAN_ENGINE_STATUS_IDLE
> + != scan_mgr_io_scan_chain_engine_is_idle(
> + MAX_WAITING_DELAY_IO_SCAN_ENGINE)) {
> + return 1;
> + }
remove {}
> +
> + /*
> + * Enable IO Scan chain based on scan chain id
> + * Note: only one chain can be enabled at a time
> + */
> + 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;
> +
> + /* 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++) {
> +
another blank line, check the whole driver.
> + /* write TDI_TDO packet header to scan manager */
> + writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte);
> +
> + /* calculate array index */
> + index = i * 4;
> +
> + /* 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);
> +
> + /*
> + * Check if the scan chain engine has completed the
> + * IO scan chain data shifting
> + */
> + if (SCAN_MGR_IO_SCAN_ENGINE_STATUS_IDLE
> + != scan_mgr_io_scan_chain_engine_is_idle(
> + MAX_WAITING_DELAY_IO_SCAN_ENGINE))
> + goto error;
> + }
> +
> + /* Calculate array index for final TDI_TDO packet */
> + index = io_program_iter * 4;
magic
> +
> + /* Final TDI_TDO packet if any */
> + if (0 != io_scan_chain_data_residual) {
> +
ditto
> + /*
> + * 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;
> +
> + /*
> + * Construct TDI_TDO packet for remaining IO
> + * scan chain (2 bytes)
> + */
> + 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);
> +
> + 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);
> + }
remove {} and check the whole driver.
> +
> + index += io_program_iter;
> + residual = io_scan_chain_data_residual &
> + IO_SCAN_CHAIN_32BIT_MASK;
> +
> + if (IO_SCAN_CHAIN_PAYLOAD_24BIT < residual) {
> + /*
> + * write the last 4B scan chain data
> + * into scan manager WFIFO
> + */
> + writel(iocsr_scan_chain[index],
> + &scan_manager_base->fifo_quad_byte);
> +
> + } 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) {
> + writel(((iocsr_scan_chain[index] >> i)
> + & IO_SCAN_CHAIN_BYTE_MASK),
> + &scan_manager_base->fifo_single_byte);
> +
> + }
ditto.
> + }
> +
> + /*
> + * Check if the scan chain engine has completed the
> + * IO scan chain data shifting
> + */
> + if (SCAN_MGR_IO_SCAN_ENGINE_STATUS_IDLE
> + != scan_mgr_io_scan_chain_engine_is_idle(
> + MAX_WAITING_DELAY_IO_SCAN_ENGINE))
> + goto error;
> + } /* if (io_scan_chain_data_residual) */
nice commen but probably no.
> +
> + /* Disable IO Scan chain when configuration done*/
> + clrbits_le32(&scan_manager_base->en,
> + 1 << io_scan_chain_id);
> +
> + return 0;
> +
> +error:
> + /* Disable IO Scan chain when error detected */
> + clrbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
> + return 1;
> +}
> +
> +int scan_mgr_configure_iocsr(void)
> +{
> + int status = 0;
> +
> + /* configure the IOCSR through scan chain */
> + status |= scan_mgr_io_scan_chain_prg(0,
> + CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH, iocsr_scan_chain0_table);
> + status |= scan_mgr_io_scan_chain_prg(1,
> + CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH, iocsr_scan_chain1_table);
> + status |= scan_mgr_io_scan_chain_prg(2,
> + CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH, iocsr_scan_chain2_table);
> + status |= scan_mgr_io_scan_chain_prg(3,
> + CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH, iocsr_scan_chain3_table);
> + return status;
> +}
> diff --git a/arch/arm/cpu/armv7/socfpga/spl.c b/arch/arm/cpu/armv7/socfpga/spl.c
> index 36a00c3..8a49a1a 100644
> --- a/arch/arm/cpu/armv7/socfpga/spl.c
> +++ b/arch/arm/cpu/armv7/socfpga/spl.c
> @@ -32,6 +32,10 @@ void spl_board_init(void)
> /* freeze all IO banks */
> sys_mgr_frzctrl_freeze_req();
>
> + /* configure the IOCSR / IO buffer settings */
> + if (scan_mgr_configure_iocsr())
> + hang();
> +
> /* configure the pin muxing through system manager */
> sysmgr_pinmux_init();
> #endif /* CONFIG_SOCFPGA_VIRTUAL_TARGET */
> diff --git a/arch/arm/include/asm/arch-socfpga/scan_manager.h b/arch/arm/include/asm/arch-socfpga/scan_manager.h
> new file mode 100644
> index 0000000..4c5a582
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-socfpga/scan_manager.h
> @@ -0,0 +1,97 @@
> +/*
> + * Copyright (C) 2013 Altera Corporation <www.altera.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +#ifndef _SCAN_MANAGER_H_
> +#define _SCAN_MANAGER_H_
> +
> +struct socfpga_scan_manager {
> + u32 stat;
> + u32 en;
> + u32 padding[2];
> + u32 fifo_single_byte;
> + u32 fifo_double_byte;
> + 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)
> +
> +/* IO scan chain engine is idle */
> +#define SCAN_MGR_IO_SCAN_ENGINE_STATUS_IDLE (0)
> +
> +/* IO scan chain engine is active */
> +#define SCAN_MGR_IO_SCAN_ENGINE_STATUS_ACTIVE (1)
> +
> +/*
> + * Maximum polling loop to wait for IO scan chain engine
> + * becomes idle to prevent infinite loop
> + */
> +#define MAX_WAITING_DELAY_IO_SCAN_ENGINE (100)
> +
> +#define SCANMGR_STAT_ACTIVE_GET(x) (((x) & 0x80000000) >> 31)
> +#define SCANMGR_STAT_WFIFOCNT_GET(x) (((x) & 0x70000000) >> 28)
> +
> +/*
> + * Program HPS IO Scan Chain
> + * io_scan_chain_id - IO scan chain ID
> + * io_scan_chain_len_in_bits - IO scan chain length in bits
> + * iocsr_scan_chain - IO scan chain table
> + */
> +uint32_t scan_mgr_io_scan_chain_prg(
> + uint32_t io_scan_chain_id,
> + uint32_t io_scan_chain_len_in_bits,
> + const uint32_t *iocsr_scan_chain);
> +
> +
blank line
> +extern const uint32_t iocsr_scan_chain0_table[
> + ((CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH / 32) + 1)];
> +extern const uint32_t iocsr_scan_chain1_table[
> + ((CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH / 32) + 1)];
> +extern const uint32_t iocsr_scan_chain2_table[
> + ((CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH / 32) + 1)];
> +extern const uint32_t iocsr_scan_chain3_table[
> + ((CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH / 32) + 1)];
> +
> +#endif /* _SCAN_MANAGER_H_ */
> diff --git a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h
> index 50c4ebd..8d329cf 100644
> --- a/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h
> +++ b/arch/arm/include/asm/arch-socfpga/socfpga_base_addrs.h
> @@ -13,5 +13,6 @@
> #define SOCFPGA_OSC1TIMER0_ADDRESS 0xffd00000
> #define SOCFPGA_RSTMGR_ADDRESS 0xffd05000
> #define SOCFPGA_SYSMGR_ADDRESS 0xffd08000
> +#define SOCFPGA_SCANMGR_ADDRESS 0xfff02000
>
> #endif /* _SOCFPGA_BASE_ADDRS_H_ */
> diff --git a/board/altera/socfpga/iocsr_config.c b/board/altera/socfpga/iocsr_config.c
> new file mode 100644
> index 0000000..b4b5ff8
> --- /dev/null
> +++ b/board/altera/socfpga/iocsr_config.c
> @@ -0,0 +1,657 @@
> +/*
> + * Copyright Altera Corporation (C) 2012-2014. All rights reserved
> + *
> + * SPDX-License-Identifier: BSD-3-Clause
> + */
> +
> +/* This file is generated by Preloader Generator */
> +
> +#include <iocsr_config.h>
> +
> +const unsigned long iocsr_scan_chain0_table[((
> + CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH / 32) + 1)] = {
> + 0x00000000,
> + 0x00000000,
> + 0x0FF00000,
> + 0xC0000000,
> + 0x0000003F,
> + 0x00008000,
> + 0x00020080,
> + 0x08020000,
> + 0x08000000,
> + 0x00018020,
> + 0x00000000,
> + 0x00004000,
> + 0x00010040,
> + 0x04010000,
> + 0x04000000,
> + 0x00000010,
> + 0x00004010,
> + 0x00002000,
> + 0x00020000,
> + 0x02008000,
> + 0x02000000,
> + 0x00000008,
> + 0x00002008,
> + 0x00001000,
> +};
This is nice and I believe it is just target specific hw design
and configuration that's why it is generated.
Do we really want these magic values here?
Isn't it better to keep these arrays empty instead
of values which targets just one design/configuration?
<snip>
> diff --git a/board/altera/socfpga/iocsr_config.h b/board/altera/socfpga/iocsr_config.h
> new file mode 100644
> index 0000000..490f109
> --- /dev/null
> +++ b/board/altera/socfpga/iocsr_config.h
> @@ -0,0 +1,17 @@
> +/*
> + * Copyright Altera Corporation (C) 2012-2014. All rights reserved
> + *
> + * SPDX-License-Identifier: BSD-3-Clause
> + */
> +
> +/* This file is generated by Preloader Generator */
> +
> +#ifndef _PRELOADER_IOCSR_CONFIG_H_
> +#define _PRELOADER_IOCSR_CONFIG_H_
> +
> +#define CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH (764)
> +#define CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH (1719)
> +#define CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH (955)
> +#define CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH (16766)
And here just write any value.
Thanks,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 263 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20140221/2cc652d7/attachment.pgp>
More information about the U-Boot
mailing list