mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Michael Graichen <michael.graichen@hotmail.com>
To: Michael Tretter <m.tretter@pengutronix.de>,
	Ahmad Fatoum <a.fatoum@pengutronix.de>
Cc: "barebox@lists.infradead.org" <barebox@lists.infradead.org>
Subject: AW: [PATCH 1/1] added support for zynq7000-fpga-manager
Date: Tue, 30 Mar 2021 12:05:31 +0000	[thread overview]
Message-ID: <AM9P192MB08704EEEF035BA67815E5991AB7D9@AM9P192MB0870.EURP192.PROD.OUTLOOK.COM> (raw)
In-Reply-To: <20210325084255.GA11014@pengutronix.de>

Hey, 

Ahmad, thanks for your reply. I'll will work your points out for the next patch. 

> I think, it would be fine to use only "zynq" instead of zynqmp for the
> firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
> level interfaces for programming the FPGA, yet, but I guess that programming
> the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
> Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
> driver. 

As I compared https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf page 211ff and https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf page 261ff the programming of the PCAP seem to be similar, but PCAP is embedded in CSU/PMU on ZynqMP, which looks much more complex then DEVC on Zynq7000. But I don't know how much of CSUs functionality is acctually needed to programm the FPGA.

Is the CSU within ZynqMP used for something other than programming the firmware in barebox?

Best regard,
Michael 

________________________________________
Von: Michael Tretter <m.tretter@pengutronix.de>
Gesendet: Donnerstag, 25. März 2021 09:42
An: Michael Graichen
Cc: barebox@lists.infradead.org
Betreff: Re: [PATCH 1/1] added support for zynq7000-fpga-manager

On Thu, 25 Mar 2021 07:53:33 +0000, Michael Graichen wrote:
> i have reworked the ZynqMP FPGA manager to program the FPGA within the Zynq7000.

Great, thanks.

>
> Michael Tretter, would you be so kind an test this on your ZynqMP board?
> Since I have no access to a ZynqMP chip I have only tested compiling.

I will test the patch and I already have a few comments down below.

>
> The name "ZynqMP" may now be missleading for the firmwareload tool, because
> I intended to use it on both, ZynqMP and Zynq7000.  I would be happy to get
> read your feedback.

I think, it would be fine to use only "zynq" instead of zynqmp for the
firmware loader/fpga manager. (I didn't compare the Zynq7000 and ZynqMP low
level interfaces for programming the FPGA, yet, but I guess that programming
the FPGA on the ZynqMP in EL3 instead of EL2/EL1 is actually the same as on
Zynq7000.) I am also ok with treating ZynqMP as a second class citizen in the
driver.

>
> Best Regards
> Michael
>
>
> Signed-off-by: Michael Graichen <michael.graichen@hotmail.com>
> ---
>  arch/arm/configs/zynq_defconfig               |   2 +
>  arch/arm/mach-zynq/Makefile                   |   2 +-
>  arch/arm/mach-zynq/firmware-zynq.c            | 124 ++++++++++++++++++
>  .../mach-zynq/include/mach/firmware-zynq.h    |  85 ++++++++++++
>  .../include/mach/firmware-zynqmp.h            |  46 +++++++
>  drivers/firmware/Kconfig                      |   7 +
>  drivers/firmware/Makefile                     |   1 +
>  drivers/firmware/zynqmp-fpga.c                | 115 ++++++++--------
>  8 files changed, 324 insertions(+), 58 deletions(-)
>  create mode 100644 arch/arm/mach-zynq/firmware-zynq.c
>  create mode 100644 arch/arm/mach-zynq/include/mach/firmware-zynq.h
>
> diff --git a/arch/arm/configs/zynq_defconfig b/arch/arm/configs/zynq_defconfig
> index a16c57d5c..82ea899e2 100644
> --- a/arch/arm/configs/zynq_defconfig
> +++ b/arch/arm/configs/zynq_defconfig
> @@ -36,6 +36,7 @@ CONFIG_CMD_MENU_MANAGEMENT=y
>  CONFIG_CMD_READLINE=y
>  CONFIG_CMD_TIMEOUT=y
>  CONFIG_CMD_CLK=y
> +CONFIG_CMD_FIRMWARELOAD=y
>  CONFIG_CMD_OFTREE=y
>  CONFIG_CMD_TIME=y
>  CONFIG_NET=y
> @@ -43,5 +44,6 @@ CONFIG_DRIVER_SERIAL_CADENCE=y
>  CONFIG_DRIVER_NET_MACB=y
>  # CONFIG_SPI is not set
>  # CONFIG_PINCTRL is not set
> +CONFIG_FIRMWARE_ZYNQ7000_FPGA=y
>  CONFIG_FS_TFTP=y
>  CONFIG_DIGEST=y
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 06c2ce996..2484abe5c 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -1,2 +1,2 @@
> -obj-y += zynq.o bootm-zynqimg.o
> +obj-y += bootm-zynqimg.o firmware-zynq.o zynq.o
>  lwl-y += cpu_init.o
> diff --git a/arch/arm/mach-zynq/firmware-zynq.c b/arch/arm/mach-zynq/firmware-zynq.c
> new file mode 100644
> index 000000000..307b22fe5
> --- /dev/null
> +++ b/arch/arm/mach-zynq/firmware-zynq.c
> @@ -0,0 +1,124 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + */
> +#include <common.h>
> +#include <init.h>
> +#include <linux/iopoll.h>
> +#include <mach/firmware-zynq.h>
> +
> +/*
> + * zynq_devc_fpga_load - Perform the fpga load
> + * @mgr:     FPGA-Manager
> + * @address: Address to write to
> + * @size:    PL bitstream size
> + * @flags:   Flags - unused
> + *
> + * This function provides access to PCAP to transfer
> + * the required bitstream into PL.
> + *
> + * Return:   Returns status, either success or error+reason
> + */
> +static int zynq_devc_fpga_load(struct fpgamgr *mgr, u64 address,
> +                             u32 size, u32 flags)
> +{
> +     unsigned long reg;
> +
> +     if (!address || !size)
> +             return -EINVAL;
> +
> +     /*
> +      * The Programming Seqenze, see ug585 (v.12.2) Juny 1, 2018 Chapter
> +      * 6.4.2 on page 211 Configure the PL via PCAP Bridge Example for
> +      * detailed information to this Sequenze
> +      */
> +
> +     /* Enable the PCAP bridge and select PCAP for reconfiguration */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= ( CTRL_PCAP_PR_MASK | CTRL_PCAP_MODE_MASK );
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Clear the Interrupts */
> +     writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +     /* Initialize the PL */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg &= ~CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     !(reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg |= CTRL_PCFG_PROG_B_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Clear the Interrupts */
> +     writel(0xffffffff, mgr->regs + INT_STS_OFFSET);
> +
> +     /* Ensure that the PL is ready for programming */
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     (reg & STATUS_PCFG_INIT_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Check that there is room in the Command Queue */
> +     readl_poll_timeout(mgr->regs + STATUS_OFFSET, reg,
> +                     !(reg & STATUS_DMA_CMD_Q_F_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Disable the PCAP loopback */
> +     reg = readl(mgr->regs + MCTRL_OFFSET);
> +     reg &= ~MCTRL_INT_PCAP_LPBK_MASK;
> +     writel(reg, mgr->regs + MCTRL_OFFSET);
> +
> +     /* Program the PCAP_2x clock divider */
> +     reg = readl(mgr->regs + CTRL_OFFSET);
> +     reg &= ~CTRL_PCAP_RATE_EN_MASK;
> +     writel(reg, mgr->regs + CTRL_OFFSET);
> +
> +     /* Source Address: Location of bitstream */
> +     writel(address, mgr->regs + DMA_SRC_ADDR_OFFSET);
> +
> +     /* Destination Address: 0xFFFF_FFFF */
> +     writel(0xffffffff, mgr->regs + DMA_DST_ADDR_OFFSET);
> +
> +     /* Source Length: Total number of 32-bit words in the bitstream */
> +     writel((size >> 2), mgr->regs + DMA_SRC_LEN_OFFSET);
> +
> +     /* Destination Length: Total number of 32-bit words in the bitstream */
> +     writel((size >> 2), mgr->regs + DMA_DEST_LEN_OFFSET);
> +
> +     /* Wait for the DMA transfer to be done */
> +     readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +                     (reg & INT_STS_D_P_DONE_MASK), 100 * USEC_PER_MSEC);
> +
> +     /* Check for errors */
> +     if(reg & INT_STS_ERROR_FLAGS_MASK) {
> +             printf("interrupt status register (0x%04lx)\n", reg);
> +             return -EIO;
> +     }
> +
> +     /* Wait for the DMA transfer to be done */
> +     readl_poll_timeout(mgr->regs + INT_STS_OFFSET, reg,
> +                     (reg & INT_STS_DONE_INT_MASK), 100 * USEC_PER_MSEC);
> +
> +     printf("FPGA config done\n");
> +
> +     return 0;
> +}
> +
> +static const struct zynq_devc_ops devc_ops = {
> +     .fpga_load = zynq_devc_fpga_load,
> +};
> +
> +/**
> + * zynq_get_devc_ops - Get devc ops functions
> + *
> + * Return: Pointer of devc_ops structure
> + */
> +const struct zynq_devc_ops *zynq_get_devc_ops(void)
> +{
> +     return &devc_ops;
> +}
> +EXPORT_SYMBOL_GPL(zynq_get_devc_ops);

Don't try to hide the loading code behind function pointers in machine
specific code. Just put the zynq_devc_fpga_load function straight into
drivers/firmware/zynqmp-fpga.c.

For the ZynqMP there is this abstraction, because the ZyqnMP has another
driver that is used to instruct another firmware (TF-A) to program the FPGA.
As this isn't the case for the Zynq7000, I don't see a reason to make things
more complicated than they are.

> diff --git a/arch/arm/mach-zynq/include/mach/firmware-zynq.h b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> new file mode 100644
> index 000000000..217b1e9b2
> --- /dev/null
> +++ b/arch/arm/mach-zynq/include/mach/firmware-zynq.h
> @@ -0,0 +1,85 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Xilinx Zynq Firmware layer
> + *
> + */
> +
> +#ifndef FIRMWARE_ZYNQ_H_
> +#define FIRMWARE_ZYNQ_H_
> +
> +#include <firmware.h>
> +
> +#define CTRL_OFFSET                          0x00
> +#define LOCK_OFFSET                          0x04
> +#define INT_STS_OFFSET                               0x0c
> +#define INT_MASK_OFFSET                      0x10
> +#define STATUS_OFFSET                                0x14
> +#define DMA_SRC_ADDR_OFFSET                  0x18
> +#define DMA_DST_ADDR_OFFSET                  0x1c
> +#define DMA_SRC_LEN_OFFSET                   0x20
> +#define DMA_DEST_LEN_OFFSET                  0x24
> +#define UNLOCK_OFFSET                                0x34
> +#define MCTRL_OFFSET                         0x80
> +
> +#define CTRL_PCFG_PROG_B_MASK                        BIT(30)
> +#define CTRL_PCAP_PR_MASK                    BIT(27)
> +#define CTRL_PCAP_MODE_MASK                  BIT(26)
> +#define CTRL_PCAP_RATE_EN_MASK               BIT(25)
> +
> +#define STATUS_DMA_CMD_Q_F_MASK              BIT(31)
> +#define STATUS_PCFG_INIT_MASK                        BIT(4)
> +
> +#define INT_STS_D_P_DONE_MASK                        BIT(12)
> +#define INT_STS_DONE_INT_MASK                        BIT(2)
> +#define INT_STS_ERROR_FLAGS_MASK             0x00f4c860
> +
> +#define MCTRL_INT_PCAP_LPBK_MASK             BIT(4)
> +
> +/*
> + * Xilinx 7-Series Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 13 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + *  7: 0xFFFFFFFF (Dummy pad word)
> + *  8: 0x000000BB (Bus width auto detect word 1)
> + *  9: 0x11220044 (Bus width auto detect word 2)
> + * 10: 0xFFFFFFFF (Dummy pad word)
> + * 11: 0xFFFFFFFF (Dummy pad word)
> + * 12: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG470 (v1.13.1) August 20 2018, Chapter 5 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +
> +#define DUMMY_WORD                           0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET                8
> +#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET                9
> +#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> +#define SYNC_WORD_OFFSET                     12
> +#define SYNC_WORD                            0xAA995566
> +#define BIN_HEADER_LENGTH                    13
> +
> +#define DEVC_UNLOCK_CODE                     0x757bdf0d
> +
> +struct fpgamgr {
> +     struct firmware_handler fh;
> +     struct device_d dev;
> +     void __iomem *regs;
> +     const struct zynq_devc_ops *devc_ops;
> +     int programmed;
> +     char *buf;
> +     size_t size;
> +     u32 features;
> +};
> +
> +struct zynq_devc_ops {
> +     int (*fpga_load)(struct fpgamgr *mgr, u64 address, u32 size, u32 flags);
> +};
> +
> +const struct zynq_devc_ops *zynq_get_devc_ops(void);
> +
> +#endif /* FIRMWARE_ZYNQ_H_ */
> diff --git a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> index a04482237..1764a2db3 100644
> --- a/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> +++ b/arch/arm/mach-zynqmp/include/mach/firmware-zynqmp.h
> @@ -15,6 +15,8 @@
>  #ifndef FIRMWARE_ZYNQMP_H_
>  #define FIRMWARE_ZYNQMP_H_
>
> +#include <firmware.h>
> +
>  #define PAYLOAD_ARG_CNT                      4
>
>  #define ZYNQMP_PM_VERSION(MAJOR, MINOR)      ((MAJOR << 16) | MINOR)
> @@ -27,6 +29,50 @@
>
>  #define ZYNQMP_PCAP_STATUS_FPGA_DONE BIT(3)
>
> +#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL   BIT(0)
> +#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED    BIT(1)
> +
> +#define ZYNQMP_PM_VERSION_1_0_FEATURES       0
> +#define ZYNQMP_PM_VERSION_1_1_FEATURES       (ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> +                                      ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> +
> +/*
> + * Xilinx KU040 Bitstream Composition:
> + *
> + * Bitstream can be provided with an optinal header (`struct bs_header`).
> + * The true bitstream starts with the binary-header composed of 21 words:
> + *
> + *  0: 0xFFFFFFFF (Dummy pad word)
> + *     ...
> + * 15: 0xFFFFFFFF (Dummy pad word)
> + * 16: 0x000000BB (Bus width auto detect word 1)
> + * 17: 0x11220044 (Bus width auto detect word 2)
> + * 18: 0xFFFFFFFF (Dummy pad word)
> + * 19: 0xFFFFFFFF (Dummy pad word)
> + * 20: 0xAA995566 (Sync word)
> + *
> + * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> + * Details - Bitstream Composition" for further details.
> + */
> +#define DUMMY_WORD                   0xFFFFFFFF
> +#define BUS_WIDTH_AUTO_DETECT1_OFFSET        16
> +#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> +#define BUS_WIDTH_AUTO_DETECT2_OFFSET        17
> +#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> +#define SYNC_WORD_OFFSET             20
> +#define SYNC_WORD                    0xAA995566
> +#define BIN_HEADER_LENGTH            21
> +
> +struct fpgamgr {
> +     struct firmware_handler fh;
> +     struct device_d dev;
> +     const struct zynqmp_eemi_ops *eemi_ops;
> +     int programmed;
> +     char *buf;
> +     size_t size;
> +     u32 features;
> +};
> +
>  enum pm_ioctl_id {
>       IOCTL_SET_PLL_FRAC_MODE = 8,
>       IOCTL_GET_PLL_FRAC_MODE,
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index 90b4c0ab9..a00d682a9 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -15,6 +15,13 @@ config FIRMWARE_ALTERA_SOCFPGA
>       depends on ARCH_SOCFPGA
>       select FIRMWARE
>
> +config FIRMWARE_ZYNQ7000_FPGA
> +     bool "Xilinx Zynq 7000 FPGA loader"
> +     depends on ARCH_ZYNQ
> +     select FIRMWARE
> +     help
> +       Load a bitstream to the PL of Zynq
> +
>  config FIRMWARE_ZYNQMP_FPGA
>       bool "Xilinx ZynqMP FPGA loader"
>       depends on ARCH_ZYNQMP
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index b162b08b0..a7c6344bf 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_FIRMWARE_ALTERA_SERIAL) += altera_serial.o
>  obj-$(CONFIG_FIRMWARE_ALTERA_SOCFPGA) += socfpga.o
> +obj-$(CONFIG_FIRMWARE_ZYNQ7000_FPGA) += zynqmp-fpga.o
>  obj-$(CONFIG_FIRMWARE_ZYNQMP_FPGA) += zynqmp-fpga.o
> diff --git a/drivers/firmware/zynqmp-fpga.c b/drivers/firmware/zynqmp-fpga.c
> index ab70d9993..4ce835e18 100644
> --- a/drivers/firmware/zynqmp-fpga.c
> +++ b/drivers/firmware/zynqmp-fpga.c
> @@ -15,57 +15,19 @@
>  #include <common.h>
>  #include <init.h>
>  #include <dma.h>
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>  #include <mach/firmware-zynqmp.h>
> -
> -#define ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL   BIT(0)
> -#define ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED    BIT(1)
> -
> -#define ZYNQMP_PM_VERSION_1_0_FEATURES       0
> -#define ZYNQMP_PM_VERSION_1_1_FEATURES       (ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL | \
> -                                      ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)
> -
> -/*
> - * Xilinx KU040 Bitstream Composition:
> - *
> - * Bitstream can be provided with an optinal header (`struct bs_header`).
> - * The true bitstream starts with the binary-header composed of 21 words:
> - *
> - *  0: 0xFFFFFFFF (Dummy pad word)
> - *     ...
> - * 15: 0xFFFFFFFF (Dummy pad word)
> - * 16: 0x000000BB (Bus width auto detect word 1)
> - * 17: 0x11220044 (Bus width auto detect word 2)
> - * 18: 0xFFFFFFFF (Dummy pad word)
> - * 19: 0xFFFFFFFF (Dummy pad word)
> - * 20: 0xAA995566 (Sync word)
> - *
> - * See Xilinx UG570 (v1.11) September 30 2019, Chapter 9 "Configuration
> - * Details - Bitstream Composition" for further details.
> - */
> -#define DUMMY_WORD                   0xFFFFFFFF
> -#define BUS_WIDTH_AUTO_DETECT1_OFFSET        16
> -#define BUS_WIDTH_AUTO_DETECT1               0x000000BB
> -#define BUS_WIDTH_AUTO_DETECT2_OFFSET        17
> -#define BUS_WIDTH_AUTO_DETECT2               0x11220044
> -#define SYNC_WORD_OFFSET             20
> -#define SYNC_WORD                    0xAA995566
> -#define BIN_HEADER_LENGTH            21
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +#include <mach/firmware-zynq.h>
> +#include <mach/zynq7000-regs.h>
> +#endif

Is it possible to change the is_bin_header_valid() function to identify the
(slightly) different bitstream header formats at runtime? I would like to keep
the header specification in the driver instead of moving it to header files
and making it configuration dependent.

>
>  enum xilinx_byte_order {
>       XILINX_BYTE_ORDER_BIT,
>       XILINX_BYTE_ORDER_BIN,
>  };
>
> -struct fpgamgr {
> -     struct firmware_handler fh;
> -     struct device_d dev;
> -     const struct zynqmp_eemi_ops *eemi_ops;
> -     int programmed;
> -     char *buf;
> -     size_t size;
> -     u32 features;
> -};
> -
>  struct bs_header {
>       __be16 length;
>       u8 padding[9];
> @@ -234,6 +196,13 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               goto err_free;
>       }
>
> +     buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> +     if (!buf_aligned) {
> +             status = -ENOBUFS;
> +             goto err_free;
> +     }
> +
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA

Avoid the #ifdefs in the driver. Check for the compatible or add an identifier
to struct fpgamgr to decide if the driver can access the register directly or
needs to use the ZynqMP firmware calls.

If necessary, stub functions in the headers if some configuration is not set
and return an error.

Michael

>       if (!(mgr->features & ZYNQMP_PM_FEATURE_SIZE_NOT_NEEDED)) {
>               buf_size = dma_alloc_coherent(sizeof(*buf_size),
>               DMA_ADDRESS_BROKEN);
> @@ -244,12 +213,6 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               *buf_size = body_length;
>       }
>
> -     buf_aligned = dma_alloc_coherent(body_length, DMA_ADDRESS_BROKEN);
> -     if (!buf_aligned) {
> -             status = -ENOBUFS;
> -             goto err_free;
> -     }
> -
>       if (!(mgr->features & ZYNQMP_PM_FEATURE_BYTE_ORDER_IRREL) &&
>           byte_order == XILINX_BYTE_ORDER_BIN)
>               copy_words_swapped((u32 *)buf_aligned, body,
> @@ -271,7 +234,32 @@ static int fpgamgr_program_finish(struct firmware_handler *fh)
>               status = mgr->eemi_ops->fpga_load(addr, (u32)(body_length),
>                                                 flags);
>       }
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +     /* UG585 (v1.12.2) July 1, 2018 Chapter 6.4.3
> +      * In all modes, the DMA transactions must be 64-byte aligned to prevent
> +      * accidently crossing a 4K byte boundary.
> +      */
> +     if(byte_order == XILINX_BYTE_ORDER_BIN)
> +             copy_words_swapped((u32 *)buf_aligned, body, body_length / sizeof(u32));
> +     else
> +             memcpy((u32 *)buf_aligned, body, body_length);
> +
> +     addr = (u32)buf_aligned;
> +
> +     writel(0x0000DF0D, ZYNQ_SLCR_UNLOCK);
> +     writel(0x0000000f, ZYNQ_SLCR_BASE + 0x240); // assert FPGA resets
> +
> +     writel(0x00000000, ZYNQ_SLCR_BASE + 0x900); // disable levelshifter
> +     writel(0x0000000a, ZYNQ_SLCR_BASE + 0x900); // enable levelshifter PS-PL
> +
> +     status = mgr->devc_ops->fpga_load(mgr, addr, (u32)(body_length), 0);
>
> +     writel(0x0000000f, ZYNQ_SLCR_BASE + 0x900); // enable all levelshifter
> +     writel(0x00000000, ZYNQ_SLCR_BASE + 0x240); // deassert FPGA resets
> +
> +     writel(0x0000767B, ZYNQ_SLCR_LOCK);
> +#endif
>       if (status < 0)
>               dev_err(&mgr->dev, "unable to load fpga\n");
>
> @@ -313,8 +301,10 @@ static int fpgamgr_program_start(struct firmware_handler *fh)
>       return 0;
>  }
>
> +
>  static int programmed_get(struct param_d *p, void *priv)
>  {
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>       struct fpgamgr *mgr = priv;
>       u32 status = 0x00;
>       int ret = 0;
> @@ -324,7 +314,7 @@ static int programmed_get(struct param_d *p, void *priv)
>               return ret;
>
>       mgr->programmed = !!(status & ZYNQMP_PCAP_STATUS_FPGA_DONE);
> -
> +#endif
>       return 0;
>  }
>
> @@ -336,6 +326,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>       const char *model = NULL;
>       struct param_d *p;
>       u32 api_version;
> +     struct resource *iores;
>       int ret;
>
>       mgr = xzalloc(sizeof(*mgr));
> @@ -354,6 +345,7 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>               fh->model = xstrdup(model);
>       fh->dev = dev;
>
> +#ifdef CONFIG_FIRMWARE_ZYNQMP_FPGA
>       mgr->eemi_ops = zynqmp_pm_get_eemi_ops();
>
>       ret = mgr->eemi_ops->get_api_version(&api_version);
> @@ -361,11 +353,21 @@ static int zynqmp_fpga_probe(struct device_d *dev)
>               dev_err(&mgr->dev, "could not get API version\n");
>               goto out;
>       }
> -
> -     mgr->features = 0;
> -
>       if (api_version >= ZYNQMP_PM_VERSION(1, 1))
>               mgr->features |= ZYNQMP_PM_VERSION_1_1_FEATURES;
> +#endif
> +#ifdef CONFIG_FIRMWARE_ZYNQ7000_FPGA
> +     iores = dev_request_mem_resource(dev, 0);
> +     if (IS_ERR(iores)) {
> +             ret = PTR_ERR(iores);
> +             goto out;
> +     }
> +     mgr->regs = IOMEM(iores->start);
> +     mgr->devc_ops = zynq_get_devc_ops();
> +     /* Unlock DevC in case BootROM did not do it */
> +     writel(DEVC_UNLOCK_CODE, mgr->regs + UNLOCK_OFFSET);
> +#endif
> +     mgr->features = 0;
>
>       dev_dbg(dev, "Registering ZynqMP FPGA programmer\n");
>       mgr->dev.id = DEVICE_ID_SINGLE;
> @@ -400,9 +402,8 @@ out:
>  }
>
>  static struct of_device_id zynqmpp_fpga_id_table[] = {
> -     {
> -             .compatible = "xlnx,zynqmp-pcap-fpga",
> -     },
> +     { .compatible = "xlnx,zynqmp-pcap-fpga" },
> +     { .compatible = "xlnx,zynq-devcfg-1.0" },
>       { /* sentinel */ }
>  };
>
> --
> 2.25.1
>
>

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


  reply	other threads:[~2021-03-30 12:07 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-25  7:53 Michael Graichen
2021-03-25  8:09 ` Ahmad Fatoum
2021-03-25  8:42 ` Michael Tretter
2021-03-30 12:05   ` Michael Graichen [this message]
2021-04-08 15:28     ` Michael Tretter
2021-04-28  8:16       ` AW: " Michael Graichen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AM9P192MB08704EEEF035BA67815E5991AB7D9@AM9P192MB0870.EURP192.PROD.OUTLOOK.COM \
    --to=michael.graichen@hotmail.com \
    --cc=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    --cc=m.tretter@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox