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