From patchwork Thu Oct 5 13:07:23 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "See, Chin Liang" X-Patchwork-Id: 821760 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3y7CmV3Lzgz9s7F for ; Fri, 6 Oct 2017 00:10:01 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id D17DDC21FB9; Thu, 5 Oct 2017 13:09:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 075A2C21EBA; Thu, 5 Oct 2017 13:08:02 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 20D93C21EFF; Thu, 5 Oct 2017 13:07:54 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by lists.denx.de (Postfix) with ESMTPS id 5BCC9C21F9C for ; Thu, 5 Oct 2017 13:07:49 +0000 (UTC) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 05 Oct 2017 06:07:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,481,1500966000"; d="scan'208";a="907051142" Received: from pg-interactive1.altera.com ([137.57.137.156]) by FMSMGA003.fm.intel.com with ESMTP; 05 Oct 2017 06:07:46 -0700 From: chin.liang.see@intel.com To: u-boot@lists.denx.de, Marek Vasut Date: Thu, 5 Oct 2017 21:07:23 +0800 Message-Id: <1507208851-32672-7-git-send-email-chin.liang.see@intel.com> X-Mailer: git-send-email 2.2.2 In-Reply-To: <1507208851-32672-1-git-send-email-chin.liang.see@intel.com> References: <1507208851-32672-1-git-send-email-chin.liang.see@intel.com> Cc: Tien Fong Chee , Chin Liang See Subject: [U-Boot] [PATCH v2 06/14] arm: socfpga: stratix10: Add mailbox support for Stratix10 SoC X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Chin Liang See Add mailbox support for Stratix SoC Signed-off-by: Ley Foon Tan Signed-off-by: Chin Liang See --- arch/arm/mach-socfpga/Makefile | 1 + arch/arm/mach-socfpga/include/mach/mailbox_s10.h | 108 ++++++++++ arch/arm/mach-socfpga/mailbox_s10.c | 238 +++++++++++++++++++++++ 3 files changed, 347 insertions(+) create mode 100644 arch/arm/mach-socfpga/include/mach/mailbox_s10.h create mode 100644 arch/arm/mach-socfpga/mailbox_s10.c diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile index b253914..43e18d2 100644 --- a/arch/arm/mach-socfpga/Makefile +++ b/arch/arm/mach-socfpga/Makefile @@ -32,6 +32,7 @@ endif ifdef CONFIG_TARGET_SOCFPGA_STRATIX10 obj-y += clock_manager_s10.o +obj-y += mailbox_s10.o obj-y += misc_s10.o obj-y += reset_manager_s10.o obj-y += system_manager_s10.o diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h new file mode 100644 index 0000000..b9bddf6 --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0 + */ +#ifndef _MAILBOX_S10_H_ +#define _MAILBOX_S10_H_ + +/* user define Uboot ID */ +#define MBOX_CLIENT_ID_UBOOT 0xB +#define MBOX_ID_UBOOT 0x1 + +#define MBOX_MAX_CMD_INDEX 2047 +#define MBOX_CMD_BUFFER_SIZE 32 +#define MBOX_RESP_BUFFER_SIZE 16 + +#define MBOX_HDR_CMD_LSB 0 +#define MBOX_HDR_CMD_MSK (BIT(11) - 1) +#define MBOX_HDR_I_LSB 11 +#define MBOX_HDR_I_MSK BIT(11) +#define MBOX_HDR_LEN_LSB 12 +#define MBOX_HDR_LEN_MSK 0x007FF000 +#define MBOX_HDR_ID_LSB 24 +#define MBOX_HDR_ID_MSK 0x0F000000 +#define MBOX_HDR_CLIENT_LSB 28 +#define MBOX_HDR_CLIENT_MSK 0xF0000000 + +/* Interrupt flags */ +#define MBOX_FLAGS_INT_COE BIT(0) /* COUT update interrupt enable */ +#define MBOX_FLAGS_INT_RIE BIT(1) /* RIN update interrupt enable */ +#define MBOX_FLAGS_INT_UAE BIT(8) /* Urgent ACK interrupt enable */ +#define MBOX_ALL_INTRS (MBOX_FLAGS_INT_COE | \ + MBOX_FLAGS_INT_RIE | \ + MBOX_FLAGS_INT_UAE) + +/* Status */ +#define MBOX_STATUS_UA_MSK BIT(8) + +#define MBOX_CMD_HEADER(client, id, len, cmd) \ + (((cmd) << MBOX_HDR_CMD_LSB) & MBOX_HDR_CMD_MSK) | \ + (((len) << MBOX_HDR_LEN_LSB) & MBOX_HDR_LEN_MSK) | \ + (((id) << MBOX_HDR_ID_LSB) & MBOX_HDR_ID_MSK) | \ + (((client) << MBOX_HDR_CLIENT_LSB) & MBOX_HDR_CLIENT_MSK) + +#define MBOX_RESP_ERR_GET(resp) \ + (((resp) & MBOX_HDR_CMD_MSK) >> MBOX_HDR_CMD_LSB) +#define MBOX_RESP_LEN_GET(resp) \ + (((resp) & MBOX_HDR_LEN_MSK) >> MBOX_HDR_LEN_LSB) +#define MBOX_RESP_ID_GET(resp) \ + (((resp) & MBOX_HDR_ID_MSK) >> MBOX_HDR_ID_LSB) +#define MBOX_RESP_CLIENT_GET(resp) \ + (((resp) & MBOX_HDR_CLIENT_MSK) >> MBOX_HDR_CLIENT_LSB) + +/* Response error list */ +typedef enum { + /* CMD completed succesfully, but check resp ARGS for any errors */ + MBOX_RESP_STATOK = 0, + /* CMD is incorrectly formatted in some way */ + MBOX_RESP_INVALID_COMMAND = 1, + /* BootROM Command code not undesrtood */ + MBOX_RESP_UNKNOWN_BR = 2, + /* CMD code not recognized by firmware */ + MBOX_RESP_UNKNOWN = 3, + /* Indicates that the device is not configured */ + MBOX_RESP_NOT_CONFIGURED = 256, + /* Indicates that the device is busy */ + MBOX_RESP_DEVICE_BUSY = 0x1FF, + /* Indicates that there is no valid response available */ + MBOX_RESP_NO_VALID_RESP_AVAILABLE = 0x2FF, + /* General Error */ + MBOX_RESP_ERROR = 0x3FF, +} ALT_SDM_MBOX_RESP_CODE; + +/* Mailbox command list */ +#define MBOX_RESTART 2 +#define MBOX_QSPI_OPEN 50 +#define MBOX_QSPI_CLOSE 51 +#define MBOX_QSPI_DIRECT 59 + +struct socfpga_mailbox { + u32 cin; /* command valid offset */ + u32 rout; /* response output offset */ + u32 urg; /* urgent command */ + u32 flags; /* interrupt enables */ + u32 pad_0x10_0x1f[4]; /* 0x10 - 0x1F reserved */ + u32 cout; /* command free offset */ + u32 rin; /* respond valid offset */ + u32 pad_0x28; /* 0x28 reserved */ + u32 status; /* mailbox status */ + u32 pad_0x30_0x3f[4]; /* 0x30 - 0x3F reserved */ + u32 cmd_buf[MBOX_CMD_BUFFER_SIZE]; /* 0x40 - 0xBC circular command + buffer to SDM */ + u32 resp_buf[MBOX_RESP_BUFFER_SIZE]; /* 0xC0 - 0xFF circular + response buffer */ +}; + +/* Use define other than put into struct socfpga_mailbox to save spaces */ +#define MBOX_DOORBELL_TO_SDM_REG (SOCFPGA_MAILBOX_ADDRESS + 0x400) +#define MBOX_DOORBELL_FROM_SDM_REG (SOCFPGA_MAILBOX_ADDRESS + 0x480) + +int mbox_init(void); + +#ifdef CONFIG_CADENCE_QSPI +int mbox_qspi_close(void); +int mbox_qspi_open(void); +#endif + +#endif /* _MAILBOX_S10_H_ */ diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c new file mode 100644 index 0000000..de836b1 --- /dev/null +++ b/arch/arm/mach-socfpga/mailbox_s10.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2017 Intel Corporation + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct socfpga_mailbox *mbox_base = + (void *)SOCFPGA_MAILBOX_ADDRESS; + +#define MBOX_POLL_RESP_TIMEOUT 50 /* ms */ + +static int mbox_polling_resp(u32 rout) +{ + u32 rin; + unsigned long start = get_timer(0); + + while (1) { + rin = readl(&mbox_base->rin); + if (rout != rin) + return 0; + + if (get_timer(start) > MBOX_POLL_RESP_TIMEOUT) + break; + + udelay(1); + } + + debug("mailbox: polling response timeout\n"); + return -ETIMEDOUT; +} + +/* Check for available slot and write to circular buffer. + * It also update command valid offset (cin) register. + */ +static int mbox_fill_cmd_circular_buff(u32 header, u32 len, u32 *arg) +{ + u32 cmd_free_offset; + u32 i; + + /* checking available command free slot */ + cmd_free_offset = readl(&mbox_base->cout); + if (cmd_free_offset >= MBOX_CMD_BUFFER_SIZE) { + error("ERROR: Not enough space, cout %d\n", cmd_free_offset); + return -ENOMEM; + } + + /* write header to circular buffer */ + writel(header, &mbox_base->cmd_buf[cmd_free_offset++]); + /* wrapping around when it reach the buffer size */ + cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; + + /* write arguments */ + for (i = 0; i < len; i++) { + writel(arg[i], &mbox_base->cmd_buf[cmd_free_offset++]); + /* wrapping around when it reach the buffer size */ + cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; + } + + /* write command valid offset */ + writel(cmd_free_offset, &mbox_base->cin); + return 0; +} + +/* Support one command and up to 31 words argument length only */ +int mbox_send_cmd(u8 id, u32 cmd, u32 len, u32 *arg, u8 urgent, + u32 *resp_buf_len, u32 *resp_buf) +{ + u32 header; + u32 rin; + u32 resp; + u32 rout; + u32 status; + u32 resp_len; + u32 buf_len; + int ret; + + /* Total lenght is command + argument length */ + if ((len + 1) > MBOX_CMD_BUFFER_SIZE) { + error("ERROR: command %d arguments too long, max %d\n", cmd, + MBOX_CMD_BUFFER_SIZE - 1); + return -EINVAL; + } + + if (cmd > MBOX_MAX_CMD_INDEX) { + error("ERROR: Unsupported command index %d\n", cmd); + return -EINVAL; + } + + header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_UBOOT, id , len, cmd); + + ret = mbox_fill_cmd_circular_buff(header, len, arg); + if (ret) + return ret; + + if (urgent) { + /* Send command as urgent command */ + writel(1, &mbox_base->urg); + } + + /* write doorbell */ + writel(1, MBOX_DOORBELL_TO_SDM_REG); + + while (1) { + /* Wait for doorbell from SDM */ + ret = wait_for_bit(__func__, + (const u32 *)MBOX_DOORBELL_FROM_SDM_REG, + 1, true, 500000, false); + if (ret) { + error("mailbox: timeout from SDM\n"); + return ret; + } + + /* clear interrupt */ + writel(0, MBOX_DOORBELL_FROM_SDM_REG); + + if (urgent) { + /* urgent command doesn't has response */ + writel(0, &mbox_base->urg); + status = readl(&mbox_base->status); + if (status & MBOX_STATUS_UA_MSK) + return 0; + + error("mailbox: cmd %d no urgent ACK\n", cmd); + return -1; + } + + /* read current response offset */ + rout = readl(&mbox_base->rout); + + /* read response valid offset */ + rin = readl(&mbox_base->rin); + + if (rout != rin) { + /* Response received */ + resp = readl(&mbox_base->resp_buf[rout]); + rout++; + /* wrapping around when it reach the buffer size */ + rout %= MBOX_RESP_BUFFER_SIZE; + /* update next ROUT */ + writel(rout, &mbox_base->rout); + + /* check client ID and ID */ + if ((MBOX_RESP_CLIENT_GET(resp) == + MBOX_CLIENT_ID_UBOOT) && + (MBOX_RESP_ID_GET(resp) == id)) { + ret = MBOX_RESP_ERR_GET(resp); + if (ret) { + error("mailbox send command %d error %d\n", + cmd, ret); + return ret; + } + + if (resp_buf_len) { + buf_len = *resp_buf_len; + *resp_buf_len = 0; + } else { + buf_len = 0; + } + + resp_len = MBOX_RESP_LEN_GET(resp); + while (resp_len) { + ret = mbox_polling_resp(rout); + if (ret) + return ret; + /* we need to process response buffer + even caller doesn't need it */ + resp = readl(&mbox_base->resp_buf[rout]); + rout++; + resp_len--; + rout %= MBOX_RESP_BUFFER_SIZE; + writel(rout, &mbox_base->rout); + if (buf_len) { + /* copy response to buffer */ + resp_buf[*resp_buf_len] = resp; + (*resp_buf_len)++; + buf_len--; + } + } + return ret; + } + } + }; + + return -EIO; +} + +int mbox_init(void) +{ + int ret; + + /* enable mailbox interrupts */ + writel(MBOX_ALL_INTRS, &mbox_base->flags); + + ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RESTART, 0, NULL, 1, 0, NULL); + if (ret) + return ret; + + /* Renable mailbox interrupts after MBOX_RESTART */ + writel(MBOX_ALL_INTRS, &mbox_base->flags); + + return 0; +} + +#ifdef CONFIG_CADENCE_QSPI +int mbox_qspi_close(void) +{ + return mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_CLOSE, 0, NULL, 0, 0, + NULL); +} + +int mbox_qspi_open(void) +{ + int ret; + + ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_OPEN, 0, NULL, 0, 0, NULL); + if (ret) + return ret; + + ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_QSPI_DIRECT, 0, NULL, 0, 0, + NULL); + if (ret) + goto error; + + return ret; + +error: + mbox_qspi_close(); + + return ret; +} +#endif /* CONFIG_CADENCE_QSPI */