On 04/26/2018 08:12 AM, Ang, Chee Hong wrote:
> On Fri, 2018-04-20 at 05:41 +0200, Marek Vasut wrote:
>> On 04/20/2018 05:26 AM, chee.hong....@intel.com wrote:
>>>
>>> From: Chee Hong Ang <chee.hong....@intel.com>
>>>
>>> Enable FPGA reconfiguration support on Stratix10 SoC.
>>>
>>> Signed-off-by: Chee Hong Ang <chee.hong....@intel.com>
>>> ---
>>>  drivers/fpga/Kconfig     |  10 ++
>>>  drivers/fpga/Makefile    |   1 +
>>>  drivers/fpga/stratix10.c | 298
>>> +++++++++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 309 insertions(+)
>>>  create mode 100644 drivers/fpga/stratix10.c
>>>
>>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>>> index d36c4c5..255683d 100644
>>> --- a/drivers/fpga/Kconfig
>>> +++ b/drivers/fpga/Kconfig
>>> @@ -31,6 +31,16 @@ config FPGA_CYCLON2
>>>       Enable FPGA driver for loading bitstream in BIT and BIN
>>> format
>>>       on Altera Cyclone II device.
>>>  
>>> +config FPGA_STRATIX10
>>> +   bool "Enable Altera FPGA driver for Stratix 10"
>>> +   depends on FPGA_ALTERA && TARGET_SOCFPGA_STRATIX10
>>> +   help
>>> +     Say Y here to enable the Altera Stratix 10 FPGA specific
>>> driver
>>> +
>>> +     This provides common functionality for Altera Stratix 10
>>> devices.
>>> +     Enable FPGA driver for writing bitstream into Altera
>>> Stratix10
>>> +     device.
>>> +
>>>  config FPGA_XILINX
>>>     bool "Enable Xilinx FPGA drivers"
>>>     select FPGA
>>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>>> index 08c9ff8..3c906ec 100644
>>> --- a/drivers/fpga/Makefile
>>> +++ b/drivers/fpga/Makefile
>>> @@ -19,6 +19,7 @@ obj-$(CONFIG_FPGA_ACEX1K) += ACEX1K.o
>>>  obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
>>>  obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
>>>  obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
>>> +obj-$(CONFIG_FPGA_STRATIX10) += stratix10.o
>>>  obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
>>>  obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o
>>>  obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o
>>> diff --git a/drivers/fpga/stratix10.c b/drivers/fpga/stratix10.c
>>> new file mode 100644
>>> index 0000000..f0c5ace
>>> --- /dev/null
>>> +++ b/drivers/fpga/stratix10.c
>>> @@ -0,0 +1,298 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Copyright (C) 2016-2018 Intel Corporation <www.intel.com>
>>> + *
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <altera.h>
>>> +#include <asm/arch/mailbox_s10.h>
>>> +
>>> +#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS               60000
>>> +#define RECONFIG_STATUS_INTERVAL_DELAY_US          1000000
>>> +
>>> +static const struct mbox_cfgstat_state {
>>> +   int                     err_no;
>>> +   const char              *error_name;
>>> +} mbox_cfgstat_state[] = {
>>> +   {MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
>>> +   {MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
>>> +   {MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgement failed!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted
>>> bitstream!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot
>>> info!"},
>>> +   {MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
>>> +   {-ETIMEDOUT, "I/O timeout error"},
>>> +   {-1, "Unknown error!"}
>>> +};
>>> +
>>> +#define MBOX_CFGSTAT_MAX \
>>> +     (sizeof(mbox_cfgstat_state) / sizeof(struct
>>> mbox_cfgstat_state))
>>> +
>>> +static const char *mbox_cfgstat_to_str(int err)
>>> +{
>>> +   int i;
>>> +
>>> +   for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
>>> +           if (mbox_cfgstat_state[i].err_no == err)
>>> +                   return mbox_cfgstat_state[i].error_name;
>>> +   }
>>> +
>>> +   return mbox_cfgstat_state[MBOX_CFGSTAT_MAX -
>>> 1].error_name;
>>> +}
>>> +
>>> +static void inc_cmd_id(u8 *id)
>>> +{
>>> +   u8 val = *id + 1;
>>> +
>>> +   if (val > 15)
>>> +           val = 1;
>> What's this function about, elaborate implementation of (i % 15) + 1
>> ?
> This function increment the 4 bits transaction ID (1-15, 0 is unused)
> used for sending mailbox command to device.
>>
>>>
>>> +   *id = val;
>>> +}
>>> +
>>> +/*
>>> + * Polling the FPGA configuration status.
>>> + * Return 0 for success, non-zero for error.
>>> + */
>>> +static int reconfig_status_polling_resp(void)
>>> +{
>>> +   u32 reconfig_status_resp_len;
>>> +   u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
>>> +   int ret;
>>> +   unsigned long start = get_timer(0);
>>> +
>>> +   while (1) {
>>> +           reconfig_status_resp_len =
>>> RECONFIG_STATUS_RESPONSE_LEN;
>>> +           ret = mbox_send_cmd(MBOX_ID_UBOOT,
>>> MBOX_RECONFIG_STATUS,
>>> +                               MBOX_CMD_DIRECT, 0, NULL, 0,
>>> +                               &reconfig_status_resp_len,
>>> +                               reconfig_status_resp);
>>> +
>>> +           if (ret) {
>>> +                   puts("Failure in RECONFIG_STATUS mailbox
>>> command!\n");
>>> +                   return ret;
>>> +           }
>>> +
>>> +           /* Check for any error */
>>> +           ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
>>> +           if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
>>> +                   return ret;
>>> +
>>> +           /* Make sure nStatus is not 0 */
>>> +           ret =
>>> reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
>>> +           if (!(ret & RCF_PIN_STATUS_NSTATUS))
>>> +                   return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
>> wait_for_bit_le32() or somesuch ?
> No, we don't read the bit status directly from register. We only need
> to test the bit of the pin status stored in memory.

Who's populating the memory ?

>>
>>>
>>> +           ret =
>>> reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
>>> +           if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR)
>>> +                   return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
>>> +
>>> +           if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
>>> +               (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
>>> +               !reconfig_status_resp[RECONFIG_STATUS_STATE])
>>> +                   return 0;       /* configuration success
>>> */
>>> +
>>> +           if (get_timer(start) >
>>> RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
>>> +                   break;  /* time out */
>>> +
>>> +           puts(".");
>>> +           udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
>>> +   }
>>> +
>>> +   return -ETIMEDOUT;
>>> +}
>>> +
>>> +static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32
>>> *resp_count,
>>> +                   u32 *resp_buf, u32 buf_size, u32
>>> client_id)
>>> +{
>>> +   u32 i;
>>> +   u32 mbox_hdr;
>>> +   u32 resp_len;
>>> +   u32 hdr_len;
>>> +   u32 buf[MBOX_RESP_BUFFER_SIZE];
>>> +
>>> +   if (*resp_count < buf_size) {
>>> +           u32 rcv_len_max = buf_size - *resp_count;
>>> +
>>> +           if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
>>> +                   rcv_len_max = MBOX_RESP_BUFFER_SIZE;
>>> +           resp_len = mbox_rcv_resp(buf, rcv_len_max);
>>> +
>>> +           for (i = 0; i < resp_len; i++) {
>>> +                   resp_buf[(*w_index)++] = buf[i];
>> Is this like a memcpy() ?
> No. This is a circular buffer, index to the memory location may wrap
> around.

Two memcpys then ?

>>>
>>> +                   *w_index %= buf_size;
>>> +                   (*resp_count)++;
>>> +           }
>>> +   }
>>> +
>>> +   /* No response in buffer */
>>> +   if (*resp_count == 0)
>>> +           return 0;
>>> +
>>> +   mbox_hdr = resp_buf[*r_index];
>>> +
>>> +   hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
>>> +
>>> +   /* Insufficient header length to return a mailbox header
>>> */
>>> +   if ((*resp_count - 1) < hdr_len)
>>> +           return 0;
>>> +
>>> +   *r_index += (hdr_len + 1);
>>> +   *r_index %= buf_size;
>>> +   *resp_count -= (hdr_len + 1);
>>> +
>>> +   /* Make sure response belongs to us */
>>> +   if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
>>> +           return 0;
>>> +
>>> +   return mbox_hdr;
>>> +}
>>> +
>>> +static int send_reconfig_data(const void *rbf_data, size_t
>>> rbf_size,
>>> +                         u32 xfer_max, u32 buf_size_max)
>>> +{
>>> +   u32 resp_rindex = 0;
>>> +   u32 resp_windex = 0;
>>> +   u32 resp_count = 0;
>>> +   u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
>>> +   u8 resp_err = 0;
>>> +   u8 cmd_id = 1;
>>> +   u32 xfer_count = 0;
>>> +   u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
>>> +   u32 args[3];
>>> +   int ret = 0;
>>> +   u32 i;
>>> +
>>> +   debug("SDM xfer_max = %d\n", xfer_max);
>>> +   debug("SDM buf_size_max = %x\n\n", buf_size_max);
>>> +
>>> +   for (i = 0; i < MBOX_RESP_BUFFER_SIZE; i++)
>>> +           xfer_pending[i] = 0;
>>> +
>>> +   while (rbf_size || xfer_count) {
>>> +           if (!resp_err && rbf_size && xfer_count <
>>> xfer_max) {
>> This function is clearly too long, split it into separate functions
> This function is not short but not too long. But let me see what sort
> of refactoring can be done to make it shorter abit.

Split it, it is too long.

>>>
>>> +                   args[0] = (1 << 8);
>> That's BIT(8) .
> Will be addressed in v2 patch.
>>
>>>
>>> +                   args[1] = (u32)rbf_data;
>>> +                   if (rbf_size >= buf_size_max) {
>>> +                           args[2] = buf_size_max;
>>> +                           rbf_size -= buf_size_max;
>>> +                           rbf_data += buf_size_max;
>>> +                   } else {
>>> +                           args[2] = (u32)rbf_size;
>>> +                           rbf_size = 0;
>>> +                   }
>>> +
>>> +                   debug("Sending MBOX_RECONFIG_DATA...\n");
>>> +
>>> +                   ret = mbox_send_cmd_only(cmd_id,
>>> MBOX_RECONFIG_DATA,
>>> +                                            MBOX_CMD_INDIRECT
>>> , 3, args);
>>> +                   if (ret) {
>>> +                           resp_err = 1;
>>> +                   } else {
>>> +                           xfer_count++;
>>> +                           for (i = 0; i <
>>> MBOX_RESP_BUFFER_SIZE; i++) {
>>> +                                   if (!xfer_pending[i]) {
>>> +                                           xfer_pending[i] =
>>> cmd_id;
>>> +                                           inc_cmd_id(&cmd_id
>>> );
>>> +                                           break;
>>> +                                   }
>>> +                           }
>>> +                           debug("+xfer_count = %d\n",
>>> xfer_count);
>>> +                           debug("xfer ID = %d\n",
>>> xfer_pending[i]);
>>> +                           debug("data offset = %08x\n",
>>> args[1]);
>>> +                           debug("data size = %08x\n",
>>> args[2]);
>>> +                   }
>>> +#ifndef DEBUG
>>> +                   puts(".");
>> debug(".") is the same, except without the ifdef
> This is #ifndef DEBUG, we only print '.' in non-debug environment.

Oh, OK

>>>
>>> +#endif
>>> +           } else {
>>> +                   u32 r_id = 0;
>>> +                   u32 resp_hdr = get_resp_hdr(&resp_rindex,
>>> &resp_windex,
>>> +                                               &resp_count,
>>> +                                               response_buffe
>>> r,
>>> +                                               MBOX_RESP_BUFF
>>> ER_SIZE,
>>> +                                               MBOX_CLIENT_ID
>>> _UBOOT);
>>> +
>>> +                   /* If no valid response header found */
>>> +                   if (!resp_hdr)
>>> +                           continue;
>>> +
>>> +                   /* Expect 0 length from RECONFIG_DATA */
>>> +                   if (MBOX_RESP_LEN_GET(resp_hdr))
>>> +                           continue;
>>> +
>>> +                   /* Check for response's status */
>>> +                   if (!resp_err) {
>>> +                           ret = MBOX_RESP_ERR_GET(resp_hdr);
>>> +                           debug("Response error code:
>>> %08x\n", ret);
>>> +                           /* Error in response */
>>> +                           if (ret)
>>> +                                   resp_err = 1;
>>> +                   }
>>> +
>>> +                   /* Read the response header's ID */
>>> +                   r_id = MBOX_RESP_ID_GET(resp_hdr);
>>> +                   for (i = 0; i < MBOX_RESP_BUFFER_SIZE;
>>> i++) {
>>> +                           if (r_id == xfer_pending[i]) {
>>> +                                   /* Reclaim ID */
>>> +                                   cmd_id =
>>> (u32)xfer_pending[i];
>>> +                                   xfer_pending[i] = 0;
>>> +                                   xfer_count--;
>>> +                                   break;
>>> +                           }
>>> +                   }
>>> +
>>> +                   debug("Reclaimed xfer ID = %d\n", cmd_id);
>>> +                   debug("-xfer_count = %d\n", xfer_count);
>>> +                   if (resp_err && !xfer_count)
>>> +                           return ret;
>>> +           }
>>> +   }
>>> +
>>> +   return 0;
>>> +}
>>> +
>>> +/*
>>> + * This is the interface used by FPGA driver.
>>> + * Return 0 for success, non-zero for error.
>>> + */
>>> +int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t
>>> rbf_size)
>>> +{
>>> +   int ret;
>>> +   u32 resp_len = 2;
>>> +   u32 resp_buf[2];
>>> +
>>> +   debug("Sending MBOX_RECONFIG...\n");
>>> +   ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG,
>>> MBOX_CMD_DIRECT, 0,
>>> +                       NULL, 0, &resp_len, resp_buf);
>>> +   if (ret) {
>>> +           puts("Failure in RECONFIG mailbox command!\n");
>>> +           return ret;
>>> +   }
>>> +
>>> +   ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0],
>>> resp_buf[1]);
>>> +   if (ret) {
>>> +           printf("RECONFIG_DATA error: %08x, %s\n", ret,
>>> +                  mbox_cfgstat_to_str(ret));
>>> +           return ret;
>>> +   }
>>> +
>>> +   /* Make sure we don't send MBOX_RECONFIG_STATUS too fast
>>> */
>>> +   udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
>> Hum, this is iffy, is that a hardware bug ?
> Yes. The firmware running in that device is not able to response
> quickly.

And you cannot poll it in some way ?

>>>
>>> +   debug("\nPolling with MBOX_RECONFIG_STATUS...\n");
>>> +   ret = reconfig_status_polling_resp();
>>> +   if (ret) {
>>> +           printf("Error: %s\n", mbox_cfgstat_to_str(ret));
>>> +           return ret;
>>> +   }
>>> +
>>> +   puts("\nFPGA reconfiguration OK!\n");
>>> +
>>> +   return ret;
>>> +}
>>>


-- 
Best regards,
Marek Vasut
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to