aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/fpga/intel_sdm_mb.c139
-rw-r--r--drivers/mmc/ca_dw_mmc.c4
-rw-r--r--drivers/mmc/dw_mmc.c9
-rw-r--r--drivers/mmc/exynos_dw_mmc.c4
-rw-r--r--drivers/mmc/nexell_dw_mmc.c4
-rw-r--r--drivers/mmc/socfpga_dw_mmc.c18
-rw-r--r--drivers/net/dwmac_socfpga.c37
7 files changed, 203 insertions, 12 deletions
diff --git a/drivers/fpga/intel_sdm_mb.c b/drivers/fpga/intel_sdm_mb.c
index 9a1dc2c..f5fd9a1 100644
--- a/drivers/fpga/intel_sdm_mb.c
+++ b/drivers/fpga/intel_sdm_mb.c
@@ -8,11 +8,149 @@
#include <log.h>
#include <watchdog.h>
#include <asm/arch/mailbox_s10.h>
+#include <asm/arch/smc_api.h>
#include <linux/delay.h>
+#include <linux/intel-smc.h>
#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000
#define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
+
+#define BITSTREAM_CHUNK_SIZE 0xFFFF0
+#define RECONFIG_STATUS_POLL_RETRY_MAX 100
+
+/*
+ * Polling the FPGA configuration status.
+ * Return 0 for success, non-zero for error.
+ */
+static int reconfig_status_polling_resp(void)
+{
+ int ret;
+ unsigned long start = get_timer(0);
+
+ while (1) {
+ ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE, NULL, 0,
+ NULL, 0);
+
+ if (!ret)
+ return 0; /* configuration success */
+
+ if (ret != INTEL_SIP_SMC_STATUS_BUSY)
+ return ret;
+
+ if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
+ return -ETIMEDOUT; /* time out */
+
+ puts(".");
+ udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+ WATCHDOG_RESET();
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int send_bitstream(const void *rbf_data, size_t rbf_size)
+{
+ int i;
+ u64 res_buf[3];
+ u64 args[2];
+ u32 xfer_count = 0;
+ int ret, wr_ret = 0, retry = 0;
+ size_t buf_size = (rbf_size > BITSTREAM_CHUNK_SIZE) ?
+ BITSTREAM_CHUNK_SIZE : rbf_size;
+
+ while (rbf_size || xfer_count) {
+ if (!wr_ret && rbf_size) {
+ args[0] = (u64)rbf_data;
+ args[1] = buf_size;
+ wr_ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_WRITE,
+ args, 2, NULL, 0);
+
+ debug("wr_ret = %d, rbf_data = %p, buf_size = %08lx\n",
+ wr_ret, rbf_data, buf_size);
+
+ if (wr_ret)
+ continue;
+
+ rbf_size -= buf_size;
+ rbf_data += buf_size;
+
+ if (buf_size >= rbf_size)
+ buf_size = rbf_size;
+
+ xfer_count++;
+ puts(".");
+ } else {
+ ret = invoke_smc(
+ INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
+ NULL, 0, res_buf, ARRAY_SIZE(res_buf));
+ if (!ret) {
+ for (i = 0; i < ARRAY_SIZE(res_buf); i++) {
+ if (!res_buf[i])
+ break;
+ xfer_count--;
+ wr_ret = 0;
+ retry = 0;
+ }
+ } else if (ret !=
+ INTEL_SIP_SMC_STATUS_BUSY)
+ return ret;
+ else if (!xfer_count)
+ return INTEL_SIP_SMC_STATUS_ERROR;
+
+ if (++retry >= RECONFIG_STATUS_POLL_RETRY_MAX)
+ return -ETIMEDOUT;
+
+ udelay(20000);
+ }
+ WATCHDOG_RESET();
+ }
+
+ return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+ int ret;
+ u64 arg = 1;
+
+ debug("Invoking FPGA_CONFIG_START...\n");
+
+ ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, &arg, 1, NULL, 0);
+
+ if (ret) {
+ puts("Failure in RECONFIG mailbox command!\n");
+ return ret;
+ }
+
+ ret = send_bitstream(rbf_data, rbf_size);
+ if (ret) {
+ puts("Error sending bitstream!\n");
+ return ret;
+ }
+
+ /* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
+ udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+
+ debug("Polling with MBOX_RECONFIG_STATUS...\n");
+ ret = reconfig_status_polling_resp();
+ if (ret) {
+ puts("FPGA reconfiguration failed!");
+ return ret;
+ }
+
+ puts("FPGA reconfiguration OK!\n");
+
+ return ret;
+}
+
+#else
+
static const struct mbox_cfgstat_state {
int err_no;
const char *error_name;
@@ -286,3 +424,4 @@ int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
return ret;
}
+#endif
diff --git a/drivers/mmc/ca_dw_mmc.c b/drivers/mmc/ca_dw_mmc.c
index fad2ff5..2b79356 100644
--- a/drivers/mmc/ca_dw_mmc.c
+++ b/drivers/mmc/ca_dw_mmc.c
@@ -40,7 +40,7 @@ struct ca_dwmmc_priv_data {
u8 ds;
};
-static void ca_dwmci_clksel(struct dwmci_host *host)
+static int ca_dwmci_clksel(struct dwmci_host *host)
{
struct ca_dwmmc_priv_data *priv = host->priv;
u32 val = readl(priv->sd_dll_reg);
@@ -52,6 +52,8 @@ static void ca_dwmci_clksel(struct dwmci_host *host)
val |= SD_CLK_SEL_100MHZ;
writel(val, priv->sd_dll_reg);
+
+ return 0;
}
static void ca_dwmci_board_init(struct dwmci_host *host)
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 7702f4b..7c8a312 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -496,8 +496,13 @@ static int dwmci_set_ios(struct mmc *mmc)
dwmci_writel(host, DWMCI_UHS_REG, regs);
- if (host->clksel)
- host->clksel(host);
+ if (host->clksel) {
+ int ret;
+
+ ret = host->clksel(host);
+ if (ret)
+ return ret;
+ }
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (mmc->vqmmc_supply) {
diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 3aa9fb3..2fc1ef1 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -44,7 +44,7 @@ struct dwmci_exynos_priv_data {
* Function used as callback function to initialise the
* CLKSEL register for every mmc channel.
*/
-static void exynos_dwmci_clksel(struct dwmci_host *host)
+static int exynos_dwmci_clksel(struct dwmci_host *host)
{
#ifdef CONFIG_DM_MMC
struct dwmci_exynos_priv_data *priv =
@@ -53,6 +53,8 @@ static void exynos_dwmci_clksel(struct dwmci_host *host)
struct dwmci_exynos_priv_data *priv = host->priv;
#endif
dwmci_writel(host, DWMCI_CLKSEL, priv->sdr_timing);
+
+ return 0;
}
unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
diff --git a/drivers/mmc/nexell_dw_mmc.c b/drivers/mmc/nexell_dw_mmc.c
index 753c89d..2723e48 100644
--- a/drivers/mmc/nexell_dw_mmc.c
+++ b/drivers/mmc/nexell_dw_mmc.c
@@ -51,7 +51,7 @@ struct nexell_dwmmc_priv {
struct clk *clk_get(const char *id);
-static void nx_dw_mmc_clksel(struct dwmci_host *host)
+static int nx_dw_mmc_clksel(struct dwmci_host *host)
{
/* host->priv is pointer to "struct udevice" */
struct nexell_dwmmc_priv *priv = dev_get_priv(host->priv);
@@ -65,6 +65,8 @@ static void nx_dw_mmc_clksel(struct dwmci_host *host)
DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3);
dwmci_writel(host, DWMCI_CLKSEL, val);
+
+ return 0;
}
static void nx_dw_mmc_reset(int ch)
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index dc008c5..aa0d3a2 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <log.h>
#include <asm/arch/clock_manager.h>
+#include <asm/arch/secure_reg_helper.h>
#include <asm/arch/system_manager.h>
#include <clk.h>
#include <dm.h>
@@ -13,6 +14,7 @@
#include <errno.h>
#include <fdtdec.h>
#include <dm/device_compat.h>
+#include <linux/intel-smc.h>
#include <linux/libfdt.h>
#include <linux/err.h>
#include <malloc.h>
@@ -46,7 +48,7 @@ static void socfpga_dwmci_reset(struct udevice *dev)
reset_deassert_bulk(&reset_bulk);
}
-static void socfpga_dwmci_clksel(struct dwmci_host *host)
+static int socfpga_dwmci_clksel(struct dwmci_host *host)
{
struct dwmci_socfpga_priv_data *priv = host->priv;
u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) |
@@ -58,14 +60,28 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host)
debug("%s: drvsel %d smplsel %d\n", __func__,
priv->drvsel, priv->smplsel);
+
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
+ int ret;
+
+ ret = socfpga_secure_reg_write32(SOCFPGA_SECURE_REG_SYSMGR_SOC64_SDMMC,
+ sdmmc_mask);
+ if (ret) {
+ printf("DWMMC: Failed to set clksel via SMC call");
+ return ret;
+ }
+#else
writel(sdmmc_mask, socfpga_get_sysmgr_addr() + SYSMGR_SDMMC);
debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__,
readl(socfpga_get_sysmgr_addr() + SYSMGR_SDMMC));
+#endif
/* Enable SDMMC clock */
setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN,
CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK);
+
+ return 0;
}
static int socfpga_dwmmc_get_clk_rate(struct udevice *dev)
diff --git a/drivers/net/dwmac_socfpga.c b/drivers/net/dwmac_socfpga.c
index 939f199..82fdff5 100644
--- a/drivers/net/dwmac_socfpga.c
+++ b/drivers/net/dwmac_socfpga.c
@@ -6,6 +6,8 @@
*/
#include <common.h>
+#include <asm/arch/secure_reg_helper.h>
+#include <asm/arch/system_manager.h>
#include <asm/io.h>
#include <dm.h>
#include <clk.h>
@@ -17,8 +19,6 @@
#include <dm/device_compat.h>
#include <linux/err.h>
-#include <asm/arch/system_manager.h>
-
struct dwmac_socfpga_plat {
struct dw_eth_pdata dw_eth_pdata;
void *phy_intf;
@@ -64,6 +64,32 @@ static int dwmac_socfpga_of_to_plat(struct udevice *dev)
return designware_eth_of_to_plat(dev);
}
+static int dwmac_socfpga_do_setphy(struct udevice *dev, u32 modereg)
+{
+ struct dwmac_socfpga_plat *pdata = dev_get_plat(dev);
+ u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift;
+
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
+ u32 index = ((u64)pdata->phy_intf - socfpga_get_sysmgr_addr() -
+ SYSMGR_SOC64_EMAC0) >> 2;
+
+ u32 id = SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 + index;
+
+ int ret = socfpga_secure_reg_update32(id,
+ modemask,
+ modereg << pdata->reg_shift);
+ if (ret) {
+ dev_err(dev, "Failed to set PHY register via SMC call\n");
+ return ret;
+ }
+#else
+ clrsetbits_le32(pdata->phy_intf, modemask,
+ modereg << pdata->reg_shift);
+#endif
+
+ return 0;
+}
+
static int dwmac_socfpga_probe(struct udevice *dev)
{
struct dwmac_socfpga_plat *pdata = dev_get_plat(dev);
@@ -71,7 +97,6 @@ static int dwmac_socfpga_probe(struct udevice *dev)
struct reset_ctl_bulk reset_bulk;
int ret;
u32 modereg;
- u32 modemask;
switch (edata->phy_interface) {
case PHY_INTERFACE_MODE_MII:
@@ -97,9 +122,9 @@ static int dwmac_socfpga_probe(struct udevice *dev)
reset_assert_bulk(&reset_bulk);
- modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift;
- clrsetbits_le32(pdata->phy_intf, modemask,
- modereg << pdata->reg_shift);
+ ret = dwmac_socfpga_do_setphy(dev, modereg);
+ if (ret)
+ return ret;
reset_release_bulk(&reset_bulk);