diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/ti/clk-k3-pll.c | 81 | ||||
-rw-r--r-- | drivers/crypto/fsl/Kconfig | 1 | ||||
-rw-r--r-- | drivers/firmware/arm-ffa/arm-ffa-uclass.c | 2 | ||||
-rw-r--r-- | drivers/memory/Kconfig | 1 | ||||
-rw-r--r-- | drivers/misc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/misc/i2c_eeprom.c | 13 | ||||
-rw-r--r-- | drivers/misc/k3_avs.c | 104 | ||||
-rw-r--r-- | drivers/misc/vexpress_config.c | 5 | ||||
-rw-r--r-- | drivers/mmc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/pci_mmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/renesas-sdhi.c | 4 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 19 | ||||
-rw-r--r-- | drivers/mmc/sh_sdhi.c | 910 | ||||
-rw-r--r-- | drivers/mmc/tmio-common.c | 8 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mtd/spi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c | 1 | ||||
-rw-r--r-- | drivers/sm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 10 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/meson_spifc_a1.c | 383 | ||||
-rw-r--r-- | drivers/tpm/tpm2_tis_sandbox.c | 100 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 2 |
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. |