uboot/drivers/fpga/stratix10.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Intel Corporation <www.intel.com>
   4 */
   5
   6#include <common.h>
   7#include <altera.h>
   8#include <asm/arch/mailbox_s10.h>
   9
  10#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS            60000
  11#define RECONFIG_STATUS_INTERVAL_DELAY_US               1000000
  12
  13static const struct mbox_cfgstat_state {
  14        int                     err_no;
  15        const char              *error_name;
  16} mbox_cfgstat_state[] = {
  17        {MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
  18        {MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
  19        {MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgment failed!"},
  20        {MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
  21        {MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted bitstream!"},
  22        {MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
  23        {MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
  24        {MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
  25        {MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
  26        {MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot info!"},
  27        {MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
  28        {MBOX_RESP_ERROR, "Mailbox general error!"},
  29        {-ETIMEDOUT, "I/O timeout error"},
  30        {-1, "Unknown error!"}
  31};
  32
  33#define MBOX_CFGSTAT_MAX ARRAY_SIZE(mbox_cfgstat_state)
  34
  35static const char *mbox_cfgstat_to_str(int err)
  36{
  37        int i;
  38
  39        for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
  40                if (mbox_cfgstat_state[i].err_no == err)
  41                        return mbox_cfgstat_state[i].error_name;
  42        }
  43
  44        return mbox_cfgstat_state[MBOX_CFGSTAT_MAX - 1].error_name;
  45}
  46
  47/*
  48 * Add the ongoing transaction's command ID into pending list and return
  49 * the command ID for next transfer.
  50 */
  51static u8 add_transfer(u32 *xfer_pending_list, size_t list_size, u8 id)
  52{
  53        int i;
  54
  55        for (i = 0; i < list_size; i++) {
  56                if (xfer_pending_list[i])
  57                        continue;
  58                xfer_pending_list[i] = id;
  59                debug("ID(%d) added to transaction pending list\n", id);
  60                /*
  61                 * Increment command ID for next transaction.
  62                 * Valid command ID (4 bits) is from 1 to 15.
  63                 */
  64                id = (id % 15) + 1;
  65                break;
  66        }
  67
  68        return id;
  69}
  70
  71/*
  72 * Check whether response ID match the command ID in the transfer
  73 * pending list. If a match is found in the transfer pending list,
  74 * it clears the transfer pending list and return the matched
  75 * command ID.
  76 */
  77static int get_and_clr_transfer(u32 *xfer_pending_list, size_t list_size,
  78                                u8 id)
  79{
  80        int i;
  81
  82        for (i = 0; i < list_size; i++) {
  83                if (id != xfer_pending_list[i])
  84                        continue;
  85                xfer_pending_list[i] = 0;
  86                return id;
  87        }
  88
  89        return 0;
  90}
  91
  92/*
  93 * Polling the FPGA configuration status.
  94 * Return 0 for success, non-zero for error.
  95 */
  96static int reconfig_status_polling_resp(void)
  97{
  98        int ret;
  99        unsigned long start = get_timer(0);
 100
 101        while (1) {
 102                ret = mbox_get_fpga_config_status(MBOX_RECONFIG_STATUS);
 103                if (!ret)
 104                        return 0;       /* configuration success */
 105
 106                if (ret != MBOX_CFGSTAT_STATE_CONFIG)
 107                        return ret;
 108
 109                if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
 110                        break;  /* time out */
 111
 112                puts(".");
 113                udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
 114        }
 115
 116        return -ETIMEDOUT;
 117}
 118
 119static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32 *resp_count,
 120                        u32 *resp_buf, u32 buf_size, u32 client_id)
 121{
 122        u32 buf[MBOX_RESP_BUFFER_SIZE];
 123        u32 mbox_hdr;
 124        u32 resp_len;
 125        u32 hdr_len;
 126        u32 i;
 127
 128        if (*resp_count < buf_size) {
 129                u32 rcv_len_max = buf_size - *resp_count;
 130
 131                if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
 132                        rcv_len_max = MBOX_RESP_BUFFER_SIZE;
 133                resp_len = mbox_rcv_resp(buf, rcv_len_max);
 134
 135                for (i = 0; i < resp_len; i++) {
 136                        resp_buf[(*w_index)++] = buf[i];
 137                        *w_index %= buf_size;
 138                        (*resp_count)++;
 139                }
 140        }
 141
 142        /* No response in buffer */
 143        if (*resp_count == 0)
 144                return 0;
 145
 146        mbox_hdr = resp_buf[*r_index];
 147
 148        hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
 149
 150        /* Insufficient header length to return a mailbox header */
 151        if ((*resp_count - 1) < hdr_len)
 152                return 0;
 153
 154        *r_index += (hdr_len + 1);
 155        *r_index %= buf_size;
 156        *resp_count -= (hdr_len + 1);
 157
 158        /* Make sure response belongs to us */
 159        if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
 160                return 0;
 161
 162        return mbox_hdr;
 163}
 164
 165/* Send bit stream data to SDM via RECONFIG_DATA mailbox command */
 166static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
 167                              u32 xfer_max, u32 buf_size_max)
 168{
 169        u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
 170        u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
 171        u32 resp_rindex = 0;
 172        u32 resp_windex = 0;
 173        u32 resp_count = 0;
 174        u32 xfer_count = 0;
 175        int resp_err = 0;
 176        u8 cmd_id = 1;
 177        u32 args[3];
 178        int ret;
 179
 180        debug("SDM xfer_max = %d\n", xfer_max);
 181        debug("SDM buf_size_max = %x\n\n", buf_size_max);
 182
 183        memset(xfer_pending, 0, sizeof(xfer_pending));
 184
 185        while (rbf_size || xfer_count) {
 186                if (!resp_err && rbf_size && xfer_count < xfer_max) {
 187                        args[0] = MBOX_ARG_DESC_COUNT(1);
 188                        args[1] = (u64)rbf_data;
 189                        if (rbf_size >= buf_size_max) {
 190                                args[2] = buf_size_max;
 191                                rbf_size -= buf_size_max;
 192                                rbf_data += buf_size_max;
 193                        } else {
 194                                args[2] = (u64)rbf_size;
 195                                rbf_size = 0;
 196                        }
 197
 198                        resp_err = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
 199                                                 MBOX_CMD_INDIRECT, 3, args);
 200                        if (!resp_err) {
 201                                xfer_count++;
 202                                cmd_id = add_transfer(xfer_pending,
 203                                                      MBOX_RESP_BUFFER_SIZE,
 204                                                      cmd_id);
 205                        }
 206                        puts(".");
 207                } else {
 208                        u32 resp_hdr = get_resp_hdr(&resp_rindex, &resp_windex,
 209                                                    &resp_count,
 210                                                    response_buffer,
 211                                                    MBOX_RESP_BUFFER_SIZE,
 212                                                    MBOX_CLIENT_ID_UBOOT);
 213
 214                        /*
 215                         * If no valid response header found or
 216                         * non-zero length from RECONFIG_DATA
 217                         */
 218                        if (!resp_hdr || MBOX_RESP_LEN_GET(resp_hdr))
 219                                continue;
 220
 221                        /* Check for response's status */
 222                        if (!resp_err) {
 223                                resp_err = MBOX_RESP_ERR_GET(resp_hdr);
 224                                debug("Response error code: %08x\n", resp_err);
 225                        }
 226
 227                        ret = get_and_clr_transfer(xfer_pending,
 228                                                   MBOX_RESP_BUFFER_SIZE,
 229                                                   MBOX_RESP_ID_GET(resp_hdr));
 230                        if (ret) {
 231                                /* Claim and reuse the ID */
 232                                cmd_id = (u8)ret;
 233                                xfer_count--;
 234                        }
 235
 236                        if (resp_err && !xfer_count)
 237                                return resp_err;
 238                }
 239        }
 240
 241        return 0;
 242}
 243
 244/*
 245 * This is the interface used by FPGA driver.
 246 * Return 0 for success, non-zero for error.
 247 */
 248int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
 249{
 250        int ret;
 251        u32 resp_len = 2;
 252        u32 resp_buf[2];
 253
 254        debug("Sending MBOX_RECONFIG...\n");
 255        ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0,
 256                            NULL, 0, &resp_len, resp_buf);
 257        if (ret) {
 258                puts("Failure in RECONFIG mailbox command!\n");
 259                return ret;
 260        }
 261
 262        ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0], resp_buf[1]);
 263        if (ret) {
 264                printf("RECONFIG_DATA error: %08x, %s\n", ret,
 265                       mbox_cfgstat_to_str(ret));
 266                return ret;
 267        }
 268
 269        /* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
 270        udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
 271
 272        debug("Polling with MBOX_RECONFIG_STATUS...\n");
 273        ret = reconfig_status_polling_resp();
 274        if (ret) {
 275                printf("RECONFIG_STATUS Error: %08x, %s\n", ret,
 276                       mbox_cfgstat_to_str(ret));
 277                return ret;
 278        }
 279
 280        puts("FPGA reconfiguration OK!\n");
 281
 282        return ret;
 283}
 284