uboot/arch/arm/mach-socfpga/mailbox_s10.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
   4 *
   5 */
   6
   7#include <common.h>
   8#include <wait_bit.h>
   9#include <asm/io.h>
  10#include <asm/arch/mailbox_s10.h>
  11#include <asm/arch/system_manager.h>
  12#include <asm/secure.h>
  13
  14DECLARE_GLOBAL_DATA_PTR;
  15
  16#define MBOX_READL(reg)                 \
  17         readl(SOCFPGA_MAILBOX_ADDRESS + (reg))
  18
  19#define MBOX_WRITEL(data, reg)          \
  20        writel(data, SOCFPGA_MAILBOX_ADDRESS + (reg))
  21
  22#define MBOX_READ_RESP_BUF(rout)        \
  23        MBOX_READL(MBOX_RESP_BUF + ((rout) * sizeof(u32)))
  24
  25#define MBOX_WRITE_CMD_BUF(data, cin)   \
  26        MBOX_WRITEL(data, MBOX_CMD_BUF + ((cin) * sizeof(u32)))
  27
  28static __always_inline int mbox_polling_resp(u32 rout)
  29{
  30        u32 rin;
  31        unsigned long i = ~0;
  32
  33        while (i) {
  34                rin = MBOX_READL(MBOX_RIN);
  35                if (rout != rin)
  36                        return 0;
  37
  38                i--;
  39        }
  40
  41        return -ETIMEDOUT;
  42}
  43
  44/* Check for available slot and write to circular buffer.
  45 * It also update command valid offset (cin) register.
  46 */
  47static __always_inline int mbox_fill_cmd_circular_buff(u32 header, u32 len,
  48                                                       u32 *arg)
  49{
  50        u32 cin;
  51        u32 cout;
  52        u32 i;
  53
  54        cin = MBOX_READL(MBOX_CIN) % MBOX_CMD_BUFFER_SIZE;
  55        cout = MBOX_READL(MBOX_COUT) % MBOX_CMD_BUFFER_SIZE;
  56
  57        /* if command buffer is full or not enough free space
  58         * to fit the data. Note, len is in u32 unit.
  59         */
  60        if (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == cout ||
  61            ((MBOX_CMD_BUFFER_SIZE - cin + cout - 1) %
  62             MBOX_CMD_BUFFER_SIZE) < (len + 1))
  63                return -ENOMEM;
  64
  65        /* write header to circular buffer */
  66        MBOX_WRITE_CMD_BUF(header, cin++);
  67        /* wrapping around when it reach the buffer size */
  68        cin %= MBOX_CMD_BUFFER_SIZE;
  69
  70        /* write arguments */
  71        for (i = 0; i < len; i++) {
  72                MBOX_WRITE_CMD_BUF(arg[i], cin++);
  73                /* wrapping around when it reach the buffer size */
  74                cin %= MBOX_CMD_BUFFER_SIZE;
  75        }
  76
  77        /* write command valid offset */
  78        MBOX_WRITEL(cin, MBOX_CIN);
  79
  80        return 0;
  81}
  82
  83/* Check the command and fill it into circular buffer */
  84static __always_inline int mbox_prepare_cmd_only(u8 id, u32 cmd,
  85                                                 u8 is_indirect, u32 len,
  86                                                 u32 *arg)
  87{
  88        u32 header;
  89        int ret;
  90
  91        /* Total length is command + argument length */
  92        if ((len + 1) > MBOX_CMD_BUFFER_SIZE)
  93                return -EINVAL;
  94
  95        if (cmd > MBOX_MAX_CMD_INDEX)
  96                return -EINVAL;
  97
  98        header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id, len,
  99                                 (is_indirect) ? 1 : 0, cmd);
 100
 101        ret = mbox_fill_cmd_circular_buff(header, len, arg);
 102
 103        return ret;
 104}
 105
 106/* Send command only without waiting for responses from SDM */
 107static __always_inline int mbox_send_cmd_only_common(u8 id, u32 cmd,
 108                                                     u8 is_indirect, u32 len,
 109                                                     u32 *arg)
 110{
 111        int ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
 112        /* write doorbell */
 113        MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
 114
 115        return ret;
 116}
 117
 118/* Return number of responses received in buffer */
 119static __always_inline int __mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
 120{
 121        u32 rin;
 122        u32 rout;
 123        u32 resp_len = 0;
 124
 125        /* clear doorbell from SDM if it was SET */
 126        if (MBOX_READL(MBOX_DOORBELL_FROM_SDM) & 1)
 127                MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
 128
 129        /* read current response offset */
 130        rout = MBOX_READL(MBOX_ROUT);
 131        /* read response valid offset */
 132        rin = MBOX_READL(MBOX_RIN);
 133
 134        while (rin != rout && (resp_len < resp_buf_max_len)) {
 135                /* Response received */
 136                if (resp_buf)
 137                        resp_buf[resp_len++] = MBOX_READ_RESP_BUF(rout);
 138
 139                rout++;
 140                /* wrapping around when it reach the buffer size */
 141                rout %= MBOX_RESP_BUFFER_SIZE;
 142                /* update next ROUT */
 143                MBOX_WRITEL(rout, MBOX_ROUT);
 144        }
 145
 146        return resp_len;
 147}
 148
 149/* Support one command and up to 31 words argument length only */
 150static __always_inline int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect,
 151                                                u32 len, u32 *arg, u8 urgent,
 152                                                u32 *resp_buf_len,
 153                                                u32 *resp_buf)
 154{
 155        u32 rin;
 156        u32 resp;
 157        u32 rout;
 158        u32 status;
 159        u32 resp_len;
 160        u32 buf_len;
 161        int ret;
 162
 163        if (urgent) {
 164                /* Read status because it is toggled */
 165                status = MBOX_READL(MBOX_STATUS) & MBOX_STATUS_UA_MSK;
 166                /* Write urgent command to urgent register */
 167                MBOX_WRITEL(cmd, MBOX_URG);
 168        } else {
 169                ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
 170                if (ret)
 171                        return ret;
 172        }
 173
 174        /* write doorbell */
 175        MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
 176
 177        while (1) {
 178                ret = ~0;
 179
 180                /* Wait for doorbell from SDM */
 181                while (!MBOX_READL(MBOX_DOORBELL_FROM_SDM) && ret--)
 182                        ;
 183                if (!ret)
 184                        return -ETIMEDOUT;
 185
 186                /* clear interrupt */
 187                MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
 188
 189                if (urgent) {
 190                        u32 new_status = MBOX_READL(MBOX_STATUS);
 191
 192                        /* Urgent ACK is toggled */
 193                        if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
 194                                return 0;
 195
 196                        return -ECOMM;
 197                }
 198
 199                /* read current response offset */
 200                rout = MBOX_READL(MBOX_ROUT);
 201
 202                /* read response valid offset */
 203                rin = MBOX_READL(MBOX_RIN);
 204
 205                if (rout != rin) {
 206                        /* Response received */
 207                        resp = MBOX_READ_RESP_BUF(rout);
 208                        rout++;
 209                        /* wrapping around when it reach the buffer size */
 210                        rout %= MBOX_RESP_BUFFER_SIZE;
 211                        /* update next ROUT */
 212                        MBOX_WRITEL(rout, MBOX_ROUT);
 213
 214                        /* check client ID and ID */
 215                        if ((MBOX_RESP_CLIENT_GET(resp) ==
 216                             MBOX_CLIENT_ID_UBOOT) &&
 217                            (MBOX_RESP_ID_GET(resp) == id)) {
 218                                ret = MBOX_RESP_ERR_GET(resp);
 219                                if (ret)
 220                                        return ret;
 221
 222                                if (resp_buf_len) {
 223                                        buf_len = *resp_buf_len;
 224                                        *resp_buf_len = 0;
 225                                } else {
 226                                        buf_len = 0;
 227                                }
 228
 229                                resp_len = MBOX_RESP_LEN_GET(resp);
 230                                while (resp_len) {
 231                                        ret = mbox_polling_resp(rout);
 232                                        if (ret)
 233                                                return ret;
 234                                        /* we need to process response buffer
 235                                         * even caller doesn't need it
 236                                         */
 237                                        resp = MBOX_READ_RESP_BUF(rout);
 238                                        rout++;
 239                                        resp_len--;
 240                                        rout %= MBOX_RESP_BUFFER_SIZE;
 241                                        MBOX_WRITEL(rout, MBOX_ROUT);
 242                                        if (buf_len) {
 243                                                /* copy response to buffer */
 244                                                resp_buf[*resp_buf_len] = resp;
 245                                                (*resp_buf_len)++;
 246                                                buf_len--;
 247                                        }
 248                                }
 249                                return ret;
 250                        }
 251                }
 252        };
 253
 254        return -EIO;
 255}
 256
 257int mbox_init(void)
 258{
 259        int ret;
 260
 261        /* enable mailbox interrupts */
 262        MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
 263
 264        /* Ensure urgent request is cleared */
 265        MBOX_WRITEL(0, MBOX_URG);
 266
 267        /* Ensure the Doorbell Interrupt is cleared */
 268        MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
 269
 270        ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
 271                            NULL, 1, 0, NULL);
 272        if (ret)
 273                return ret;
 274
 275        /* Renable mailbox interrupts after MBOX_RESTART */
 276        MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
 277
 278        return 0;
 279}
 280
 281#ifdef CONFIG_CADENCE_QSPI
 282int mbox_qspi_close(void)
 283{
 284        return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
 285                             0, NULL, 0, 0, NULL);
 286}
 287
 288int mbox_qspi_open(void)
 289{
 290        static const struct socfpga_system_manager *sysmgr_regs =
 291                (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
 292
 293        int ret;
 294        u32 resp_buf[1];
 295        u32 resp_buf_len;
 296
 297        ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
 298                            0, NULL, 0, 0, NULL);
 299        if (ret) {
 300                /* retry again by closing and reopen the QSPI again */
 301                ret = mbox_qspi_close();
 302                if (ret)
 303                        return ret;
 304
 305                ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN,
 306                                    MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
 307                if (ret)
 308                        return ret;
 309        }
 310
 311        /* HPS will directly control the QSPI controller, no longer mailbox */
 312        resp_buf_len = 1;
 313        ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
 314                            0, NULL, 0, (u32 *)&resp_buf_len,
 315                            (u32 *)&resp_buf);
 316        if (ret)
 317                goto error;
 318
 319        /* We are getting QSPI ref clock and set into sysmgr boot register */
 320        printf("QSPI: Reference clock at %d Hz\n", resp_buf[0]);
 321        writel(resp_buf[0], &sysmgr_regs->boot_scratch_cold0);
 322
 323        return 0;
 324
 325error:
 326        mbox_qspi_close();
 327
 328        return ret;
 329}
 330#endif /* CONFIG_CADENCE_QSPI */
 331
 332int mbox_reset_cold(void)
 333{
 334        int ret;
 335
 336        ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_REBOOT_HPS, MBOX_CMD_DIRECT,
 337                            0, NULL, 0, 0, NULL);
 338        if (ret) {
 339                /* mailbox sent failure, wait for watchdog to kick in */
 340                hang();
 341        }
 342        return 0;
 343}
 344
 345/* Accepted commands: CONFIG_STATUS or RECONFIG_STATUS */
 346static __always_inline int mbox_get_fpga_config_status_common(u32 cmd)
 347{
 348        u32 reconfig_status_resp_len;
 349        u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
 350        int ret;
 351
 352        reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN;
 353        ret = mbox_send_cmd_common(MBOX_ID_UBOOT, cmd,
 354                                   MBOX_CMD_DIRECT, 0, NULL, 0,
 355                                   &reconfig_status_resp_len,
 356                                   reconfig_status_resp);
 357
 358        if (ret)
 359                return ret;
 360
 361        /* Check for any error */
 362        ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
 363        if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
 364                return ret;
 365
 366        /* Make sure nStatus is not 0 */
 367        ret = reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
 368        if (!(ret & RCF_PIN_STATUS_NSTATUS))
 369                return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
 370
 371        ret = reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
 372        if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR)
 373                return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
 374
 375        if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
 376            (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
 377            !reconfig_status_resp[RECONFIG_STATUS_STATE])
 378                return 0;       /* configuration success */
 379
 380        return MBOX_CFGSTAT_STATE_CONFIG;
 381}
 382
 383int mbox_get_fpga_config_status(u32 cmd)
 384{
 385        return mbox_get_fpga_config_status_common(cmd);
 386}
 387
 388int __secure mbox_get_fpga_config_status_psci(u32 cmd)
 389{
 390        return mbox_get_fpga_config_status_common(cmd);
 391}
 392
 393int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
 394                  u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
 395{
 396        return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent,
 397                               resp_buf_len, resp_buf);
 398}
 399
 400int __secure mbox_send_cmd_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
 401                                u32 *arg, u8 urgent, u32 *resp_buf_len,
 402                                u32 *resp_buf)
 403{
 404        return mbox_send_cmd_common(id, cmd, is_indirect, len, arg, urgent,
 405                               resp_buf_len, resp_buf);
 406}
 407
 408int mbox_send_cmd_only(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg)
 409{
 410        return mbox_send_cmd_only_common(id, cmd, is_indirect, len, arg);
 411}
 412
 413int __secure mbox_send_cmd_only_psci(u8 id, u32 cmd, u8 is_indirect, u32 len,
 414                                     u32 *arg)
 415{
 416        return mbox_send_cmd_only_common(id, cmd, is_indirect, len, arg);
 417}
 418
 419int mbox_rcv_resp(u32 *resp_buf, u32 resp_buf_max_len)
 420{
 421        return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
 422}
 423
 424int __secure mbox_rcv_resp_psci(u32 *resp_buf, u32 resp_buf_max_len)
 425{
 426        return __mbox_rcv_resp(resp_buf, resp_buf_max_len);
 427}
 428