aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/ti/clk-k3-pll.c81
-rw-r--r--drivers/crypto/fsl/Kconfig1
-rw-r--r--drivers/firmware/arm-ffa/arm-ffa-uclass.c2
-rw-r--r--drivers/memory/Kconfig1
-rw-r--r--drivers/misc/Kconfig1
-rw-r--r--drivers/misc/i2c_eeprom.c13
-rw-r--r--drivers/misc/k3_avs.c104
-rw-r--r--drivers/misc/vexpress_config.c5
-rw-r--r--drivers/mmc/Kconfig7
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/pci_mmc.c4
-rw-r--r--drivers/mmc/renesas-sdhi.c4
-rw-r--r--drivers/mmc/sdhci.c19
-rw-r--r--drivers/mmc/sh_sdhi.c910
-rw-r--r--drivers/mmc/tmio-common.c8
-rw-r--r--drivers/mtd/nand/raw/Kconfig1
-rw-r--r--drivers/mtd/spi/Kconfig2
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c1
-rw-r--r--drivers/sm/Kconfig1
-rw-r--r--drivers/spi/Kconfig10
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/meson_spifc_a1.c383
-rw-r--r--drivers/tpm/tpm2_tis_sandbox.c100
-rw-r--r--drivers/usb/host/Kconfig2
24 files changed, 684 insertions, 978 deletions
diff --git a/drivers/clk/ti/clk-k3-pll.c b/drivers/clk/ti/clk-k3-pll.c
index bf762c558e..c1158c1329 100644
--- a/drivers/clk/ti/clk-k3-pll.c
+++ b/drivers/clk/ti/clk-k3-pll.c
@@ -25,6 +25,23 @@
#define PLL_16FFT_FREQ_CTRL0 0x30
#define PLL_16FFT_FREQ_CTRL1 0x34
#define PLL_16FFT_DIV_CTRL 0x38
+#define PLL_16FFT_CAL_CTRL 0x60
+#define PLL_16FFT_CAL_STAT 0x64
+
+/* CAL STAT register bits */
+#define PLL_16FFT_CAL_STAT_CAL_LOCK BIT(31)
+
+/* CFG register bits */
+#define PLL_16FFT_CFG_PLL_TYPE_SHIFT (0)
+#define PLL_16FFT_CFG_PLL_TYPE_MASK (0x3 << 0)
+#define PLL_16FFT_CFG_PLL_TYPE_FRACF 1
+
+/* CAL CTRL register bits */
+#define PLL_16FFT_CAL_CTRL_CAL_EN BIT(31)
+#define PLL_16FFT_CAL_CTRL_FAST_CAL BIT(20)
+#define PLL_16FFT_CAL_CTRL_CAL_BYP BIT(15)
+#define PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT 16
+#define PLL_16FFT_CAL_CTRL_CAL_CNT_MASK (0x7 << 16)
/* CTRL register bits */
#define PLL_16FFT_CTRL_BYPASS_EN BIT(31)
@@ -40,9 +57,14 @@
/* DIV CTRL register bits */
#define PLL_16FFT_DIV_CTRL_REF_DIV_MASK 0x3f
-#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
+/* HSDIV register bits*/
#define PLL_16FFT_HSDIV_CTRL_CLKOUT_EN BIT(15)
+/* FREQ_CTRL1 bits */
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_BITS 24
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK 0xffffff
+#define PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT 0
+
/* KICK register magic values */
#define PLL_KICK0_VALUE 0x68ef3490
#define PLL_KICK1_VALUE 0xd172bc5a
@@ -63,18 +85,65 @@ static int ti_pll_wait_for_lock(struct clk *clk)
{
struct ti_pll_clk *pll = to_clk_pll(clk);
u32 stat;
+ u32 cfg;
+ u32 cal;
+ u32 freq_ctrl1;
int i;
+ u32 pllfm;
+ u32 pll_type;
+ int success;
for (i = 0; i < 100000; i++) {
stat = readl(pll->reg + PLL_16FFT_STAT);
- if (stat & PLL_16FFT_STAT_LOCK)
- return 0;
+ if (stat & PLL_16FFT_STAT_LOCK) {
+ success = 1;
+ break;
+ }
}
- printf("%s: pll (%s) failed to lock\n", __func__,
- clk->dev->name);
+ /* Enable calibration if not in fractional mode of the FRACF PLL */
+ freq_ctrl1 = readl(pll->reg + PLL_16FFT_FREQ_CTRL1);
+ pllfm = freq_ctrl1 & PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_MASK;
+ pllfm >>= PLL_16FFT_FREQ_CTRL1_FB_DIV_FRAC_SHIFT;
+ cfg = readl(pll->reg + PLL_16FFT_CFG);
+ pll_type = (cfg & PLL_16FFT_CFG_PLL_TYPE_MASK) >> PLL_16FFT_CFG_PLL_TYPE_SHIFT;
+
+ if (success && pll_type == PLL_16FFT_CFG_PLL_TYPE_FRACF && pllfm == 0) {
+ cal = readl(pll->reg + PLL_16FFT_CAL_CTRL);
- return -EBUSY;
+ /* Enable calibration for FRACF */
+ cal |= PLL_16FFT_CAL_CTRL_CAL_EN;
+
+ /* Enable fast cal mode */
+ cal |= PLL_16FFT_CAL_CTRL_FAST_CAL;
+
+ /* Disable calibration bypass */
+ cal &= ~PLL_16FFT_CAL_CTRL_CAL_BYP;
+
+ /* Set CALCNT to 2 */
+ cal &= ~PLL_16FFT_CAL_CTRL_CAL_CNT_MASK;
+ cal |= 2 << PLL_16FFT_CAL_CTRL_CAL_CNT_SHIFT;
+
+ /* Note this register does not readback the written value. */
+ writel(cal, pll->reg + PLL_16FFT_CAL_CTRL);
+
+ success = 0;
+ for (i = 0; i < 100000; i++) {
+ stat = readl(pll->reg + PLL_16FFT_CAL_STAT);
+ if (stat & PLL_16FFT_CAL_STAT_CAL_LOCK) {
+ success = 1;
+ break;
+ }
+ }
+ }
+
+ if (success == 0) {
+ printf("%s: pll (%s) failed to lock\n", __func__,
+ clk->dev->name);
+ return -EBUSY;
+ } else {
+ return 0;
+ }
}
static ulong ti_pll_clk_get_rate(struct clk *clk)
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index 91a51cc5fe..eaad19633f 100644
--- a/drivers/crypto/fsl/Kconfig
+++ b/drivers/crypto/fsl/Kconfig
@@ -77,7 +77,6 @@ endif
config FSL_DCP_RNG
bool "Enable Random Number Generator support"
depends on DM_RNG
- default n
help
Enable support for the hardware based random number generator
module of the DCP. It uses the True Random Number Generator (TRNG)
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 8c17b19eaf..f1e91d151e 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -144,8 +144,6 @@ static int ffa_print_error_log(u32 ffa_id, int ffa_errno)
return -EINVAL;
abi_idx = FFA_ID_TO_ERRMAP_ID(ffa_id);
- if (abi_idx < 0 || abi_idx >= FFA_ERRMAP_COUNT)
- return -EINVAL;
if (!err_msg_map[abi_idx].err_str[err_idx])
return -EINVAL;
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 22cb9d637c..d10edd2774 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -61,7 +61,6 @@ config TI_GPMC
if TI_GPMC
config TI_GPMC_DEBUG
bool "Debug Texas Instruments GPMC timings"
- default n
help
Enable this to print GPMC timings before and after the GPMC registers
are programmed. This should not be left enabled on production systems.
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index fccd9b89b8..97057de8bf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -375,7 +375,6 @@ config SPL_MXC_OCOTP
config NPCM_OTP
bool "Nnvoton NPCM BMC On-Chip OTP Memory Support"
depends on (ARM && ARCH_NPCM)
- default n
help
Support NPCM BMC OTP memory (fuse).
To compile this driver as a module, choose M here: the module
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index e1d0b8f918..9111bd724c 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -60,6 +60,17 @@ static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
return dm_i2c_read(dev, offset, buf, size);
}
+static int i2c_eeprom_len(int offset, int len, int pagesize)
+{
+ int page_offset = offset & (pagesize - 1);
+ int maxlen = pagesize - page_offset;
+
+ if (len > maxlen)
+ len = maxlen;
+
+ return len;
+}
+
static int i2c_eeprom_std_write(struct udevice *dev, int offset,
const uint8_t *buf, int size)
{
@@ -67,7 +78,7 @@ static int i2c_eeprom_std_write(struct udevice *dev, int offset,
int ret;
while (size > 0) {
- int write_size = min_t(int, size, priv->pagesize);
+ int write_size = i2c_eeprom_len(offset, size, priv->pagesize);
ret = dm_i2c_write(dev, offset, buf, write_size);
if (ret)
diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c
index acfc731845..9a088244dd 100644
--- a/drivers/misc/k3_avs.c
+++ b/drivers/misc/k3_avs.c
@@ -15,6 +15,7 @@
#include <k3-avs.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <power/regulator.h>
#define AM6_VTM_DEVINFO(i) (priv->base + 0x100 + 0x20 * (i))
@@ -25,11 +26,28 @@
#define AM6_VTM_OPP_SHIFT(opp) (8 * (opp))
#define AM6_VTM_OPP_MASK 0xff
+#define K3_VTM_DEVINFO_PWR0_OFFSET 0x4
+#define K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK 0xf0
+#define K3_VTM_TMPSENS0_CTRL_OFFSET 0x300
+#define K3_VTM_TMPSENS_STAT_OFFSET 0x8
+#define K3_VTM_ANYMAXT_OUTRG_ALERT_EN 0x1
+#define K3_VTM_LOW_TEMP_OFFSET 0x10
+#define K3_VTM_MISC_CTRL2_OFFSET 0x10
+#define K3_VTM_MISC_CTRL1_OFFSET 0xc
+#define K3_VTM_TMPSENS_CTRL1_SOC BIT(5)
+#define K3_VTM_TMPSENS_CTRL_CLRZ BIT(6)
+#define K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN BIT(11)
+#define K3_VTM_ADC_COUNT_FOR_123C 0x2f8
+#define K3_VTM_ADC_COUNT_FOR_105C 0x288
+#define K3_VTM_ADC_WA_VALUE 0x2c
+#define K3_VTM_FUSE_MASK 0xc0000000
+
#define VD_FLAG_INIT_DONE BIT(0)
struct k3_avs_privdata {
void *base;
struct vd_config *vd_config;
+ struct udevice *dev;
};
struct opp {
@@ -237,6 +255,88 @@ static int k3_avs_configure(struct udevice *dev, struct k3_avs_privdata *priv)
return 0;
}
+/* k3_avs_program_tshut : Program thermal shutdown value for SOC
+ * set the values corresponding to thresholds to ~123C and 105C
+ * This is optional feature, Few times OS driver takes care of
+ * tshut programing.
+ */
+
+static void k3_avs_program_tshut(struct k3_avs_privdata *priv)
+{
+ int cnt, id, val;
+ int workaround_needed = 0;
+ u32 ctrl_offset;
+ void __iomem *cfg2_base;
+ void __iomem *fuse_base;
+
+ cfg2_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 1);
+ if (IS_ERR(cfg2_base)) {
+ dev_err(priv->dev, "cfg base is not defined\n");
+ return;
+ }
+
+ /*
+ * Some of TI's J721E SoCs require a software trimming procedure
+ * for the temperature monitors to function properly. To determine
+ * if this particular SoC is NOT affected, both bits in the
+ * WKUP_SPARE_FUSE0[31:30] will be set (0xC0000000) indicating
+ * when software trimming should NOT be applied.
+ *
+ * https://www.ti.com/lit/er/sprz455c/sprz455c.pdf
+ * This routine checks if workaround_needed to be applied or not
+ * based upon workaround_needed, adjust fixed value of tshut high and low
+ */
+
+ if (device_is_compatible(priv->dev, "ti,j721e-vtm")) {
+ fuse_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 2);
+ if (IS_ERR(fuse_base)) {
+ dev_err(priv->dev, "fuse-base is not defined for J721E Soc\n");
+ return;
+ }
+
+ if (!((readl(fuse_base) & K3_VTM_FUSE_MASK) == K3_VTM_FUSE_MASK))
+ workaround_needed = 1;
+ }
+
+ dev_dbg(priv->dev, "Work around %sneeded\n", workaround_needed ? "" : "not ");
+
+ /* Get the sensor count in the VTM */
+ val = readl(priv->base + K3_VTM_DEVINFO_PWR0_OFFSET);
+ cnt = val & K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK;
+ cnt >>= __ffs(K3_VTM_DEVINFO_PWR0_TEMPSENS_CT_MASK);
+
+ /* Program the thermal sensors */
+ for (id = 0; id < cnt; id++) {
+ ctrl_offset = K3_VTM_TMPSENS0_CTRL_OFFSET + id * 0x20;
+
+ val = readl(cfg2_base + ctrl_offset);
+ val |= (K3_VTM_TMPSENS_CTRL_MAXT_OUTRG_EN |
+ K3_VTM_TMPSENS_CTRL1_SOC |
+ K3_VTM_TMPSENS_CTRL_CLRZ | BIT(4));
+ writel(val, cfg2_base + ctrl_offset);
+ }
+
+ /*
+ * Program TSHUT thresholds
+ * Step 1: set the thresholds to ~123C and 105C WKUP_VTM_MISC_CTRL2
+ * Step 2: WKUP_VTM_TMPSENS_CTRL_j set the MAXT_OUTRG_EN bit
+ * This is already taken care as per of init
+ * Step 3: WKUP_VTM_MISC_CTRL set the ANYMAXT_OUTRG_ALERT_EN bit
+ */
+
+ /* Low thresholds for tshut*/
+ val = (K3_VTM_ADC_COUNT_FOR_105C - workaround_needed * K3_VTM_ADC_WA_VALUE)
+ << K3_VTM_LOW_TEMP_OFFSET;
+ /* high thresholds */
+ val |= K3_VTM_ADC_COUNT_FOR_123C - workaround_needed * K3_VTM_ADC_WA_VALUE;
+
+ writel(val, cfg2_base + K3_VTM_MISC_CTRL2_OFFSET);
+ /* ramp-up delay from Linux code */
+ mdelay(100);
+ val = readl(cfg2_base + K3_VTM_MISC_CTRL1_OFFSET) | K3_VTM_ANYMAXT_OUTRG_ALERT_EN;
+ writel(val, cfg2_base + K3_VTM_MISC_CTRL1_OFFSET);
+}
+
/**
* k3_avs_probe: parses VD info from VTM, and re-configures the OPP data
*
@@ -255,6 +355,7 @@ static int k3_avs_probe(struct udevice *dev)
int ret;
priv = dev_get_priv(dev);
+ priv->dev = dev;
k3_avs_priv = priv;
@@ -294,6 +395,9 @@ static int k3_avs_probe(struct udevice *dev)
k3_avs_program_voltage(priv, vd, vd->opp);
}
+ if (!device_is_compatible(priv->dev, "ti,am654-avs"))
+ k3_avs_program_tshut(priv);
+
return 0;
}
diff --git a/drivers/misc/vexpress_config.c b/drivers/misc/vexpress_config.c
index 2baca48109..99aad1412a 100644
--- a/drivers/misc/vexpress_config.c
+++ b/drivers/misc/vexpress_config.c
@@ -92,7 +92,7 @@ static struct misc_ops vexpress_config_ops = {
static int vexpress_config_probe(struct udevice *dev)
{
struct ofnode_phandle_args args;
- struct vexpress_config_sysreg *priv;
+ struct vexpress_config_sysreg *priv = dev_get_priv(dev);
const char *prop;
int err, prop_size;
@@ -105,11 +105,9 @@ static int vexpress_config_probe(struct udevice *dev)
if (!prop || (strncmp(prop, "arm,vexpress-sysreg", 19) != 0))
return -ENOENT;
- priv = calloc(1, sizeof(*priv));
if (!priv)
return -ENOMEM;
- dev_get_uclass_priv(dev) = priv;
priv->addr = ofnode_get_addr(args.node);
return dev_read_u32(dev, "arm,vexpress,site", &priv->site);
@@ -127,4 +125,5 @@ U_BOOT_DRIVER(vexpress_config_drv) = {
.bind = dm_scan_fdt_dev,
.probe = vexpress_config_probe,
.ops = &vexpress_config_ops,
+ .priv_auto = sizeof(struct vexpress_config_sysreg),
};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index de01b9687b..17618c3bdc 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -46,6 +46,7 @@ config SPL_DM_MMC
depends on SPL_DM && DM_MMC
default n if ARCH_MVEBU && !MVEBU_SPL_BOOT_DEVICE_MMC
default y
+ select SPL_BLK
help
This enables the MultiMediaCard (MMC) uclass which supports MMC and
Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
@@ -390,12 +391,6 @@ config HSMMC2_8BIT
depends on MMC_OMAP_HS && (OMAP44XX || OMAP54XX || DRA7XX || AM33XX || \
AM43XX || ARCH_KEYSTONE)
-config SH_SDHI
- bool "SuperH/Renesas ARM SoCs on-chip SDHI host controller support"
- depends on ARCH_RMOBILE
- help
- Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform
-
config SH_MMCIF
bool "SuperH/Renesas ARM SoCs on-chip MMCIF host controller support"
depends on ARCH_RMOBILE || SH
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 2c65c4765a..e9cf1fcc64 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -49,7 +49,6 @@ obj-$(CONFIG_MMC_PCI) += pci_mmc.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
-obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc.o
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index 9fb7044029..4d163ccba0 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -50,8 +50,8 @@ static int pci_mmc_probe(struct udevice *dev)
desc = mmc_get_blk_desc(&plat->mmc);
desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE);
- host->ioaddr = (void *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE,
- PCI_REGION_MEM);
+ host->ioaddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
+ PCI_REGION_TYPE, PCI_REGION_MEM);
host->name = dev->name;
host->cd_gpio = priv->cd_gpio;
host->mmc = &plat->mmc;
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 1ea6e1066f..865efdd321 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -998,7 +998,7 @@ static int rzg2l_sdhi_setup(struct udevice *dev)
ret = reset_get_by_index(dev, 0, &rst);
if (ret < 0) {
dev_err(dev, "failed to get reset line\n");
- goto err_reset;
+ goto err_get_reset;
}
ret = reset_deassert(&rst);
@@ -1016,6 +1016,8 @@ static int rzg2l_sdhi_setup(struct udevice *dev)
err_tmio_probe:
reset_assert(&rst);
err_reset:
+ reset_free(&rst);
+err_get_reset:
clk_disable(&aclk);
err_aclk:
clk_disable(&imclk2);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index fc9c6c3799..0178ed8a11 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -306,14 +306,19 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (stat & SDHCI_INT_ERROR)
break;
- if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_R1B &&
+ cmd->resp_type & MMC_RSP_BUSY && !data) {
+ unsigned int state =
+ sdhci_readl(host, SDHCI_PRESENT_STATE);
+
+ if (!(state & SDHCI_DAT_ACTIVE))
return 0;
- } else {
- printf("%s: Timeout for status update!\n",
- __func__);
- return -ETIMEDOUT;
- }
+ }
+
+ if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
+ printf("%s: Timeout for status update: %08x %08x\n",
+ __func__, stat, mask);
+ return -ETIMEDOUT;
}
} while ((stat & mask) != mask);
diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c
deleted file mode 100644
index 3ce7cbf71f..0000000000
--- a/drivers/mmc/sh_sdhi.c
+++ /dev/null
@@ -1,910 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * drivers/mmc/sh_sdhi.c
- *
- * SD/MMC driver for Renesas rmobile ARM SoCs.
- *
- * Copyright (C) 2011,2013-2017 Renesas Electronics Corporation
- * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
- * Copyright (C) 2008-2009 Renesas Solutions Corp.
- */
-
-#include <common.h>
-#include <log.h>
-#include <malloc.h>
-#include <mmc.h>
-#include <dm.h>
-#include <part.h>
-#include <dm/device_compat.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/compat.h>
-#include <linux/io.h>
-#include <linux/sizes.h>
-#include <asm/arch/rmobile.h>
-#include <asm/arch/sh_sdhi.h>
-#include <asm/global_data.h>
-#include <clk.h>
-
-#define DRIVER_NAME "sh-sdhi"
-
-struct sh_sdhi_host {
- void __iomem *addr;
- int ch;
- int bus_shift;
- unsigned long quirks;
- unsigned char wait_int;
- unsigned char sd_error;
- unsigned char detect_waiting;
- unsigned char app_cmd;
-};
-
-static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
-{
- writeq(val, host->addr + (reg << host->bus_shift));
-}
-
-static inline u64 sh_sdhi_readq(struct sh_sdhi_host *host, int reg)
-{
- return readq(host->addr + (reg << host->bus_shift));
-}
-
-static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
-{
- writew(val, host->addr + (reg << host->bus_shift));
-}
-
-static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
-{
- return readw(host->addr + (reg << host->bus_shift));
-}
-
-static void sh_sdhi_detect(struct sh_sdhi_host *host)
-{
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
-
- host->detect_waiting = 0;
-}
-
-static int sh_sdhi_intr(void *dev_id)
-{
- struct sh_sdhi_host *host = dev_id;
- int state1 = 0, state2 = 0;
-
- state1 = sh_sdhi_readw(host, SDHI_INFO1);
- state2 = sh_sdhi_readw(host, SDHI_INFO2);
-
- debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
-
- /* CARD Insert */
- if (state1 & INFO1_CARD_IN) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
- if (!host->detect_waiting) {
- host->detect_waiting = 1;
- sh_sdhi_detect(host);
- }
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_IN |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return -EAGAIN;
- }
- /* CARD Removal */
- if (state1 & INFO1_CARD_RE) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
- if (!host->detect_waiting) {
- host->detect_waiting = 1;
- sh_sdhi_detect(host);
- }
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_RE |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
- sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
- return -EAGAIN;
- }
-
- if (state2 & INFO2_ALL_ERR) {
- sh_sdhi_writew(host, SDHI_INFO2,
- (unsigned short)~(INFO2_ALL_ERR));
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2M_ALL_ERR |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->sd_error = 1;
- host->wait_int = 1;
- return 0;
- }
- /* Respons End */
- if (state1 & INFO1_RESP_END) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_RESP_END |
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* SD_BUF Read Enable */
- if (state2 & INFO2_BRE_ENABLE) {
- sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* SD_BUF Write Enable */
- if (state2 & INFO2_BWE_ENABLE) {
- sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- host->wait_int = 1;
- return 0;
- }
- /* Access End */
- if (state1 & INFO1_ACCESS_END) {
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1_ACCESS_END |
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- host->wait_int = 1;
- return 0;
- }
- return -EAGAIN;
-}
-
-static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
-{
- int timeout = 10000000;
-
- while (1) {
- timeout--;
- if (timeout < 0) {
- debug(DRIVER_NAME": %s timeout\n", __func__);
- return 0;
- }
-
- if (!sh_sdhi_intr(host))
- break;
-
- udelay(1); /* 1 usec */
- }
-
- return 1; /* Return value: NOT 0 = complete waiting */
-}
-
-static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
-{
- u32 clkdiv, i, timeout;
-
- if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
- printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
- return -EBUSY;
- }
-
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
-
- if (clk == 0)
- return -EIO;
-
- clkdiv = 0x80;
- i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
- for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
- i <<= 1;
-
- sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
-
- timeout = 100000;
- /* Waiting for SD Bus busy to be cleared */
- while (timeout--) {
- if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
- break;
- }
-
- if (timeout)
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
- else
- return -EBUSY;
-
- return 0;
-}
-
-static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
-{
- u32 timeout;
- sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
- sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
- sh_sdhi_writew(host, SDHI_CLK_CTRL,
- CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
-
- timeout = 100000;
- while (timeout--) {
- if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
- break;
- udelay(100);
- }
-
- if (!timeout)
- return -EBUSY;
-
- if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
-
- return 0;
-}
-
-static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
-{
- unsigned short e_state1, e_state2;
- int ret;
-
- host->sd_error = 0;
- host->wait_int = 0;
-
- e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
- e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
- if (e_state2 & ERR_STS2_SYS_ERROR) {
- if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
- ret = -ETIMEDOUT;
- else
- ret = -EILSEQ;
- debug("%s: ERR_STS2 = %04x\n",
- DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
- sh_sdhi_sync_reset(host);
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return ret;
- }
- if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
- ret = -EILSEQ;
- else
- ret = -ETIMEDOUT;
-
- debug("%s: ERR_STS1 = %04x\n",
- DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
- sh_sdhi_sync_reset(host);
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
- return ret;
-}
-
-static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i;
- unsigned short *p = (unsigned short *)data->dest;
- u64 *q = (u64 *)data->dest;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- *q++ = sh_sdhi_readq(host, SDHI_BUF0);
- else
- for (i = 0; i < blocksize / 2; i++)
- *p++ = sh_sdhi_readw(host, SDHI_BUF0);
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- return 0;
-}
-
-static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i, sec;
- unsigned short *p = (unsigned short *)data->dest;
- u64 *q = (u64 *)data->dest;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- for (sec = 0; sec < data->blocks; sec++) {
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- *q++ = sh_sdhi_readq(host, SDHI_BUF0);
- else
- for (i = 0; i < blocksize / 2; i++)
- *p++ = sh_sdhi_readw(host, SDHI_BUF0);
- }
-
- return 0;
-}
-
-static int sh_sdhi_single_write(struct sh_sdhi_host *host,
- struct mmc_data *data)
-{
- long time;
- unsigned short blocksize, i;
- const unsigned short *p = (const unsigned short *)data->src;
- const u64 *q = (const u64 *)data->src;
-
- if ((unsigned long)p & 0x00000001) {
- debug(DRIVER_NAME": %s: The data pointer is unaligned.",
- __func__);
- return -EIO;
- }
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- sh_sdhi_writeq(host, SDHI_BUF0, *q++);
- else
- for (i = 0; i < blocksize / 2; i++)
- sh_sdhi_writew(host, SDHI_BUF0, *p++);
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- return 0;
-}
-
-static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
-{
- long time;
- unsigned short i, sec, blocksize;
- const unsigned short *p = (const unsigned short *)data->src;
- const u64 *q = (const u64 *)data->src;
-
- debug("%s: blocks = %d, blocksize = %d\n",
- __func__, data->blocks, data->blocksize);
-
- host->wait_int = 0;
- for (sec = 0; sec < data->blocks; sec++) {
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- host->wait_int = 0;
- blocksize = sh_sdhi_readw(host, SDHI_SIZE);
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- for (i = 0; i < blocksize / 8; i++)
- sh_sdhi_writeq(host, SDHI_BUF0, *q++);
- else
- for (i = 0; i < blocksize / 2; i++)
- sh_sdhi_writew(host, SDHI_BUF0, *p++);
- }
-
- return 0;
-}
-
-static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
-{
- unsigned short i, j, cnt = 1;
- unsigned short resp[8];
-
- if (cmd->resp_type & MMC_RSP_136) {
- cnt = 4;
- resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
- resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
- resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
- resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
- resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
- resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
- resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
- resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
-
- /* SDHI REGISTER SPECIFICATION */
- for (i = 7, j = 6; i > 0; i--) {
- resp[i] = (resp[i] << 8) & 0xff00;
- resp[i] |= (resp[j--] >> 8) & 0x00ff;
- }
- resp[0] = (resp[0] << 8) & 0xff00;
- } else {
- resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
- resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
- }
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- if (cnt == 4) {
- cmd->response[0] = (resp[6] << 16) | resp[7];
- cmd->response[1] = (resp[4] << 16) | resp[5];
- cmd->response[2] = (resp[2] << 16) | resp[3];
- cmd->response[3] = (resp[0] << 16) | resp[1];
- } else {
- cmd->response[0] = (resp[0] << 16) | resp[1];
- }
-#else
- if (cnt == 4) {
- cmd->response[0] = (resp[7] << 16) | resp[6];
- cmd->response[1] = (resp[5] << 16) | resp[4];
- cmd->response[2] = (resp[3] << 16) | resp[2];
- cmd->response[3] = (resp[1] << 16) | resp[0];
- } else {
- cmd->response[0] = (resp[1] << 16) | resp[0];
- }
-#endif /* __BIG_ENDIAN_BITFIELD */
-}
-
-static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
- struct mmc_data *data, unsigned short opc)
-{
- if (host->app_cmd) {
- if (!data)
- host->app_cmd = 0;
- return opc | BIT(6);
- }
-
- switch (opc) {
- case MMC_CMD_SWITCH:
- return opc | (data ? 0x1c00 : 0x40);
- case MMC_CMD_SEND_EXT_CSD:
- return opc | (data ? 0x1c00 : 0);
- case MMC_CMD_SEND_OP_COND:
- return opc | 0x0700;
- case MMC_CMD_APP_CMD:
- host->app_cmd = 1;
- default:
- return opc;
- }
-}
-
-static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
- struct mmc_data *data, unsigned short opc)
-{
- if (host->app_cmd) {
- host->app_cmd = 0;
- switch (opc) {
- case SD_CMD_APP_SEND_SCR:
- case SD_CMD_APP_SD_STATUS:
- return sh_sdhi_single_read(host, data);
- default:
- printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
- opc);
- return -EINVAL;
- }
- } else {
- switch (opc) {
- case MMC_CMD_WRITE_MULTIPLE_BLOCK:
- return sh_sdhi_multi_write(host, data);
- case MMC_CMD_READ_MULTIPLE_BLOCK:
- return sh_sdhi_multi_read(host, data);
- case MMC_CMD_WRITE_SINGLE_BLOCK:
- return sh_sdhi_single_write(host, data);
- case MMC_CMD_READ_SINGLE_BLOCK:
- case MMC_CMD_SWITCH:
- case MMC_CMD_SEND_EXT_CSD:;
- return sh_sdhi_single_read(host, data);
- default:
- printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
- return -EINVAL;
- }
- }
-}
-
-static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
- struct mmc_data *data, struct mmc_cmd *cmd)
-{
- long time;
- unsigned short shcmd, opc = cmd->cmdidx;
- int ret = 0;
- unsigned long timeout;
-
- debug("opc = %d, arg = %x, resp_type = %x\n",
- opc, cmd->cmdarg, cmd->resp_type);
-
- if (opc == MMC_CMD_STOP_TRANSMISSION) {
- /* SDHI sends the STOP command automatically by STOP reg */
- sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
- sh_sdhi_readw(host, SDHI_INFO1_MASK));
-
- time = sh_sdhi_wait_interrupt_flag(host);
- if (time == 0 || host->sd_error != 0)
- return sh_sdhi_error_manage(host);
-
- sh_sdhi_get_response(host, cmd);
- return 0;
- }
-
- if (data) {
- if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
- opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
- sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
- sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
- }
- sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
- }
-
- shcmd = sh_sdhi_set_cmd(host, data, opc);
-
- /*
- * U-Boot cannot use interrupt.
- * So this flag may not be clear by timing
- */
- sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
- sh_sdhi_writew(host, SDHI_ARG0,
- (unsigned short)(cmd->cmdarg & ARG0_MASK));
- sh_sdhi_writew(host, SDHI_ARG1,
- (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
-
- timeout = 100000;
- /* Waiting for SD Bus busy to be cleared */
- while (timeout--) {
- if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
- break;
- }
-
- host->wait_int = 0;
- sh_sdhi_writew(host, SDHI_INFO1_MASK,
- ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
- sh_sdhi_writew(host, SDHI_INFO2_MASK,
- ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
- INFO2M_END_ERROR | INFO2M_TIMEOUT |
- INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
- sh_sdhi_readw(host, SDHI_INFO2_MASK));
-
- sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
- time = sh_sdhi_wait_interrupt_flag(host);
- if (!time) {
- host->app_cmd = 0;
- return sh_sdhi_error_manage(host);
- }
-
- if (host->sd_error) {
- switch (cmd->cmdidx) {
- case MMC_CMD_ALL_SEND_CID:
- case MMC_CMD_SELECT_CARD:
- case SD_CMD_SEND_IF_COND:
- case MMC_CMD_APP_CMD:
- ret = -ETIMEDOUT;
- break;
- default:
- debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
- debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
- ret = sh_sdhi_error_manage(host);
- break;
- }
- host->sd_error = 0;
- host->wait_int = 0;
- host->app_cmd = 0;
- return ret;
- }
-
- if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
- host->app_cmd = 0;
- return -EINVAL;
- }
-
- if (host->wait_int) {
- sh_sdhi_get_response(host, cmd);
- host->wait_int = 0;
- }
-
- if (data)
- ret = sh_sdhi_data_trans(host, data, opc);
-
- debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
- ret, cmd->response[0], cmd->response[1],
- cmd->response[2], cmd->response[3]);
- return ret;
-}
-
-static int sh_sdhi_send_cmd_common(struct sh_sdhi_host *host,
- struct mmc_cmd *cmd, struct mmc_data *data)
-{
- host->sd_error = 0;
-
- return sh_sdhi_start_cmd(host, data, cmd);
-}
-
-static int sh_sdhi_set_ios_common(struct sh_sdhi_host *host, struct mmc *mmc)
-{
- int ret;
-
- ret = sh_sdhi_clock_control(host, mmc->clock);
- if (ret)
- return -EINVAL;
-
- if (mmc->bus_width == 8)
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_8 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
- else if (mmc->bus_width == 4)
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_4 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
- else
- sh_sdhi_writew(host, SDHI_OPTION,
- OPT_BUS_WIDTH_1 | (~OPT_BUS_WIDTH_M &
- sh_sdhi_readw(host, SDHI_OPTION)));
-
- debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
-
- return 0;
-}
-
-static int sh_sdhi_initialize_common(struct sh_sdhi_host *host)
-{
- int ret = sh_sdhi_sync_reset(host);
-
- sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
-
-#if defined(__BIG_ENDIAN_BITFIELD)
- sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
-#endif
-
- sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
- INFO1M_ACCESS_END | INFO1M_CARD_RE |
- INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
-
- return ret;
-}
-
-#ifndef CONFIG_DM_MMC
-static void *mmc_priv(struct mmc *mmc)
-{
- return (void *)mmc->priv;
-}
-
-static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_send_cmd_common(host, cmd, data);
-}
-
-static int sh_sdhi_set_ios(struct mmc *mmc)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_set_ios_common(host, mmc);
-}
-
-static int sh_sdhi_initialize(struct mmc *mmc)
-{
- struct sh_sdhi_host *host = mmc_priv(mmc);
-
- return sh_sdhi_initialize_common(host);
-}
-
-static const struct mmc_ops sh_sdhi_ops = {
- .send_cmd = sh_sdhi_send_cmd,
- .set_ios = sh_sdhi_set_ios,
- .init = sh_sdhi_initialize,
-};
-
-#ifdef CONFIG_RCAR_GEN3
-static struct mmc_config sh_sdhi_cfg = {
- .name = DRIVER_NAME,
- .ops = &sh_sdhi_ops,
- .f_min = CLKDEV_INIT,
- .f_max = CLKDEV_HS_DATA,
- .voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
- .host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS |
- MMC_MODE_HS_52MHz,
- .part_type = PART_TYPE_DOS,
- .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
-};
-#else
-static struct mmc_config sh_sdhi_cfg = {
- .name = DRIVER_NAME,
- .ops = &sh_sdhi_ops,
- .f_min = CLKDEV_INIT,
- .f_max = CLKDEV_HS_DATA,
- .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
- .host_caps = MMC_MODE_4BIT | MMC_MODE_HS,
- .part_type = PART_TYPE_DOS,
- .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
-};
-#endif
-
-int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
-{
- int ret = 0;
- struct mmc *mmc;
- struct sh_sdhi_host *host = NULL;
-
- if (ch >= CFG_SYS_SH_SDHI_NR_CHANNEL)
- return -ENODEV;
-
- host = malloc(sizeof(struct sh_sdhi_host));
- if (!host)
- return -ENOMEM;
-
- mmc = mmc_create(&sh_sdhi_cfg, host);
- if (!mmc) {
- ret = -1;
- goto error;
- }
-
- host->ch = ch;
- host->addr = (void __iomem *)addr;
- host->quirks = quirks;
-
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- host->bus_shift = 2;
- else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- host->bus_shift = 1;
-
- return ret;
-error:
- free(host);
- return ret;
-}
-
-#else
-
-struct sh_sdhi_plat {
- struct mmc_config cfg;
- struct mmc mmc;
-};
-
-int sh_sdhi_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct sh_sdhi_host *host = dev_get_priv(dev);
-
- return sh_sdhi_send_cmd_common(host, cmd, data);
-}
-
-int sh_sdhi_dm_set_ios(struct udevice *dev)
-{
- struct sh_sdhi_host *host = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
-
- return sh_sdhi_set_ios_common(host, mmc);
-}
-
-static const struct dm_mmc_ops sh_sdhi_dm_ops = {
- .send_cmd = sh_sdhi_dm_send_cmd,
- .set_ios = sh_sdhi_dm_set_ios,
-};
-
-static int sh_sdhi_dm_bind(struct udevice *dev)
-{
- struct sh_sdhi_plat *plat = dev_get_plat(dev);
-
- return mmc_bind(dev, &plat->mmc, &plat->cfg);
-}
-
-static int sh_sdhi_dm_probe(struct udevice *dev)
-{
- struct sh_sdhi_plat *plat = dev_get_plat(dev);
- struct sh_sdhi_host *host = dev_get_priv(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct clk sh_sdhi_clk;
- const u32 quirks = dev_get_driver_data(dev);
- fdt_addr_t base;
- int ret;
-
- base = dev_read_addr(dev);
- if (base == FDT_ADDR_T_NONE)
- return -EINVAL;
-
- host->addr = devm_ioremap(dev, base, SZ_2K);
- if (!host->addr)
- return -ENOMEM;
-
- ret = clk_get_by_index(dev, 0, &sh_sdhi_clk);
- if (ret) {
- debug("failed to get clock, ret=%d\n", ret);
- return ret;
- }
-
- ret = clk_enable(&sh_sdhi_clk);
- if (ret) {
- debug("failed to enable clock, ret=%d\n", ret);
- return ret;
- }
-
- host->quirks = quirks;
-
- if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
- host->bus_shift = 2;
- else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
- host->bus_shift = 1;
-
- plat->cfg.name = dev->name;
- plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
-
- switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
- 1)) {
- case 8:
- plat->cfg.host_caps |= MMC_MODE_8BIT;
- break;
- case 4:
- plat->cfg.host_caps |= MMC_MODE_4BIT;
- break;
- case 1:
- break;
- default:
- dev_err(dev, "Invalid \"bus-width\" value\n");
- return -EINVAL;
- }
-
- sh_sdhi_initialize_common(host);
-
- plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
- plat->cfg.f_min = CLKDEV_INIT;
- plat->cfg.f_max = CLKDEV_HS_DATA;
- plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
-
- upriv->mmc = &plat->mmc;
-
- return 0;
-}
-
-static const struct udevice_id sh_sdhi_sd_match[] = {
- { .compatible = "renesas,sdhi-r8a7795", .data = SH_SDHI_QUIRK_64BIT_BUF },
- { .compatible = "renesas,sdhi-r8a7796", .data = SH_SDHI_QUIRK_64BIT_BUF },
- { /* sentinel */ }
-};
-
-U_BOOT_DRIVER(sh_sdhi_mmc) = {
- .name = "sh-sdhi-mmc",
- .id = UCLASS_MMC,
- .of_match = sh_sdhi_sd_match,
- .bind = sh_sdhi_dm_bind,
- .probe = sh_sdhi_dm_probe,
- .priv_auto = sizeof(struct sh_sdhi_host),
- .plat_auto = sizeof(struct sh_sdhi_plat),
- .ops = &sh_sdhi_dm_ops,
-};
-#endif
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c
index d1e2681599..890c496b53 100644
--- a/drivers/mmc/tmio-common.c
+++ b/drivers/mmc/tmio-common.c
@@ -122,7 +122,10 @@ static int tmio_sd_wait_for_irq(struct udevice *dev, struct mmc_cmd *cmd,
long wait = 1000000;
int ret;
- while (!(tmio_sd_readl(priv, reg) & flag)) {
+ while (true) {
+ if (tmio_sd_readl(priv, reg) & flag)
+ return tmio_sd_check_error(dev, cmd);
+
if (wait-- < 0) {
dev_err(dev, "timeout\n");
return -ETIMEDOUT;
@@ -756,7 +759,8 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
dev_dbg(dev, "version %x\n", priv->version);
if (priv->version >= 0x10) {
priv->caps |= TMIO_SD_CAP_DMA_INTERNAL;
- priv->caps |= TMIO_SD_CAP_DIV1024;
+ if (!(priv->caps & TMIO_SD_CAP_RCAR))
+ priv->caps |= TMIO_SD_CAP_DIV1024;
}
if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 72547f00fb..a13e6f59cb 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -614,7 +614,6 @@ config ROCKCHIP_NAND
config ROCKCHIP_NAND_SKIP_BBTSCAN
bool "Skip the automatic BBT scan with Rockchip NAND controllers"
depends on ROCKCHIP_NAND
- default n
help
Skip the automatic BBT scan with the NAND_SKIP_BBTSCAN
option when data content is not in MTD format or
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index a9617c6c58..2b2efc8531 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -82,6 +82,7 @@ if SPI_FLASH
config BOOTDEV_SPI_FLASH
bool "SPI Flash bootdev support"
+ depends on BOOTSTD
help
Enable a boot device for SPI flash. This allows reading a script
from SPI flash so that it can be used to boot an Operating System.
@@ -107,7 +108,6 @@ config SPI_FLASH_SMART_HWCAPS
config SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT
bool "Command extension type is INVERT for Software Reset on boot"
- default n
help
Because of SFDP information can not be get before boot.
So define command extension type is INVERT when Software Reset on boot only.
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
index 7976e3b3ed..ff49819b58 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
@@ -329,6 +329,7 @@ struct group_info {
static const struct group_info npcm8xx_groups[] = {
FUNC_LIST
+ {FN_gpio, "GPIO", NULL, 0, 0, 0}
};
/* Pin flags */
diff --git a/drivers/sm/Kconfig b/drivers/sm/Kconfig
index f0987275d2..926af28633 100644
--- a/drivers/sm/Kconfig
+++ b/drivers/sm/Kconfig
@@ -4,6 +4,5 @@ config SM
config MESON_SM
bool "Amlogic Secure Monitor driver"
select SM
- default n
help
Say y here to enable the Amlogic secure monitor driver.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 854b8b88da..69b184b0d9 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -251,6 +251,15 @@ config MICROCHIP_COREQSPI
Enable the QSPI driver for Microchip FPGA QSPI controllers.
This driver can be used on Polarfire SoC.
+config MESON_SPIFC_A1
+ bool "Amlogic Meson A1 SPI Flash Controller driver"
+ depends on ARCH_MESON
+ help
+ Enable the Amlogic A1 SPI Flash Controller (SPIFC) driver.
+ This driver can be used to access the SPI NOR/NAND flash chips
+ with STR mode frequency up to 98MHz. Dual and quad modes are
+ supported by controller.
+
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
depends on MPC8xx
@@ -451,7 +460,6 @@ config SANDBOX_SPI_MAX_CS
config SPI_ASPEED_SMC
bool "ASPEED SPI flash controller driver"
depends on DM_SPI && SPI_MEM
- default n
help
Enable ASPEED SPI flash controller driver for AST2500
and AST2600 SoCs.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c27b3327c3..14bdb97f18 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
+obj-$(CONFIG_MESON_SPIFC_A1) += meson_spifc_a1.o
obj-$(CONFIG_MICROCHIP_COREQSPI) += microchip_coreqspi.o
obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
diff --git a/drivers/spi/meson_spifc_a1.c b/drivers/spi/meson_spifc_a1.c
new file mode 100644
index 0000000000..099c4c037d
--- /dev/null
+++ b/drivers/spi/meson_spifc_a1.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Amlogic A1 SPI flash controller (SPIFC)
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ *
+ * Author: Martin Kurbanov <mmkurbanov@sberdevices.ru>
+ *
+ * Ported to u-boot:
+ * Author: Igor Prusov <ivprusov@sberdevices.ru>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <asm/io.h>
+#include <linux/log2.h>
+#include <linux/iopoll.h>
+#include <linux/bitfield.h>
+
+#define SPIFC_A1_AHB_CTRL_REG 0x0
+#define SPIFC_A1_AHB_BUS_EN BIT(31)
+
+#define SPIFC_A1_USER_CTRL0_REG 0x200
+#define SPIFC_A1_USER_REQUEST_ENABLE BIT(31)
+#define SPIFC_A1_USER_REQUEST_FINISH BIT(30)
+#define SPIFC_A1_USER_DATA_UPDATED BIT(0)
+
+#define SPIFC_A1_USER_CTRL1_REG 0x204
+#define SPIFC_A1_USER_CMD_ENABLE BIT(30)
+#define SPIFC_A1_USER_CMD_MODE GENMASK(29, 28)
+#define SPIFC_A1_USER_CMD_CODE GENMASK(27, 20)
+#define SPIFC_A1_USER_ADDR_ENABLE BIT(19)
+#define SPIFC_A1_USER_ADDR_MODE GENMASK(18, 17)
+#define SPIFC_A1_USER_ADDR_BYTES GENMASK(16, 15)
+#define SPIFC_A1_USER_DOUT_ENABLE BIT(14)
+#define SPIFC_A1_USER_DOUT_MODE GENMASK(11, 10)
+#define SPIFC_A1_USER_DOUT_BYTES GENMASK(9, 0)
+
+#define SPIFC_A1_USER_CTRL2_REG 0x208
+#define SPIFC_A1_USER_DUMMY_ENABLE BIT(31)
+#define SPIFC_A1_USER_DUMMY_MODE GENMASK(30, 29)
+#define SPIFC_A1_USER_DUMMY_CLK_SYCLES GENMASK(28, 23)
+
+#define SPIFC_A1_USER_CTRL3_REG 0x20c
+#define SPIFC_A1_USER_DIN_ENABLE BIT(31)
+#define SPIFC_A1_USER_DIN_MODE GENMASK(28, 27)
+#define SPIFC_A1_USER_DIN_BYTES GENMASK(25, 16)
+
+#define SPIFC_A1_USER_ADDR_REG 0x210
+
+#define SPIFC_A1_AHB_REQ_CTRL_REG 0x214
+#define SPIFC_A1_AHB_REQ_ENABLE BIT(31)
+
+#define SPIFC_A1_ACTIMING0_REG (0x0088 << 2)
+#define SPIFC_A1_TSLCH GENMASK(31, 30)
+#define SPIFC_A1_TCLSH GENMASK(29, 28)
+#define SPIFC_A1_TSHWL GENMASK(20, 16)
+#define SPIFC_A1_TSHSL2 GENMASK(15, 12)
+#define SPIFC_A1_TSHSL1 GENMASK(11, 8)
+#define SPIFC_A1_TWHSL GENMASK(7, 0)
+
+#define SPIFC_A1_DBUF_CTRL_REG 0x240
+#define SPIFC_A1_DBUF_DIR BIT(31)
+#define SPIFC_A1_DBUF_AUTO_UPDATE_ADDR BIT(30)
+#define SPIFC_A1_DBUF_ADDR GENMASK(7, 0)
+
+#define SPIFC_A1_DBUF_DATA_REG 0x244
+
+#define SPIFC_A1_USER_DBUF_ADDR_REG 0x248
+
+#define SPIFC_A1_BUFFER_SIZE 512U
+
+#define SPIFC_A1_MAX_HZ 200000000
+#define SPIFC_A1_MIN_HZ 1000000
+
+#define SPIFC_A1_USER_CMD(op) ( \
+ SPIFC_A1_USER_CMD_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_CMD_CODE, (op)->cmd.opcode) | \
+ FIELD_PREP(SPIFC_A1_USER_CMD_MODE, ilog2((op)->cmd.buswidth)))
+
+#define SPIFC_A1_USER_ADDR(op) ( \
+ SPIFC_A1_USER_ADDR_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_ADDR_MODE, ilog2((op)->addr.buswidth)) | \
+ FIELD_PREP(SPIFC_A1_USER_ADDR_BYTES, (op)->addr.nbytes - 1))
+
+#define SPIFC_A1_USER_DUMMY(op) ( \
+ SPIFC_A1_USER_DUMMY_ENABLE | \
+ FIELD_PREP(SPIFC_A1_USER_DUMMY_MODE, ilog2((op)->dummy.buswidth)) | \
+ FIELD_PREP(SPIFC_A1_USER_DUMMY_CLK_SYCLES, (op)->dummy.nbytes << 3))
+
+#define SPIFC_A1_TSLCH_VAL FIELD_PREP(SPIFC_A1_TSLCH, 1)
+#define SPIFC_A1_TCLSH_VAL FIELD_PREP(SPIFC_A1_TCLSH, 1)
+#define SPIFC_A1_TSHWL_VAL FIELD_PREP(SPIFC_A1_TSHWL, 7)
+#define SPIFC_A1_TSHSL2_VAL FIELD_PREP(SPIFC_A1_TSHSL2, 7)
+#define SPIFC_A1_TSHSL1_VAL FIELD_PREP(SPIFC_A1_TSHSL1, 7)
+#define SPIFC_A1_TWHSL_VAL FIELD_PREP(SPIFC_A1_TWHSL, 2)
+#define SPIFC_A1_ACTIMING0_VAL (SPIFC_A1_TSLCH_VAL | SPIFC_A1_TCLSH_VAL | \
+ SPIFC_A1_TSHWL_VAL | SPIFC_A1_TSHSL2_VAL | \
+ SPIFC_A1_TSHSL1_VAL | SPIFC_A1_TWHSL_VAL)
+
+struct amlogic_spifc_a1 {
+ struct clk clk;
+ void __iomem *base;
+ u32 curr_speed_hz;
+};
+
+static int amlogic_spifc_a1_request(struct amlogic_spifc_a1 *spifc, bool read)
+{
+ u32 mask = SPIFC_A1_USER_REQUEST_FINISH |
+ (read ? SPIFC_A1_USER_DATA_UPDATED : 0);
+ u32 val;
+
+ writel(SPIFC_A1_USER_REQUEST_ENABLE,
+ spifc->base + SPIFC_A1_USER_CTRL0_REG);
+
+ return readl_poll_timeout(spifc->base + SPIFC_A1_USER_CTRL0_REG,
+ val, (val & mask) == mask,
+ 200 * 1000);
+}
+
+static void amlogic_spifc_a1_drain_buffer(struct amlogic_spifc_a1 *spifc,
+ char *buf, u32 len)
+{
+ u32 data;
+ const u32 count = len / sizeof(data);
+ const u32 pad = len % sizeof(data);
+
+ writel(SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
+ spifc->base + SPIFC_A1_DBUF_CTRL_REG);
+ readsl(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
+
+ if (pad) {
+ data = readl(spifc->base + SPIFC_A1_DBUF_DATA_REG);
+ memcpy(buf + len - pad, &data, pad);
+ }
+}
+
+static void amlogic_spifc_a1_fill_buffer(struct amlogic_spifc_a1 *spifc,
+ const char *buf, u32 len)
+{
+ u32 data;
+ const u32 count = len / sizeof(data);
+ const u32 pad = len % sizeof(data);
+
+ writel(SPIFC_A1_DBUF_DIR | SPIFC_A1_DBUF_AUTO_UPDATE_ADDR,
+ spifc->base + SPIFC_A1_DBUF_CTRL_REG);
+ writesl(spifc->base + SPIFC_A1_DBUF_DATA_REG, buf, count);
+
+ if (pad) {
+ memcpy(&data, buf + len - pad, pad);
+ writel(data, spifc->base + SPIFC_A1_DBUF_DATA_REG);
+ }
+}
+
+static void amlogic_spifc_a1_user_init(struct amlogic_spifc_a1 *spifc)
+{
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL0_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL2_REG);
+ writel(0, spifc->base + SPIFC_A1_USER_CTRL3_REG);
+}
+
+static void amlogic_spifc_a1_set_cmd(struct amlogic_spifc_a1 *spifc,
+ u32 cmd_cfg)
+{
+ u32 val;
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_CMD_MODE | SPIFC_A1_USER_CMD_CODE);
+ val |= cmd_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+}
+
+static void amlogic_spifc_a1_set_addr(struct amlogic_spifc_a1 *spifc, u32 addr,
+ u32 addr_cfg)
+{
+ u32 val;
+
+ writel(addr, spifc->base + SPIFC_A1_USER_ADDR_REG);
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_ADDR_MODE | SPIFC_A1_USER_ADDR_BYTES);
+ val |= addr_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+}
+
+static void amlogic_spifc_a1_set_dummy(struct amlogic_spifc_a1 *spifc,
+ u32 dummy_cfg)
+{
+ u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL2_REG);
+
+ val &= ~(SPIFC_A1_USER_DUMMY_MODE | SPIFC_A1_USER_DUMMY_CLK_SYCLES);
+ val |= dummy_cfg;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL2_REG);
+}
+
+static int amlogic_spifc_a1_read(struct amlogic_spifc_a1 *spifc, void *buf,
+ u32 size, u32 mode)
+{
+ u32 val = readl(spifc->base + SPIFC_A1_USER_CTRL3_REG);
+ int ret;
+
+ val &= ~(SPIFC_A1_USER_DIN_MODE | SPIFC_A1_USER_DIN_BYTES);
+ val |= SPIFC_A1_USER_DIN_ENABLE;
+ val |= FIELD_PREP(SPIFC_A1_USER_DIN_MODE, mode);
+ val |= FIELD_PREP(SPIFC_A1_USER_DIN_BYTES, size);
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL3_REG);
+
+ ret = amlogic_spifc_a1_request(spifc, true);
+ if (!ret)
+ amlogic_spifc_a1_drain_buffer(spifc, buf, size);
+
+ return ret;
+}
+
+static int amlogic_spifc_a1_write(struct amlogic_spifc_a1 *spifc,
+ const void *buf, u32 size, u32 mode)
+{
+ u32 val;
+
+ amlogic_spifc_a1_fill_buffer(spifc, buf, size);
+
+ val = readl(spifc->base + SPIFC_A1_USER_CTRL1_REG);
+ val &= ~(SPIFC_A1_USER_DOUT_MODE | SPIFC_A1_USER_DOUT_BYTES);
+ val |= FIELD_PREP(SPIFC_A1_USER_DOUT_MODE, mode);
+ val |= FIELD_PREP(SPIFC_A1_USER_DOUT_BYTES, size);
+ val |= SPIFC_A1_USER_DOUT_ENABLE;
+ writel(val, spifc->base + SPIFC_A1_USER_CTRL1_REG);
+
+ return amlogic_spifc_a1_request(spifc, false);
+}
+
+static int amlogic_spifc_a1_set_freq(struct amlogic_spifc_a1 *spifc, u32 freq)
+{
+ int ret;
+
+ if (freq == spifc->curr_speed_hz)
+ return 0;
+
+ ret = clk_set_rate(&spifc->clk, freq);
+ if (ret)
+ return ret;
+
+ spifc->curr_speed_hz = freq;
+ return 0;
+}
+
+static int amlogic_spifc_a1_exec_op(struct spi_slave *slave,
+ const struct spi_mem_op *op)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(slave->dev->parent);
+ size_t data_size = op->data.nbytes;
+ int ret;
+
+ ret = amlogic_spifc_a1_set_freq(spifc, slave->max_hz);
+ if (ret)
+ return ret;
+
+ amlogic_spifc_a1_user_init(spifc);
+ amlogic_spifc_a1_set_cmd(spifc, SPIFC_A1_USER_CMD(op));
+
+ if (op->addr.nbytes)
+ amlogic_spifc_a1_set_addr(spifc, op->addr.val,
+ SPIFC_A1_USER_ADDR(op));
+
+ if (op->dummy.nbytes)
+ amlogic_spifc_a1_set_dummy(spifc, SPIFC_A1_USER_DUMMY(op));
+
+ if (data_size) {
+ u32 mode = ilog2(op->data.buswidth);
+
+ writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ ret = amlogic_spifc_a1_read(spifc, op->data.buf.in,
+ data_size, mode);
+ else
+ ret = amlogic_spifc_a1_write(spifc, op->data.buf.out,
+ data_size, mode);
+ } else {
+ ret = amlogic_spifc_a1_request(spifc, false);
+ }
+
+ return ret;
+}
+
+static int amlogic_spifc_a1_adjust_op_size(struct spi_slave *slave,
+ struct spi_mem_op *op)
+{
+ op->data.nbytes = min(op->data.nbytes, SPIFC_A1_BUFFER_SIZE);
+ return 0;
+}
+
+static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
+{
+ u32 regv;
+
+ regv = readl(spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
+ regv &= ~(SPIFC_A1_AHB_REQ_ENABLE);
+ writel(regv, spifc->base + SPIFC_A1_AHB_REQ_CTRL_REG);
+
+ regv = readl(spifc->base + SPIFC_A1_AHB_CTRL_REG);
+ regv &= ~(SPIFC_A1_AHB_BUS_EN);
+ writel(regv, spifc->base + SPIFC_A1_AHB_CTRL_REG);
+
+ writel(SPIFC_A1_ACTIMING0_VAL, spifc->base + SPIFC_A1_ACTIMING0_REG);
+
+ writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
+}
+
+static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
+ .exec_op = amlogic_spifc_a1_exec_op,
+ .adjust_op_size = amlogic_spifc_a1_adjust_op_size,
+};
+
+static int amlogic_spifc_a1_probe(struct udevice *dev)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(dev);
+ int ret;
+ struct udevice *bus = dev;
+
+ spifc->base = dev_read_addr_ptr(dev);
+ if (!spifc->base)
+ return -EINVAL;
+
+ ret = clk_get_by_index(bus, 0, &spifc->clk);
+ if (ret) {
+ pr_err("can't get clk spifc_gate!\n");
+ return ret;
+ }
+
+ ret = clk_enable(&spifc->clk);
+ if (ret) {
+ pr_err("enable clk fail\n");
+ return ret;
+ }
+
+ amlogic_spifc_a1_hw_init(spifc);
+
+ return 0;
+}
+
+static int amlogic_spifc_a1_remove(struct udevice *dev)
+{
+ struct amlogic_spifc_a1 *spifc = dev_get_priv(dev);
+
+ clk_free(&spifc->clk);
+
+ return 0;
+}
+
+static const struct udevice_id meson_spifc_ids[] = {
+ { .compatible = "amlogic,a1-spifc", },
+ { }
+};
+
+int amlogic_spifc_a1_set_speed(struct udevice *bus, uint hz)
+{
+ return 0;
+}
+
+int amlogic_spifc_a1_set_mode(struct udevice *bus, uint mode)
+{
+ return 0;
+}
+
+static const struct dm_spi_ops amlogic_spifc_a1_ops = {
+ .mem_ops = &amlogic_spifc_a1_mem_ops,
+ .set_speed = amlogic_spifc_a1_set_speed,
+ .set_mode = amlogic_spifc_a1_set_mode,
+};
+
+U_BOOT_DRIVER(meson_spifc_a1) = {
+ .name = "meson_spifc_a1",
+ .id = UCLASS_SPI,
+ .of_match = meson_spifc_ids,
+ .ops = &amlogic_spifc_a1_ops,
+ .probe = amlogic_spifc_a1_probe,
+ .remove = amlogic_spifc_a1_remove,
+ .priv_auto = sizeof(struct amlogic_spifc_a1),
+};
diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index e4004cfcca..d15a28d9fc 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -22,11 +22,6 @@ enum tpm2_hierarchy {
TPM2_HIERARCHY_NB,
};
-/* Subset of supported capabilities */
-enum tpm2_capability {
- TPM_CAP_TPM_PROPERTIES = 0x6,
-};
-
/* Subset of supported properties */
#define TPM2_PROPERTIES_OFFSET 0x0000020E
@@ -38,7 +33,8 @@ enum tpm2_cap_tpm_property {
TPM2_PROPERTY_NB,
};
-#define SANDBOX_TPM_PCR_NB 1
+#define SANDBOX_TPM_PCR_NB TPM2_MAX_PCRS
+#define SANDBOX_TPM_PCR_SELECT_MAX ((SANDBOX_TPM_PCR_NB + 7) / 8)
/*
* Information about our TPM emulation. This is preserved in the sandbox
@@ -433,7 +429,7 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
int i, j;
/* TPM2_GetProperty */
- u32 capability, property, property_count;
+ u32 capability, property, property_count, val;
/* TPM2_PCR_Read/Extend variables */
int pcr_index = 0;
@@ -542,19 +538,32 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
case TPM2_CC_GET_CAPABILITY:
capability = get_unaligned_be32(sent);
sent += sizeof(capability);
- if (capability != TPM_CAP_TPM_PROPERTIES) {
- printf("Sandbox TPM only support TPM_CAPABILITIES\n");
- return TPM2_RC_HANDLE;
- }
-
property = get_unaligned_be32(sent);
sent += sizeof(property);
- property -= TPM2_PROPERTIES_OFFSET;
-
property_count = get_unaligned_be32(sent);
sent += sizeof(property_count);
- if (!property_count ||
- property + property_count > TPM2_PROPERTY_NB) {
+
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ if (!property_count) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+
+ if (property >= TPM2_PROPERTIES_OFFSET &&
+ ((property - TPM2_PROPERTIES_OFFSET) +
+ property_count > TPM2_PROPERTY_NB)) {
+ rc = TPM2_RC_HANDLE;
+ return sandbox_tpm2_fill_buf(recv, recv_len,
+ tag, rc);
+ }
+ break;
+ default:
+ printf("Sandbox TPM2 only supports TPM2_CAP_PCRS or "
+ "TPM2_CAP_TPM_PROPERTIES\n");
rc = TPM2_RC_HANDLE;
return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
}
@@ -578,18 +587,53 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
put_unaligned_be32(capability, recv);
recv += sizeof(capability);
- /* Give the number of properties that follow */
- put_unaligned_be32(property_count, recv);
- recv += sizeof(property_count);
-
- /* Fill with the properties */
- for (i = 0; i < property_count; i++) {
- put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property +
- i, recv);
- recv += sizeof(property);
- put_unaligned_be32(tpm->properties[property + i],
- recv);
- recv += sizeof(property);
+ switch (capability) {
+ case TPM2_CAP_PCRS:
+ /* Give the number of algorithms supported - just SHA256 */
+ put_unaligned_be32(1, recv);
+ recv += sizeof(u32);
+
+ /* Give SHA256 algorithm */
+ put_unaligned_be16(TPM2_ALG_SHA256, recv);
+ recv += sizeof(u16);
+
+ /* Select the PCRs supported */
+ *recv = SANDBOX_TPM_PCR_SELECT_MAX;
+ recv++;
+
+ /* Activate all the PCR bits */
+ for (i = 0; i < SANDBOX_TPM_PCR_SELECT_MAX; ++i) {
+ *recv = 0xff;
+ recv++;
+ }
+ break;
+ case TPM2_CAP_TPM_PROPERTIES:
+ /* Give the number of properties that follow */
+ put_unaligned_be32(property_count, recv);
+ recv += sizeof(property_count);
+
+ /* Fill with the properties */
+ for (i = 0; i < property_count; i++) {
+ put_unaligned_be32(property + i, recv);
+ recv += sizeof(property);
+ if (property >= TPM2_PROPERTIES_OFFSET) {
+ val = tpm->properties[(property -
+ TPM2_PROPERTIES_OFFSET) + i];
+ } else {
+ switch (property) {
+ case TPM2_PT_PCR_COUNT:
+ val = SANDBOX_TPM_PCR_NB;
+ break;
+ default:
+ val = 0xffffffff;
+ break;
+ }
+ }
+
+ put_unaligned_be32(val, recv);
+ recv += sizeof(property);
+ }
+ break;
}
/* Add trailing \0 */
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a883babf4..b501ea514b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -231,7 +231,6 @@ config USB_EHCI_MXS
config USB_EHCI_NPCM
bool "Support for Nuvoton NPCM on-chip EHCI USB controller"
depends on ARCH_NPCM
- default n
---help---
Enables support for the on-chip EHCI controller on
Nuvoton NPCM chips.
@@ -368,7 +367,6 @@ config USB_OHCI_DA8XX
config USB_OHCI_NPCM
bool "Support for Nuvoton NPCM on-chip OHCI USB controller"
depends on ARCH_NPCM
- default n
---help---
Enables support for the on-chip OHCI controller on
Nuvoton NPCM chips.