diff options
Diffstat (limited to 'drivers')
386 files changed, 21427 insertions, 1948 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1acd94f3c17..9440af1b09b 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,60 +1,60 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-$(CONFIG_$(SPL_TPL_)ADC) += adc/ -obj-$(CONFIG_$(SPL_TPL_)BIOSEMU) += bios_emulator/ -obj-$(CONFIG_$(SPL_TPL_)BLK) += block/ -obj-$(CONFIG_$(SPL_TPL_)BOOTCOUNT_LIMIT) += bootcount/ -obj-$(CONFIG_$(SPL_TPL_)BUTTON) += button/ -obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache/ -obj-$(CONFIG_$(SPL_TPL_)CLK) += clk/ -obj-$(CONFIG_$(SPL_TPL_)DM) += core/ -obj-$(CONFIG_$(SPL_TPL_)DMA) += dma/ -obj-$(CONFIG_$(SPL_TPL_)DMA_LEGACY) += dma/ -obj-$(CONFIG_$(SPL_TPL_)DFU) += dfu/ -obj-$(CONFIG_$(SPL_TPL_)EXTCON) += extcon/ -obj-$(CONFIG_$(SPL_TPL_)GPIO) += gpio/ -obj-$(CONFIG_$(SPL_TPL_)DRIVERS_MISC) += misc/ -obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset/ -obj-$(CONFIG_$(SPL_TPL_)FIRMWARE) +=firmware/ -obj-$(CONFIG_$(SPL_TPL_)I2C) += i2c/ -obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/ -obj-$(CONFIG_$(SPL_TPL_)LED) += led/ -obj-$(CONFIG_$(SPL_TPL_)MMC) += mmc/ +obj-$(CONFIG_$(PHASE_)ADC) += adc/ +obj-$(CONFIG_$(PHASE_)BIOSEMU) += bios_emulator/ +obj-$(CONFIG_$(PHASE_)BLK) += block/ +obj-$(CONFIG_$(PHASE_)BOOTCOUNT_LIMIT) += bootcount/ +obj-$(CONFIG_$(PHASE_)BUTTON) += button/ +obj-$(CONFIG_$(PHASE_)CACHE) += cache/ +obj-$(CONFIG_$(PHASE_)CLK) += clk/ +obj-$(CONFIG_$(PHASE_)DM) += core/ +obj-$(CONFIG_$(PHASE_)DMA) += dma/ +obj-$(CONFIG_$(PHASE_)DMA_LEGACY) += dma/ +obj-$(CONFIG_$(PHASE_)DFU) += dfu/ +obj-$(CONFIG_$(PHASE_)EXTCON) += extcon/ +obj-$(CONFIG_$(PHASE_)GPIO) += gpio/ +obj-$(CONFIG_$(PHASE_)DRIVERS_MISC) += misc/ +obj-$(CONFIG_$(PHASE_)SYSRESET) += sysreset/ +obj-$(CONFIG_$(PHASE_)FIRMWARE) +=firmware/ +obj-$(CONFIG_$(PHASE_)I2C) += i2c/ +obj-$(CONFIG_$(PHASE_)INPUT) += input/ +obj-$(CONFIG_$(PHASE_)LED) += led/ +obj-$(CONFIG_$(PHASE_)MMC) += mmc/ obj-y += mtd/ -obj-$(CONFIG_$(SPL_TPL_)ETH) += net/ -obj-$(CONFIG_$(SPL_TPL_)PCH) += pch/ -obj-$(CONFIG_$(SPL_TPL_)PCI) += pci/ -obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/ -obj-$(CONFIG_$(SPL_TPL_)PINCTRL) += pinctrl/ -obj-$(CONFIG_$(SPL_TPL_)POWER) += power/ -obj-$(CONFIG_$(SPL_TPL_)RAM) += ram/ -obj-$(CONFIG_$(SPL_TPL_)RTC) += rtc/ -obj-$(CONFIG_$(SPL_TPL_)SERIAL) += serial/ -obj-$(CONFIG_$(SPL_TPL_)SPI) += spi/ -obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/ -obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/ -obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ -obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ -obj-$(CONFIG_$(SPL_)SYSINFO) += sysinfo/ -obj-$(CONFIG_$(SPL_TPL_)SM) += sm/ -obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ -obj-$(CONFIG_$(SPL_)NVME) += nvme/ +obj-$(CONFIG_$(PHASE_)ETH) += net/ +obj-$(CONFIG_$(PHASE_)PCH) += pch/ +obj-$(CONFIG_$(PHASE_)PCI) += pci/ +obj-$(CONFIG_$(PHASE_)PHY) += phy/ +obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/ +obj-$(CONFIG_$(PHASE_)POWER) += power/ +obj-$(CONFIG_$(PHASE_)RAM) += ram/ +obj-$(CONFIG_$(PHASE_)RTC) += rtc/ +obj-$(CONFIG_$(PHASE_)SERIAL) += serial/ +obj-$(CONFIG_$(PHASE_)SPI) += spi/ +obj-$(CONFIG_$(PHASE_)TIMER) += timer/ +obj-$(CONFIG_$(PHASE_)VIRTIO) += virtio/ +obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox/ +obj-$(CONFIG_$(XPL_)REMOTEPROC) += remoteproc/ +obj-$(CONFIG_$(XPL_)SYSINFO) += sysinfo/ +obj-$(CONFIG_$(PHASE_)SM) += sm/ +obj-$(CONFIG_$(PHASE_)TPM) += tpm/ +obj-$(CONFIG_$(XPL_)NVME) += nvme/ obj-$(CONFIG_XEN) += xen/ -obj-$(CONFIG_$(SPL_)FPGA) += fpga/ -obj-$(CONFIG_$(SPL_)VIDEO) += video/ +obj-$(CONFIG_$(XPL_)FPGA) += fpga/ +obj-$(CONFIG_$(XPL_)VIDEO) += video/ obj-y += bus/ ifndef CONFIG_TPL_BUILD ifndef CONFIG_VPL_BUILD -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_CPU) += cpu/ obj-$(CONFIG_SPL_CRYPTO) += crypto/ obj-$(CONFIG_SPL_MPC8XXX_INIT_DDR) += ddr/fsl/ obj-$(CONFIG_ARMADA_38X) += ddr/marvell/a38x/ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/ -obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/ +obj-$(CONFIG_$(XPL_)ALTERA_SDRAM) += ddr/altera/ obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/ obj-$(CONFIG_IMX8ULP_DRAM) += ddr/imx/imx8ulp/ obj-$(CONFIG_ARCH_IMX9) += ddr/imx/imx9/ @@ -80,7 +80,7 @@ obj-$(CONFIG_TPL_MPC8XXX_INIT_DDR) += ddr/fsl/ endif -ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),) obj-y += ata/ obj-$(CONFIG_DM_DEMO) += demo/ @@ -126,7 +126,7 @@ obj-$(CONFIG_W1_EEPROM) += w1-eeprom/ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/ obj-$(CONFIG_FUZZ) += fuzz/ obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/ -obj-$(CONFIG_$(SPL_TPL_)DM_RNG) += rng/ +obj-$(CONFIG_$(PHASE_)DM_RNG) += rng/ endif obj-y += soc/ diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index dca0b39c2e2..665a7965412 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -4,7 +4,7 @@ # Przemyslaw Marczak <p.marczak@samsung.com> # -obj-$(CONFIG_$(SPL_TPL_)ADC) += adc-uclass.o +obj-$(CONFIG_$(PHASE_)ADC) += adc-uclass.o obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o obj-$(CONFIG_ADC_SANDBOX) += sandbox.o obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o diff --git a/drivers/adc/adc-uclass.c b/drivers/adc/adc-uclass.c index 16600be821c..b02430eb7d7 100644 --- a/drivers/adc/adc-uclass.c +++ b/drivers/adc/adc-uclass.c @@ -382,7 +382,7 @@ static int adc_vdd_plat_set(struct udevice *dev) if (!ret) return adc_vdd_plat_update(dev); - if (ret != -ENOENT) + if (ret != -ENOSYS && ret != -ENOENT) return ret; /* No vdd-supply phandle. */ @@ -406,7 +406,7 @@ static int adc_vss_plat_set(struct udevice *dev) if (!ret) return adc_vss_plat_update(dev); - if (ret != -ENOENT) + if (ret != -ENOSYS && ret != -ENOENT) return ret; /* No vss-supply phandle. */ diff --git a/drivers/adc/rockchip-saradc.c b/drivers/adc/rockchip-saradc.c index f6832ab3073..7cf9735f60d 100644 --- a/drivers/adc/rockchip-saradc.c +++ b/drivers/adc/rockchip-saradc.c @@ -241,7 +241,7 @@ int rockchip_saradc_probe(struct udevice *dev) { struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); struct rockchip_saradc_priv *priv = dev_get_priv(dev); - struct udevice *vref; + struct udevice *vref = NULL; struct clk clk; int vref_uv; int ret; @@ -259,7 +259,7 @@ int rockchip_saradc_probe(struct udevice *dev) priv->active_channel = -1; ret = device_get_supply_regulator(dev, "vref-supply", &vref); - if (ret) { + if (ret && uc_pdata->vdd_microvolts <= 0) { printf("can't get vref-supply: %d\n", ret); return ret; } @@ -267,7 +267,10 @@ int rockchip_saradc_probe(struct udevice *dev) if (priv->reset) rockchip_saradc_reset_controller(priv->reset); - vref_uv = regulator_get_value(vref); + if (vref) + vref_uv = regulator_get_value(vref); + else + vref_uv = uc_pdata->vdd_microvolts; if (vref_uv < 0) { printf("can't get vref-supply value: %d\n", vref_uv); return vref_uv; diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 507bf84c14c..69fa9b707e0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o obj-$(CONFIG_AHCI) += ahci-uclass.o -obj-$(CONFIG_$(SPL_)AHCI_PCI) += ahci-pci.o +obj-$(CONFIG_$(XPL_)AHCI_PCI) += ahci-pci.o obj-$(CONFIG_SCSI_AHCI) += ahci.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o obj-$(CONFIG_FSL_SATA) += fsl_sata.o diff --git a/drivers/block/Makefile b/drivers/block/Makefile index fe6a1fcf486..ee290620545 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -3,20 +3,20 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_TPL_)BLK) += blk-uclass.o +obj-$(CONFIG_$(PHASE_)BLK) += blk-uclass.o -ifndef CONFIG_$(SPL_)BLK +ifndef CONFIG_$(XPL_)BLK obj-$(CONFIG_SPL_LEGACY_BLOCK) += blk_legacy.o endif -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_RKMTD) += rkmtd.o endif obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o -obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o -obj-$(CONFIG_$(SPL_TPL_)BLKMAP) += blkmap.o -obj-$(CONFIG_$(SPL_TPL_)BLKMAP) += blkmap_helper.o +obj-$(CONFIG_$(PHASE_)BLOCK_CACHE) += blkcache.o +obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap.o +obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap_helper.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o obj-$(CONFIG_EFI_MEDIA_SANDBOX) += sb_efi_media.o diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 312e038445c..f3ac8db9464 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -695,9 +695,22 @@ static int blk_claim_devnum(enum uclass_id uclass_id, int devnum) return -ENOENT; } -int blk_create_device(struct udevice *parent, const char *drv_name, - const char *name, int uclass_id, int devnum, int blksz, - lbaint_t lba, struct udevice **devp) +/** + * blk_create_device() - Create a new block device + * + * @parent: Parent of the new device + * @drv_name: Driver name to use for the block device + * @name: Name for the device + * @uclass_id: Interface type (enum uclass_id_t) + * @devnum: Device number, specific to the interface type, or -1 to + * allocate the next available number + * @blksz: Block size of the device in bytes (typically 512) + * @lba: Total number of blocks of the device + * @devp: the new device (which has not been probed) + */ +static int blk_create_device(struct udevice *parent, const char *drv_name, + const char *name, int uclass_id, int devnum, + int blksz, lbaint_t lba, struct udevice **devp) { struct blk_desc *desc; struct udevice *dev; diff --git a/drivers/block/rkmtd.c b/drivers/block/rkmtd.c index c55f052e51b..f84cacd7ead 100644 --- a/drivers/block/rkmtd.c +++ b/drivers/block/rkmtd.c @@ -794,36 +794,19 @@ int rkmtd_init_plat(struct udevice *dev) return 0; } -static void rkmtd_blk_kmalloc_release(struct udevice *dev, void *res) -{ - /* noop */ -} - static int rkmtd_bind(struct udevice *dev) { struct rkmtd_dev *plat = dev_get_plat(dev); - char dev_name[30], *str; struct blk_desc *desc; struct udevice *bdev; int ret; - snprintf(dev_name, sizeof(dev_name), "%s.%s", dev->name, "blk"); - - str = devres_alloc(rkmtd_blk_kmalloc_release, strlen(dev_name) + 1, GFP_KERNEL); - if (unlikely(!str)) - return -ENOMEM; - - strcpy(str, dev_name); - - ret = blk_create_device(dev, "rkmtd_blk", str, UCLASS_RKMTD, - -1, 512, LBA, &bdev); + ret = blk_create_devicef(dev, "rkmtd_blk", "blk", UCLASS_RKMTD, + -1, 512, LBA, &bdev); if (ret) { - free(str); return log_msg_ret("blk", ret); } - devres_add(dev, str); - desc = dev_get_uclass_plat(bdev); sprintf(desc->vendor, "0x%.4x", 0x2207); memcpy(desc->product, "RKMTD", sizeof("RKMTD")); diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 0802b9666bf..7daf8247247 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -3,9 +3,9 @@ # Makefile for the bus drivers. # -ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),) obj-$(CONFIG_TI_PWMSS) += ti-pwmss.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o endif -obj-$(CONFIG_$(SPL_)TI_SYSC) += ti-sysc.o +obj-$(CONFIG_$(XPL_)TI_SYSC) += ti-sysc.o diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index e1b71e0ed51..2f683866b87 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,5 +1,5 @@ -obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache-uclass.o +obj-$(CONFIG_$(PHASE_)CACHE) += cache-uclass.o obj-$(CONFIG_SANDBOX) += sandbox_cache.o obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o obj-$(CONFIG_NCORE_CACHE) += cache-ncore.o diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f9b90a38b00..7f84f22d4b1 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -4,13 +4,13 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # -obj-$(CONFIG_$(SPL_TPL_)CLK) += clk-uclass.o -obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_rate.o -obj-$(CONFIG_$(SPL_TPL_)CLK) += clk_fixed_factor.o -obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o -obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-fixed-factor.o -obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o -obj-$(CONFIG_$(SPL_TPL_)CLK_GPIO) += clk-gpio.o +obj-$(CONFIG_$(PHASE_)CLK) += clk-uclass.o +obj-$(CONFIG_$(PHASE_)CLK) += clk_fixed_rate.o +obj-$(CONFIG_$(PHASE_)CLK) += clk_fixed_factor.o +obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk.o clk-divider.o clk-mux.o clk-gate.o +obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk-fixed-factor.o +obj-$(CONFIG_$(PHASE_)CLK_COMPOSITE_CCF) += clk-composite.o +obj-$(CONFIG_$(PHASE_)CLK_GPIO) += clk-gpio.o obj-y += adi/ obj-y += analogbits/ @@ -18,7 +18,7 @@ obj-y += imx/ obj-$(CONFIG_CLK_JH7110) += starfive/ obj-y += tegra/ obj-y += ti/ -obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/ +obj-$(CONFIG_$(PHASE_)CLK_INTEL) += intel/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ @@ -42,7 +42,7 @@ obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o obj-$(CONFIG_CLK_OWL) += owl/ obj-$(CONFIG_CLK_QCOM) += qcom/ obj-$(CONFIG_CLK_RENESAS) += renesas/ -obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o +obj-$(CONFIG_$(PHASE_)CLK_SCMI) += clk_scmi.o obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_CLK_SOPHGO) += sophgo/ obj-$(CONFIG_CLK_SUNXI) += sunxi/ diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c index bdc7be0fb5d..e1ddd02f356 100644 --- a/drivers/clk/altera/clk-agilex.c +++ b/drivers/clk/altera/clk-agilex.c @@ -242,7 +242,7 @@ static void clk_basic_init(struct udevice *dev, if (!cfg) return; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* Always force clock manager into boot mode before any configuration */ clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE); diff --git a/drivers/clk/altera/clk-agilex5.c b/drivers/clk/altera/clk-agilex5.c index 72b923465df..716c71598bc 100644 --- a/drivers/clk/altera/clk-agilex5.c +++ b/drivers/clk/altera/clk-agilex5.c @@ -263,7 +263,7 @@ static void clk_basic_init(struct udevice *dev, clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) & ~CLKMGR_CTRL_BOOTMODE); } else { -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* Always force clock manager into boot mode before any configuration */ clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE); diff --git a/drivers/clk/altera/clk-n5x.c b/drivers/clk/altera/clk-n5x.c index 3e256101a94..09db250ab6d 100644 --- a/drivers/clk/altera/clk-n5x.c +++ b/drivers/clk/altera/clk-n5x.c @@ -52,7 +52,7 @@ static void clk_basic_init(struct udevice *dev, if (!cfg) return; -#if IS_ENABLED(CONFIG_SPL_BUILD) +#if IS_ENABLED(CONFIG_XPL_BUILD) /* Always force clock manager into boot mode before any configuration */ clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE); diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 16169dac234..a9937c22dcb 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -378,7 +378,7 @@ int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage) * However, still set them for SPL. And still set them if explicitly * asked. */ - if (!(IS_ENABLED(CONFIG_SPL_BUILD) || (gd->flags & GD_FLG_RELOC))) + if (!(IS_ENABLED(CONFIG_XPL_BUILD) || (gd->flags & GD_FLG_RELOC))) if (stage != CLK_DEFAULTS_POST_FORCE) return 0; diff --git a/drivers/clk/clk_vexpress_osc.c b/drivers/clk/clk_vexpress_osc.c index 2e0e7bbe68f..85ac92c908a 100644 --- a/drivers/clk/clk_vexpress_osc.c +++ b/drivers/clk/clk_vexpress_osc.c @@ -37,7 +37,7 @@ static ulong vexpress_osc_clk_get_rate(struct clk *clk) return data; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong vexpress_osc_clk_set_rate(struct clk *clk, ulong rate) { int err; @@ -64,7 +64,7 @@ static ulong vexpress_osc_clk_set_rate(struct clk *clk, ulong rate) static struct clk_ops vexpress_osc_clk_ops = { .get_rate = vexpress_osc_clk_get_rate, -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD .set_rate = vexpress_osc_clk_set_rate, #endif }; diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index b62b4646f4e..a8505f62bba 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -43,13 +43,13 @@ DECLARE_GLOBAL_DATA_PTR; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD enum zynq_clk_rclk {mio_clk, emio_clk}; #endif struct zynq_clk_priv { ulong ps_clk_freq; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD struct clk gem_emio_clk[2]; #endif }; @@ -75,7 +75,7 @@ static void *zynq_clk_get_register(enum zynq_clk id) return &slcr_base->uart_clk_ctrl; case spi0_clk ... spi1_clk: return &slcr_base->spi_clk_ctrl; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case dci_clk: return &slcr_base->dci_clk_ctrl; case gem0_clk: @@ -150,7 +150,7 @@ static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum zynq_clk id) return priv->ps_clk_freq * mul; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) { u32 clk_ctrl, srcsel; @@ -199,7 +199,7 @@ static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum zynq_clk id) return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) { u32 clk_ctrl, div; @@ -223,7 +223,7 @@ static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) { u32 clk_ctrl, div0, div1; @@ -251,7 +251,7 @@ static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, if (!div0) div0 = 1; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD if (two_divs) { div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; if (!div1) @@ -268,7 +268,7 @@ static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, div1); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) { struct clk *parent; @@ -366,7 +366,7 @@ static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id, } #endif -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong zynq_clk_get_rate(struct clk *clk) { struct zynq_clk_priv *priv = dev_get_priv(clk->dev); @@ -502,7 +502,7 @@ static void zynq_clk_dump(struct udevice *dev) static struct clk_ops zynq_clk_ops = { .get_rate = zynq_clk_get_rate, -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD .set_rate = zynq_clk_set_rate, #endif .enable = dummy_enable, @@ -514,7 +514,7 @@ static struct clk_ops zynq_clk_ops = { static int zynq_clk_probe(struct udevice *dev) { struct zynq_clk_priv *priv = dev_get_priv(dev); -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD unsigned int i; char name[16]; int ret; diff --git a/drivers/clk/exynos/Makefile b/drivers/clk/exynos/Makefile index 734100e2bff..77385864fef 100644 --- a/drivers/clk/exynos/Makefile +++ b/drivers/clk/exynos/Makefile @@ -7,6 +7,6 @@ # Thomas Abraham <thomas.ab@samsung.com> # Sam Protsenko <semen.protsenko@linaro.org> -obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk.o clk-pll.o +obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk.o clk-pll.o obj-$(CONFIG_CLK_EXYNOS7420) += clk-exynos7420.o obj-$(CONFIG_CLK_EXYNOS850) += clk-exynos850.o diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 6d4bcd35714..a89ee7acb12 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -2,25 +2,25 @@ # # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_$(SPL_TPL_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX6Q) += clk-imx6q.o +obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o +obj-$(CONFIG_$(PHASE_)CLK_IMX6Q) += clk-imx6q.o obj-$(CONFIG_CLK_IMX8) += clk-imx8.o ifdef CONFIG_CLK_IMX8 obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o obj-$(CONFIG_IMX8QM) += clk-imx8qm.o endif -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \ clk-gate-93.o clk-composite-93.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o -obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1170) += clk-imxrt1170.o +obj-$(CONFIG_$(PHASE_)CLK_IMXRT1020) += clk-imxrt1020.o +obj-$(CONFIG_$(PHASE_)CLK_IMXRT1050) += clk-imxrt1050.o +obj-$(CONFIG_$(PHASE_)CLK_IMXRT1170) += clk-imxrt1170.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index a91c6767fac..bb6958f0ec2 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -31,7 +31,7 @@ static const char * const imx8mm_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static const char * const imx8mm_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", }; @@ -95,7 +95,7 @@ static const char * const imx8mm_pcie1_aux_sels[] = {"clock-osc-24m", "sys_pll2_ "sys_pll1_160m", "sys_pll1_200m", }; #endif -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static const char * const imx8mm_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", }; @@ -357,7 +357,7 @@ static int imx8mm_clk_probe(struct udevice *dev) imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0)); /* clks not needed in SPL stage */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD clk_dm(IMX8MM_CLK_ENET_AXI, imx8m_clk_composite("enet_axi", imx8mm_enet_axi_sels, base + 0x8880)); diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 125215e84f4..be15ebd0e25 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -37,7 +37,7 @@ static const char * const imx8mn_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_2 "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", "video_pll_out", "sys_pll3_out", }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static const char * const imx8mn_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m", "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out", "video_pll_out", "clk_ext4", }; @@ -97,7 +97,7 @@ static const char * const imx8mn_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m" "sys_pll3_out", "audio_pll1_out", "video_pll_out", "audio_pll2_out", "sys_pll1_133m", }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static const char * const imx8mn_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll_out", }; @@ -359,7 +359,7 @@ static int imx8mn_clk_probe(struct udevice *dev) imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0)); /* clks not needed in SPL stage */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD clk_dm(IMX8MN_CLK_ENET_REF, imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels, base + 0xa980)); diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 34d91cd6880..1d04090ca00 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -197,6 +197,8 @@ static int imx8mp_clk_probe(struct udevice *dev) base = (void *)ANATOP_BASE_ADDR; + clk_dm(IMX8MP_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0)); + clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); diff --git a/drivers/clk/imx/clk-imx8qm.c b/drivers/clk/imx/clk-imx8qm.c index 62fed7e3e32..466d71786cf 100644 --- a/drivers/clk/imx/clk-imx8qm.c +++ b/drivers/clk/imx/clk-imx8qm.c @@ -48,6 +48,8 @@ ulong imx8_clk_get_rate(struct clk *clk) debug("%s(#%lu)\n", __func__, clk->id); switch (clk->id) { + case IMX8QM_CLK_DUMMY: + return 0; case IMX8QM_A53_DIV: resource = SC_R_A53; pm_clk = SC_PM_CLK_CPU; @@ -264,6 +266,8 @@ int __imx8_clk_enable(struct clk *clk, bool enable) debug("%s(#%lu)\n", __func__, clk->id); switch (clk->id) { + case IMX8QM_CLK_DUMMY: + return 0; case IMX8QM_I2C0_IPG_CLK: case IMX8QM_I2C0_CLK: case IMX8QM_I2C0_DIV: diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 18bdc08971b..79098623bc8 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -51,6 +51,8 @@ ulong imx8_clk_get_rate(struct clk *clk) debug("%s(#%lu)\n", __func__, clk->id); switch (clk->id) { + case IMX8QXP_CLK_DUMMY: + return 0; case IMX8QXP_A35_DIV: resource = SC_R_A35; pm_clk = SC_PM_CLK_CPU; @@ -248,6 +250,8 @@ int __imx8_clk_enable(struct clk *clk, bool enable) debug("%s(#%lu)\n", __func__, clk->id); switch (clk->id) { + case IMX8QXP_CLK_DUMMY: + return 0; case IMX8QXP_I2C0_CLK: case IMX8QXP_I2C0_IPG_CLK: resource = SC_R_I2C_0; diff --git a/drivers/clk/imx/clk-imxrt1020.c b/drivers/clk/imx/clk-imxrt1020.c index c80b02975aa..752434cb0ad 100644 --- a/drivers/clk/imx/clk-imxrt1020.c +++ b/drivers/clk/imx/clk-imxrt1020.c @@ -124,7 +124,7 @@ static int imxrt1020_clk_probe(struct udevice *dev) clk_dm(IMXRT1020_CLK_SEMC, imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD struct clk *clk, *clk1; clk_get_by_id(IMXRT1020_CLK_SEMC_SEL, &clk1); diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c index 754f3948427..2c029ec5a6e 100644 --- a/drivers/clk/imx/clk-imxrt1050.c +++ b/drivers/clk/imx/clk-imxrt1050.c @@ -144,6 +144,9 @@ static int imxrt1050_clk_probe(struct udevice *dev) clk_dm(IMXRT1050_CLK_AHB_PODF, imx_clk_divider("ahb_podf", "periph_sel", base + 0x14, 10, 3)); + clk_dm(IMXRT1050_CLK_IPG_PDOF, + imx_clk_divider("ipg_podf", "ahb_podf", + base + 0x14, 8, 2)); clk_dm(IMXRT1050_CLK_USDHC1_PODF, imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3)); @@ -180,7 +183,7 @@ static int imxrt1050_clk_probe(struct udevice *dev) struct clk *clk, *clk1; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* bypass pll1 before setting its rate */ clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 72ad4fd0e85..51f124869c9 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -66,6 +66,8 @@ #define CLKID_VDEC_HEVC_SEL 154 #define CLKID_VDEC_HEVC_DIV 155 +#define CLKID_XTAL 0x10000000 + #define XTAL_RATE 24000000 struct meson_clk { @@ -192,6 +194,7 @@ static struct meson_gate gates[] = { MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8), MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24), MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30), + MESON_GATE(CLKID_HDMI, HHI_HDMI_CLK_CNTL, 8), }; static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) @@ -267,6 +270,12 @@ static struct parm meson_vapb_1_div_parm = { int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL; +static struct parm meson_hdmi_div_parm = { + HHI_HDMI_CLK_CNTL, 0, 7, +}; + +int meson_hdmi_div_parent = CLKID_HDMI_SEL; + static ulong meson_div_get_rate(struct clk *clk, unsigned long id) { struct meson_clk *priv = dev_get_priv(clk->dev); @@ -292,6 +301,10 @@ static ulong meson_div_get_rate(struct clk *clk, unsigned long id) parm = &meson_vapb_1_div_parm; parent = meson_vapb_1_div_parent; break; + case CLKID_HDMI_DIV: + parm = &meson_hdmi_div_parm; + parent = meson_hdmi_div_parent; + break; default: return -ENOENT; } @@ -347,6 +360,10 @@ static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, parm = &meson_vapb_1_div_parm; parent = meson_vapb_1_div_parent; break; + case CLKID_HDMI_DIV: + parm = &meson_hdmi_div_parm; + parent = meson_hdmi_div_parent; + break; default: return -ENOENT; } @@ -443,6 +460,17 @@ static int meson_vapb_0_1_mux_parents[] = { CLKID_FCLK_DIV7, }; +static struct parm meson_hdmi_mux_parm = { + HHI_HDMI_CLK_CNTL, 9, 2, +}; + +static int meson_hdmi_mux_parents[] = { + CLKID_XTAL, + CLKID_FCLK_DIV4, + CLKID_FCLK_DIV3, + CLKID_FCLK_DIV5, +}; + static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) { struct meson_clk *priv = dev_get_priv(clk->dev); @@ -475,6 +503,10 @@ static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) parm = &meson_vapb_1_mux_parm; parents = meson_vapb_0_1_mux_parents; break; + case CLKID_HDMI_SEL: + parm = &meson_hdmi_mux_parm; + parents = meson_hdmi_mux_parents; + break; default: return -ENOENT; } @@ -532,6 +564,10 @@ static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, parm = &meson_vapb_1_mux_parm; parents = meson_vapb_0_1_mux_parents; break; + case CLKID_HDMI_SEL: + parm = &meson_hdmi_mux_parm; + parents = meson_hdmi_mux_parents; + break; default: /* Not a mux */ return -ENOENT; @@ -572,7 +608,7 @@ static unsigned long meson_clk81_get_rate(struct clk *clk) unsigned long parent_rate; uint reg; int parents[] = { - -1, + CLKID_XTAL, -1, CLKID_FCLK_DIV7, CLKID_MPLL1, @@ -727,6 +763,9 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) ulong rate; switch (id) { + case CLKID_XTAL: + rate = XTAL_RATE; + break; case CLKID_FIXED_PLL: case CLKID_SYS_PLL: rate = meson_pll_get_rate(clk, id); @@ -769,10 +808,14 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) case CLKID_VAPB_1: rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); break; + case CLKID_HDMI: + rate = meson_div_get_rate(clk, CLKID_HDMI_DIV); + break; case CLKID_VPU_0_DIV: case CLKID_VPU_1_DIV: case CLKID_VAPB_0_DIV: case CLKID_VAPB_1_DIV: + case CLKID_HDMI_DIV: rate = meson_div_get_rate(clk, id); break; case CLKID_VPU: @@ -781,6 +824,7 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) case CLKID_VAPB_SEL: case CLKID_VAPB_0_SEL: case CLKID_VAPB_1_SEL: + case CLKID_HDMI_SEL: rate = meson_mux_get_rate(clk, id); break; default: @@ -851,7 +895,11 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, case CLKID_VPU_1_DIV: case CLKID_VAPB_0_DIV: case CLKID_VAPB_1_DIV: + case CLKID_HDMI_DIV: return meson_div_set_rate(clk, id, rate, current_rate); + case CLKID_HDMI: + return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV, + rate, current_rate); default: return -ENOENT; } diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 0d2c0ac225c..d76fca5dba4 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -63,12 +63,21 @@ config CLK_QCOM_SM6115 on the Snapdragon SM6115 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_SM8150 + bool "Qualcomm SM8150 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon 8150 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SM8250 bool "Qualcomm SM8250 GCC" select CLK_QCOM help Say Y here to enable support for the Global Clock Controller on the Snapdragon SM8250 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. config CLK_QCOM_SM8550 bool "Qualcomm SM8550 GCC" diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index e223c131ee4..ab33f1c5faf 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o +obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o obj-$(CONFIG_CLK_QCOM_SM8650) += clock-sm8650.o diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c index 79c7606a225..25ca67e537d 100644 --- a/drivers/clk/qcom/clock-qcom.c +++ b/drivers/clk/qcom/clock-qcom.c @@ -13,6 +13,7 @@ */ #include <clk-uclass.h> +#include <linux/clk-provider.h> #include <dm.h> #include <dm/device-internal.h> #include <dm/lists.h> @@ -215,9 +216,127 @@ static int msm_clk_enable(struct clk *clk) return 0; } +static void dump_gplls(struct udevice *dev, phys_addr_t base) +{ + struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev); + u32 i; + bool locked; + u64 l, a, xo_rate = 19200000; + struct clk *clk = NULL; + struct udevice *xodev; + const phys_addr_t *gplls = data->dbg_pll_addrs; + + uclass_foreach_dev_probe(UCLASS_CLK, xodev) { + if (!strcmp(xodev->name, "xo-board") || !strcmp(xodev->name, "xo_board")) { + clk = dev_get_clk_ptr(xodev); + break; + } + } + + if (clk) { + xo_rate = clk_get_rate(clk); + + /* On SDM845 this needs to be divided by 2 for some reason */ + if (xo_rate && of_machine_is_compatible("qcom,sdm845")) + xo_rate /= 2; + } else { + printf("Can't find XO clock, XO_BOARD rate may be wrong\n"); + } + + printf("GPLL clocks:\n"); + printf("| GPLL | LOCKED | XO_BOARD | PLL_L | ALPHA |\n"); + printf("+--------+--------+-----------+------------+----------------+\n"); + for (i = 0; i < data->num_plls; i++) { + locked = !!(readl(gplls[i]) & BIT(31)); + l = readl(gplls[i] + 4) & (BIT(16) - 1); + a = readq(gplls[i] + 40) & (BIT(16) - 1); + printf("| GPLL%-2d | %-6s | %9llu * (%#-9llx + %#-13llx * 2 ** -40 ) / 1000000\n", + i, locked ? "X" : "", xo_rate, l, a); + } +} + +static void dump_rcgs(struct udevice *dev) +{ + struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev); + int i; + u32 cmd; + u32 cfg; + u32 not_n_minus_m; + u32 src, m, n, div; + bool root_on, d_odd; + + printf("\nRCGs:\n"); + + /* + * Which GPLL SRC corresponds to depends on the parent map, see gcc-<soc>.c in Linux + * and find the parent map associated with the clock. Note that often there are multiple + * outputs from a single GPLL where one is actually half the rate of the other (_EVEN). + * intput_freq = associated GPLL output freq (potentially divided depending on SRC). + */ + printf("| NAME | ON | SRC | OUT_FREQ = input_freq * (m/n) * (1/d) | [CMD REG ] |\n"); + printf("+----------------------------------+----+-----+---------------------------------------+--------------+\n"); + for (i = 0; i < data->num_rcgs; i++) { + cmd = readl(data->dbg_rcg_addrs[i]); + cfg = readl(data->dbg_rcg_addrs[i] + 0x4); + m = readl(data->dbg_rcg_addrs[i] + 0x8); + n = 0; + not_n_minus_m = readl(data->dbg_rcg_addrs[i] + 0xc); + + root_on = !(cmd & BIT(31)); // ROOT_OFF + src = (cfg >> 8) & 7; + + if (not_n_minus_m) { + n = (~not_n_minus_m & 0xffff); + + /* A clumsy assumption that this is an 8-bit MND RCG */ + if ((n & 0xff00) == 0xff00) + n = n & 0xff; + + n += m; + } + + div = ((cfg & 0b11111) + 1) / 2; + d_odd = ((cfg & 0b11111) + 1) % 2 == 1; + printf("%-34s | %-2s | %3d | input_freq * (%4d/%5d) * (1/%1d%-2s) | [%#010x]\n", + data->dbg_rcg_names[i], root_on ? "X" : "", src, + m ?: 1, n ?: 1, div, d_odd ? ".5" : "", cmd); + } + + printf("\n"); +} + +static void __maybe_unused msm_dump_clks(struct udevice *dev) +{ + struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev); + struct msm_clk_priv *priv = dev_get_priv(dev); + const struct gate_clk *sclk; + int val, i; + + if (!data->clks) { + printf("No clocks\n"); + return; + } + + printf("Gate Clocks:\n"); + for (i = 0; i < data->num_clks; i++) { + sclk = &data->clks[i]; + if (!sclk->name) + continue; + printf("%-32s: ", sclk->name); + val = readl(priv->base + sclk->reg) & sclk->en_val; + printf("%s\n", val ? "ON" : ""); + } + + dump_gplls(dev, priv->base); + dump_rcgs(dev); +} + static struct clk_ops msm_clk_ops = { .set_rate = msm_clk_set_rate, .enable = msm_clk_enable, +#if IS_ENABLED(CONFIG_CMD_CLK) + .dump = msm_dump_clks, +#endif }; U_BOOT_DRIVER(qcom_clk) = { diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index 7aa6ca59aad..78d9b1d81ec 100644 --- a/drivers/clk/qcom/clock-qcom.h +++ b/drivers/clk/qcom/clock-qcom.h @@ -77,6 +77,12 @@ struct msm_clk_data { const struct gate_clk *clks; unsigned long num_clks; + const phys_addr_t *dbg_pll_addrs; + unsigned long num_plls; + const phys_addr_t *dbg_rcg_addrs; + unsigned long num_rcgs; + const char * const *dbg_rcg_names; + int (*enable)(struct clk *clk); unsigned long (*set_rate)(struct clk *clk, unsigned long rate); }; diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c index f41f8c9e8de..adffb0cb240 100644 --- a/drivers/clk/qcom/clock-sdm845.c +++ b/drivers/clk/qcom/clock-sdm845.c @@ -203,6 +203,94 @@ static const struct qcom_power_map sdm845_gdscs[] = { [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = { 0x7d044 }, }; +static const phys_addr_t sdm845_gpll_addrs[] = { + 0x00100000, // GCC_GPLL0_MODE + 0x00101000, // GCC_GPLL1_MODE + 0x00102000, // GCC_GPLL2_MODE + 0x00103000, // GCC_GPLL3_MODE + 0x00176000, // GCC_GPLL4_MODE + 0x00174000, // GCC_GPLL5_MODE + 0x00113000, // GCC_GPLL6_MODE +}; + +static const phys_addr_t sdm845_rcg_addrs[] = { + 0x0010f018, // GCC_USB30_PRIM_MASTER + 0x0010f030, // GCC_USB30_PRIM_MOCK_UTMI + 0x0010f05c, // GCC_USB3_PRIM_PHY_AUX + 0x00110018, // GCC_USB30_SEC_MASTER + 0x00110030, // GCC_USB30_SEC_MOCK_UTMI + 0x0011005c, // GCC_USB3_SEC_PHY_AUX + 0x0011400c, // GCC_SDCC2_APPS + 0x0011600c, // GCC_SDCC4_APPS + 0x00117018, // GCC_QUPV3_WRAP0_CORE_2X + 0x00117034, // GCC_QUPV3_WRAP0_S0 + 0x00117164, // GCC_QUPV3_WRAP0_S1 + 0x00117294, // GCC_QUPV3_WRAP0_S2 + 0x001173c4, // GCC_QUPV3_WRAP0_S3 + 0x001174f4, // GCC_QUPV3_WRAP0_S4 + 0x00117624, // GCC_QUPV3_WRAP0_S5 + 0x00117754, // GCC_QUPV3_WRAP0_S6 + 0x00117884, // GCC_QUPV3_WRAP0_S7 + 0x00118018, // GCC_QUPV3_WRAP1_S0 + 0x00118148, // GCC_QUPV3_WRAP1_S1 + 0x00118278, // GCC_QUPV3_WRAP1_S2 + 0x001183a8, // GCC_QUPV3_WRAP1_S3 + 0x001184d8, // GCC_QUPV3_WRAP1_S4 + 0x00118608, // GCC_QUPV3_WRAP1_S5 + 0x00118738, // GCC_QUPV3_WRAP1_S6 + 0x00118868, // GCC_QUPV3_WRAP1_S7 + 0x0016b028, // GCC_PCIE_0_AUX + 0x0018d028, // GCC_PCIE_1_AUX + 0x0016f014, // GCC_PCIE_PHY_REFGEN + 0x0017501c, // GCC_UFS_CARD_AXI + 0x0017505c, // GCC_UFS_CARD_ICE_CORE + 0x00175074, // GCC_UFS_CARD_UNIPRO_CORE + 0x00175090, // GCC_UFS_CARD_PHY_AUX + 0x0017701c, // GCC_UFS_PHY_AXI + 0x0017705c, // GCC_UFS_PHY_ICE_CORE + 0x00177074, // GCC_UFS_PHY_UNIPRO_CORE + 0x00177090, // GCC_UFS_PHY_PHY_AUX +}; + +static const char *const sdm845_rcg_names[] = { + "GCC_USB30_PRIM_MASTER", + "GCC_USB30_PRIM_MOCK_UTMI", + "GCC_USB3_PRIM_PHY_AUX", + "GCC_USB30_SEC_MASTER", + "GCC_USB30_SEC_MOCK_UTMI", + "GCC_USB3_SEC_PHY_AUX", + "GCC_SDCC2_APPS", + "GCC_SDCC4_APPS", + "GCC_QUPV3_WRAP0_CORE_2X", + "GCC_QUPV3_WRAP0_S0", + "GCC_QUPV3_WRAP0_S1", + "GCC_QUPV3_WRAP0_S2", + "GCC_QUPV3_WRAP0_S3", + "GCC_QUPV3_WRAP0_S4", + "GCC_QUPV3_WRAP0_S5", + "GCC_QUPV3_WRAP0_S6", + "GCC_QUPV3_WRAP0_S7", + "GCC_QUPV3_WRAP1_S0", + "GCC_QUPV3_WRAP1_S1", + "GCC_QUPV3_WRAP1_S2", + "GCC_QUPV3_WRAP1_S3", + "GCC_QUPV3_WRAP1_S4", + "GCC_QUPV3_WRAP1_S5", + "GCC_QUPV3_WRAP1_S6", + "GCC_QUPV3_WRAP1_S7", + "GCC_PCIE_0_AUX", + "GCC_PCIE_1_AUX", + "GCC_PCIE_PHY_REFGEN", + "GCC_UFS_CARD_AXI", + "GCC_UFS_CARD_ICE_CORE", + "GCC_UFS_CARD_UNIPRO_CORE", + "GCC_UFS_CARD_PHY_AUX", + "GCC_UFS_PHY_AXI", + "GCC_UFS_PHY_ICE_CORE", + "GCC_UFS_PHY_UNIPRO_CORE", + "GCC_UFS_PHY_PHY_AUX", +}; + static struct msm_clk_data sdm845_clk_data = { .resets = sdm845_gcc_resets, .num_resets = ARRAY_SIZE(sdm845_gcc_resets), @@ -213,6 +301,11 @@ static struct msm_clk_data sdm845_clk_data = { .enable = sdm845_clk_enable, .set_rate = sdm845_clk_set_rate, + .dbg_pll_addrs = sdm845_gpll_addrs, + .num_plls = ARRAY_SIZE(sdm845_gpll_addrs), + .dbg_rcg_addrs = sdm845_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sdm845_rcg_addrs), + .dbg_rcg_names = sdm845_rcg_names, }; static const struct udevice_id gcc_sdm845_of_match[] = { diff --git a/drivers/clk/qcom/clock-sm6115.c b/drivers/clk/qcom/clock-sm6115.c index 8314a0deb34..9057dfe0bb1 100644 --- a/drivers/clk/qcom/clock-sm6115.c +++ b/drivers/clk/qcom/clock-sm6115.c @@ -170,6 +170,63 @@ static const struct qcom_power_map sm6115_gdscs[] = { [GCC_USB30_PRIM_GDSC] = { 0x1a004 }, }; +static const phys_addr_t sm6115_gpll_addrs[] = { + 0x01400000, // GCC_GPLL0_MODE + 0x01401000, // GCC_GPLL1_MODE + 0x01402000, // GCC_GPLL2_MODE + 0x01403000, // GCC_GPLL3_MODE + 0x01404000, // GCC_GPLL4_MODE + 0x01405000, // GCC_GPLL5_MODE + 0x01406000, // GCC_GPLL6_MODE + 0x01407000, // GCC_GPLL7_MODE + 0x01408000, // GCC_GPLL8_MODE + 0x01409000, // GCC_GPLL9_MODE + 0x0140a000, // GCC_GPLL10_MODE + 0x0140b000, // GCC_GPLL11_MODE +}; + +static const phys_addr_t sm6115_rcg_addrs[] = { + 0x0141a01c, // GCC_USB30_PRIM_MASTER_CMD_RCGR + 0x0141a034, // GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR + 0x0141a060, // GCC_USB3_PRIM_PHY_AUX_CMD_RCGR + 0x01438028, // GCC_SDCC1_APPS_CMD_RCGR + 0x0141e00c, // GCC_SDCC2_APPS_CMD_RCGR + 0x0141f018, // GCC_QUPV3_WRAP0_CORE_2X_CMD_RCGR + 0x0141f148, // GCC_QUPV3_WRAP0_S0_CMD_RCGR + 0x0141f278, // GCC_QUPV3_WRAP0_S1_CMD_RCGR + 0x0141f3a8, // GCC_QUPV3_WRAP0_S2_CMD_RCGR + 0x0141f4d8, // GCC_QUPV3_WRAP0_S3_CMD_RCGR + 0x0141f608, // GCC_QUPV3_WRAP0_S4_CMD_RCGR + 0x0141f738, // GCC_QUPV3_WRAP0_S5_CMD_RCGR + 0x01428014, // GCC_SLEEP_CMD_RCGR + 0x0142802c, // GCC_XO_CMD_RCGR + 0x01445020, // GCC_UFS_PHY_AXI_CMD_RCGR + 0x01445048, // GCC_UFS_PHY_ICE_CORE_CMD_RCGR + 0x01445060, // GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR + 0x0144507c, // GCC_UFS_PHY_PHY_AUX_CMD_RCGR +}; + +static const char *const sm6115_rcg_names[] = { + "GCC_USB30_PRIM_MASTER_CMD_RCGR", + "GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR", + "GCC_USB3_PRIM_PHY_AUX_CMD_RCGR", + "GCC_SDCC1_APPS_CMD_RCGR", + "GCC_SDCC2_APPS_CMD_RCGR", + "GCC_QUPV3_WRAP0_CORE_2X_CMD_RCGR", + "GCC_QUPV3_WRAP0_S0_CMD_RCGR", + "GCC_QUPV3_WRAP0_S1_CMD_RCGR", + "GCC_QUPV3_WRAP0_S2_CMD_RCGR", + "GCC_QUPV3_WRAP0_S3_CMD_RCGR", + "GCC_QUPV3_WRAP0_S4_CMD_RCGR", + "GCC_QUPV3_WRAP0_S5_CMD_RCGR", + "GCC_SLEEP_CMD_RCGR", + "GCC_XO_CMD_RCGR", + "GCC_UFS_PHY_AXI_CMD_RCGR", + "GCC_UFS_PHY_ICE_CORE_CMD_RCGR", + "GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR", + "GCC_UFS_PHY_PHY_AUX_CMD_RCGR", +}; + static struct msm_clk_data sm6115_gcc_data = { .resets = sm6115_gcc_resets, .num_resets = ARRAY_SIZE(sm6115_gcc_resets), @@ -180,6 +237,12 @@ static struct msm_clk_data sm6115_gcc_data = { .enable = sm6115_enable, .set_rate = sm6115_set_rate, + + .dbg_pll_addrs = sm6115_gpll_addrs, + .num_plls = ARRAY_SIZE(sm6115_gpll_addrs), + .dbg_rcg_addrs = sm6115_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm6115_rcg_addrs), + .dbg_rcg_names = sm6115_rcg_names, }; static const struct udevice_id gcc_sm6115_of_match[] = { diff --git a/drivers/clk/qcom/clock-sm8150.c b/drivers/clk/qcom/clock-sm8150.c new file mode 100644 index 00000000000..88f2e678f43 --- /dev/null +++ b/drivers/clk/qcom/clock-sm8150.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm SM8150 + * + * Volodymyr Babchuk <volodymyr_babchuk@epam.com> + * Copyright (c) 2024 EPAM Systems. + * + * (C) Copyright 2024 Julius Lehmann <lehmanju@devpi.de> + * + * Based on U-Boot driver for SM8250. Constants are taken from the Linux driver. + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,gcc-sm8150.h> + +#include "clock-qcom.h" + +#define EMAC_RGMII_CLK_CMD_RCGR 0x601c +#define QUPV3_WRAP0_S0_CLK_CMD_RCGR 0x18148 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034 +#define USB30_PRIM_PHY_AUX_CLK_CMD_RCGR 0xf060 +#define USB30_SEC_MASTER_CLK_CMD_RCGR 0x1001c +#define USB30_SEC_MOCK_UTMI_CLK_CMD_RCGR 0x10034 +#define USB30_SEC_PHY_AUX_CLK_CMD_RCGR 0x10060 +#define SDCC2_APPS_CLK_CMD_RCGR 0x1400c + +static struct pll_vote_clk gpll7_vote_clk = { + .status = 0x1a000, + .status_bit = BIT(31), + .ena_vote = 0x52000, + .vote_bit = BIT(7), +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75), + { } +}; + +static const struct freq_tbl ftbl_gcc_emac_rgmii_clk_src[] = { + F(2500000, CFG_CLK_SRC_CXO, 1, 25, 192), + F(5000000, CFG_CLK_SRC_CXO, 1, 25, 96), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(125000000, CFG_CLK_SRC_GPLL7, 4, 0, 0), + F(250000000, CFG_CLK_SRC_GPLL7, 2, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(33333333, CFG_CLK_SRC_GPLL0_EVEN, 9, 0, 0), + F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), + F(133333333, CFG_CLK_SRC_GPLL0, 4.5, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 15, 0, 0), + F(60000000, CFG_CLK_SRC_GPLL0_EVEN, 5, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0, 12, 1, 2), + F(50000000, CFG_CLK_SRC_GPLL0, 12, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(202000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + { } +}; + +static ulong sm8150_clk_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S4_CLK: /* UART2 aka debug-uart */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, QUPV3_WRAP0_S0_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_EMAC_RGMII_CLK: + freq = qcom_find_freq(ftbl_gcc_emac_rgmii_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, EMAC_RGMII_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MASTER_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_USB3_PRIM_PHY_AUX_CLK_SRC: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_USB30_SEC_MASTER_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_SEC_MASTER_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_SEC_MOCK_UTMI_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_SEC_MOCK_UTMI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_USB3_SEC_PHY_AUX_CLK_SRC: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_SEC_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_SDCC2_APPS_CLK: + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SDCC2_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + default: + return 0; + } +} + +static const struct gate_clk sm8150_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_CARD_AXI_CLK, 0x750c0, 0x00000001), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770c0, 0x00000001), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0xf07c, 0x00000001), + GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x1007c, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0xf078, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x10078, 0x00000001), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, 0x00001000), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, 0x00002000), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, 0x00004000), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, 0x00008000), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, 0x00400000), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, 0x00800000), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, 0x02000000), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, 0x04000000), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, 0x08000000), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, 0x00000040), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, 0x00000080), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, 0x00100000), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, 0x00200000), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, 0x00000001), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, 0x00000001), + GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, 0x00000001), + GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, 0x00000001), + GATE_CLK(GCC_UFS_CARD_AHB_CLK, 0x75014, 0x00000001), + GATE_CLK(GCC_UFS_CARD_AXI_CLK, 0x75010, 0x00000001), + GATE_CLK(GCC_UFS_CARD_CLKREF_CLK, 0x8c004, 0x00000001), + GATE_CLK(GCC_UFS_CARD_ICE_CORE_CLK, 0x7505c, 0x00000001), + GATE_CLK(GCC_UFS_CARD_PHY_AUX_CLK, 0x75090, 0x00000001), + GATE_CLK(GCC_UFS_CARD_RX_SYMBOL_0_CLK, 0x7501c, 0x00000001), + GATE_CLK(GCC_UFS_CARD_RX_SYMBOL_1_CLK, 0x750ac, 0x00000001), + GATE_CLK(GCC_UFS_CARD_TX_SYMBOL_0_CLK, 0x75018, 0x00000001), + GATE_CLK(GCC_UFS_CARD_UNIPRO_CORE_CLK, 0x75058, 0x00000001), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, 0x00000001), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x7705c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77090, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x770ac, 0x00000001), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, 0x00000001), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77058, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f00c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f014, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f010, 0x00000001), + GATE_CLK(GCC_USB30_SEC_MASTER_CLK, 0x1000c, 0x00000001), + GATE_CLK(GCC_USB30_SEC_MOCK_UTMI_CLK, 0x10014, 0x00000001), + GATE_CLK(GCC_USB30_SEC_SLEEP_CLK, 0x10010, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c008, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f04c, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f050, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f054, 0x00000001), + GATE_CLK(GCC_USB3_SEC_CLKREF_CLK, 0x8c028, 0x00000001), + GATE_CLK(GCC_USB3_SEC_PHY_AUX_CLK, 0x1004c, 0x00000001), + GATE_CLK(GCC_USB3_SEC_PHY_PIPE_CLK, 0x10054, 0x00000001), + GATE_CLK(GCC_USB3_SEC_PHY_COM_AUX_CLK, 0x10050, 0x00000001), + GATE_CLK(GCC_EMAC_AXI_CLK, 0x06010, 0x00000001), + GATE_CLK(GCC_EMAC_SLV_AHB_CLK, 0x06014, 0x00000001), + GATE_CLK(GCC_EMAC_PTP_CLK, 0x06034, 0x00000001), + GATE_CLK(GCC_EMAC_RGMII_CLK, 0x06018, 0x00000001), +}; + +static int sm8150_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks <= clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm8150_clks[clk->id].name); + + switch (clk->id) { + case GCC_EMAC_RGMII_CLK: + clk_enable_gpll0(priv->base, &gpll7_vote_clk); + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + case GCC_AGGRE_USB3_SEC_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_SEC_MASTER_CLK); + fallthrough; + case GCC_USB30_SEC_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_SEC_PHY_COM_AUX_CLK); + break; + }; + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map sm8150_gcc_resets[] = { + [GCC_EMAC_BCR] = { 0x6000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_MMSS_BCR] = { 0xb000 }, + [GCC_NPU_BCR] = { 0x4d000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_PRNG_BCR] = { 0x34000 }, + [GCC_QSPI_BCR] = { 0x24008 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x17000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_TSIF_BCR] = { 0x36000 }, + [GCC_UFS_CARD_BCR] = { 0x75000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB30_SEC_BCR] = { 0x10000 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, +}; + +static const struct qcom_power_map sm8150_gcc_power_domains[] = { + [EMAC_GDSC] = { 0x6004 }, + [PCIE_0_GDSC] = { 0x6b004 }, + [PCIE_1_GDSC] = { 0x8d004 }, + [UFS_CARD_GDSC] = { 0x75004 }, + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, + [USB30_SEC_GDSC] = { 0x10004 }, +}; + +static struct msm_clk_data sm8150_clk_data = { + .resets = sm8150_gcc_resets, + .num_resets = ARRAY_SIZE(sm8150_gcc_resets), + .clks = sm8150_clks, + .num_clks = ARRAY_SIZE(sm8150_clks), + .power_domains = sm8150_gcc_power_domains, + .num_power_domains = ARRAY_SIZE(sm8150_gcc_power_domains), + + .enable = sm8150_clk_enable, + .set_rate = sm8150_clk_set_rate, +}; + +static const struct udevice_id gcc_sm8150_of_match[] = { + { + .compatible = "qcom,gcc-sm8150", + .data = (ulong)&sm8150_clk_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_sm8150) = { + .name = "gcc_sm8150", + .id = UCLASS_NOP, + .of_match = gcc_sm8150_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c index af10fc11621..e322a923a5c 100644 --- a/drivers/clk/qcom/clock-sm8250.c +++ b/drivers/clk/qcom/clock-sm8250.c @@ -253,6 +253,115 @@ static const struct qcom_power_map sm8250_gdscs[] = { [USB30_SEC_GDSC] = { 0x10004 }, }; +static const phys_addr_t sm8250_gpll_addrs[] = { + 0x00100000, // GCC_GPLL0_MODE + 0x00101000, // GCC_GPLL1_MODE + 0x00102000, // GCC_GPLL2_MODE + 0x00103000, // GCC_GPLL3_MODE + 0x00176000, // GCC_GPLL4_MODE + 0x00174000, // GCC_GPLL5_MODE + 0x00113000, // GCC_GPLL6_MODE + 0x0011a000, // GCC_GPLL7_MODE + 0x0011b000, // GCC_GPLL8_MODE + 0x0011c000, // GCC_GPLL9_MODE + 0x0011d000, // GCC_GPLL10_MODE + 0x0014a000, // GCC_GPLL11_MODE +}; + +static const phys_addr_t sm8250_rcg_addrs[] = { + 0x0010f020, // GCC_USB30_PRIM_MASTER_CMD_RCGR + 0x0010f038, // GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR + 0x0010f064, // GCC_USB3_PRIM_PHY_AUX_CMD_RCGR + 0x00110020, // GCC_USB30_SEC_MASTER_CMD_RCGR + 0x00110038, // GCC_USB30_SEC_MOCK_UTMI_CMD_RCGR + 0x00110064, // GCC_USB3_SEC_PHY_AUX_CMD_RCGR + 0x0011400c, // GCC_SDCC2_APPS_CMD_RCGR + 0x0011600c, // GCC_SDCC4_APPS_CMD_RCGR + 0x0012300c, // GCC_QUPV3_WRAP0_CORE_2X_CMD_RCGR + 0x00117010, // GCC_QUPV3_WRAP0_S0_CMD_RCGR + 0x00117140, // GCC_QUPV3_WRAP0_S1_CMD_RCGR + 0x00117270, // GCC_QUPV3_WRAP0_S2_CMD_RCGR + 0x001173a0, // GCC_QUPV3_WRAP0_S3_CMD_RCGR + 0x001174d0, // GCC_QUPV3_WRAP0_S4_CMD_RCGR + 0x00117600, // GCC_QUPV3_WRAP0_S5_CMD_RCGR + 0x00117730, // GCC_QUPV3_WRAP0_S6_CMD_RCGR + 0x00117860, // GCC_QUPV3_WRAP0_S7_CMD_RCGR + 0x00123144, // GCC_QUPV3_WRAP1_CORE_2X_CMD_RCGR + 0x00118010, // GCC_QUPV3_WRAP1_S0_CMD_RCGR + 0x00118140, // GCC_QUPV3_WRAP1_S1_CMD_RCGR + 0x00118270, // GCC_QUPV3_WRAP1_S2_CMD_RCGR + 0x001183a0, // GCC_QUPV3_WRAP1_S3_CMD_RCGR + 0x001184d0, // GCC_QUPV3_WRAP1_S4_CMD_RCGR + 0x00118600, // GCC_QUPV3_WRAP1_S5_CMD_RCGR + 0x0016b038, // GCC_PCIE_0_AUX_CMD_RCGR + 0x0018d038, // GCC_PCIE_1_AUX_CMD_RCGR + 0x0016f014, // GCC_PCIE_PHY_REFGEN_CMD_RCGR + 0x00175024, // GCC_UFS_CARD_AXI_CMD_RCGR + 0x0017506c, // GCC_UFS_CARD_ICE_CORE_CMD_RCGR + 0x00175084, // GCC_UFS_CARD_UNIPRO_CORE_CMD_RCGR + 0x001750a0, // GCC_UFS_CARD_PHY_AUX_CMD_RCGR + 0x00177024, // GCC_UFS_PHY_AXI_CMD_RCGR + 0x0017706c, // GCC_UFS_PHY_ICE_CORE_CMD_RCGR + 0x00177084, // GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR + 0x001770a0, // GCC_UFS_PHY_PHY_AUX_CMD_RCGR + 0x0012327c, // GCC_QUPV3_WRAP2_CORE_2X_CMD_RCGR + 0x0011e010, // GCC_QUPV3_WRAP2_S0_CMD_RCGR + 0x0011e140, // GCC_QUPV3_WRAP2_S1_CMD_RCGR + 0x0011e270, // GCC_QUPV3_WRAP2_S2_CMD_RCGR + 0x0011e3a0, // GCC_QUPV3_WRAP2_S3_CMD_RCGR + 0x0011e4d0, // GCC_QUPV3_WRAP2_S4_CMD_RCGR + 0x0011e600, // GCC_QUPV3_WRAP2_S5_CMD_RCGR + 0x0010d00c, // GCC_RBCPR_MMCX_CMD_RCGR + 0x00106038, // GCC_PCIE_2_AUX_CMD_RCGR +}; + +static const char *const sm8250_rcg_names[] = { + "GCC_USB30_PRIM_MASTER_CMD_RCGR", + "GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR", + "GCC_USB3_PRIM_PHY_AUX_CMD_RCGR", + "GCC_USB30_SEC_MASTER_CMD_RCGR", + "GCC_USB30_SEC_MOCK_UTMI_CMD_RCGR", + "GCC_USB3_SEC_PHY_AUX_CMD_RCGR", + "GCC_SDCC2_APPS_CMD_RCGR", + "GCC_SDCC4_APPS_CMD_RCGR", + "GCC_QUPV3_WRAP0_CORE_2X_CMD_RCGR", + "GCC_QUPV3_WRAP0_S0_CMD_RCGR", + "GCC_QUPV3_WRAP0_S1_CMD_RCGR", + "GCC_QUPV3_WRAP0_S2_CMD_RCGR", + "GCC_QUPV3_WRAP0_S3_CMD_RCGR", + "GCC_QUPV3_WRAP0_S4_CMD_RCGR", + "GCC_QUPV3_WRAP0_S5_CMD_RCGR", + "GCC_QUPV3_WRAP0_S6_CMD_RCGR", + "GCC_QUPV3_WRAP0_S7_CMD_RCGR", + "GCC_QUPV3_WRAP1_CORE_2X_CMD_RCGR", + "GCC_QUPV3_WRAP1_S0_CMD_RCGR", + "GCC_QUPV3_WRAP1_S1_CMD_RCGR", + "GCC_QUPV3_WRAP1_S2_CMD_RCGR", + "GCC_QUPV3_WRAP1_S3_CMD_RCGR", + "GCC_QUPV3_WRAP1_S4_CMD_RCGR", + "GCC_QUPV3_WRAP1_S5_CMD_RCGR", + "GCC_PCIE_0_AUX_CMD_RCGR", + "GCC_PCIE_1_AUX_CMD_RCGR", + "GCC_PCIE_PHY_REFGEN_CMD_RCGR", + "GCC_UFS_CARD_AXI_CMD_RCGR", + "GCC_UFS_CARD_ICE_CORE_CMD_RCGR", + "GCC_UFS_CARD_UNIPRO_CORE_CMD_RCGR", + "GCC_UFS_CARD_PHY_AUX_CMD_RCGR", + "GCC_UFS_PHY_AXI_CMD_RCGR", + "GCC_UFS_PHY_ICE_CORE_CMD_RCGR", + "GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR", + "GCC_UFS_PHY_PHY_AUX_CMD_RCGR", + "GCC_QUPV3_WRAP2_CORE_2X_CMD_RCGR", + "GCC_QUPV3_WRAP2_S0_CMD_RCGR", + "GCC_QUPV3_WRAP2_S1_CMD_RCGR", + "GCC_QUPV3_WRAP2_S2_CMD_RCGR", + "GCC_QUPV3_WRAP2_S3_CMD_RCGR", + "GCC_QUPV3_WRAP2_S4_CMD_RCGR", + "GCC_QUPV3_WRAP2_S5_CMD_RCGR", + "GCC_RBCPR_MMCX_CMD_RCGR", + "GCC_PCIE_2_AUX_CMD_RCGR", +}; + static struct msm_clk_data qcs404_gcc_data = { .resets = sm8250_gcc_resets, .num_resets = ARRAY_SIZE(sm8250_gcc_resets), @@ -263,6 +372,12 @@ static struct msm_clk_data qcs404_gcc_data = { .enable = sm8250_enable, .set_rate = sm8250_set_rate, + + .dbg_pll_addrs = sm8250_gpll_addrs, + .num_plls = ARRAY_SIZE(sm8250_gpll_addrs), + .dbg_rcg_addrs = sm8250_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm8250_rcg_addrs), + .dbg_rcg_names = sm8250_rcg_names, }; static const struct udevice_id gcc_sm8250_of_match[] = { diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index b84024266f4..4f1dfbc174a 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -69,7 +69,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return ret; if (core->type == CLK_TYPE_GEN3_MDSEL) { - shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; + shift = priv->cpg_mode & BIT(core->offset) ? 0 : 16; parent->dev = clk->dev; parent->id = core->parent >> shift; parent->id &= 0xffff; @@ -318,7 +318,7 @@ static u64 gen3_clk_get_rate64(struct clk *clk) "FIXED"); case CLK_TYPE_GEN3_MDSEL: - shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; + shift = priv->cpg_mode & BIT(core->offset) ? 0 : 16; div = (core->div >> shift) & 0xffff; rate = gen3_clk_get_rate64(&parent) / div; debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n", diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index b44d5603edd..7875a990c2f 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -55,6 +55,17 @@ enum clk_ids { DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL2X_3X, CLK_MAIN, \ .offset = _offset) +#define CPG_PLL20CR 0x0834 /* PLL20 Control Register */ +#define CPG_PLL21CR 0x0838 /* PLL21 Control Register */ +#define CPG_PLL30CR 0x083c /* PLL30 Control Register */ +#define CPG_PLL31CR 0x0840 /* PLL31 Control Register */ + +#define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ +#define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ +#define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ +#define CPG_CSICKCR 0x880 /* CSI Clock Frequency Control Register */ +#define CPG_DSIEXTCKCR 0x884 /* DSI Clock Frequency Control Register */ + static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), @@ -64,10 +75,10 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN), DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), - DEF_PLL(".pll20", CLK_PLL20, 0x0834), - DEF_PLL(".pll21", CLK_PLL21, 0x0838), - DEF_PLL(".pll30", CLK_PLL30, 0x083c), - DEF_PLL(".pll31", CLK_PLL31, 0x0840), + DEF_PLL(".pll20", CLK_PLL20, CPG_PLL20CR), + DEF_PLL(".pll21", CLK_PLL21, CPG_PLL21CR), + DEF_PLL(".pll30", CLK_PLL30, CPG_PLL30CR), + DEF_PLL(".pll31", CLK_PLL31, CPG_PLL31CR), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), DEF_FIXED(".pll20_div2", CLK_PLL20_DIV2, CLK_PLL20, 2, 1), @@ -110,17 +121,17 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_FIXED("cp", R8A779A0_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cl16mck", R8A779A0_CLK_CL16MCK, CLK_PLL1_DIV2, 64, 1), - DEF_GEN4_SDH("sd0h", R8A779A0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779A0_CLK_SD0, R8A779A0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779A0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779A0_CLK_SD0, R8A779A0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779A0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779A0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779A0_CLK_RPC), - DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), - DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880), - DEF_DIV6P1("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, 0x884), + DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), + DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, CPG_CSICKCR), + DEF_DIV6P1("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), DEF_GEN4_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8), DEF_GEN4_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index ea98bc6e50c..fdca63a3e8e 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -15,6 +15,12 @@ #include "renesas-cpg-mssr.h" #include "rcar-gen3-cpg.h" +#define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ +#define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ +#define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ +#define CPG_CSICKCR 0x880 /* CSI Clock Frequency Control Register */ +#define CPG_DSIEXTCKCR 0x884 /* DSI Clock Frequency Control Register */ + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R8A779F0_CLK_R, @@ -110,13 +116,13 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { DEF_FIXED("sasyncperd2",R8A779F0_CLK_SASYNCPERD2, CLK_SASYNCPER,2, 1), DEF_FIXED("sasyncperd4",R8A779F0_CLK_SASYNCPERD4, CLK_SASYNCPER,4, 1), - DEF_GEN4_SDH("sd0h", R8A779F0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779F0_CLK_SD0, R8A779F0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779F0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779F0_CLK_SD0, R8A779F0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779F0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779F0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779F0_CLK_RPC), - DEF_DIV6P1("mso", R8A779F0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_DIV6P1("mso", R8A779F0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), DEF_GEN4_OSC("osc", R8A779F0_CLK_OSC, CLK_EXTAL, 8), DEF_GEN4_MDSEL("r", R8A779F0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index 4df0a69cfe1..9fb672a5369 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -15,6 +15,12 @@ #include "renesas-cpg-mssr.h" #include "rcar-gen3-cpg.h" +#define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ +#define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ +#define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ +#define CPG_CSICKCR 0x880 /* CSI Clock Frequency Control Register */ +#define CPG_DSIEXTCKCR 0x884 /* DSI Clock Frequency Control Register */ + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R8A779G0_CLK_CP, @@ -141,14 +147,14 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { DEF_FIXED("viobusd2", R8A779G0_CLK_VIOBUSD2, CLK_VIO, 2, 1), DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1), DEF_FIXED("vcbusd2", R8A779G0_CLK_VCBUSD2, CLK_VC, 2, 1), - DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi", R8A779G0_CLK_CSI, CLK_PLL5_DIV4, 0x880), + DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi", R8A779G0_CLK_CSI, CLK_PLL5_DIV4, CPG_CSICKCR), DEF_FIXED("dsiref", R8A779G0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1), - DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884), + DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), - DEF_GEN4_SDH("sd0h", R8A779G0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779G0_CLK_SD0, R8A779G0_CLK_SD0H, 0x870), - DEF_DIV6P1("mso", R8A779G0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_GEN4_SDH("sd0h", R8A779G0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779G0_CLK_SD0, R8A779G0_CLK_SD0H, CPG_SD0CKCR), + DEF_DIV6P1("mso", R8A779G0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), DEF_BASE("rpc", R8A779G0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779G0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779G0_CLK_RPC), diff --git a/drivers/clk/renesas/r8a779h0-cpg-mssr.c b/drivers/clk/renesas/r8a779h0-cpg-mssr.c index b20d559bee2..2e98e262fb0 100644 --- a/drivers/clk/renesas/r8a779h0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779h0-cpg-mssr.c @@ -15,6 +15,12 @@ #include "renesas-cpg-mssr.h" #include "rcar-gen3-cpg.h" +#define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ +#define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ +#define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ +#define CPG_CSICKCR 0x880 /* CSI Clock Frequency Control Register */ +#define CPG_DSIEXTCKCR 0x884 /* DSI Clock Frequency Control Register */ + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R8A779H0_CLK_R, @@ -155,14 +161,14 @@ static const struct cpg_core_clk r8a779h0_core_clks[] = { DEF_FIXED("viobusd2", R8A779H0_CLK_VIOBUSD2, CLK_VIOSRC, 2, 1), DEF_FIXED("vcbusd1", R8A779H0_CLK_VCBUSD1, CLK_VCSRC, 1, 1), DEF_FIXED("vcbusd2", R8A779H0_CLK_VCBUSD2, CLK_VCSRC, 2, 1), - DEF_DIV6P1("canfd", R8A779H0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi", R8A779H0_CLK_CSI, CLK_PLL5_DIV4, 0x880), + DEF_DIV6P1("canfd", R8A779H0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi", R8A779H0_CLK_CSI, CLK_PLL5_DIV4, CPG_CSICKCR), DEF_FIXED("dsiref", R8A779H0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1), - DEF_DIV6P1("dsiext", R8A779H0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884), - DEF_DIV6P1("mso", R8A779H0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_DIV6P1("dsiext", R8A779H0_CLK_DSIEXT, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), + DEF_DIV6P1("mso", R8A779H0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), - DEF_GEN4_SDH("sd0h", R8A779H0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779H0_CLK_SD0, R8A779H0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779H0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779H0_CLK_SD0, R8A779H0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779H0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779H0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779H0_CLK_RPC), @@ -175,6 +181,9 @@ static const struct mssr_mod_clk r8a779h0_mod_clks[] = { DEF_MOD("avb0:rgmii0", 211, R8A779H0_CLK_S0D8_HSC), DEF_MOD("avb1:rgmii1", 212, R8A779H0_CLK_S0D8_HSC), DEF_MOD("avb2:rgmii2", 213, R8A779H0_CLK_S0D8_HSC), + DEF_MOD("canfd0", 328, R8A779H0_CLK_SASYNCPERD2), + DEF_MOD("csi40", 331, R8A779H0_CLK_CSI), + DEF_MOD("csi41", 400, R8A779H0_CLK_CSI), DEF_MOD("hscif0", 514, R8A779H0_CLK_SASYNCPERD1), DEF_MOD("hscif1", 515, R8A779H0_CLK_SASYNCPERD1), DEF_MOD("hscif2", 516, R8A779H0_CLK_SASYNCPERD1), @@ -183,14 +192,57 @@ static const struct mssr_mod_clk r8a779h0_mod_clks[] = { DEF_MOD("i2c1", 519, R8A779H0_CLK_S0D6_PER), DEF_MOD("i2c2", 520, R8A779H0_CLK_S0D6_PER), DEF_MOD("i2c3", 521, R8A779H0_CLK_S0D6_PER), + DEF_MOD("irqc", 611, R8A779H0_CLK_CL16M), + DEF_MOD("ispcs0", 612, R8A779H0_CLK_S0D2_VIO), + DEF_MOD("ispcs1", 613, R8A779H0_CLK_S0D2_VIO), + DEF_MOD("msi0", 618, R8A779H0_CLK_MSO), + DEF_MOD("msi1", 619, R8A779H0_CLK_MSO), + DEF_MOD("msi2", 620, R8A779H0_CLK_MSO), + DEF_MOD("msi3", 621, R8A779H0_CLK_MSO), + DEF_MOD("msi4", 622, R8A779H0_CLK_MSO), + DEF_MOD("msi5", 623, R8A779H0_CLK_MSO), + DEF_MOD("pcie0", 624, R8A779H0_CLK_S0D2_HSC), + DEF_MOD("pwm", 628, R8A779H0_CLK_SASYNCPERD4), DEF_MOD("rpc-if", 629, R8A779H0_CLK_RPCD2), + DEF_MOD("scif0", 702, R8A779H0_CLK_SASYNCPERD4), + DEF_MOD("scif1", 703, R8A779H0_CLK_SASYNCPERD4), + DEF_MOD("scif3", 704, R8A779H0_CLK_SASYNCPERD4), + DEF_MOD("scif4", 705, R8A779H0_CLK_SASYNCPERD4), DEF_MOD("sdhi0", 706, R8A779H0_CLK_SD0), DEF_MOD("sydm1", 709, R8A779H0_CLK_S0D6_PER), DEF_MOD("sydm2", 710, R8A779H0_CLK_S0D6_PER), + DEF_MOD("tmu0", 713, R8A779H0_CLK_SASYNCRT), + DEF_MOD("tmu1", 714, R8A779H0_CLK_SASYNCPERD2), + DEF_MOD("tmu2", 715, R8A779H0_CLK_SASYNCPERD2), + DEF_MOD("tmu3", 716, R8A779H0_CLK_SASYNCPERD2), + DEF_MOD("tmu4", 717, R8A779H0_CLK_SASYNCPERD2), + DEF_MOD("vin00", 730, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin01", 731, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin02", 800, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin03", 801, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin04", 802, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin05", 803, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin06", 804, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin07", 805, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin10", 806, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin11", 807, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin12", 808, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin13", 809, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin14", 810, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin15", 811, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin16", 812, R8A779H0_CLK_S0D4_VIO), + DEF_MOD("vin17", 813, R8A779H0_CLK_S0D4_VIO), DEF_MOD("wdt1:wdt0", 907, R8A779H0_CLK_R), + DEF_MOD("cmt0", 910, R8A779H0_CLK_R), + DEF_MOD("cmt1", 911, R8A779H0_CLK_R), + DEF_MOD("cmt2", 912, R8A779H0_CLK_R), + DEF_MOD("cmt3", 913, R8A779H0_CLK_R), DEF_MOD("pfc0", 915, R8A779H0_CLK_CP), DEF_MOD("pfc1", 916, R8A779H0_CLK_CP), DEF_MOD("pfc2", 917, R8A779H0_CLK_CP), + DEF_MOD("tsc2:tsc1", 919, R8A779H0_CLK_CL16M), + DEF_MOD("ssiu", 2926, R8A779H0_CLK_S0D6_PER), + DEF_MOD("ssi", 2927, R8A779H0_CLK_S0D6_PER), }; /* diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c index d7825c66493..ad7e1c0f246 100644 --- a/drivers/clk/rockchip/clk_px30.c +++ b/drivers/clk/rockchip/clk_px30.c @@ -989,7 +989,7 @@ static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id, return px30_peri_get_clk(priv, clk_id); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong px30_crypto_get_clk(struct px30_clk_priv *priv, ulong clk_id) { struct px30_cru *cru = priv->cru; @@ -1261,7 +1261,7 @@ static ulong px30_clk_get_rate(struct clk *clk) case HCLK_PERI_PRE: rate = px30_peri_get_clk(priv, clk->id); break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case SCLK_CRYPTO: case SCLK_CRYPTO_APK: rate = px30_crypto_get_clk(priv, clk->id); @@ -1345,7 +1345,7 @@ static ulong px30_clk_set_rate(struct clk *clk, ulong rate) case HCLK_PERI_PRE: ret = px30_peri_set_clk(priv, clk->id, rate); break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case SCLK_CRYPTO: case SCLK_CRYPTO_APK: ret = px30_crypto_set_clk(priv, clk->id, rate); @@ -1588,6 +1588,105 @@ static ulong px30_pmuclk_set_gpll_rate(struct px30_pmuclk_priv *priv, ulong hz) return priv->gpll_hz; } +static ulong px30_pmu_uart0_get_clk(struct px30_pmuclk_priv *priv) +{ + struct px30_pmucru *pmucru = priv->pmucru; + u32 clk_div_con; + u32 clk_pll_sel; + ulong pll_rate; + u32 clk_sel; + ulong clk; + u32 con; + + con = readl(&pmucru->pmu_clksel_con[3]); + clk_div_con = bitfield_extract_by_mask(con, UART0_DIV_CON_MASK); + clk_pll_sel = bitfield_extract_by_mask(con, UART0_PLL_SEL_MASK); + + switch (clk_pll_sel) { + case UART0_PLL_SEL_GPLL: + pll_rate = px30_pmuclk_get_gpll_rate(priv); + break; + case UART0_PLL_SEL_24M: + pll_rate = OSC_HZ; + break; + case UART0_PLL_SEL_480M: + case UART0_PLL_SEL_NPLL: + /* usbphy480M and NPLL clocks, generated by CRU, are not supported yet */ + default: + return -ENOENT; + } + + clk = DIV_TO_RATE(pll_rate, clk_div_con); + con = readl(&pmucru->pmu_clksel_con[4]); + clk_sel = bitfield_extract_by_mask(con, UART0_CLK_SEL_MASK); + + switch (clk_sel) { + case UART0_CLK_SEL_UART0: + return clk; + case UART0_CLK_SEL_UART0_NP5:{ + u32 clk_divnp5_div_con; + + clk_divnp5_div_con = + bitfield_extract_by_mask(con, UART0_DIVNP5_MASK); + return 2 * (u64) clk / (2 * clk_divnp5_div_con + 3); + } + case UART0_CLK_SEL_UART0_FRAC:{ + u32 fracdiv, n, m; + + fracdiv = readl(&pmucru->pmu_clksel_con[5]); + n = bitfield_extract_by_mask(fracdiv, + CLK_UART_FRAC_NUMERATOR_MASK); + m = bitfield_extract_by_mask(fracdiv, + CLK_UART_FRAC_DENOMINATOR_MASK); + return (u64) clk * n / m; + } + default: + return -ENOENT; + } +} + +static ulong px30_pmu_uart0_set_clk(struct px30_pmuclk_priv *priv, ulong rate) +{ + struct px30_pmucru *pmucru = priv->pmucru; + ulong m = 0, n = 0; + ulong gpll_rate; + u32 clk_div_con; + u32 clk_pll_sel; + u32 clk_sel; + + gpll_rate = px30_pmuclk_get_gpll_rate(priv); + if (gpll_rate % rate == 0) { + clk_pll_sel = UART0_PLL_SEL_GPLL; + clk_sel = UART0_CLK_SEL_UART0; + clk_div_con = DIV_ROUND_UP(priv->gpll_hz, rate); + } else if (rate == OSC_HZ) { + clk_pll_sel = UART0_PLL_SEL_24M; + clk_sel = UART0_CLK_SEL_UART0; + clk_div_con = 1; + } else { + clk_pll_sel = UART0_PLL_SEL_GPLL; + clk_sel = UART0_CLK_SEL_UART0_FRAC; + clk_div_con = 1; + rational_best_approximation(rate, priv->gpll_hz, + GENMASK(16 - 1, 0), + GENMASK(16 - 1, 0), &m, &n); + } + + rk_clrsetreg(&pmucru->pmu_clksel_con[3], + UART0_PLL_SEL_MASK | UART0_DIV_CON_MASK, + clk_pll_sel << UART0_PLL_SEL_SHIFT | (clk_div_con - 1)); + rk_clrsetreg(&pmucru->pmu_clksel_con[4], UART0_CLK_SEL_MASK, + clk_sel << UART0_CLK_SEL_SHIFT); + if (m && n) { + u32 fracdiv; + + fracdiv = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; + writel(fracdiv, &pmucru->pmu_clksel_con[5]); + } + + return px30_pmu_uart0_get_clk(priv); +} + static ulong px30_pmuclk_get_rate(struct clk *clk) { struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev); @@ -1601,6 +1700,9 @@ static ulong px30_pmuclk_get_rate(struct clk *clk) case PCLK_PMU_PRE: rate = px30_pclk_pmu_get_pmuclk(priv); break; + case SCLK_UART0_PMU: + rate = px30_pmu_uart0_get_clk(priv); + break; default: return -ENOENT; } @@ -1621,6 +1723,9 @@ static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate) case PCLK_PMU_PRE: ret = px30_pclk_pmu_set_pmuclk(priv, rate); break; + case SCLK_UART0_PMU: + ret = px30_pmu_uart0_set_clk(priv, rate); + break; default: return -ENOENT; } diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c index f569a100f22..d8b03e1d7ab 100644 --- a/drivers/clk/rockchip/clk_rk3188.c +++ b/drivers/clk/rockchip/clk_rk3188.c @@ -80,7 +80,7 @@ enum { "divisors on line " __stringify(__LINE__)); /* Keep divisors as low as possible to reduce jitter and power usage */ -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); #endif @@ -371,7 +371,7 @@ static ulong rockchip_spi_set_clk(struct rk3188_cru *cru, uint gclk_rate, return rockchip_spi_get_clk(cru, gclk_rate, periph); } -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static void rkclk_init(struct rk3188_cru *cru, struct rk3188_grf *grf, bool has_bwadj) { @@ -557,7 +557,7 @@ static int rk3188_clk_probe(struct udevice *dev) return PTR_ERR(priv->grf); priv->has_bwadj = (type == RK3188A_CRU) ? 1 : 0; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD #if CONFIG_IS_ENABLED(OF_PLATDATA) struct rk3188_clk_plat *plat = dev_get_plat(dev); diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c index 432a79291c8..43c44fadbe7 100644 --- a/drivers/clk/rockchip/clk_rk3288.c +++ b/drivers/clk/rockchip/clk_rk3288.c @@ -223,7 +223,7 @@ static int rkclk_configure_ddr(struct rockchip_cru *cru, struct rk3288_grf *grf, return 0; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD #define VCO_MAX_KHZ 2200000 #define VCO_MIN_KHZ 440000 #define FREF_MAX_KHZ 2200000 @@ -421,7 +421,7 @@ static ulong rockchip_i2s_set_clk(struct rockchip_cru *cru, uint gclk_rate, return rockchip_i2s_get_clk(cru, gclk_rate); } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ static void rkclk_init(struct rockchip_cru *cru, struct rk3288_grf *grf) { @@ -819,7 +819,7 @@ static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate) case SCLK_SPI2: new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate); break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case SCLK_I2S0: new_rate = rockchip_i2s_set_clk(cru, gclk_rate, rate); break; @@ -973,7 +973,7 @@ static int rk3288_clk_probe(struct udevice *dev) priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); if (IS_ERR(priv->grf)) return PTR_ERR(priv->grf); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD #if CONFIG_IS_ENABLED(OF_PLATDATA) struct rk3288_clk_plat *plat = dev_get_plat(dev); diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c index 9137dbe69ce..7701a9734ee 100644 --- a/drivers/clk/rockchip/clk_rk3328.c +++ b/drivers/clk/rockchip/clk_rk3328.c @@ -582,7 +582,7 @@ static ulong rk3328_spi_set_clk(struct rk3328_cru *cru, uint hz) return rk3328_spi_get_clk(cru); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong rk3328_vop_get_clk(struct rk3328_clk_priv *priv, ulong clk_id) { struct rk3328_cru *cru = priv->cru; @@ -746,7 +746,7 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) case SCLK_SPI: ret = rk3328_spi_set_clk(priv->cru, rate); break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case DCLK_LCDC: case ACLK_VOP_PRE: case ACLK_VIO_PRE: diff --git a/drivers/clk/rockchip/clk_rk3368.c b/drivers/clk/rockchip/clk_rk3368.c index d8943980521..630253fbb1d 100644 --- a/drivers/clk/rockchip/clk_rk3368.c +++ b/drivers/clk/rockchip/clk_rk3368.c @@ -50,7 +50,7 @@ struct pll_div { (_nr * _no) == hz, #hz "Hz cannot be hit with PLL " \ "divisors on line " __stringify(__LINE__)); -#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) +#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) static const struct pll_div apll_l_init_cfg = PLL_DIVISORS(APLL_L_HZ, 12, 2); static const struct pll_div apll_b_init_cfg = PLL_DIVISORS(APLL_B_HZ, 1, 2); #if !defined(CONFIG_TPL_BUILD) @@ -88,7 +88,7 @@ static uint32_t rkclk_pll_get_rate(struct rk3368_cru *cru, } } -#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) +#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id, const struct pll_div *div) { @@ -130,7 +130,7 @@ static int rkclk_set_pll(struct rk3368_cru *cru, enum rk3368_pll_id pll_id, } #endif -#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) +#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) static void rkclk_init(struct rk3368_cru *cru) { u32 apllb, aplll, dpll, cpll, gpll; @@ -157,7 +157,7 @@ static void rkclk_init(struct rk3368_cru *cru) } #endif -#if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC) +#if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC) static ulong rk3368_mmc_get_clk(struct rk3368_cru *cru, uint clk_id) { u32 div, con, con_id, rate; @@ -469,7 +469,7 @@ static ulong rk3368_clk_get_rate(struct clk *clk) case SCLK_SPI0 ... SCLK_SPI2: rate = rk3368_spi_get_clk(priv->cru, clk->id); break; -#if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC) +#if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC) case HCLK_SDMMC: case HCLK_EMMC: rate = rk3368_mmc_get_clk(priv->cru, clk->id); @@ -500,7 +500,7 @@ static ulong rk3368_clk_set_rate(struct clk *clk, ulong rate) ret = rk3368_ddr_set_clk(priv->cru, rate); break; #endif -#if !IS_ENABLED(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(MMC) +#if !IS_ENABLED(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(MMC) case HCLK_SDMMC: case HCLK_EMMC: ret = rk3368_mmc_set_clk(clk, rate); @@ -586,7 +586,7 @@ static int rk3368_clk_probe(struct udevice *dev) priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); #endif -#if IS_ENABLED(CONFIG_SPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) +#if IS_ENABLED(CONFIG_XPL_BUILD) || IS_ENABLED(CONFIG_TPL_BUILD) rkclk_init(priv->cru); #endif diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c index 89924041299..155ea8d6353 100644 --- a/drivers/clk/rockchip/clk_rk3399.c +++ b/drivers/clk/rockchip/clk_rk3399.c @@ -56,7 +56,7 @@ struct pll_div { static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1); static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2, 2); -#if !defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_XPL_BUILD) static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1); #endif @@ -1464,7 +1464,7 @@ static int rk3399_clk_probe(struct udevice *dev) priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); #endif -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_XPL_BUILD) init_clocks = true; #elif CONFIG_IS_ENABLED(HANDOFF) if (!(gd->flags & GD_FLG_RELOC)) { @@ -1658,7 +1658,7 @@ static struct clk_ops rk3399_pmuclk_ops = { .set_rate = rk3399_pmuclk_set_rate, }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static void pmuclk_init(struct rk3399_pmucru *pmucru) { u32 pclk_div; @@ -1676,7 +1676,7 @@ static void pmuclk_init(struct rk3399_pmucru *pmucru) static int rk3399_pmuclk_probe(struct udevice *dev) { -#if CONFIG_IS_ENABLED(OF_PLATDATA) || !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(OF_PLATDATA) || !defined(CONFIG_XPL_BUILD) struct rk3399_pmuclk_priv *priv = dev_get_priv(dev); #endif @@ -1686,7 +1686,7 @@ static int rk3399_pmuclk_probe(struct udevice *dev) priv->pmucru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); #endif -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD pmuclk_init(priv->pmucru); #endif return 0; diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c index 35563509d61..977699d509d 100644 --- a/drivers/clk/rockchip/clk_rk3568.c +++ b/drivers/clk/rockchip/clk_rk3568.c @@ -91,7 +91,7 @@ static struct rockchip_pll_clock rk3568_pll_clks[] = { RK3568_PMU_MODE, 2, 10, 0, rk3568_pll_rates), }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong rk3568_pmu_pll_set_rate(struct rk3568_clk_priv *priv, ulong pll_id, ulong rate) @@ -1707,7 +1707,7 @@ static ulong rk3568_emmc_set_bclk(struct rk3568_clk_priv *priv, ulong rate) return rk3568_emmc_get_bclk(priv); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong rk3568_aclk_vop_get_clk(struct rk3568_clk_priv *priv) { struct rk3568_cru *cru = priv->cru; @@ -2413,7 +2413,7 @@ static ulong rk3568_clk_get_rate(struct clk *clk) case TCLK_EMMC: rate = OSC_HZ; break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case ACLK_VOP: rate = rk3568_aclk_vop_get_clk(priv); break; @@ -2594,7 +2594,7 @@ static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate) case TCLK_EMMC: ret = OSC_HZ; break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case ACLK_VOP: ret = rk3568_aclk_vop_set_clk(priv, rate); break; @@ -2894,7 +2894,7 @@ static void rk3568_clk_init(struct rk3568_clk_priv *priv) priv->gpll_hz = GPLL_HZ; } -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD ret = rk3568_bus_set_clk(priv, ACLK_BUS, 150000000); if (ret < 0) printf("Fail to set the ACLK_BUS clock.\n"); diff --git a/drivers/clk/rockchip/clk_rk3588.c b/drivers/clk/rockchip/clk_rk3588.c index db1384dacd2..6042fc10cdb 100644 --- a/drivers/clk/rockchip/clk_rk3588.c +++ b/drivers/clk/rockchip/clk_rk3588.c @@ -65,7 +65,7 @@ static struct rockchip_pll_clock rk3588_pll_clks[] = { RK3588_MODE_CON0, 0, 15, 0, rk3588_pll_rates), [PPLL] = PLL(pll_rk3588, PLL_PPLL, RK3588_PMU_PLL_CON(128), RK3588_MODE_CON0, 10, 15, 0, rk3588_pll_rates), -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* * The SPLL is part of the SBUSCRU, not the main CRU and as * such only directly accessible during the SPL stage. @@ -76,7 +76,7 @@ static struct rockchip_pll_clock rk3588_pll_clks[] = { }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD /* * * rational_best_approximation(31415, 10000, @@ -875,7 +875,7 @@ static ulong rk3588_mmc_set_clk(struct rk3588_clk_priv *priv, return rk3588_mmc_get_clk(priv, clk_id); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static ulong rk3588_aux16m_get_clk(struct rk3588_clk_priv *priv, ulong clk_id) { struct rk3588_cru *cru = priv->cru; @@ -1600,7 +1600,7 @@ static ulong rk3588_clk_get_rate(struct clk *clk) case CLK_GPU: rate = 200000000; break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case CLK_AUX16M_0: case CLK_AUX16M_1: rate = rk3588_aux16m_get_clk(priv, clk->id); @@ -1760,7 +1760,7 @@ static ulong rk3588_clk_set_rate(struct clk *clk, ulong rate) case CLK_150M_SRC: ret = 0; break; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD case CLK_AUX16M_0: case CLK_AUX16M_1: ret = rk3588_aux16m_set_clk(priv, clk->id, rate); @@ -1965,7 +1965,7 @@ static int rk3588_clk_probe(struct udevice *dev) priv->sync_kernel = false; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD rockchip_pll_set_rate(&rk3588_pll_clks[B0PLL], priv->cru, B0PLL, LPLL_HZ); rockchip_pll_set_rate(&rk3588_pll_clks[B1PLL], priv->cru, @@ -2051,7 +2051,7 @@ U_BOOT_DRIVER(rockchip_rk3588_cru) = { .probe = rk3588_clk_probe, }; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD #define SCRU_BASE 0xfd7d0000 #define SBUSCRU_BASE 0xfd7d8000 diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index aa26d3a109b..de55504b5c9 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -670,7 +670,7 @@ static int sifive_prci_probe(struct udevice *dev) __prci_wrpll_read_cfg0(pd, pc->pwd); } - if (IS_ENABLED(CONFIG_SPL_BUILD)) { + if (IS_ENABLED(CONFIG_XPL_BUILD)) { if (device_is_compatible(dev, "sifive,fu740-c000-prci")) { u32 prci_pll_reg; unsigned long parent_rate; diff --git a/drivers/clk/starfive/clk-jh7110-pll.c b/drivers/clk/starfive/clk-jh7110-pll.c index 581035842fc..6d2bfb3ecb7 100644 --- a/drivers/clk/starfive/clk-jh7110-pll.c +++ b/drivers/clk/starfive/clk-jh7110-pll.c @@ -348,10 +348,10 @@ struct clk *starfive_jh7110_pll(const char *name, const char *parent_name, return ERR_PTR(ret); } - if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL0) + if (IS_ENABLED(CONFIG_XPL_BUILD) && pll->type == PLL0) jh7110_pllx_set_rate(clk, 1000000000); - if (IS_ENABLED(CONFIG_SPL_BUILD) && pll->type == PLL2) + if (IS_ENABLED(CONFIG_XPL_BUILD) && pll->type == PLL2) jh7110_pllx_set_rate(clk, 1188000000); return clk; diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c index 204ac170531..4044edfb768 100644 --- a/drivers/clk/stm32/clk-stm32mp1.c +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -26,7 +26,7 @@ DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_XPL_BUILD) /* activate clock tree initialization in the driver */ #define STM32MP1_CLOCK_TREE_INIT #endif @@ -2279,7 +2279,7 @@ static int stm32mp1_clk_probe(struct udevice *dev) dev_err(dev, "clock tree initialization failed (%d)\n", result); #endif -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD #if defined(VERBOSE_DEBUG) /* display debug information for probe after relocation */ if (gd->flags & GD_FLG_RELOC) @@ -2314,7 +2314,7 @@ static const struct clk_ops stm32mp1_clk_ops = { .disable = stm32mp1_clk_disable, .get_rate = stm32mp1_clk_get_rate, .set_rate = stm32mp1_clk_set_rate, -#if IS_ENABLED(CONFIG_CMD_CLK) && !IS_ENABLED(CONFIG_SPL_BUILD) +#if IS_ENABLED(CONFIG_CMD_CLK) && !IS_ENABLED(CONFIG_XPL_BUILD) .dump = stm32mp1_clk_dump, #endif }; diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c index 6751af8a803..091aaeee987 100644 --- a/drivers/clk/sunxi/clk_a80.c +++ b/drivers/clk/sunxi/clk_a80.c @@ -75,10 +75,10 @@ static const struct ccu_clk_gate a80_mmc_gates[] = { }; static const struct ccu_reset a80_mmc_resets[] = { - [0] = GATE(0x0, BIT(18)), - [1] = GATE(0x4, BIT(18)), - [2] = GATE(0x8, BIT(18)), - [3] = GATE(0xc, BIT(18)), + [0] = RESET(0x0, BIT(18)), + [1] = RESET(0x4, BIT(18)), + [2] = RESET(0x8, BIT(18)), + [3] = RESET(0xc, BIT(18)), }; const struct ccu_desc a80_ccu_desc = { diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 07aa9a53e08..a58f19f46d9 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -11,5 +11,5 @@ obj-$(CONFIG_CLK_TI_DIVIDER) += clk-divider.o obj-$(CONFIG_CLK_TI_GATE) += clk-gate.o obj-$(CONFIG_CLK_TI_MUX) += clk-mux.o obj-$(CONFIG_CLK_TI_SCI) += clk-sci.o -obj-$(CONFIG_$(SPL_TPL_)CLK_K3_PLL) += clk-k3-pll.o -obj-$(CONFIG_$(SPL_TPL_)CLK_K3) += clk-k3.o +obj-$(CONFIG_$(PHASE_)CLK_K3_PLL) += clk-k3-pll.o +obj-$(CONFIG_$(PHASE_)CLK_K3) += clk-k3.o diff --git a/drivers/core/Makefile b/drivers/core/Makefile index acbd2bf2cef..9ea57911f89 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -3,19 +3,19 @@ # Copyright (c) 2013 Google, Inc obj-y += device.o fdtaddr.o lists.o root.o uclass.o util.o tag.o -obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o -obj-$(CONFIG_$(SPL_TPL_)DEVRES) += devres.o -obj-$(CONFIG_$(SPL_TPL_)DM_DEVICE_REMOVE) += device-remove.o -obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o +obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi.o +obj-$(CONFIG_$(PHASE_)DEVRES) += devres.o +obj-$(CONFIG_$(PHASE_)DM_DEVICE_REMOVE) += device-remove.o +obj-$(CONFIG_$(XPL_)SIMPLE_BUS) += simple-bus.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_DM) += dump.o -obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o -obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o -obj-$(CONFIG_$(SPL_)OF_LIVE) += of_access.o of_addr.o +obj-$(CONFIG_$(PHASE_)REGMAP) += regmap.o +obj-$(CONFIG_$(PHASE_)SYSCON) += syscon-uclass.o +obj-$(CONFIG_$(XPL_)OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif -obj-$(CONFIG_$(SPL_)OF_PLATDATA) += read.o +obj-$(CONFIG_$(XPL_)OF_PLATDATA) += read.o obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 7e3b3719d18..48ae8ce830e 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -611,7 +611,7 @@ int ofnode_read_u32_array(ofnode node, const char *propname, out_values, sz); /* get the error right, but space is more important in SPL */ - if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { if (ret == -FDT_ERR_NOTFOUND) return -EINVAL; else if (ret == -FDT_ERR_BADLAYOUT) @@ -1468,7 +1468,7 @@ int ofnode_read_simple_size_cells(ofnode node) bool ofnode_pre_reloc(ofnode node) { -#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD) +#if defined(CONFIG_XPL_BUILD) || defined(CONFIG_TPL_BUILD) /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass * had property bootph-all or bootph-pre-sram/bootph-pre-ram. * They are removed in final dtb (fdtgrep 2nd pass) @@ -1735,6 +1735,39 @@ const char *ofnode_conf_read_str(const char *prop_name) return ofnode_read_string(node, prop_name); } +bool ofnode_options_read_bool(const char *prop_name) +{ + ofnode uboot; + + uboot = ofnode_path("/options/u-boot"); + if (!ofnode_valid(uboot)) + return false; + + return ofnode_read_bool(uboot, prop_name); +} + +int ofnode_options_read_int(const char *prop_name, int default_val) +{ + ofnode uboot; + + uboot = ofnode_path("/options/u-boot"); + if (!ofnode_valid(uboot)) + return default_val; + + return ofnode_read_u32_default(uboot, prop_name, default_val); +} + +const char *ofnode_options_read_str(const char *prop_name) +{ + ofnode uboot; + + uboot = ofnode_path("/options/u-boot"); + if (!ofnode_valid(uboot)) + return NULL; + + return ofnode_read_string(uboot, prop_name); +} + int ofnode_read_bootscript_address(u64 *bootscr_address, u64 *bootscr_offset) { int ret; diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 6c0a8c0cbe4..51262befaff 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -20,10 +20,11 @@ DECLARE_GLOBAL_DATA_PTR; +#define IMX_REV_LEN 4 struct cpu_imx_plat { const char *name; - const char *rev; const char *type; + char rev[IMX_REV_LEN]; u32 cpu_rsrc; u32 cpurev; u32 freq_mhz; @@ -69,28 +70,29 @@ static const char *get_imx_type_str(u32 imxtype) } } -static const char *get_imx_rev_str(u32 rev) +static void get_imx_rev_str(struct cpu_imx_plat *plat, u32 rev) { - static char revision[4]; - if (IS_ENABLED(CONFIG_IMX8)) { switch (rev) { case CHIP_REV_A: - return "A"; + plat->rev[0] = 'A'; + break; case CHIP_REV_B: - return "B"; + plat->rev[0] = 'B'; + break; case CHIP_REV_C: - return "C"; + plat->rev[0] = 'C'; + break; default: - return "?"; + plat->rev[0] = '?'; + break; } + plat->rev[1] = '\0'; } else { - revision[0] = '1' + (((rev & 0xf0) - CHIP_REV_1_0) >> 4); - revision[1] = '.'; - revision[2] = '0' + (rev & 0xf); - revision[3] = '\0'; - - return revision; + plat->rev[0] = '1' + (((rev & 0xf0) - CHIP_REV_1_0) >> 4); + plat->rev[1] = '.'; + plat->rev[2] = '0' + (rev & 0xf); + plat->rev[3] = '\0'; } } @@ -318,7 +320,7 @@ static int imx_cpu_probe(struct udevice *dev) set_core_data(dev); cpurev = get_cpu_rev(); plat->cpurev = cpurev; - plat->rev = get_imx_rev_str(cpurev & 0xFFF); + get_imx_rev_str(plat, cpurev & 0xFFF); plat->type = get_imx_type_str((cpurev & 0x1FF000) >> 12); plat->freq_mhz = imx_get_cpu_rate(dev) / 1000000; plat->mpidr = dev_read_addr(dev); diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index 473e3e5a863..6efcd7da738 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -28,3 +28,13 @@ config ASPEED_CPTRA_SHA Enabling this allows the use of SHA operations in hardware. Note that only SHA384 and SHA512 are supported by Caliptra 1.0. + +config ASPEED_CPTRA_ECDSA + bool "Caliptra ECDSA384 signature verifier for Aspeed SoCs" + depends on ECDSA_VERIFY || SPL_ECDSA_VERIFY + help + Select this option to enable a driver for using the ECDSA384_SIGNATURE_VERIFY + feature of Caliptra, which is integrated in AST27xx BMC SoCs. + + Enabling this allows the use of ECDSA384 signature verification in hardware. + Note that only ECDSA384 is supported by Caliptra. diff --git a/drivers/crypto/aspeed/Makefile b/drivers/crypto/aspeed/Makefile index 570587e744f..00def358ddf 100644 --- a/drivers/crypto/aspeed/Makefile +++ b/drivers/crypto/aspeed/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_ASPEED_HACE) += aspeed_hace.o obj-$(CONFIG_ASPEED_ACRY) += aspeed_acry.o obj-$(CONFIG_ASPEED_CPTRA_SHA) += cptra_sha.o +obj-$(CONFIG_ASPEED_CPTRA_ECDSA) += cptra_ecdsa.o diff --git a/drivers/crypto/aspeed/cptra_ecdsa.c b/drivers/crypto/aspeed/cptra_ecdsa.c new file mode 100644 index 00000000000..4b70d89def7 --- /dev/null +++ b/drivers/crypto/aspeed/cptra_ecdsa.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2024 ASPEED Technology Inc. + */ +#include <asm/io.h> +#include <config.h> +#include <crypto/ecdsa-uclass.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/iopoll.h> +#include <malloc.h> +#include <u-boot/ecdsa.h> + +/* SCU register offsets */ +#define SCU1_CPTRA 0x130 +#define SCU1_CPTRA_RDY_FOR_RT BIT(18) + +/* CPTRA MBOX register offsets */ +#define CPTRA_MBOX_LOCK 0x00 +#define CPTRA_MBOX_USER 0x04 +#define CPTRA_MBOX_CMD 0x08 +#define CPTRA_MBOX_DLEN 0x0c +#define CPTRA_MBOX_DATAIN 0x10 +#define CPTRA_MBOX_DATAOUT 0x14 +#define CPTRA_MBOX_EXEC 0x18 +#define CPTRA_MBOX_STS 0x1c +#define CPTRA_MBOX_STS_SOC_LOCK BIT(9) +#define CPTRA_MBOX_STS_FSM_PS GENMASK(8, 6) +#define CPTRA_MBOX_STS_PS GENMASK(3, 0) +#define CPTRA_MBOX_UNLOCK 0x20 + +#define CPTRA_ECDSA_SIG_LEN 96 /* ECDSA384 */ +#define CPTRA_ECDSA_SHA_LEN 48 /* SHA384 */ + +#define CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY 0x53494756 + +enum cptra_mbox_sts { + CPTRA_MBSTS_CMD_BUSY, + CPTRA_MBSTS_DATA_READY, + CPTRA_MBSTS_CMD_COMPLETE, + CPTRA_MBSTS_CMD_FAILURE, +}; + +enum cptra_mbox_fsm { + CPTRA_MBFSM_IDLE, + CPTRA_MBFSM_RDY_FOR_CMD, + CPTRA_MBFSM_RDY_FOR_DLEN, + CPTRA_MBFSM_RDY_FOR_DATA, + CPTRA_MBFSM_EXEC_UC, + CPTRA_MBFSM_EXEC_SOC, + CPTRA_MBFSM_ERROR, +}; + +struct cptra_ecdsa { + void *regs; +}; + +static uint32_t mbox_csum(uint32_t csum, uint8_t *data, uint32_t dlen) +{ + uint32_t i; + + for (i = 0; i < dlen; ++i) + csum -= data[i]; + + return csum; +} + +static int cptra_ecdsa_verify(struct udevice *dev, const struct ecdsa_public_key *pubkey, + const void *hash, size_t hash_len, + const void *signature, size_t sig_len) +{ + struct cptra_ecdsa *ce; + uint8_t *x, *y, *r, *s; + uint32_t cmd, csum; + uint32_t reg, sts; + uint32_t *p32; + int i; + + if (hash_len != CPTRA_ECDSA_SHA_LEN || sig_len != CPTRA_ECDSA_SIG_LEN) + return -EINVAL; + + if ((strcmp(pubkey->curve_name, "secp384r1") && strcmp(pubkey->curve_name, "prime384v1")) || + pubkey->size_bits != ((CPTRA_ECDSA_SIG_LEN / 2) << 3)) + return -EINVAL; + + ce = dev_get_priv(dev); + + /* get CPTRA MBOX lock */ + if (readl_poll_timeout(ce->regs + CPTRA_MBOX_LOCK, reg, reg == 0, 1000000)) + return -EBUSY; + + /* check MBOX is ready for command */ + sts = readl(ce->regs + CPTRA_MBOX_STS); + if (FIELD_GET(CPTRA_MBOX_STS_FSM_PS, sts) != CPTRA_MBFSM_RDY_FOR_CMD) + return -EACCES; + + /* init mbox parameters */ + cmd = CPTRA_MBCMD_ECDSA384_SIGNATURE_VERIFY; + csum = 0; + x = (uint8_t *)pubkey->x; + y = (uint8_t *)pubkey->y; + r = (uint8_t *)signature; + s = (uint8_t *)signature + (CPTRA_ECDSA_SIG_LEN / 2); + + /* calculate checksum */ + csum = mbox_csum(csum, (uint8_t *)&cmd, sizeof(cmd)); + csum = mbox_csum(csum, x, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, y, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, r, CPTRA_ECDSA_SIG_LEN / 2); + csum = mbox_csum(csum, s, CPTRA_ECDSA_SIG_LEN / 2); + + /* write command, data length */ + writel(cmd, ce->regs + CPTRA_MBOX_CMD); + writel(sizeof(csum) + (CPTRA_ECDSA_SIG_LEN << 1), ce->regs + CPTRA_MBOX_DLEN); + + /* write ECDSA384_SIGNATURE_VERIFY command parameters */ + writel(csum, ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)x; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)y; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)r; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + for (i = 0, p32 = (uint32_t *)s; i < ((CPTRA_ECDSA_SIG_LEN / 2) / sizeof(*p32)); ++i) + writel(p32[i], ce->regs + CPTRA_MBOX_DATAIN); + + /* trigger mbox command */ + writel(0x1, ce->regs + CPTRA_MBOX_EXEC); + + /* poll for result */ + while (1) { + sts = FIELD_GET(CPTRA_MBOX_STS_PS, readl(ce->regs + CPTRA_MBOX_STS)); + if (sts != CPTRA_MBSTS_CMD_BUSY) + break; + } + + /* unlock mbox */ + writel(0x0, ce->regs + CPTRA_MBOX_EXEC); + + return (sts == CPTRA_MBSTS_CMD_FAILURE) ? sts : 0; +} + +static int cptra_ecdsa_probe(struct udevice *dev) +{ + struct cptra_ecdsa *ce = dev_get_priv(dev); + + ce->regs = (void *)devfdt_get_addr(dev); + if (ce->regs == (void *)FDT_ADDR_T_NONE) { + debug("cannot map Caliptra mailbox registers\n"); + return -EINVAL; + } + + return 0; +} + +static int cptra_ecdsa_remove(struct udevice *dev) +{ + return 0; +} + +static const struct ecdsa_ops cptra_ecdsa_ops = { + .verify = cptra_ecdsa_verify, +}; + +static const struct udevice_id cptra_ecdsa_ids[] = { + { .compatible = "aspeed,ast2700-cptra-ecdsa" }, + { } +}; + +U_BOOT_DRIVER(aspeed_cptra_ecdsa) = { + .name = "aspeed_cptra_ecdsa", + .id = UCLASS_ECDSA, + .of_match = cptra_ecdsa_ids, + .ops = &cptra_ecdsa_ops, + .probe = cptra_ecdsa_probe, + .remove = cptra_ecdsa_remove, + .priv_auto = sizeof(struct cptra_ecdsa), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile index 4fbce519a0b..965c4938c8c 100644 --- a/drivers/crypto/fsl/Makefile +++ b/drivers/crypto/fsl/Makefile @@ -6,6 +6,6 @@ obj-y += sec.o obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o obj-$(CONFIG_CMD_BLOB)$(CONFIG_IMX_CAAM_DEK_ENCAP) += fsl_blob.o obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o -obj-$(CONFIG_$(SPL_TPL_)FSL_CAAM_RNG) += rng.o +obj-$(CONFIG_$(PHASE_)FSL_CAAM_RNG) += rng.o obj-$(CONFIG_FSL_DCP_RNG) += dcp_rng.o obj-$(CONFIG_FSL_MFGPROT) += fsl_mfgprot.o diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c index 55191736931..9c4ff4960fc 100644 --- a/drivers/crypto/fsl/jobdesc.c +++ b/drivers/crypto/fsl/jobdesc.c @@ -207,7 +207,7 @@ void inline_cnstr_jobdesc_hash(uint32_t *desc, append_store(desc, dma_addr_out, storelen, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD void inline_cnstr_jobdesc_blob_encap(uint32_t *desc, uint8_t *key_idnfr, uint8_t *plain_txt, uint8_t *enc_blob, uint32_t in_sz) diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 27e24808946..c45481bef0b 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -713,7 +713,7 @@ int sec_init_idx(uint8_t sec_idx) ccsr_sec_t *sec = caam->sec; uint32_t mcr = sec_in32(&sec->mcfgr); -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX8M) +#if defined(CONFIG_XPL_BUILD) && defined(CONFIG_IMX8M) uint32_t jrdid_ms = 0; #endif #ifdef CONFIG_FSL_CORENET @@ -745,14 +745,14 @@ int sec_init_idx(uint8_t sec_idx) mcr |= (1 << MCFGR_PS_SHIFT); #endif sec_out32(&sec->mcfgr, mcr); -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX8M) +#if defined(CONFIG_XPL_BUILD) && defined(CONFIG_IMX8M) jrdid_ms = JRDID_MS_TZ_OWN | JRDID_MS_PRIM_TZ | JRDID_MS_PRIM_DID; sec_out32(&sec->jrliodnr[caam->jrid].ms, jrdid_ms); #endif jr_reset(); #ifdef CONFIG_FSL_CORENET -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* * For SPL Build, Set the Liodns in SEC JR0 for * creating PAMU entries corresponding to these. diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile index 9fa5d85a27e..c1d6a6b6c59 100644 --- a/drivers/ddr/altera/Makefile +++ b/drivers/ddr/altera/Makefile @@ -6,7 +6,7 @@ # (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw> # Copyright (C) 2014-2021 Altera Corporation <www.altera.com> -ifdef CONFIG_$(SPL_)ALTERA_SDRAM +ifdef CONFIG_$(XPL_)ALTERA_SDRAM obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c index 46c53e7c7a3..3c79bb11802 100644 --- a/drivers/ddr/altera/sdram_gen5.c +++ b/drivers/ddr/altera/sdram_gen5.c @@ -20,7 +20,7 @@ #include "sequencer.h" -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD struct altera_gen5_sdram_priv { struct ram_info info; @@ -651,4 +651,4 @@ U_BOOT_DRIVER(altera_gen5_sdram) = { .priv_auto = sizeof(struct altera_gen5_sdram_priv), }; -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ diff --git a/drivers/ddr/altera/sdram_n5x.c b/drivers/ddr/altera/sdram_n5x.c index db09986f64b..d1fc93b6bdd 100644 --- a/drivers/ddr/altera/sdram_n5x.c +++ b/drivers/ddr/altera/sdram_n5x.c @@ -22,6 +22,7 @@ #include <asm/io.h> #include <linux/err.h> #include <linux/sizes.h> +#include <u-boot/schedule.h> DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index 9e57c2ecfa4..10a8e64af3d 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <dm/device_compat.h> #include <linux/sizes.h> +#include <u-boot/schedule.h> #define PGTABLE_OFF 0x4000 diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c index cc128112e4f..9c5b108267a 100644 --- a/drivers/ddr/fsl/lc_common_dimm_params.c +++ b/drivers/ddr/fsl/lc_common_dimm_params.c @@ -409,18 +409,18 @@ compute_lowest_common_dimm_parameters(const unsigned int ctrl_num, if (dimm_params[i].n_ranks) { if (dimm_params[i].registered_dimm) { temp1 = 1; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD printf("Detected RDIMM %s\n", dimm_params[i].mpart); #endif } else { temp2 = 1; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD printf("Detected UDIMM %s\n", dimm_params[i].mpart); #endif } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD puts(" "); #endif } diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index 888dfb7ff33..d59e94779ff 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -863,16 +863,16 @@ phys_size_t __fsl_ddr_sdram(fsl_ddr_info_t *pinfo) if ((first_ctrl == 0) && (total_memory - 1 > (phys_size_t)~0ULL)) { puts("Detected "); print_size(total_memory, " of memory\n"); -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD puts(" "); /* re-align to match init_dram print */ #endif puts("This U-Boot only supports <= "); print_size((unsigned long long)((phys_size_t)~0ULL)+1, " of DDR\n"); -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD puts(" "); /* re-align to match init_dram print */ #endif puts("You could rebuild it with CONFIG_PHYS_64BIT\n"); -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD puts(" "); /* re-align to match init_dram print */ #endif } diff --git a/drivers/ddr/imx/imx8m/Makefile b/drivers/ddr/imx/imx8m/Makefile index aed91dc23f4..883e6e1b0d7 100644 --- a/drivers/ddr/imx/imx8m/Makefile +++ b/drivers/ddr/imx/imx8m/Makefile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_IMX8M_DRAM) += ddr_init.o obj-y += ../phy/ endif diff --git a/drivers/ddr/imx/imx8ulp/Makefile b/drivers/ddr/imx/imx8ulp/Makefile index 7f44a92180f..4f2ad32351c 100644 --- a/drivers/ddr/imx/imx8ulp/Makefile +++ b/drivers/ddr/imx/imx8ulp/Makefile @@ -4,6 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_IMX8ULP_DRAM) += ddr_init.o endif diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig index b1795eec353..0a45340ffb6 100644 --- a/drivers/ddr/imx/imx9/Kconfig +++ b/drivers/ddr/imx/imx9/Kconfig @@ -17,6 +17,11 @@ config IMX9_DRAM_PM_COUNTER help Enable DDR controller performance monitor counter for reference events. +config IMX9_DRAM_INLINE_ECC + bool "Enable DDR INLINE ECC feature" + help + Select to enable DDR INLINE ECC feature + config SAVED_DRAM_TIMING_BASE hex "Define the base address for saved dram timing" help diff --git a/drivers/ddr/imx/imx9/Makefile b/drivers/ddr/imx/imx9/Makefile index 9403f988b32..6c9506055b8 100644 --- a/drivers/ddr/imx/imx9/Makefile +++ b/drivers/ddr/imx/imx9/Makefile @@ -4,7 +4,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_IMX9_DRAM) += ddr_init.o obj-y += ../phy/ endif diff --git a/drivers/ddr/imx/phy/Makefile b/drivers/ddr/imx/phy/Makefile index bb3d4ee5b74..592d0c6ebad 100644 --- a/drivers/ddr/imx/phy/Makefile +++ b/drivers/ddr/imx/phy/Makefile @@ -4,6 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_IMX_SNPS_DDR_PHY) += helper.o ddrphy_utils.o ddrphy_train.o ddrphy_csr.o endif diff --git a/drivers/ddr/marvell/a38x/Makefile b/drivers/ddr/marvell/a38x/Makefile index 4e8a9d190d7..f49d009920e 100644 --- a/drivers/ddr/marvell/a38x/Makefile +++ b/drivers/ddr/marvell/a38x/Makefile @@ -1,29 +1,29 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-$(CONFIG_SPL_BUILD) += mv_ddr_plat.o -obj-$(CONFIG_SPL_BUILD) += mv_ddr_sys_env_lib.o -obj-$(CONFIG_SPL_BUILD) += ddr3_debug.o -obj-$(CONFIG_SPL_BUILD) += ddr3_init.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_bist.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_centralization.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_db.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_hw_algo.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_ip_engine.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_leveling.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_pbs.o -obj-$(CONFIG_SPL_BUILD) += mv_ddr_build_message.o -obj-$(CONFIG_SPL_BUILD) += mv_ddr_common.o -obj-$(CONFIG_SPL_BUILD) += mv_ddr_spd.o -obj-$(CONFIG_SPL_BUILD) += mv_ddr_topology.o -obj-$(CONFIG_SPL_BUILD) += xor.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_plat.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_sys_env_lib.o +obj-$(CONFIG_XPL_BUILD) += ddr3_debug.o +obj-$(CONFIG_XPL_BUILD) += ddr3_init.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_bist.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_centralization.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_db.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_hw_algo.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_ip_engine.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_leveling.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_pbs.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_build_message.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_common.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_spd.o +obj-$(CONFIG_XPL_BUILD) += mv_ddr_topology.o +obj-$(CONFIG_XPL_BUILD) += xor.o obj-$(CONFIG_ARMADA_38X_SUPPORT_OLD_DDR3_TRAINING) += old/ ifdef CONFIG_DDR4 - obj-$(CONFIG_SPL_BUILD) += mv_ddr4_mpr_pda_if.o - obj-$(CONFIG_SPL_BUILD) += mv_ddr4_training.o - obj-$(CONFIG_SPL_BUILD) += mv_ddr4_training_calibration.o - obj-$(CONFIG_SPL_BUILD) += mv_ddr4_training_db.o - obj-$(CONFIG_SPL_BUILD) += mv_ddr4_training_leveling.o + obj-$(CONFIG_XPL_BUILD) += mv_ddr4_mpr_pda_if.o + obj-$(CONFIG_XPL_BUILD) += mv_ddr4_training.o + obj-$(CONFIG_XPL_BUILD) += mv_ddr4_training_calibration.o + obj-$(CONFIG_XPL_BUILD) += mv_ddr4_training_db.o + obj-$(CONFIG_XPL_BUILD) += mv_ddr4_training_leveling.o endif diff --git a/drivers/ddr/marvell/a38x/old/Makefile b/drivers/ddr/marvell/a38x/old/Makefile index 1645a79b405..c9bc746cc2b 100644 --- a/drivers/ddr/marvell/a38x/old/Makefile +++ b/drivers/ddr/marvell/a38x/old/Makefile @@ -2,20 +2,20 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-$(CONFIG_SPL_BUILD) += ddr3_a38x.o -obj-$(CONFIG_SPL_BUILD) += ddr3_a38x_training.o -obj-$(CONFIG_SPL_BUILD) += ddr3_debug.o -obj-$(CONFIG_SPL_BUILD) += ddr3_hws_hw_training.o -obj-$(CONFIG_SPL_BUILD) += ddr3_init.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_bist.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_centralization.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_db.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_hw_algo.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_ip_engine.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_leveling.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_pbs.o -obj-$(CONFIG_SPL_BUILD) += ddr3_training_static.o +obj-$(CONFIG_XPL_BUILD) += ddr3_a38x.o +obj-$(CONFIG_XPL_BUILD) += ddr3_a38x_training.o +obj-$(CONFIG_XPL_BUILD) += ddr3_debug.o +obj-$(CONFIG_XPL_BUILD) += ddr3_hws_hw_training.o +obj-$(CONFIG_XPL_BUILD) += ddr3_init.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_bist.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_centralization.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_db.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_hw_algo.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_ip_engine.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_leveling.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_pbs.o +obj-$(CONFIG_XPL_BUILD) += ddr3_training_static.o define IncludeSymbolRename CFLAGS_$(1) = -include $(srctree)/drivers/ddr/marvell/a38x/old/glue_symbol_renames.h diff --git a/drivers/ddr/marvell/axp/Makefile b/drivers/ddr/marvell/axp/Makefile index d04d9a21db2..01e427296e6 100644 --- a/drivers/ddr/marvell/axp/Makefile +++ b/drivers/ddr/marvell/axp/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-$(CONFIG_SPL_BUILD) += ddr3_dfs.o -obj-$(CONFIG_SPL_BUILD) += ddr3_dqs.o -obj-$(CONFIG_SPL_BUILD) += ddr3_hw_training.o -obj-$(CONFIG_SPL_BUILD) += ddr3_init.o -obj-$(CONFIG_SPL_BUILD) += ddr3_pbs.o -obj-$(CONFIG_SPL_BUILD) += ddr3_read_leveling.o -obj-$(CONFIG_SPL_BUILD) += ddr3_sdram.o -obj-$(CONFIG_SPL_BUILD) += ddr3_spd.o -obj-$(CONFIG_SPL_BUILD) += ddr3_write_leveling.o -obj-$(CONFIG_SPL_BUILD) += xor.o +obj-$(CONFIG_XPL_BUILD) += ddr3_dfs.o +obj-$(CONFIG_XPL_BUILD) += ddr3_dqs.o +obj-$(CONFIG_XPL_BUILD) += ddr3_hw_training.o +obj-$(CONFIG_XPL_BUILD) += ddr3_init.o +obj-$(CONFIG_XPL_BUILD) += ddr3_pbs.o +obj-$(CONFIG_XPL_BUILD) += ddr3_read_leveling.o +obj-$(CONFIG_XPL_BUILD) += ddr3_sdram.o +obj-$(CONFIG_XPL_BUILD) += ddr3_spd.o +obj-$(CONFIG_XPL_BUILD) += ddr3_write_leveling.o +obj-$(CONFIG_XPL_BUILD) += xor.o diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index aadd7e8cf7f..604386bb734 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -20,6 +20,7 @@ config DFU_WRITE_ALT config DFU_TFTP bool "DFU via TFTP" depends on NETDEVICES + depends on !NET_LWIP select UPDATE_COMMON select DFU_OVER_TFTP help diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile index dfbf64da667..05d7cc61caa 100644 --- a/drivers/dfu/Makefile +++ b/drivers/dfu/Makefile @@ -3,11 +3,11 @@ # Copyright (C) 2012 Samsung Electronics # Lukasz Majewski <l.majewski@samsung.com> -obj-$(CONFIG_$(SPL_)DFU) += dfu.o -obj-$(CONFIG_$(SPL_)DFU_MMC) += dfu_mmc.o -obj-$(CONFIG_$(SPL_)DFU_MTD) += dfu_mtd.o -obj-$(CONFIG_$(SPL_)DFU_NAND) += dfu_nand.o -obj-$(CONFIG_$(SPL_)DFU_RAM) += dfu_ram.o -obj-$(CONFIG_$(SPL_)DFU_SF) += dfu_sf.o -obj-$(CONFIG_$(SPL_)DFU_WRITE_ALT) += dfu_alt.o -obj-$(CONFIG_$(SPL_)DFU_VIRT) += dfu_virt.o +obj-$(CONFIG_$(XPL_)DFU) += dfu.o +obj-$(CONFIG_$(XPL_)DFU_MMC) += dfu_mmc.o +obj-$(CONFIG_$(XPL_)DFU_MTD) += dfu_mtd.o +obj-$(CONFIG_$(XPL_)DFU_NAND) += dfu_nand.o +obj-$(CONFIG_$(XPL_)DFU_RAM) += dfu_ram.o +obj-$(CONFIG_$(XPL_)DFU_SF) += dfu_sf.o +obj-$(CONFIG_$(XPL_)DFU_WRITE_ALT) += dfu_alt.o +obj-$(CONFIG_$(XPL_)DFU_VIRT) += dfu_virt.o diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 540d48fab77..7a4d7ba2a7f 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -27,6 +27,21 @@ static unsigned long dfu_timeout = 0; #endif bool dfu_reinit_needed = false; +bool dfu_alt_info_changed = false; + +static int on_dfu_alt_info(const char *name, const char *value, enum env_op op, + int flags) +{ + switch (op) { + case env_op_create: + case env_op_overwrite: + case env_op_delete: + dfu_alt_info_changed = true; + break; + } + return 0; +} +U_BOOT_ENV_CALLBACK(dfu_alt_info, on_dfu_alt_info); /* * The purpose of the dfu_flush_callback() function is to @@ -152,6 +167,7 @@ int dfu_init_env_entities(char *interface, char *devstr) int ret = 0; dfu_reinit_needed = false; + dfu_alt_info_changed = false; #ifdef CONFIG_SET_DFU_ALT_INFO set_dfu_alt_info(interface, devstr); diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 8f7ecfa8fc7..c19eb919388 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -232,7 +232,8 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) break; case DFU_SCRIPT: /* script may have changed the dfu_alt_info */ - dfu_reinit_needed = true; + if (dfu_alt_info_changed) + dfu_reinit_needed = true; break; case DFU_RAW_ADDR: case DFU_SKIP: diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index 7c1c0f9e2dc..8f7296adec6 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -123,6 +123,7 @@ static struct spi_flash *parse_dev(char *devstr) unsigned int mode = CONFIG_SF_DEFAULT_MODE; char *s, *endp; struct spi_flash *dev; + bool use_dt = true; s = strsep(&devstr, ":"); if (!s || !*s || (bus = simple_strtoul(s, &endp, 0), *endp)) { @@ -143,6 +144,8 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI speed %s\n", s); return NULL; } + if (IS_ENABLED(CONFIG_DM_SPI_FLASH)) + use_dt = false; } s = strsep(&devstr, ":"); @@ -152,9 +155,20 @@ static struct spi_flash *parse_dev(char *devstr) printf("Invalid SPI mode %s\n", s); return NULL; } + if (IS_ENABLED(CONFIG_DM_SPI_FLASH)) + use_dt = false; } - dev = spi_flash_probe(bus, cs, speed, mode); + if (IS_ENABLED(CONFIG_DM_SPI_FLASH) && use_dt) { + struct udevice *new; + + if (!spi_flash_probe_bus_cs(bus, cs, &new)) + dev = dev_get_uclass_priv(new); + else + dev = NULL; + } else { + dev = spi_flash_probe(bus, cs, speed, mode); + } if (!dev) { printf("Failed to create SPI flash at %u:%u:%u:%u\n", bus, cs, speed, mode); diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index e23d09e6b81..dac4023ccfd 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -1700,141 +1700,6 @@ static int setup_resources(struct udma_dev *ud) return ch_count; } -static int udma_probe(struct udevice *dev) -{ - struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); - struct udma_dev *ud = dev_get_priv(dev); - int i, ret; - struct udevice *tmp; - struct udevice *tisci_dev = NULL; - struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; - ofnode navss_ofnode = ofnode_get_parent(dev_ofnode(dev)); - - ud->match_data = (void *)dev_get_driver_data(dev); - ret = udma_get_mmrs(dev); - if (ret) - return ret; - - ud->psil_base = ud->match_data->psil_base; - - ret = uclass_get_device_by_phandle(UCLASS_FIRMWARE, dev, - "ti,sci", &tisci_dev); - if (ret) { - debug("Failed to get TISCI phandle (%d)\n", ret); - tisci_rm->tisci = NULL; - return -EINVAL; - } - tisci_rm->tisci = (struct ti_sci_handle *) - (ti_sci_get_handle_from_sysfw(tisci_dev)); - - tisci_rm->tisci_dev_id = -1; - ret = dev_read_u32(dev, "ti,sci-dev-id", &tisci_rm->tisci_dev_id); - if (ret) { - dev_err(dev, "ti,sci-dev-id read failure %d\n", ret); - return ret; - } - - tisci_rm->tisci_navss_dev_id = -1; - ret = ofnode_read_u32(navss_ofnode, "ti,sci-dev-id", - &tisci_rm->tisci_navss_dev_id); - if (ret) { - dev_err(dev, "navss sci-dev-id read failure %d\n", ret); - return ret; - } - - tisci_rm->tisci_udmap_ops = &tisci_rm->tisci->ops.rm_udmap_ops; - tisci_rm->tisci_psil_ops = &tisci_rm->tisci->ops.rm_psil_ops; - - if (ud->match_data->type == DMA_TYPE_UDMA) { - ret = uclass_get_device_by_phandle(UCLASS_MISC, dev, - "ti,ringacc", &tmp); - ud->ringacc = dev_get_priv(tmp); - } else { - struct k3_ringacc_init_data ring_init_data; - - ring_init_data.tisci = ud->tisci_rm.tisci; - ring_init_data.tisci_dev_id = ud->tisci_rm.tisci_dev_id; - if (ud->match_data->type == DMA_TYPE_BCDMA) { - ring_init_data.num_rings = ud->bchan_cnt + - ud->tchan_cnt + - ud->rchan_cnt; - } else { - ring_init_data.num_rings = ud->rflow_cnt + - ud->tflow_cnt; - } - - ud->ringacc = k3_ringacc_dmarings_init(dev, &ring_init_data); - } - if (IS_ERR(ud->ringacc)) - return PTR_ERR(ud->ringacc); - - ud->dev = dev; - ret = setup_resources(ud); - if (ret < 0) - return ret; - - ud->ch_count = ret; - - for (i = 0; i < ud->bchan_cnt; i++) { - struct udma_bchan *bchan = &ud->bchans[i]; - - bchan->id = i; - bchan->reg_rt = ud->mmrs[MMR_BCHANRT] + i * 0x1000; - } - - for (i = 0; i < ud->tchan_cnt; i++) { - struct udma_tchan *tchan = &ud->tchans[i]; - - tchan->id = i; - tchan->reg_chan = ud->mmrs[MMR_TCHAN] + UDMA_CH_100(i); - tchan->reg_rt = ud->mmrs[MMR_TCHANRT] + UDMA_CH_1000(i); - } - - for (i = 0; i < ud->rchan_cnt; i++) { - struct udma_rchan *rchan = &ud->rchans[i]; - - rchan->id = i; - rchan->reg_chan = ud->mmrs[MMR_RCHAN] + UDMA_CH_100(i); - rchan->reg_rt = ud->mmrs[MMR_RCHANRT] + UDMA_CH_1000(i); - } - - for (i = 0; i < ud->rflow_cnt; i++) { - struct udma_rflow *rflow = &ud->rflows[i]; - - rflow->id = i; - rflow->reg_rflow = ud->mmrs[MMR_RFLOW] + UDMA_CH_40(i); - } - - for (i = 0; i < ud->ch_count; i++) { - struct udma_chan *uc = &ud->channels[i]; - - uc->ud = ud; - uc->id = i; - uc->config.remote_thread_id = -1; - uc->bchan = NULL; - uc->tchan = NULL; - uc->rchan = NULL; - uc->config.mapped_channel_id = -1; - uc->config.default_flow_id = -1; - uc->config.dir = DMA_MEM_TO_MEM; - sprintf(uc->name, "UDMA chan%d\n", i); - if (!i) - uc->in_use = true; - } - - pr_debug("%s(rev: 0x%08x) CAP0-3: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", - dev->name, - udma_read(ud->mmrs[MMR_GCFG], 0), - udma_read(ud->mmrs[MMR_GCFG], 0x20), - udma_read(ud->mmrs[MMR_GCFG], 0x24), - udma_read(ud->mmrs[MMR_GCFG], 0x28), - udma_read(ud->mmrs[MMR_GCFG], 0x2c)); - - uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | DMA_SUPPORTS_MEM_TO_DEV; - - return 0; -} - static int udma_push_to_ring(struct k3_nav_ring *ring, void *elem) { u64 addr = 0; @@ -2325,37 +2190,12 @@ static int udma_transfer(struct udevice *dev, int direction, /* Channel0 is reserved for memcpy */ struct udma_chan *uc = &ud->channels[0]; dma_addr_t paddr = 0; - int ret; - - switch (ud->match_data->type) { - case DMA_TYPE_UDMA: - ret = udma_alloc_chan_resources(uc); - break; - case DMA_TYPE_BCDMA: - ret = bcdma_alloc_chan_resources(uc); - break; - default: - return -EINVAL; - }; - if (ret) - return ret; udma_prep_dma_memcpy(uc, dst, src, len); udma_start(uc); udma_poll_completion(uc, &paddr); udma_stop(uc); - switch (ud->match_data->type) { - case DMA_TYPE_UDMA: - udma_free_chan_resources(uc); - break; - case DMA_TYPE_BCDMA: - bcdma_free_bchan_resources(uc); - break; - default: - return -EINVAL; - }; - return 0; } @@ -2717,6 +2557,177 @@ static int udma_get_cfg(struct dma *dma, u32 id, void **data) return -EINVAL; } +static int udma_probe(struct udevice *dev) +{ + struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct udma_dev *ud = dev_get_priv(dev); + int i, ret; + struct udevice *tmp; + struct udevice *tisci_dev = NULL; + struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; + struct udma_chan *uc; + ofnode navss_ofnode = ofnode_get_parent(dev_ofnode(dev)); + + ud->match_data = (void *)dev_get_driver_data(dev); + ret = udma_get_mmrs(dev); + if (ret) + return ret; + + ud->psil_base = ud->match_data->psil_base; + + ret = uclass_get_device_by_phandle(UCLASS_FIRMWARE, dev, + "ti,sci", &tisci_dev); + if (ret) { + debug("Failed to get TISCI phandle (%d)\n", ret); + tisci_rm->tisci = NULL; + return -EINVAL; + } + tisci_rm->tisci = (struct ti_sci_handle *) + (ti_sci_get_handle_from_sysfw(tisci_dev)); + + tisci_rm->tisci_dev_id = -1; + ret = dev_read_u32(dev, "ti,sci-dev-id", &tisci_rm->tisci_dev_id); + if (ret) { + dev_err(dev, "ti,sci-dev-id read failure %d\n", ret); + return ret; + } + + tisci_rm->tisci_navss_dev_id = -1; + ret = ofnode_read_u32(navss_ofnode, "ti,sci-dev-id", + &tisci_rm->tisci_navss_dev_id); + if (ret) { + dev_err(dev, "navss sci-dev-id read failure %d\n", ret); + return ret; + } + + tisci_rm->tisci_udmap_ops = &tisci_rm->tisci->ops.rm_udmap_ops; + tisci_rm->tisci_psil_ops = &tisci_rm->tisci->ops.rm_psil_ops; + + if (ud->match_data->type == DMA_TYPE_UDMA) { + ret = uclass_get_device_by_phandle(UCLASS_MISC, dev, + "ti,ringacc", &tmp); + ud->ringacc = dev_get_priv(tmp); + } else { + struct k3_ringacc_init_data ring_init_data; + + ring_init_data.tisci = ud->tisci_rm.tisci; + ring_init_data.tisci_dev_id = ud->tisci_rm.tisci_dev_id; + if (ud->match_data->type == DMA_TYPE_BCDMA) { + ring_init_data.num_rings = ud->bchan_cnt + + ud->tchan_cnt + + ud->rchan_cnt; + } else { + ring_init_data.num_rings = ud->rflow_cnt + + ud->tflow_cnt; + } + + ud->ringacc = k3_ringacc_dmarings_init(dev, &ring_init_data); + } + if (IS_ERR(ud->ringacc)) + return PTR_ERR(ud->ringacc); + + ud->dev = dev; + ret = setup_resources(ud); + if (ret < 0) + return ret; + + ud->ch_count = ret; + + for (i = 0; i < ud->bchan_cnt; i++) { + struct udma_bchan *bchan = &ud->bchans[i]; + + bchan->id = i; + bchan->reg_rt = ud->mmrs[MMR_BCHANRT] + i * 0x1000; + } + + for (i = 0; i < ud->tchan_cnt; i++) { + struct udma_tchan *tchan = &ud->tchans[i]; + + tchan->id = i; + tchan->reg_chan = ud->mmrs[MMR_TCHAN] + UDMA_CH_100(i); + tchan->reg_rt = ud->mmrs[MMR_TCHANRT] + UDMA_CH_1000(i); + } + + for (i = 0; i < ud->rchan_cnt; i++) { + struct udma_rchan *rchan = &ud->rchans[i]; + + rchan->id = i; + rchan->reg_chan = ud->mmrs[MMR_RCHAN] + UDMA_CH_100(i); + rchan->reg_rt = ud->mmrs[MMR_RCHANRT] + UDMA_CH_1000(i); + } + + for (i = 0; i < ud->rflow_cnt; i++) { + struct udma_rflow *rflow = &ud->rflows[i]; + + rflow->id = i; + rflow->reg_rflow = ud->mmrs[MMR_RFLOW] + UDMA_CH_40(i); + } + + for (i = 0; i < ud->ch_count; i++) { + struct udma_chan *uc = &ud->channels[i]; + + uc->ud = ud; + uc->id = i; + uc->config.remote_thread_id = -1; + uc->bchan = NULL; + uc->tchan = NULL; + uc->rchan = NULL; + uc->config.mapped_channel_id = -1; + uc->config.default_flow_id = -1; + uc->config.dir = DMA_MEM_TO_MEM; + sprintf(uc->name, "UDMA chan%d\n", i); + if (!i) + uc->in_use = true; + } + + pr_debug("%s(rev: 0x%08x) CAP0-3: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + dev->name, + udma_read(ud->mmrs[MMR_GCFG], 0), + udma_read(ud->mmrs[MMR_GCFG], 0x20), + udma_read(ud->mmrs[MMR_GCFG], 0x24), + udma_read(ud->mmrs[MMR_GCFG], 0x28), + udma_read(ud->mmrs[MMR_GCFG], 0x2c)); + + uc_priv->supported = DMA_SUPPORTS_MEM_TO_MEM | DMA_SUPPORTS_MEM_TO_DEV; + + uc = &ud->channels[0]; + ret = 0; + switch (ud->match_data->type) { + case DMA_TYPE_UDMA: + ret = udma_alloc_chan_resources(uc); + break; + case DMA_TYPE_BCDMA: + ret = bcdma_alloc_chan_resources(uc); + break; + default: + break; /* Do nothing in any other case */ + }; + + if (ret) + dev_err(dev, " Channel 0 allocation failure %d\n", ret); + + return ret; +} + +static int udma_remove(struct udevice *dev) +{ + struct udma_dev *ud = dev_get_priv(dev); + struct udma_chan *uc = &ud->channels[0]; + + switch (ud->match_data->type) { + case DMA_TYPE_UDMA: + udma_free_chan_resources(uc); + break; + case DMA_TYPE_BCDMA: + bcdma_free_bchan_resources(uc); + break; + default: + break; + }; + + return 0; +} + static const struct dma_ops udma_ops = { .transfer = udma_transfer, .of_xlate = udma_of_xlate, @@ -2855,5 +2866,7 @@ U_BOOT_DRIVER(ti_edma3) = { .of_match = udma_ids, .ops = &udma_ops, .probe = udma_probe, + .remove = udma_remove, .priv_auto = sizeof(struct udma_dev), + .flags = DM_FLAG_OS_PREPARE, }; diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 70207573de2..1eb460f5a02 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -1,5 +1,6 @@ menu "Fastboot support" depends on CMDLINE + depends on !NET_LWIP config FASTBOOT bool diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 7ce83d72bd3..8b979f69ed9 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_FIRMWARE) += firmware-uclass.o -obj-$(CONFIG_$(SPL_)ARM_PSCI_FW) += psci.o +obj-$(CONFIG_$(XPL_)ARM_PSCI_FW) += psci.o obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_SANDBOX) += firmware-sandbox.o obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware-zynqmp.o diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index f99507d86c6..4b1b80d7abe 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -260,7 +260,7 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) int err; u32 ret_payload[PAYLOAD_ARG_CNT]; - if (IS_ENABLED(CONFIG_SPL_BUILD)) + if (IS_ENABLED(CONFIG_XPL_BUILD)) printf("Loading new PMUFW cfg obj (%ld bytes)\n", size); flush_dcache_range((ulong)cfg_obj, (ulong)(cfg_obj + size)); @@ -282,7 +282,7 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) if (ret_payload[0]) printf("PMUFW returned 0x%08x status!\n", ret_payload[0]); - if ((err || ret_payload[0]) && IS_ENABLED(CONFIG_SPL_BUILD)) + if ((err || ret_payload[0]) && IS_ENABLED(CONFIG_XPL_BUILD)) panic("PMUFW config object loading failed in EL3\n"); return 0; @@ -354,7 +354,7 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n", __func__, current_el(), api_id, arg0, arg1, arg2, arg3); - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) { #if defined(CONFIG_ZYNQMP_IPI) /* * Use fixed payload and arg size as the EL2 call. The firmware @@ -416,10 +416,10 @@ static int zynqmp_firmware_bind(struct udevice *dev) int ret; struct udevice *child; - if ((IS_ENABLED(CONFIG_SPL_BUILD) && + if ((IS_ENABLED(CONFIG_XPL_BUILD) && IS_ENABLED(CONFIG_SPL_POWER_DOMAIN) && IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN)) || - (!IS_ENABLED(CONFIG_SPL_BUILD) && + (!IS_ENABLED(CONFIG_XPL_BUILD) && IS_ENABLED(CONFIG_ZYNQMP_POWER_DOMAIN))) { ret = device_bind_driver_to_node(dev, "zynqmp_power_domain", "zynqmp_power_domain", diff --git a/drivers/fpga/intel_sdm_mb.c b/drivers/fpga/intel_sdm_mb.c index 45caef4f5c1..5a65bd98779 100644 --- a/drivers/fpga/intel_sdm_mb.c +++ b/drivers/fpga/intel_sdm_mb.c @@ -17,7 +17,7 @@ #define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS 60000 #define RECONFIG_STATUS_INTERVAL_DELAY_US 1000000 -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF) +#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF) #define BITSTREAM_CHUNK_SIZE 0xFFFF0 #define RECONFIG_STATUS_POLL_RETRY_MAX 100 diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 57467b4d975..3e86d854a01 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -414,13 +414,13 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize, if (bstype != BIT_PARTIAL) zynq_slcr_devcfg_enable(); - if (!IS_ENABLED(CONFIG_SPL_BUILD)) + if (!IS_ENABLED(CONFIG_XPL_BUILD)) puts("INFO:post config was not run, please run manually if needed\n"); return FPGA_SUCCESS; } -#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_XPL_BUILD) static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, fpga_fs_info *fsinfo) { @@ -504,7 +504,7 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, struct xilinx_fpga_op zynq_op = { .load = zynq_load, -#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_CMD_FPGA_LOADFS) && !defined(CONFIG_XPL_BUILD) .loadfs = zynq_loadfs, #endif }; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3996333fe8d..1e5711663eb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -700,4 +700,10 @@ config RZG2L_GPIO Support the gpio functionality of the pin function controller (PFC) on the Renesas RZ/G2L SoC family. +config SPL_ADP5585_GPIO + bool "ADP5585 GPIO driver in SPL" + depends on SPL_DM_GPIO && SPL_I2C + help + Support ADP5585 GPIO expander in SPL. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index da0faf05246..fe81b6ba88b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -3,14 +3,14 @@ # Copyright 2000-2008 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_DWAPB_GPIO) += dwapb_gpio.o obj-$(CONFIG_AXP_GPIO) += axp_gpio.o obj-$(CONFIG_DM_74X164) += 74x164_gpio.o endif -obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o +obj-$(CONFIG_$(PHASE_)DM_GPIO) += gpio-uclass.o -obj-$(CONFIG_$(SPL_)DM_PCA953X) += pca953x_gpio.o +obj-$(CONFIG_$(XPL_)DM_PCA953X) += pca953x_gpio.o obj-$(CONFIG_ASPEED_GPIO) += gpio-aspeed.o obj-$(CONFIG_ASPEED_G7_GPIO) += gpio-aspeed-g7.o @@ -24,7 +24,7 @@ obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o obj-$(CONFIG_IPROC_GPIO) += iproc_gpio.o obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o -obj-$(CONFIG_$(SPL_TPL_)MCP230XX_GPIO) += mcp230xx_gpio.o +obj-$(CONFIG_$(PHASE_)MCP230XX_GPIO) += mcp230xx_gpio.o obj-$(CONFIG_MXC_GPIO) += mxc_gpio.o obj-$(CONFIG_MXS_GPIO) += mxs_gpio.o obj-$(CONFIG_NPCM_GPIO) += npcm_gpio.o @@ -57,13 +57,13 @@ obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o -obj-$(CONFIG_$(SPL_)PALMAS_GPIO) += palmas_gpio.o +obj-$(CONFIG_$(XPL_)PALMAS_GPIO) += palmas_gpio.o obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o obj-$(CONFIG_OCTEON_GPIO) += octeon_gpio.o obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o -obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o -obj-$(CONFIG_$(SPL_TPL_)QCOM_PMIC_GPIO) += qcom_pmic_gpio.o +obj-$(CONFIG_$(XPL_)PCF8575_GPIO) += pcf8575_gpio.o +obj-$(CONFIG_$(PHASE_)QCOM_PMIC_GPIO) += qcom_pmic_gpio.o obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o @@ -71,10 +71,10 @@ obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o -obj-$(CONFIG_$(SPL_)MAX77663_GPIO) += max77663_gpio.o +obj-$(CONFIG_$(XPL_)MAX77663_GPIO) += max77663_gpio.o obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o obj-$(CONFIG_FTGPIO010) += ftgpio010.o -obj-$(CONFIG_ADP5585_GPIO) += adp5585_gpio.o +obj-$(CONFIG_$(SPL_)ADP5585_GPIO) += adp5585_gpio.o obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 92ce68dd4a1..0213271e3a6 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -412,7 +412,7 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label) static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...) { -#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) +#if !defined(CONFIG_XPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) va_list args; char buf[40]; @@ -461,7 +461,7 @@ int gpio_request(unsigned gpio, const char *label) */ int gpio_requestf(unsigned gpio, const char *fmt, ...) { -#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) +#if !defined(CONFIG_XPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) va_list args; char buf[40]; diff --git a/drivers/gpio/mcp230xx_gpio.c b/drivers/gpio/mcp230xx_gpio.c index 42e7fe9d474..b6f533b1306 100644 --- a/drivers/gpio/mcp230xx_gpio.c +++ b/drivers/gpio/mcp230xx_gpio.c @@ -14,6 +14,7 @@ #include <asm/gpio.h> #include <dm/device_compat.h> #include <dt-bindings/gpio/gpio.h> +#include <linux/delay.h> enum mcp230xx_type { UNKNOWN = 0, diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 2fb266f1285..cea073b3297 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -34,13 +34,31 @@ struct msm_gpio_bank { #define GPIO_IN_OUT_REG(dev, x) \ (GPIO_CONFIG_REG(dev, x) + 0x4) +static void msm_gpio_direction_input_special(struct msm_gpio_bank *priv, + unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->ctl_reg || data->oe_bit >= 31) + return; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), 0); +} + static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return; + msm_gpio_direction_input_special(priv, gpio); /* Disable OE bit */ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio), @@ -49,13 +67,33 @@ static void msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) return; } +static int msm_gpio_set_value_special(struct msm_gpio_bank *priv, + unsigned int gpio, int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + return 0; +} + static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_set_value_special(priv, gpio, value); value = !!value; /* set value */ @@ -64,14 +102,42 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) return 0; } +static int msm_gpio_direction_output_special(struct msm_gpio_bank *priv, + unsigned int gpio, + int value) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->out_bit >= 31) + return 0; + + value = !!value; + /* set value */ + writel(value << data->out_bit, priv->base + data->io_reg); + + if (!data->ctl_reg || data->oe_bit >= 31) + return 0; + + /* switch direction */ + clrsetbits_le32(priv->base + data->ctl_reg, + BIT(data->oe_bit), BIT(data->oe_bit)); + + return 0; +} + static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_direction_output_special(priv, gpio, value); value = !!value; /* set value */ @@ -100,13 +166,28 @@ static int msm_gpio_set_flags(struct udevice *dev, unsigned int gpio, ulong flag return 0; } +static int msm_gpio_get_value_special(struct msm_gpio_bank *priv, unsigned int gpio) +{ + unsigned int offset = gpio - priv->pin_data->special_pins_start; + const struct msm_special_pin_data *data; + + if (!priv->pin_data->special_pins_data) + return 0; + + data = &priv->pin_data->special_pins_data[offset]; + + if (!data->io_reg || data->in_bit >= 31) + return 0; + + return !!(readl(priv->base + data->io_reg) >> data->in_bit); +} + static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); - /* Always NOP for special pins, assume they're in the correct state */ if (qcom_is_special_pin(priv->pin_data, gpio)) - return 0; + return msm_gpio_get_value_special(priv, gpio); return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN); } diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index fc4dcf9f986..2fb14590c0f 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -143,7 +143,7 @@ int pca953x_get_val(uint8_t chip) return (int)val; } -#if defined(CONFIG_CMD_PCA953X) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_CMD_PCA953X) && !defined(CONFIG_XPL_BUILD) /* * Display pca953x information */ diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c index 80fee841ee3..f2ef4e5ce14 100644 --- a/drivers/gpio/qcom_pmic_gpio.c +++ b/drivers/gpio/qcom_pmic_gpio.c @@ -69,17 +69,6 @@ #define REG_EN_CTL 0x46 #define REG_EN_CTL_ENABLE (1 << 7) -/** - * pmic_gpio_match_data - platform specific configuration - * - * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them. - * This is a workaround for an unknown bug on some platforms where trying to write the - * GPIO configuration registers causes the board to hang. - */ -enum pmic_gpio_quirks { - QCOM_PMIC_QUIRK_READONLY = (1 << 0), -}; - struct qcom_pmic_gpio_data { uint32_t pid; /* Peripheral ID on SPMI bus */ bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */ @@ -128,13 +117,8 @@ static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset, { struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); uint32_t gpio_base = plat->pid + REG_OFFSET(offset); - ulong quirks = dev_get_driver_data(dev); int ret = 0; - /* Some PMICs don't like their GPIOs being configured */ - if (quirks & QCOM_PMIC_QUIRK_READONLY) - return 0; - /* Disable the GPIO */ ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, REG_EN_CTL_ENABLE, 0); @@ -278,7 +262,6 @@ static int qcom_gpio_bind(struct udevice *dev) { struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); - ulong quirks = dev_get_driver_data(dev); struct udevice *child; struct driver *drv; int ret; @@ -292,7 +275,7 @@ static int qcom_gpio_bind(struct udevice *dev) /* Bind the GPIO driver as a child of the PMIC. */ ret = device_bind_with_driver_data(dev, drv, dev->name, - quirks, dev_ofnode(dev), &child); + 0, dev_ofnode(dev), &child); if (ret) return log_msg_ret("bind", ret); @@ -361,11 +344,11 @@ static int qcom_gpio_probe(struct udevice *dev) static const struct udevice_id qcom_gpio_ids[] = { { .compatible = "qcom,pm8916-gpio" }, { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */ - { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, + { .compatible = "qcom,pm8998-gpio" }, { .compatible = "qcom,pms405-gpio" }, - { .compatible = "qcom,pm6125-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, - { .compatible = "qcom,pm8150-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, - { .compatible = "qcom,pm8550-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, + { .compatible = "qcom,pm6125-gpio" }, + { .compatible = "qcom,pm8150-gpio" }, + { .compatible = "qcom,pm8550-gpio" }, { } }; diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index 24ba12dd820..57c49c75939 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -126,7 +126,7 @@ static int rockchip_gpio_get_function(struct udevice *dev, unsigned offset) } /* Simple SPL interface to GPIOs */ -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD enum { PULL_NONE_1V8 = 0, @@ -169,7 +169,7 @@ int spl_gpio_output(void *vregs, uint gpio, int value) return 0; } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ static int rockchip_gpio_probe(struct udevice *dev) { diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 83e65aa4aec..53dbbe97b5a 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -92,7 +92,7 @@ static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) writel(value, &bank->dat); } -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* Common GPIO API - SPL does not support driver model yet */ int gpio_set_value(unsigned gpio, int value) { @@ -118,7 +118,7 @@ static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) value = readl(&bank->dat); return !!(value & DAT_MASK(gpio)); } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) { @@ -185,7 +185,7 @@ int s5p_gpio_get_pin(unsigned gpio) } /* Driver model interface */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD /* set GPIO pin 'gpio' as an input */ static int exynos_gpio_direction_input(struct udevice *dev, unsigned offset) { @@ -230,7 +230,7 @@ static int exynos_gpio_set_value(struct udevice *dev, unsigned offset, return 0; } -#endif /* nCONFIG_SPL_BUILD */ +#endif /* nCONFIG_XPL_BUILD */ /* * There is no common GPIO API for pull, drv, pin, rate (yet). These @@ -260,7 +260,7 @@ void gpio_set_rate(int gpio, int mode) s5p_gpio_get_pin(gpio), mode); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static int exynos_gpio_get_function(struct udevice *dev, unsigned offset) { struct exynos_bank_info *state = dev_get_priv(dev); diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 218ca2af397..2ca4960f17a 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -245,7 +245,7 @@ int sunxi_name_to_gpio(const char *name) { unsigned int gpio; int ret; -#if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO +#if !defined CONFIG_XPL_BUILD && defined CONFIG_AXP_GPIO char lookup[8]; if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) { diff --git a/drivers/gpio/tca642x.c b/drivers/gpio/tca642x.c index 1d45b500746..8307a07e14e 100644 --- a/drivers/gpio/tca642x.c +++ b/drivers/gpio/tca642x.c @@ -164,7 +164,7 @@ int tca642x_set_inital_state(uchar chip, struct tca642x_bank_info init_data[]) return ret; } -#if defined(CONFIG_CMD_TCA642X) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_CMD_TCA642X) && !defined(CONFIG_XPL_BUILD) /* * Display tca642x information */ diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 0c40d36c41e..b83df351e74 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -257,6 +257,56 @@ static const struct dm_gpio_ops gpio_tegra_ops = { .xlate = tegra_gpio_xlate, }; +/* + * SPL GPIO functions. + */ +int spl_gpio_output(void *regs, uint gpio, int value) +{ + /* Configure GPIO output value. */ + set_level(gpio, value); + + /* Configure GPIO direction as output. */ + set_direction(gpio, DIRECTION_OUTPUT); + + /* Enable the pin as a GPIO */ + set_config(gpio, 1); + + return 0; +} + +int spl_gpio_input(void *regs, uint gpio) +{ + /* Configure GPIO direction as input. */ + set_direction(gpio, DIRECTION_INPUT); + + /* Enable the pin as a GPIO */ + set_config(gpio, 1); + + return 0; +} + +int spl_gpio_get_value(void *regs, uint gpio) +{ + struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int val; + + if (get_direction(gpio) == DIRECTION_INPUT) + val = readl(&bank->gpio_in[GPIO_PORT(gpio)]); + else + val = readl(&bank->gpio_out[GPIO_PORT(gpio)]); + + return (val >> GPIO_BIT(gpio)) & 1; +} + +int spl_gpio_set_value(void *regs, uint gpio, int value) +{ + /* Configure GPIO output value. */ + set_level(gpio, value); + + return 0; +} + /** * Returns the name of a GPIO port * @@ -323,7 +373,7 @@ static int gpio_tegra_bind(struct udevice *parent) return 0; /* TODO(sjg@chromium.org): Remove once SPL supports device tree */ -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; bank_count = TEGRA_GPIO_BANKS; #else diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 00b90523c62..bebd728e7da 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -2,15 +2,15 @@ # # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_)DM_I2C) += i2c-uclass.o -ifdef CONFIG_$(SPL_)ACPIGEN -obj-$(CONFIG_$(SPL_)DM_I2C) += acpi_i2c.o +obj-$(CONFIG_$(XPL_)DM_I2C) += i2c-uclass.o +ifdef CONFIG_$(XPL_)ACPIGEN +obj-$(CONFIG_$(XPL_)DM_I2C) += acpi_i2c.o endif -obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o -obj-$(CONFIG_$(SPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o -obj-$(CONFIG_$(SPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o +obj-$(CONFIG_$(XPL_)DM_I2C_GPIO) += i2c-gpio.o +obj-$(CONFIG_$(XPL_)I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o +obj-$(CONFIG_$(XPL_)I2C_CROS_EC_LDO) += cros_ec_ldo.o -obj-$(CONFIG_$(SPL_)SYS_I2C_LEGACY) += i2c_core.o +obj-$(CONFIG_$(XPL_)SYS_I2C_LEGACY) += i2c_core.o obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o @@ -57,4 +57,4 @@ obj-$(CONFIG_SYS_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_SYS_I2C_XILINX_XIIC) += xilinx_xiic.o obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o -obj-$(CONFIG_$(SPL_)I2C_MUX) += muxes/ +obj-$(CONFIG_$(XPL_)I2C_MUX) += muxes/ diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index 11c98672265..c21c412231c 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -37,7 +37,7 @@ static int designware_i2c_pci_of_to_plat(struct udevice *dev) { struct dw_i2c *priv = dev_get_priv(dev); - if (spl_phase() < PHASE_SPL) { + if (xpl_phase() < PHASE_SPL) { u32 base; int ret; @@ -53,7 +53,7 @@ static int designware_i2c_pci_of_to_plat(struct udevice *dev) PCI_COMMAND_MASTER); } - if (spl_phase() < PHASE_BOARD_F) { + if (xpl_phase() < PHASE_BOARD_F) { /* Handle early, fixed mapping into a different address space */ priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0); } else { diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c index e0a575fb4a4..00aef40e341 100644 --- a/drivers/i2c/i2c-gpio.c +++ b/drivers/i2c/i2c-gpio.c @@ -101,7 +101,7 @@ static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay) bus->set_scl(bus, 1); udelay(delay); - value = bus->get_sda(bus); + value = bus->get_sda ? bus->get_sda(bus) : 0; udelay(delay); bus->set_scl(bus, 0); udelay(2 * delay); @@ -256,6 +256,9 @@ static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip, { unsigned int delay = bus->udelay; + if (!bus->get_sda) + return -EOPNOTSUPP; + debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len); while (len-- > 0) @@ -353,7 +356,10 @@ static int i2c_gpio_of_to_plat(struct udevice *dev) bus->udelay = dev_read_u32_default(dev, "i2c-gpio,delay-us", DEFAULT_UDELAY); - bus->get_sda = i2c_gpio_sda_get; + if (dev_read_bool(dev, "i2c-gpio,sda-output-only")) + bus->get_sda = NULL; + else + bus->get_sda = i2c_gpio_sda_get; bus->set_sda = i2c_gpio_sda_set; if (dev_read_bool(dev, "i2c-gpio,scl-output-only")) bus->set_scl = i2c_gpio_scl_set_output_only; diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 323c4fbe9cc..cd5579aa55a 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -36,6 +36,11 @@ config I2C_MUX_PCA954x device. Supported chips are PCA9543, PCA9544, PCA9546, PCA9547, PCA9548 and PCA9646. + It's also compatible to Maxims MAX735x I2C switch chips, which are controlled + as the NXP PCA9548 and the MAX736x chips that act like the PCA9544. + This includes the: + MAX7356, MAX7357, MAX7358, MAX7367, MAX7368 and MAX7369 + config I2C_MUX_GPIO tristate "GPIO-based I2C multiplexer" depends on I2C_MUX && DM_GPIO diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 795288fe2e9..9dd26972703 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -14,6 +14,12 @@ #include <asm-generic/gpio.h> enum pca_type { + MAX7356, + MAX7357, + MAX7358, + MAX7367, + MAX7368, + MAX7369, PCA9543, PCA9544, PCA9546, @@ -39,6 +45,31 @@ struct pca954x_priv { }; static const struct chip_desc chips[] = { + [MAX7356] = { + .muxtype = pca954x_isswi, + .width = 8, + }, + [MAX7357] = { + .muxtype = pca954x_isswi, + .width = 8, + }, + [MAX7358] = { + .muxtype = pca954x_isswi, + .width = 8, + }, + [MAX7367] = { + .muxtype = pca954x_isswi, + .width = 4, + }, + [MAX7368] = { + .muxtype = pca954x_isswi, + .width = 4, + }, + [MAX7369] = { + .enable = 0x4, + .muxtype = pca954x_ismux, + .width = 4, + }, [PCA9543] = { .muxtype = pca954x_isswi, .width = 2, @@ -102,6 +133,12 @@ static const struct i2c_mux_ops pca954x_ops = { }; static const struct udevice_id pca954x_ids[] = { + { .compatible = "maxim,max7356", .data = MAX7356 }, + { .compatible = "maxim,max7357", .data = MAX7357 }, + { .compatible = "maxim,max7358", .data = MAX7358 }, + { .compatible = "maxim,max7367", .data = MAX7367 }, + { .compatible = "maxim,max7368", .data = MAX7368 }, + { .compatible = "maxim,max7369", .data = MAX7369 }, { .compatible = "nxp,pca9543", .data = PCA9543 }, { .compatible = "nxp,pca9544", .data = PCA9544 }, { .compatible = "nxp,pca9546", .data = PCA9546 }, diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 2f3cb5908c9..2dfc1c4eab5 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -29,7 +29,6 @@ #include <watchdog.h> #include <dm.h> #include <dm/pinctrl.h> -#include <fdtdec.h> DECLARE_GLOBAL_DATA_PTR; @@ -867,8 +866,7 @@ static int mxc_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) static int mxc_i2c_probe(struct udevice *bus) { struct mxc_i2c_bus *i2c_bus = dev_get_priv(bus); - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(bus); + ofnode node = dev_ofnode(bus); fdt_addr_t addr; int ret, ret2; @@ -912,17 +910,15 @@ static int mxc_i2c_probe(struct udevice *bus) * See Documentation/devicetree/bindings/i2c/i2c-imx.txt * Use gpio to force bus idle when necessary. */ - ret = fdt_stringlist_search(fdt, node, "pinctrl-names", "gpio"); + ret = ofnode_stringlist_search(node, "pinctrl-names", "gpio"); if (ret < 0) { debug("i2c bus %d at 0x%2lx, no gpio pinctrl state.\n", dev_seq(bus), i2c_bus->base); } else { - ret = gpio_request_by_name_nodev(offset_to_ofnode(node), - "scl-gpios", 0, &i2c_bus->scl_gpio, - GPIOD_IS_OUT); - ret2 = gpio_request_by_name_nodev(offset_to_ofnode(node), - "sda-gpios", 0, &i2c_bus->sda_gpio, - GPIOD_IS_OUT); + ret = gpio_request_by_name(bus, "scl-gpios", 0, &i2c_bus->scl_gpio, + GPIOD_IS_OUT); + ret2 = gpio_request_by_name(bus, "sda-gpios", 0, &i2c_bus->sda_gpio, + GPIOD_IS_OUT); if (!dm_gpio_is_valid(&i2c_bus->sda_gpio) || !dm_gpio_is_valid(&i2c_bus->scl_gpio) || ret || ret2) { diff --git a/drivers/i2c/rz_riic.c b/drivers/i2c/rz_riic.c index 5f3f8d1b24b..f292c824362 100644 --- a/drivers/i2c/rz_riic.c +++ b/drivers/i2c/rz_riic.c @@ -14,6 +14,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <reset.h> +#include <u-boot/schedule.h> #include <wait_bit.h> #define RIIC_ICCR1 0x00 diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 71f315adf6f..8d4107b8848 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -3,12 +3,12 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_TPL_)CROS_EC_KEYB) += cros_ec_keyb.o -obj-$(CONFIG_$(SPL_TPL_)OF_CONTROL) += key_matrix.o -obj-$(CONFIG_$(SPL_TPL_)DM_KEYBOARD) += input.o keyboard-uclass.o +obj-$(CONFIG_$(PHASE_)CROS_EC_KEYB) += cros_ec_keyb.o +obj-$(CONFIG_$(PHASE_)OF_CONTROL) += key_matrix.o +obj-$(CONFIG_$(PHASE_)DM_KEYBOARD) += input.o keyboard-uclass.o obj-$(CONFIG_BUTTON_KEYBOARD) += button_kbd.o -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_APPLE_SPI_KEYB) += apple_spi_kbd.o obj-$(CONFIG_I8042_KEYB) += i8042.o diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index bee74b25751..c98cbf92fab 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -9,6 +9,30 @@ config LED can provide access to board-specific LEDs. Use of the device tree for configuration is encouraged. +config LED_BOOT + bool "Enable LED boot support" + help + Enable LED boot support. + + LED boot is a specific LED assigned to signal boot operation status. + Defined in Device Tree /options/u-boot node. Refer here for the supported + options [1]. + + [1] dtschema/schemas/options/u-boot.yaml + +config LED_ACTIVITY + bool "Enable LED activity support" + help + Enable LED activity support. + + LED activity is a specific LED assigned to signal activity operation + like file trasnfer, flash write/erase... + + Defined in Device Tree /options/u-boot node. Refer here for the supported + options [1]. + + [1] dtschema/schemas/options/u-boot.yaml + config LED_BCM6328 bool "LED Support for BCM6328" depends on LED && ARCH_BMIPS diff --git a/drivers/led/Makefile b/drivers/led/Makefile index e27aa488482..aa64a38b4e1 100644 --- a/drivers/led/Makefile +++ b/drivers/led/Makefile @@ -10,6 +10,6 @@ obj-$(CONFIG_LED_BCM6358) += led_bcm6358.o obj-$(CONFIG_LED_BCM6753) += led_bcm6753.o obj-$(CONFIG_LED_BCM6858) += led_bcm6858.o obj-$(CONFIG_LED_PWM) += led_pwm.o -obj-$(CONFIG_$(SPL_)LED_GPIO) += led_gpio.o +obj-$(CONFIG_$(XPL_)LED_GPIO) += led_gpio.o obj-$(CONFIG_LED_CORTINA) += led_cortina.o obj-$(CONFIG_LED_LP5562) += led_lp5562.o diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index 199d68bc25a..05e09909b7d 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -94,6 +94,144 @@ int led_set_period(struct udevice *dev, int period_ms) return -ENOSYS; } +#ifdef CONFIG_LED_BOOT +static int led_boot_get(struct udevice **devp, int *period_ms) +{ + struct led_uc_priv *priv; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_LED, &uc); + if (ret) + return ret; + + priv = uclass_get_priv(uc); + if (!priv->boot_led_label) + return -ENOENT; + + if (period_ms) + *period_ms = priv->boot_led_period; + + return led_get_by_label(priv->boot_led_label, devp); +} + +int led_boot_on(void) +{ + struct udevice *dev; + int ret; + + ret = led_boot_get(&dev, NULL); + if (ret) + return ret; + + return led_set_state(dev, LEDST_ON); +} + +int led_boot_off(void) +{ + struct udevice *dev; + int ret; + + ret = led_boot_get(&dev, NULL); + if (ret) + return ret; + + return led_set_state(dev, LEDST_OFF); +} + +#if defined(CONFIG_LED_BLINK) || defined(CONFIG_LED_SW_BLINK) +int led_boot_blink(void) +{ + struct udevice *dev; + int period_ms, ret; + + ret = led_boot_get(&dev, &period_ms); + if (ret) + return ret; + + ret = led_set_period(dev, period_ms); + if (ret) { + if (ret != -ENOSYS) + return ret; + + /* fallback to ON with no set_period and no SW_BLINK */ + return led_set_state(dev, LEDST_ON); + } + + return led_set_state(dev, LEDST_BLINK); +} +#endif +#endif + +#ifdef CONFIG_LED_ACTIVITY +static int led_activity_get(struct udevice **devp, int *period_ms) +{ + struct led_uc_priv *priv; + struct uclass *uc; + int ret; + + ret = uclass_get(UCLASS_LED, &uc); + if (ret) + return ret; + + priv = uclass_get_priv(uc); + if (!priv->activity_led_label) + return -ENOENT; + + if (period_ms) + *period_ms = priv->activity_led_period; + + return led_get_by_label(priv->activity_led_label, devp); +} + +int led_activity_on(void) +{ + struct udevice *dev; + int ret; + + ret = led_activity_get(&dev, NULL); + if (ret) + return ret; + + return led_set_state(dev, LEDST_ON); +} + +int led_activity_off(void) +{ + struct udevice *dev; + int ret; + + ret = led_activity_get(&dev, NULL); + if (ret) + return ret; + + return led_set_state(dev, LEDST_OFF); +} + +#if defined(CONFIG_LED_BLINK) || defined(CONFIG_LED_SW_BLINK) +int led_activity_blink(void) +{ + struct udevice *dev; + int period_ms, ret; + + ret = led_activity_get(&dev, &period_ms); + if (ret) + return ret; + + ret = led_set_period(dev, period_ms); + if (ret) { + if (ret != -ENOSYS) + return ret; + + /* fallback to ON with no set_period and no SW_BLINK */ + return led_set_state(dev, LEDST_ON); + } + + return led_set_state(dev, LEDST_BLINK); +} +#endif +#endif + static int led_post_bind(struct udevice *dev) { struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev); @@ -158,10 +296,34 @@ static int led_post_probe(struct udevice *dev) return ret; } +#if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY) +static int led_init(struct uclass *uc) +{ + struct led_uc_priv *priv = uclass_get_priv(uc); + +#ifdef CONFIG_LED_BOOT + priv->boot_led_label = ofnode_options_read_str("boot-led"); + priv->boot_led_period = ofnode_options_read_int("boot-led-period", 250); +#endif + +#ifdef CONFIG_LED_ACTIVITY + priv->activity_led_label = ofnode_options_read_str("activity-led"); + priv->activity_led_period = ofnode_options_read_int("activity-led-period", + 250); +#endif + + return 0; +} +#endif + UCLASS_DRIVER(led) = { .id = UCLASS_LED, .name = "led", .per_device_plat_auto = sizeof(struct led_uc_plat), .post_bind = led_post_bind, .post_probe = led_post_probe, +#if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY) + .init = led_init, + .priv_auto = sizeof(struct led_uc_priv), +#endif }; diff --git a/drivers/led/led_sw_blink.c b/drivers/led/led_sw_blink.c index 9e36edbee47..ee1546d02d4 100644 --- a/drivers/led/led_sw_blink.c +++ b/drivers/led/led_sw_blink.c @@ -5,6 +5,7 @@ * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> */ +#include <cyclic.h> #include <dm.h> #include <led.h> #include <time.h> @@ -103,8 +104,21 @@ bool led_sw_on_state_change(struct udevice *dev, enum led_state_t state) return false; if (state == LEDST_BLINK) { - /* start blinking on next led_sw_blink() call */ - sw_blink->state = LED_SW_BLINK_ST_OFF; + struct led_ops *ops = led_get_ops(dev); + + /* + * toggle LED initially and start blinking on next + * led_sw_blink() call. + */ + switch (ops->get_state(dev)) { + case LEDST_ON: + ops->set_state(dev, LEDST_OFF); + sw_blink->state = LED_SW_BLINK_ST_OFF; + default: + ops->set_state(dev, LEDST_ON); + sw_blink->state = LED_SW_BLINK_ST_ON; + } + return true; } diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 59e8d0de93c..6072fa1956b 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2016, NVIDIA CORPORATION. # -obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o +obj-$(CONFIG_$(XPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o diff --git a/drivers/mailbox/zynqmp-ipi.c b/drivers/mailbox/zynqmp-ipi.c index 4df69734ed9..713d93a200c 100644 --- a/drivers/mailbox/zynqmp-ipi.c +++ b/drivers/mailbox/zynqmp-ipi.c @@ -108,7 +108,7 @@ static int zynqmp_ipi_send(struct mbox_chan *chan, const void *data) writel(msg->buf[i], &mbx[i]); /* Use SMC calls for Exception Level less than 3 where TF-A is available */ - if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) { + if (!IS_ENABLED(CONFIG_XPL_BUILD) && current_el() < 3) { ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_NOTIFY, 0); debug("%s, send %ld bytes\n", __func__, msg->len); @@ -148,7 +148,7 @@ static int zynqmp_ipi_recv(struct mbox_chan *chan, void *data) msg->buf[i] = readl(&mbx[i]); /* Ack to remote if EL is not 3 */ - if (!IS_ENABLED(CONFIG_SPL_BUILD) && current_el() < 3) { + if (!IS_ENABLED(CONFIG_XPL_BUILD) && current_el() < 3) { ret = zynqmp_ipi_fw_call(zynqmp, SMC_IPI_MAILBOX_ACK, IPI_SMC_ACK_EIRQ_MASK); } @@ -168,7 +168,7 @@ static int zynqmp_ipi_dest_probe(struct udevice *dev) node = dev_ofnode(dev); - if (IS_ENABLED(CONFIG_SPL_BUILD) || of_machine_is_compatible("xlnx,zynqmp")) + if (IS_ENABLED(CONFIG_XPL_BUILD) || of_machine_is_compatible("xlnx,zynqmp")) zynqmp->el3_supported = true; ret = dev_read_u32(dev->parent, "xlnx,ipi-id", &zynqmp->local_id); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ff984d7b191..dac805e4cdd 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -3,14 +3,14 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_TPL_)MISC) += misc-uclass.o -obj-$(CONFIG_$(SPL_TPL_)NVMEM) += nvmem.o +obj-$(CONFIG_$(PHASE_)MISC) += misc-uclass.o +obj-$(CONFIG_$(PHASE_)NVMEM) += nvmem.o -obj-$(CONFIG_$(SPL_TPL_)CROS_EC) += cros_ec.o -obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o -obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o +obj-$(CONFIG_$(PHASE_)CROS_EC) += cros_ec.o +obj-$(CONFIG_$(PHASE_)CROS_EC_SANDBOX) += cros_ec_sandbox.o +obj-$(CONFIG_$(PHASE_)CROS_EC_LPC) += cros_ec_lpc.o -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_SANDBOX) += sandbox_adder.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o @@ -18,14 +18,14 @@ obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o obj-$(CONFIG_SANDBOX) += swap_case.o endif -ifdef CONFIG_$(SPL_)DM_I2C -ifndef CONFIG_SPL_BUILD +ifdef CONFIG_$(XPL_)DM_I2C +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o endif endif ifdef CONFIG_SPL_OF_PLATDATA -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SANDBOX) += spltest_sandbox.o endif endif @@ -37,29 +37,29 @@ obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o -obj-$(CONFIG_$(SPL_)FS_LOADER) += fs_loader.o +obj-$(CONFIG_$(XPL_)FS_LOADER) += fs_loader.o obj-$(CONFIG_GATEWORKS_SC) += gsc.o obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o obj-$(CONFIG_IRQ) += irq-uclass.o obj-$(CONFIG_SANDBOX) += irq_sandbox.o irq_sandbox_test.o -obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o +obj-$(CONFIG_$(XPL_)I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o obj-$(CONFIG_IMX8) += imx8/ obj-$(CONFIG_IMX_ELE) += imx_ele/ obj-$(CONFIG_LED_STATUS) += status_led.o obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o -obj-$(CONFIG_$(SPL_TPL_)LS2_SFP) += ls2_sfp.o -obj-$(CONFIG_$(SPL_)MXC_OCOTP) += mxc_ocotp.o +obj-$(CONFIG_$(PHASE_)LS2_SFP) += ls2_sfp.o +obj-$(CONFIG_$(XPL_)MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NPCM_OTP) += npcm_otp.o obj-$(CONFIG_NPCM_HOST) += npcm_host_intf.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o -obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o +obj-$(CONFIG_$(XPL_)PWRSEQ) += pwrseq-uclass.o ifdef CONFIG_QFW obj-y += qfw.o obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o @@ -68,9 +68,9 @@ obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif -obj-$(CONFIG_$(SPL_TPL_)ROCKCHIP_EFUSE) += rockchip-efuse.o -obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o -obj-$(CONFIG_$(SPL_TPL_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o +obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o +obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o +obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o @@ -81,7 +81,7 @@ obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o obj-$(CONFIG_TEGRA_CAR) += tegra_car.o obj-$(CONFIG_TEST_DRV) += test_drv.o -obj-$(CONFIG_$(SPL_TPL_)TURRIS_OMNIA_MCU) += turris_omnia_mcu.o +obj-$(CONFIG_$(PHASE_)TURRIS_OMNIA_MCU) += turris_omnia_mcu.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o diff --git a/drivers/misc/gsc.c b/drivers/misc/gsc.c index feb02f97065..dee0bdd9663 100644 --- a/drivers/misc/gsc.c +++ b/drivers/misc/gsc.c @@ -389,7 +389,7 @@ static int gsc_probe(struct udevice *dev) if (priv->rtc) dev_set_priv(priv->rtc, priv); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD gsc_banner(dev); #endif diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c index bbd7e24200b..5d3db0bc4df 100644 --- a/drivers/misc/imx8/scu.c +++ b/drivers/misc/imx8/scu.c @@ -191,7 +191,7 @@ static int imx8_scu_probe(struct udevice *dev) if (addr == FDT_ADDR_T_NONE) return -EINVAL; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD plat->base = (struct mu_type *)CONFIG_MU_BASE_SPL; #else plat->base = (struct mu_type *)addr; diff --git a/drivers/misc/imx_ele/ele_api.c b/drivers/misc/imx_ele/ele_api.c index b753419f01b..661f70cf870 100644 --- a/drivers/misc/imx_ele/ele_api.c +++ b/drivers/misc/imx_ele/ele_api.c @@ -5,12 +5,12 @@ * */ -#include <hang.h> -#include <malloc.h> -#include <memalign.h> #include <asm/io.h> -#include <dm.h> +#include <asm/mach-imx/sys_proto.h> #include <asm/mach-imx/ele_api.h> +#include <dm.h> +#include <malloc.h> +#include <memalign.h> #include <misc.h> DECLARE_GLOBAL_DATA_PTR; @@ -205,8 +205,7 @@ int ele_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *respon return -EINVAL; } - if ((fuse_id != 1 && fuse_num != 1) || - (fuse_id == 1 && fuse_num != 4)) { + if (is_imx8ulp() && ((fuse_id != 1 && fuse_num != 1) || (fuse_id == 1 && fuse_num != 4))) { printf("Invalid fuse number parameter\n"); return -EINVAL; } @@ -226,7 +225,7 @@ int ele_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *respon *response = msg.data[0]; fuse_words[0] = msg.data[1]; - if (fuse_id == 1) { + if (fuse_id == 1 && is_imx8ulp()) { /* OTP_UNIQ_ID */ fuse_words[1] = msg.data[2]; fuse_words[2] = msg.data[3]; @@ -269,6 +268,72 @@ int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response) return ret; } +int ele_write_shadow_fuse(u32 fuse_id, u32 fuse_val, u32 *response) +{ + struct udevice *dev = gd->arch.ele_dev; + int size = sizeof(struct ele_msg); + struct ele_msg msg; + int ret; + + if (!dev) { + printf("ele dev is not initialized\n"); + return -ENODEV; + } + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 3; + msg.command = ELE_WRITE_SHADOW_REQ; + msg.data[0] = fuse_id; + msg.data[1] = fuse_val; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n", + __func__, ret, fuse_id, msg.data[0]); + + if (response) + *response = msg.data[0]; + + return ret; +} + +int ele_read_shadow_fuse(u32 fuse_id, u32 *fuse_val, u32 *response) +{ + struct udevice *dev = gd->arch.ele_dev; + int size = sizeof(struct ele_msg); + struct ele_msg msg = {}; + int ret; + + if (!dev) { + printf("ele dev is not initialized\n"); + return -ENODEV; + } + + if (!fuse_val) { + printf("Invalid parameters for shadow read\n"); + return -EINVAL; + } + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 2; + msg.command = ELE_READ_SHADOW_REQ; + msg.data[0] = fuse_id; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n", + __func__, ret, fuse_id, msg.data[0]); + + if (response) + *response = msg.data[0]; + + *fuse_val = msg.data[1]; + + return ret; +} + int ele_release_caam(u32 core_did, u32 *response) { struct udevice *dev = gd->arch.ele_dev; diff --git a/drivers/misc/imx_ele/ele_mu.c b/drivers/misc/imx_ele/ele_mu.c index 0cf81f33ba5..cdb85b999db 100644 --- a/drivers/misc/imx_ele/ele_mu.c +++ b/drivers/misc/imx_ele/ele_mu.c @@ -21,25 +21,35 @@ struct imx8ulp_mu { #define MU_SR_TE0_MASK BIT(0) #define MU_SR_RF0_MASK BIT(0) -#define MU_TR_COUNT 8 -#define MU_RR_COUNT 4 void mu_hal_init(ulong base) { struct mu_type *mu_base = (struct mu_type *)base; + u32 rr_num = (readl(&mu_base->par) & 0xFF00) >> 8; + int i; writel(0, &mu_base->tcr); writel(0, &mu_base->rcr); + + while (true) { + /* If there is pending RX data, clear them by read them out */ + if (!(readl(&mu_base->sr) & BIT(6))) + return; + + for (i = 0; i < rr_num; i++) + readl(&mu_base->rr[i]); + } } int mu_hal_sendmsg(ulong base, u32 reg_index, u32 msg) { struct mu_type *mu_base = (struct mu_type *)base; u32 mask = MU_SR_TE0_MASK << reg_index; - u32 val; + u32 val, tr_num; int ret; - assert(reg_index < MU_TR_COUNT); + tr_num = readl(&mu_base->par) & 0xFF; + assert(reg_index < tr_num); debug("sendmsg tsr 0x%x\n", readl(&mu_base->tsr)); @@ -61,11 +71,12 @@ int mu_hal_receivemsg(ulong base, u32 reg_index, u32 *msg) { struct mu_type *mu_base = (struct mu_type *)base; u32 mask = MU_SR_RF0_MASK << reg_index; - u32 val; + u32 val, rr_num; int ret; u32 count = 10; - assert(reg_index < MU_RR_COUNT); + rr_num = (readl(&mu_base->par) & 0xFF00) >> 8; + assert(reg_index < rr_num); debug("receivemsg rsr 0x%x\n", readl(&mu_base->rsr)); @@ -96,7 +107,7 @@ static int imx8ulp_mu_read(struct mu_type *base, void *data) { struct ele_msg *msg = (struct ele_msg *)data; int ret; - u8 count = 0; + u8 count = 0, rr_num; if (!msg) return -EINVAL; @@ -113,9 +124,11 @@ static int imx8ulp_mu_read(struct mu_type *base, void *data) return -EINVAL; } + rr_num = (readl(&base->par) & 0xFF00) >> 8; + /* Read remaining words */ while (count < msg->size) { - ret = mu_hal_receivemsg((ulong)base, count % MU_RR_COUNT, + ret = mu_hal_receivemsg((ulong)base, count % rr_num, &msg->data[count - 1]); if (ret) return ret; @@ -129,7 +142,7 @@ static int imx8ulp_mu_write(struct mu_type *base, void *data) { struct ele_msg *msg = (struct ele_msg *)data; int ret; - u8 count = 0; + u8 count = 0, tr_num; if (!msg) return -EINVAL; @@ -144,9 +157,11 @@ static int imx8ulp_mu_write(struct mu_type *base, void *data) return ret; count++; + tr_num = readl(&base->par) & 0xFF; + /* Write remaining words */ while (count < msg->size) { - ret = mu_hal_sendmsg((ulong)base, count % MU_TR_COUNT, + ret = mu_hal_sendmsg((ulong)base, count % tr_num, msg->data[count - 1]); if (ret) return ret; @@ -229,6 +244,7 @@ static struct misc_ops imx8ulp_mu_ops = { static const struct udevice_id imx8ulp_mu_ids[] = { { .compatible = "fsl,imx8ulp-mu" }, { .compatible = "fsl,imx93-mu-s4" }, + { .compatible = "fsl,imx95-mu-ele" }, { } }; diff --git a/drivers/misc/imx_ele/fuse.c b/drivers/misc/imx_ele/fuse.c index d12539c8aac..c1e7434dbf3 100644 --- a/drivers/misc/imx_ele/fuse.c +++ b/drivers/misc/imx_ele/fuse.c @@ -11,10 +11,10 @@ #include <env.h> #include <asm/mach-imx/ele_api.h> #include <asm/global_data.h> +#include <env.h> DECLARE_GLOBAL_DATA_PTR; -#define FUSE_BANKS 64 #define WORDS_PER_BANKS 8 struct fsb_map_entry { @@ -32,6 +32,7 @@ struct ele_map_entry { #if defined(CONFIG_IMX8ULP) #define FSB_OTP_SHADOW 0x800 +#define IS_FSB_ALLOWED (true) struct fsb_map_entry fsb_mapping_table[] = { { 3, 8 }, @@ -84,6 +85,8 @@ struct ele_map_entry ele_api_mapping_table[] = { }; #elif defined(CONFIG_ARCH_IMX9) #define FSB_OTP_SHADOW 0x8000 +#define IS_FSB_ALLOWED (!IS_ENABLED(CONFIG_SCMI_FIRMWARE) && \ + !(readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28) & BIT(0))) struct fsb_map_entry fsb_mapping_table[] = { { 0, 8 }, @@ -138,8 +141,7 @@ static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy) /* map the fuse from ocotp fuse map to FSB*/ for (i = 0; i < size; i++) { if (fsb_mapping_table[i].fuse_bank != -1 && - fsb_mapping_table[i].fuse_bank == bank && - fsb_mapping_table[i].fuse_words > word) { + fsb_mapping_table[i].fuse_bank == bank) { break; } @@ -150,8 +152,13 @@ static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy) return -1; /* Failed to find */ if (fsb_mapping_table[i].redundancy) { + if ((fsb_mapping_table[i].fuse_words << 1) <= word) + return -2; /* Not valid word */ + *redundancy = true; return (word >> 1) + word_pos; + } else if (fsb_mapping_table[i].fuse_words <= word) { + return -2; /* Not valid word */ } *redundancy = false; @@ -187,24 +194,14 @@ static s32 map_ele_fuse_index(u32 bank, u32 word) int fuse_sense(u32 bank, u32 word, u32 *val) { s32 word_index; - bool redundancy; - if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val) + if (word >= WORDS_PER_BANKS || !val) return -EINVAL; - word_index = map_fsb_fuse_index(bank, word, &redundancy); - if (word_index >= 0) { - *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2)); - if (redundancy) - *val = (*val >> ((word % 2) * 16)) & 0xFFFF; - - return 0; - } - word_index = map_ele_fuse_index(bank, word); if (word_index >= 0) { u32 data[4]; - u32 res, size = 4; + u32 res = 0, size = 4; int ret; /* Only UID return 4 words */ @@ -236,28 +233,29 @@ int fuse_sense(u32 bank, u32 word, u32 *val) return -ENOENT; } + #elif defined(CONFIG_ARCH_IMX9) int fuse_sense(u32 bank, u32 word, u32 *val) { s32 word_index; bool redundancy; - if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val) + if (word >= WORDS_PER_BANKS || !val) return -EINVAL; - word_index = map_fsb_fuse_index(bank, word, &redundancy); - if (word_index >= 0) { - *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2)); - if (redundancy) - *val = (*val >> ((word % 2) * 16)) & 0xFFFF; + if (!IS_ENABLED(CONFIG_SCMI_FIRMWARE)) { + word_index = map_fsb_fuse_index(bank, word, &redundancy); - return 0; + /* ELE read common fuse API supports all FSB fuse. */ + if (word_index < 0) + word_index = map_ele_fuse_index(bank, word); + } else { + word_index = bank * 8 + word; } - word_index = map_ele_fuse_index(bank, word); if (word_index >= 0) { u32 data; - u32 res, size = 1; + u32 res = 0, size = 1; int ret; ret = ele_read_common_fuse(word_index, &data, size, &res); @@ -275,18 +273,62 @@ int fuse_sense(u32 bank, u32 word, u32 *val) } #endif -int fuse_read(u32 bank, u32 word, u32 *val) +static int fuse_read_default(u32 bank, u32 word, u32 *val) { + s32 word_index; + bool redundancy; + + if (IS_FSB_ALLOWED) { + word_index = map_fsb_fuse_index(bank, word, &redundancy); + if (word_index >= 0) { + *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2)); + if (redundancy) + *val = (*val >> ((word % 2) * 16)) & 0xFFFF; + + return 0; + } + } + return fuse_sense(bank, word, val); } +static int fuse_read_ele_shd(u32 bank, u32 word, u32 *val) +{ + u32 res = 0; + int ret; + struct udevice *dev = gd->arch.ele_dev; + + if (!dev) + return -ENODEV; + + ret = ele_read_shadow_fuse((bank * 8 + word), val, &res); + if (ret) { + printf("ele read shadow fuse failed %d, 0x%x\n", ret, res); + return ret; + } + + return 0; +} + +int fuse_read(u32 bank, u32 word, u32 *val) +{ + if (word >= WORDS_PER_BANKS || !val) + return -EINVAL; + + if (!IS_ENABLED(CONFIG_SPL_BUILD) && + env_get_yesno("enable_ele_shd") == 1) + return fuse_read_ele_shd(bank, word, val); + else + return fuse_read_default(bank, word, val); +} + int fuse_prog(u32 bank, u32 word, u32 val) { - u32 res; + u32 res = 0; int ret; bool lock = false; - if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val) + if (word >= WORDS_PER_BANKS || !val) return -EINVAL; /* Lock 8ULP ECC fuse word, so second programming will return failure. @@ -314,6 +356,17 @@ int fuse_prog(u32 bank, u32 word, u32 val) int fuse_override(u32 bank, u32 word, u32 val) { - printf("Override fuse to i.MX8ULP in u-boot is forbidden\n"); - return -EPERM; + u32 res = 0; + int ret; + + if (word >= WORDS_PER_BANKS || !val) + return -EINVAL; + + ret = ele_write_shadow_fuse((bank * 8 + word), val, &res); + if (ret) { + printf("ahab write shadow fuse failed %d, 0x%x\n", ret, res); + return ret; + } + + return 0; } diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c index 87471cc3b16..99a18a109b7 100644 --- a/drivers/misc/k3_avs.c +++ b/drivers/misc/k3_avs.c @@ -352,6 +352,9 @@ static int k3_avs_probe(struct udevice *dev) struct k3_avs_privdata *priv; struct vd_data *vd; int ret; + ofnode node; + struct ofnode_phandle_args phandle_args; + int i = 0; priv = dev_get_priv(dev); priv->dev = dev; @@ -367,6 +370,32 @@ static int k3_avs_probe(struct udevice *dev) return -ENODEV; for (vd = priv->vd_config->vds; vd->id >= 0; vd++) { + /* Get the clock and dev id for Jacinto platforms */ + if (vd->id == J721E_VDD_MPU) { + node = ofnode_by_compatible(ofnode_null(), "ti,am654-rproc"); + if (!ofnode_valid(node)) + return -ENODEV; + + i = ofnode_stringlist_search(node, "clock-names", "core"); + if (i < 0) + return -ENODEV; + + ret = ofnode_parse_phandle_with_args(node, "clocks", + "#clock-cells", + 0, i, + &phandle_args); + if (ret) { + printf("Couldn't get the clock node, ret = %d\n", ret); + return ret; + } + + vd->dev_id = phandle_args.args[0]; + vd->clk_id = phandle_args.args[1]; + + debug("%s: MPU dev_id: %d, clk_id: %d", __func__, + vd->dev_id, vd->clk_id); + } + if (!(readl(AM6_VTM_DEVINFO(vd->id)) & AM6_VTM_AVS0_SUPPORTED)) { dev_warn(dev, "AVS-class 0 not supported for VD%d\n", @@ -391,7 +420,10 @@ static int k3_avs_probe(struct udevice *dev) if (vd->flags & VD_FLAG_INIT_DONE) continue; - k3_avs_program_voltage(priv, vd, vd->opp); + ret = k3_avs_program_voltage(priv, vd, vd->opp); + if (ret) + dev_warn(dev, "Could not program AVS voltage for VD%d, vd->opp=%d, ret=%d\n", + vd->id, vd->opp, ret); } if (!device_is_compatible(priv->dev, "ti,am654-avs")) @@ -460,6 +492,12 @@ static struct vd_data j721e_vd_data[] = { { .id = J721E_VDD_MPU, .opp = AM6_OPP_NOM, + /* + * XXX: DEPRECATION WARNING: Around 2 u-boot versions + * + * These values will be picked up from DT, kept for backward + * compatibility + */ .dev_id = 202, /* J721E_DEV_A72SS0_CORE0 */ .clk_id = 2, /* ARM clock */ .opps = { diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c index 016c8073378..d7ce0383ac9 100644 --- a/drivers/misc/p2sb-uclass.c +++ b/drivers/misc/p2sb-uclass.c @@ -198,7 +198,7 @@ static int p2sb_child_post_bind(struct udevice *dev) static int p2sb_post_bind(struct udevice *dev) { - if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA)) + if (xpl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA)) return dm_scan_fdt_dev(dev); return 0; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 22c65681f0a..38817622fca 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -130,6 +130,7 @@ config MMC_HW_PARTITIONING config SUPPORT_EMMC_RPMB bool "Support eMMC replay protected memory block (RPMB)" imply CMD_MMC_RPMB + select SHA256 help Enable support for reading, writing and programming the key for the Replay Protection Memory Block partition in eMMC. diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 235c477c2e0..868f3090ff2 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -4,23 +4,23 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-y += mmc.o -obj-$(CONFIG_$(SPL_)DM_MMC) += mmc-uclass.o +obj-$(CONFIG_$(XPL_)DM_MMC) += mmc-uclass.o -ifdef CONFIG_$(SPL_TPL_)DM_MMC -obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += mmc_bootdev.o +ifdef CONFIG_$(PHASE_)DM_MMC +obj-$(CONFIG_$(PHASE_)BOOTSTD) += mmc_bootdev.o endif -obj-$(CONFIG_$(SPL_TPL_)MMC_WRITE) += mmc_write.o -obj-$(CONFIG_$(SPL_)MMC_PWRSEQ) += mmc-pwrseq.o +obj-$(CONFIG_$(PHASE_)MMC_WRITE) += mmc_write.o +obj-$(CONFIG_$(XPL_)MMC_PWRSEQ) += mmc-pwrseq.o obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o -ifndef CONFIG_$(SPL_)BLK +ifndef CONFIG_$(XPL_)BLK obj-y += mmc_legacy.o endif obj-$(CONFIG_SUPPORT_EMMC_BOOT) += mmc_boot.o -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o endif diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 8551eac7018..e1110cace89 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -214,66 +214,24 @@ static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size) return timeout; } -static int dwmci_data_transfer_fifo(struct dwmci_host *host, - struct mmc_data *data, u32 mask) +static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) { - const u32 int_rx = mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO); - const u32 int_tx = mask & DWMCI_INTMSK_TXDR; + struct mmc *mmc = host->mmc; int ret = 0; - u32 len = 0, size, i; - u32 *buf; - - size = (data->blocksize * data->blocks) / 4; - if (!host->fifo_mode || !size) - return 0; + u32 timeout, mask, size, i, len = 0; + u32 *buf = NULL; + ulong start = get_timer(0); + size = data->blocksize * data->blocks; if (data->flags == MMC_DATA_READ) buf = (unsigned int *)data->dest; else buf = (unsigned int *)data->src; - if (data->flags == MMC_DATA_READ && int_rx) { - dwmci_writel(host, DWMCI_RINTSTS, int_rx); - while (size) { - ret = dwmci_fifo_ready(host, DWMCI_FIFO_EMPTY, &len); - if (ret < 0) - break; - - len = (len >> DWMCI_FIFO_SHIFT) & DWMCI_FIFO_MASK; - len = min(size, len); - for (i = 0; i < len; i++) - *buf++ = dwmci_readl(host, DWMCI_DATA); - size = size > len ? (size - len) : 0; - } - } else if (data->flags == MMC_DATA_WRITE && int_tx) { - while (size) { - ret = dwmci_fifo_ready(host, DWMCI_FIFO_FULL, &len); - if (ret < 0) - break; - - len = host->fifo_depth - ((len >> DWMCI_FIFO_SHIFT) & - DWMCI_FIFO_MASK); - len = min(size, len); - for (i = 0; i < len; i++) - dwmci_writel(host, DWMCI_DATA, *buf++); - size = size > len ? (size - len) : 0; - } - dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_TXDR); - } - - return ret; -} - -static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) -{ - struct mmc *mmc = host->mmc; - int ret = 0; - u32 timeout, mask, size; - ulong start = get_timer(0); - - size = data->blocksize * data->blocks; timeout = dwmci_get_timeout(mmc, size); + size /= 4; + for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); /* Error during data transfer */ @@ -283,7 +241,50 @@ static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data) break; } - ret = dwmci_data_transfer_fifo(host, data, mask); + if (host->fifo_mode && size) { + len = 0; + if (data->flags == MMC_DATA_READ && + (mask & (DWMCI_INTMSK_RXDR | DWMCI_INTMSK_DTO))) { + dwmci_writel(host, DWMCI_RINTSTS, + mask & (DWMCI_INTMSK_RXDR | + DWMCI_INTMSK_DTO)); + while (size) { + ret = dwmci_fifo_ready(host, + DWMCI_FIFO_EMPTY, + &len); + if (ret < 0) + break; + + len = (len >> DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK; + len = min(size, len); + for (i = 0; i < len; i++) + *buf++ = + dwmci_readl(host, DWMCI_DATA); + size = size > len ? (size - len) : 0; + } + } else if (data->flags == MMC_DATA_WRITE && + (mask & DWMCI_INTMSK_TXDR)) { + while (size) { + ret = dwmci_fifo_ready(host, + DWMCI_FIFO_FULL, + &len); + if (ret < 0) + break; + + len = host->fifo_depth - ((len >> + DWMCI_FIFO_SHIFT) & + DWMCI_FIFO_MASK); + len = min(size, len); + for (i = 0; i < len; i++) + dwmci_writel(host, DWMCI_DATA, + *buf++); + size = size > len ? (size - len) : 0; + } + dwmci_writel(host, DWMCI_RINTSTS, + DWMCI_INTMSK_TXDR); + } + } /* Data arrived correctly */ if (mask & DWMCI_INTMSK_DTO) { diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 03de7dcd505..d7a45ef0ad0 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -148,6 +148,7 @@ struct fsl_esdhc_priv { struct fsl_esdhc *esdhc_regs; unsigned int sdhc_clk; struct clk per_clk; + struct clk_bulk clk_bulk; unsigned int clock; unsigned int mode; #if !CONFIG_IS_ENABLED(DM_MMC) @@ -986,11 +987,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) ulong start; /* Reset the entire host controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* Wait until the controller is available */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 1000) return -ETIMEDOUT; } @@ -1034,6 +1035,11 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc) /* Set timout to the maximum value */ esdhc_clrsetbits32(®s->sysctl, SYSCTL_TIMEOUT_MASK, 14 << 16); + /* max 1ms delay with clock on for initialization */ + esdhc_setbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + udelay(1000); + esdhc_clrbits32(®s->vendorspec, VENDORSPEC_FRC_SDCLK_ON); + return 0; } @@ -1089,11 +1095,11 @@ static int esdhc_reset(struct fsl_esdhc *regs) ulong start; /* reset the controller */ - esdhc_setbits32(®s->sysctl, SYSCTL_RSTA); + esdhc_setbits32(®s->sysctl, SYSCTL_RSTA | SYSCTL_RSTT); /* hardware clears the bit when it is done */ start = get_timer(0); - while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA)) { + while ((esdhc_read32(®s->sysctl) & (SYSCTL_RSTA | SYSCTL_RSTT))) { if (get_timer(start) > 100) { printf("MMC/SD: Reset never completed.\n"); return -ETIMEDOUT; @@ -1188,8 +1194,6 @@ static int fsl_esdhc_init(struct fsl_esdhc_priv *priv, esdhc_write32(®s->irqstaten, SDHCI_IRQ_EN_BITS); cfg = &plat->cfg; - if (!CONFIG_IS_ENABLED(DM_MMC)) - memset(cfg, '\0', sizeof(*cfg)); caps = esdhc_read32(®s->hostcapblt); @@ -1323,6 +1327,8 @@ int fsl_esdhc_initialize(struct bd_info *bis, struct fsl_esdhc_cfg *cfg) break; default: printf("invalid max bus width %u\n", cfg->max_bus_width); + free(plat); + free(priv); return -EINVAL; } @@ -1392,8 +1398,7 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev) struct udevice *vqmmc_dev; int ret; - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(dev); + ofnode node = dev_ofnode(dev); fdt_addr_t addr; unsigned int val; @@ -1407,15 +1412,15 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev) priv->dev = dev; priv->mode = -1; - val = fdtdec_get_int(fdt, node, "fsl,tuning-step", 1); + val = ofnode_read_u32_default(node, "fsl,tuning-step", 1); priv->tuning_step = val; - val = fdtdec_get_int(fdt, node, "fsl,tuning-start-tap", - ESDHC_TUNING_START_TAP_DEFAULT); + val = ofnode_read_u32_default(node, "fsl,tuning-start-tap", + ESDHC_TUNING_START_TAP_DEFAULT); priv->tuning_start_tap = val; - val = fdtdec_get_int(fdt, node, "fsl,strobe-dll-delay-target", - ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); + val = ofnode_read_u32_default(node, "fsl,strobe-dll-delay-target", + ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); priv->strobe_dll_delay_target = val; - val = fdtdec_get_int(fdt, node, "fsl,signal-voltage-switch-extra-delay-ms", 0); + val = ofnode_read_u32_default(node, "fsl,signal-voltage-switch-extra-delay-ms", 0); priv->signal_voltage_switch_extra_delay_ms = val; if (dev_read_bool(dev, "broken-cd")) @@ -1521,14 +1526,21 @@ static int fsl_esdhc_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(CLK) /* Assigned clock already set clock */ - ret = clk_get_by_name(dev, "per", &priv->per_clk); + ret = clk_get_bulk(dev, &priv->clk_bulk); if (ret) { - printf("Failed to get per_clk\n"); + dev_err(dev, "Failed to get clks: %d\n", ret); + return ret; + } + + ret = clk_enable_bulk(&priv->clk_bulk); + if (ret) { + dev_err(dev, "Failed to enable clks: %d\n", ret); return ret; } - ret = clk_enable(&priv->per_clk); + + ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { - printf("Failed to enable per_clk\n"); + printf("Failed to get per_clk\n"); return ret; } @@ -1561,7 +1573,7 @@ static int fsl_esdhc_probe(struct udevice *dev) upriv->mmc = mmc; - return esdhc_init_common(priv, mmc); + return 0; } static int fsl_esdhc_get_cd(struct udevice *dev) @@ -1613,6 +1625,14 @@ static int fsl_esdhc_wait_dat0(struct udevice *dev, int state, return esdhc_wait_dat0_common(priv, state, timeout_us); } +static int fsl_esdhc_reinit(struct udevice *dev) +{ + struct fsl_esdhc_plat *plat = dev_get_plat(dev); + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + + return esdhc_init_common(priv, &plat->mmc); +} + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1624,6 +1644,7 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, #endif .wait_dat0 = fsl_esdhc_wait_dat0, + .reinit = fsl_esdhc_reinit, }; static struct esdhc_soc_data usdhc_imx7d_data = { diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 83cdc9fd66d..c8db4f811c2 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -301,7 +301,7 @@ struct mmc *find_mmc_device(int dev_num) ret = blk_find_device(UCLASS_MMC, dev_num, &dev); if (ret) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) printf("MMC Device %d not found\n", dev_num); #endif return NULL; @@ -373,7 +373,7 @@ void mmc_do_preinit(void) } } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) void print_mmc_devices(char separator) { struct udevice *dev; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index d4f2fd5bf89..efe98354a0f 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -328,7 +328,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) break; if (status & MMC_STATUS_MASK) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) log_err("Status Error: %#08x\n", status); #endif return -ECOMM; @@ -341,7 +341,7 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) } if (timeout_ms <= 0) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) log_err("Timeout waiting card ready\n"); #endif return -ETIMEDOUT; @@ -483,7 +483,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, if (blkcnt > 1) { if (mmc_send_stop_transmission(mmc, false)) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) log_err("mmc fail to send stop cmd\n"); #endif return 0; @@ -534,7 +534,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, return 0; if ((start + blkcnt) > block_dev->lba) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) log_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", start + blkcnt, block_dev->lba); #endif @@ -2424,7 +2424,7 @@ static int mmc_startup_v4(struct mmc *mmc) mmc->capacity_gp[i] <<= 19; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD if (part_completed) { mmc->enh_user_size = (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + @@ -2723,7 +2723,7 @@ static int mmc_startup(struct mmc *mmc) bdesc->blksz = mmc->read_bl_len; bdesc->log2blksz = LOG2(bdesc->blksz); bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); -#if !defined(CONFIG_SPL_BUILD) || \ +#if !defined(CONFIG_XPL_BUILD) || \ (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ !CONFIG_IS_ENABLED(USE_TINY_PRINTF)) sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", @@ -2741,7 +2741,7 @@ static int mmc_startup(struct mmc *mmc) bdesc->revision[0] = 0; #endif -#if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)) +#if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)) part_init(bdesc); #endif @@ -2953,7 +2953,7 @@ retry: err = mmc_send_op_cond(mmc); if (err) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) if (!quiet) log_err("Card did not respond to voltage select! : %d\n", err); @@ -3008,7 +3008,7 @@ int mmc_start_init(struct mmc *mmc) #endif if (no_card) { mmc->has_init = 0; -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) log_err("MMC: no card present\n"); #endif return -ENOMEDIUM; @@ -3195,7 +3195,7 @@ int mmc_initialize(struct bd_info *bis) if (ret) return ret; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD print_mmc_devices(','); #endif diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c index a87d2276c1b..8f8ba34be71 100644 --- a/drivers/mmc/mmc_legacy.c +++ b/drivers/mmc/mmc_legacy.c @@ -44,7 +44,7 @@ struct mmc *find_mmc_device(int dev_num) return m; } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) printf("MMC Device %d not found\n", dev_num); #endif @@ -93,7 +93,7 @@ void mmc_list_add(struct mmc *mmc) list_add_tail(&mmc->link, &mmc_devices); } -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) void print_mmc_devices(char separator) { struct mmc *m; diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index b32123758ea..fc45f017e5d 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -67,7 +67,7 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, } #endif -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ #ifdef CONFIG_MMC_TRACE void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd); diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 8e51453d2ae..e66ab25d02a 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -59,8 +59,8 @@ DECLARE_GLOBAL_DATA_PTR; /* simplify defines to OMAP_HSMMC_USE_GPIO */ -#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \ - (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO)) +#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_XPL_BUILD)) || \ + (defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_GPIO)) #define OMAP_HSMMC_USE_GPIO #else #undef OMAP_HSMMC_USE_GPIO diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 5ba99d68b7d..422b8f7e4c8 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -83,7 +83,7 @@ static int rockchip_dwmmc_of_to_plat(struct udevice *dev) return log_msg_ret("rkp", -EINVAL); priv->fifo_mode = dev_read_bool(dev, "fifo-mode"); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD if (!priv->fifo_mode) priv->fifo_mode = dev_read_bool(dev, "u-boot,spl-fifo-mode"); #endif diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index 4ea3307ed9c..da630b9d97a 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -608,7 +608,7 @@ static int rockchip_sdhci_probe(struct udevice *dev) * Disable use of DMA and force use of PIO mode in SPL to fix an issue * where loading part of TF-A into SRAM using DMA silently fails. */ - if (IS_ENABLED(CONFIG_SPL_BUILD) && + if (IS_ENABLED(CONFIG_XPL_BUILD) && dev_read_bool(dev, "u-boot,spl-fifo-mode")) host->flags &= ~USE_DMA; diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 3147d3019c0..9dc1ceaa09b 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -61,7 +61,7 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host) debug("%s: drvsel %d smplsel %d\n", __func__, priv->drvsel, priv->smplsel); -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF) +#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF) int ret; ret = socfpga_secure_reg_write32(SOCFPGA_SECURE_REG_SYSMGR_SOC64_SDMMC, diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 0b396122b46..9fff1bc1a10 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -385,7 +385,7 @@ static bool tmio_sd_addr_is_dmaable(struct mmc_data *data) return false; } -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD if (IS_ENABLED(CONFIG_ARCH_UNIPHIER) && !IS_ENABLED(CONFIG_ARM64)) { /* * For UniPhier ARMv7 SoCs, the stack is allocated in locked diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 5b3650d52ee..cc89ff767ab 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -36,7 +36,7 @@ static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv) { #if CONFIG_IS_ENABLED(CLK) return clk_get_rate(&priv->clk); -#elif CONFIG_SPL_BUILD +#elif CONFIG_XPL_BUILD return 100000000; #else return 0; @@ -50,7 +50,7 @@ static int uniphier_sd_probe(struct udevice *dev) priv->clk_get_rate = uniphier_sd_clk_get_rate; priv->read_poll_flag = TMIO_SD_DMA_INFO1_END_RD2; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD int ret; ret = clk_get_by_index(dev, 0, &priv->clk); diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 24d0556cd37..0e2bdab4e7e 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -289,7 +289,7 @@ static inline int arasan_zynqmp_set_in_tapdelay(u32 node_id, u32 itap_delay) { int ret; - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) { if (node_id == NODE_SD_0) { ret = zynqmp_mmio_write(SD_ITAP_DLY, SD0_ITAPCHGWIN, SD0_ITAPCHGWIN); @@ -339,7 +339,7 @@ static inline int arasan_zynqmp_set_in_tapdelay(u32 node_id, u32 itap_delay) static inline int arasan_zynqmp_set_out_tapdelay(u32 node_id, u32 otap_delay) { - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) { if (node_id == NODE_SD_0) return zynqmp_mmio_write(SD_OTAP_DLY, SD0_OTAPDLYSEL_MASK, @@ -356,7 +356,7 @@ static inline int arasan_zynqmp_set_out_tapdelay(u32 node_id, u32 otap_delay) static inline int zynqmp_dll_reset(u32 node_id, u32 type) { - if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) { + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) { if (node_id == NODE_SD_0) return zynqmp_mmio_write(SD_DLL_CTRL, SD0_DLL_RST, type == PM_DLL_RESET_ASSERT ? diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 10d575e9f93..ce05e206073 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -16,7 +16,7 @@ mtd-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o mtd-$(CONFIG_HBMC_AM654) += hbmc-am654.o # U-Boot build -ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),) ifneq ($(mtd-y),) obj-y += mtd.o @@ -34,9 +34,9 @@ else ifneq ($(mtd-y),) obj-$(CONFIG_SPL_MTD) += mtd.o endif -obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += nand/ +obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += nand/ obj-$(CONFIG_SPL_ONENAND_SUPPORT) += onenand/ -obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += spi/ +obj-$(CONFIG_$(PHASE_)SPI_FLASH_SUPPORT) += spi/ obj-$(CONFIG_SPL_UBI) += ubispl/ endif diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 96e186600a1..c8169cf7390 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0+ -ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) +ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),) nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_RAW_NAND) += raw/ obj-$(CONFIG_MTD_SPI_NAND) += spi/ else -obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += raw/ +obj-$(CONFIG_$(PHASE_)NAND_SUPPORT) += raw/ endif diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 9f3f1267cbd..c345fc1f1fb 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -120,6 +120,13 @@ config NAND_BRCMNAND Enable the driver for NAND flash on platforms using a Broadcom NAND controller. +config NAND_BRCMNAND_BCMBCA + bool "Support Broadcom NAND controller on BCMBCA platforms" + depends on NAND_BRCMNAND && ARCH_BCMBCA + help + Enable support for broadcom nand driver on BCA (broadband + access) platforms such as BCM6846. + config NAND_BRCMNAND_6368 bool "Support Broadcom NAND controller on bcm6368" depends on NAND_BRCMNAND && ARCH_BMIPS diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 46fead6fa48..b47a3d787ce 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -3,7 +3,7 @@ # (C) Copyright 2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD ifdef CONFIG_SPL_NAND_DRIVERS NORMAL_DRIVERS=y @@ -18,7 +18,7 @@ obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o nand_amd.o nand_hynix.o \ nand_macronix.o nand_micron.o \ nand_samsung.o nand_toshiba.o obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o -obj-$(CONFIG_$(SPL_TPL_)NAND_INIT) += nand.o +obj-$(CONFIG_$(PHASE_)NAND_INIT) += nand.o ifeq ($(CONFIG_SPL_ENV_SUPPORT),y) obj-$(CONFIG_ENV_IS_IN_NAND) += nand_util.o endif diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index ee4ec6da587..817fab4ca36 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1029,11 +1029,15 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; else if (chip->ecc.strength) req.ecc.strength = chip->ecc.strength; + else if (chip->ecc_strength_ds) + req.ecc.strength = chip->ecc_strength_ds; else req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; if (chip->ecc.size) req.ecc.sectorsize = chip->ecc.size; + else if (chip->ecc_step_ds) + req.ecc.sectorsize = chip->ecc_step_ds; else req.ecc.sectorsize = ATMEL_PMECC_SECTOR_SIZE_AUTO; diff --git a/drivers/mtd/nand/raw/atmel_nand.c b/drivers/mtd/nand/raw/atmel_nand.c index 4dbf7b47135..605298628d6 100644 --- a/drivers/mtd/nand/raw/atmel_nand.c +++ b/drivers/mtd/nand/raw/atmel_nand.c @@ -1251,7 +1251,7 @@ static int at91_nand_ready(struct mtd_info *mtd) } #endif -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* The following code is for SPL */ static struct mtd_info *mtd; static struct nand_chip nand_chip; @@ -1526,4 +1526,4 @@ void board_nand_init(void) if (atmel_nand_chip_init(i, base_addr[i])) log_err("atmel_nand: Fail to initialize #%d chip", i); } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ diff --git a/drivers/mtd/nand/raw/brcmnand/Makefile b/drivers/mtd/nand/raw/brcmnand/Makefile index 0c6325aaa61..24d0d568449 100644 --- a/drivers/mtd/nand/raw/brcmnand/Makefile +++ b/drivers/mtd/nand/raw/brcmnand/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_NAND_BRCMNAND_6753) += bcm6753_nand.o obj-$(CONFIG_NAND_BRCMNAND_68360) += bcm68360_nand.o obj-$(CONFIG_NAND_BRCMNAND_6838) += bcm6838_nand.o obj-$(CONFIG_NAND_BRCMNAND_6858) += bcm6858_nand.o +obj-$(CONFIG_NAND_BRCMNAND_BCMBCA) += bcmbca_nand.o obj-$(CONFIG_NAND_BRCMNAND_IPROC) += iproc_nand.o obj-$(CONFIG_NAND_BRCMNAND) += brcmnand.o obj-$(CONFIG_NAND_BRCMNAND) += brcmnand_compat.o diff --git a/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c b/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c new file mode 100644 index 00000000000..2753783ae70 --- /dev/null +++ b/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <asm/io.h> +#include <memalign.h> +#include <nand.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <dm.h> +#include <linux/printk.h> + +#include "brcmnand.h" + +struct bcmbca_nand_soc { + struct brcmnand_soc soc; + void __iomem *base; +}; + +#define BCMBCA_NAND_INT 0x00 +#define BCMBCA_NAND_STATUS_SHIFT 0 +#define BCMBCA_NAND_STATUS_MASK (0xfff << BCMBCA_NAND_STATUS_SHIFT) + +#define BCMBCA_NAND_INT_EN 0x04 +#define BCMBCA_NAND_ENABLE_SHIFT 0 +#define BCMBCA_NAND_ENABLE_MASK (0xffff << BCMBCA_NAND_ENABLE_SHIFT) + +enum { + BCMBCA_NP_READ = BIT(0), + BCMBCA_BLOCK_ERASE = BIT(1), + BCMBCA_COPY_BACK = BIT(2), + BCMBCA_PAGE_PGM = BIT(3), + BCMBCA_CTRL_READY = BIT(4), + BCMBCA_DEV_RBPIN = BIT(5), + BCMBCA_ECC_ERR_UNC = BIT(6), + BCMBCA_ECC_ERR_CORR = BIT(7), +}; + +#if defined(CONFIG_ARM64) +#define ALIGN_REQ 8 +#else +#define ALIGN_REQ 4 +#endif + +static inline bool bcmbca_nand_is_buf_aligned(void *flash_cache, void *buffer) +{ + return IS_ALIGNED((uintptr_t)buffer, ALIGN_REQ) && + IS_ALIGNED((uintptr_t)flash_cache, ALIGN_REQ); +} + +static bool bcmbca_nand_intc_ack(struct brcmnand_soc *soc) +{ + struct bcmbca_nand_soc *priv = + container_of(soc, struct bcmbca_nand_soc, soc); + void __iomem *mmio = priv->base + BCMBCA_NAND_INT; + u32 val = brcmnand_readl(mmio); + + if (val & (BCMBCA_CTRL_READY << BCMBCA_NAND_STATUS_SHIFT)) { + /* Ack interrupt */ + val &= ~BCMBCA_NAND_STATUS_MASK; + val |= BCMBCA_CTRL_READY << BCMBCA_NAND_STATUS_SHIFT; + brcmnand_writel(val, mmio); + return true; + } + + return false; +} + +static void bcmbca_nand_intc_set(struct brcmnand_soc *soc, bool en) +{ + struct bcmbca_nand_soc *priv = + container_of(soc, struct bcmbca_nand_soc, soc); + void __iomem *mmio = priv->base + BCMBCA_NAND_INT_EN; + u32 val = brcmnand_readl(mmio); + + /* Don't ack any interrupts */ + val &= ~BCMBCA_NAND_STATUS_MASK; + + if (en) + val |= BCMBCA_CTRL_READY << BCMBCA_NAND_ENABLE_SHIFT; + else + val &= ~(BCMBCA_CTRL_READY << BCMBCA_NAND_ENABLE_SHIFT); + + brcmnand_writel(val, mmio); +} + +static void bcmbca_read_data_bus(struct brcmnand_soc *soc, + void __iomem *flash_cache, u32 *buffer, int fc_words) +{ + /* + * memcpy can do unaligned aligned access depending on source + * and dest address, which is incompatible with nand cache. Fallback + * to the memcpy_fromio in such case + */ + if (bcmbca_nand_is_buf_aligned((void __force *)flash_cache, buffer)) + memcpy((void *)buffer, (void __force *)flash_cache, fc_words * 4); + else + memcpy_fromio((void *)buffer, flash_cache, fc_words * 4); +} + +static int bcmbca_nand_probe(struct udevice *dev) +{ + struct udevice *pdev = dev; + struct bcmbca_nand_soc *priv = dev_get_priv(dev); + struct brcmnand_soc *soc; + struct resource res; + + soc = &priv->soc; + + dev_read_resource_byname(pdev, "nand-int-base", &res); + priv->base = devm_ioremap(dev, res.start, resource_size(&res)); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + soc->ctlrdy_ack = bcmbca_nand_intc_ack; + soc->ctlrdy_set_enabled = bcmbca_nand_intc_set; + soc->read_data_bus = bcmbca_read_data_bus; + + /* Disable and ack all interrupts */ + brcmnand_writel(0, priv->base + BCMBCA_NAND_INT_EN); + brcmnand_writel(0, priv->base + BCMBCA_NAND_INT); + + return brcmnand_probe(pdev, soc); +} + +static const struct udevice_id bcmbca_nand_dt_ids[] = { + { + .compatible = "brcm,nand-bcm63138", + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(bcmbca_nand) = { + .name = "bcmbca-nand", + .id = UCLASS_MTD, + .of_match = bcmbca_nand_dt_ids, + .probe = bcmbca_nand_probe, + .priv_auto = sizeof(struct bcmbca_nand_soc), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_DRIVER_GET(bcmbca_nand), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); +} diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index b1af3f717d4..749553c9df9 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -25,6 +25,7 @@ #include <linux/completion.h> #include <linux/errno.h> #include <linux/log2.h> +#include <linux/mtd/nand.h> #include <linux/mtd/rawnand.h> #include <asm/processor.h> #include <dm.h> @@ -218,6 +219,7 @@ struct brcmnand_controller { const unsigned int *page_sizes; unsigned int page_size_shift; unsigned int max_oob; + u32 ecc_level_shift; u32 features; /* for low-power standby/resume only */ @@ -544,6 +546,34 @@ enum { INTFC_CTLR_READY = BIT(31), }; +/*********************************************************************** + * NAND ACC CONTROL bitfield + * + * Some bits have remained constant throughout hardware revision, while + * others have shifted around. + ***********************************************************************/ + +/* Constant for all versions (where supported) */ +enum { + /* See BRCMNAND_HAS_CACHE_MODE */ + ACC_CONTROL_CACHE_MODE = BIT(22), + + /* See BRCMNAND_HAS_PREFETCH */ + ACC_CONTROL_PREFETCH = BIT(23), + + ACC_CONTROL_PAGE_HIT = BIT(24), + ACC_CONTROL_WR_PREEMPT = BIT(25), + ACC_CONTROL_PARTIAL_PAGE = BIT(26), + ACC_CONTROL_RD_ERASED = BIT(27), + ACC_CONTROL_FAST_PGM_RDIN = BIT(28), + ACC_CONTROL_WR_ECC = BIT(30), + ACC_CONTROL_RD_ECC = BIT(31), +}; + +#define ACC_CONTROL_ECC_SHIFT 16 +/* Only for v7.2 */ +#define ACC_CONTROL_ECC_EXT_SHIFT 13 + static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs) { return brcmnand_readl(ctrl->nand_base + offs); @@ -675,6 +705,12 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) #endif /* __UBOOT__ */ ctrl->features |= BRCMNAND_HAS_WP; + /* v7.2 has different ecc level shift in the acc register */ + if (ctrl->nand_version == 0x0702) + ctrl->ecc_level_shift = ACC_CONTROL_ECC_EXT_SHIFT; + else + ctrl->ecc_level_shift = ACC_CONTROL_ECC_SHIFT; + return 0; } @@ -733,6 +769,20 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl, __raw_writel(val, ctrl->nand_fc + word * 4); } +static inline void brcmnand_read_data_bus(struct brcmnand_controller *ctrl, + void __iomem *flash_cache, u32 *buffer, int fc_words) +{ + struct brcmnand_soc *soc = ctrl->soc; + int i; + + if (soc && soc->read_data_bus) { + soc->read_data_bus(soc, flash_cache, buffer, fc_words); + } else { + for (i = 0; i < fc_words; i++) + buffer[i] = brcmnand_read_fc(ctrl, i); + } +} + static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl) { @@ -844,30 +894,6 @@ static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl) return 0; } -/*********************************************************************** - * NAND ACC CONTROL bitfield - * - * Some bits have remained constant throughout hardware revision, while - * others have shifted around. - ***********************************************************************/ - -/* Constant for all versions (where supported) */ -enum { - /* See BRCMNAND_HAS_CACHE_MODE */ - ACC_CONTROL_CACHE_MODE = BIT(22), - - /* See BRCMNAND_HAS_PREFETCH */ - ACC_CONTROL_PREFETCH = BIT(23), - - ACC_CONTROL_PAGE_HIT = BIT(24), - ACC_CONTROL_WR_PREEMPT = BIT(25), - ACC_CONTROL_PARTIAL_PAGE = BIT(26), - ACC_CONTROL_RD_ERASED = BIT(27), - ACC_CONTROL_FAST_PGM_RDIN = BIT(28), - ACC_CONTROL_WR_ECC = BIT(30), - ACC_CONTROL_RD_ECC = BIT(31), -}; - static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) { if (ctrl->nand_version == 0x0702) @@ -880,18 +906,15 @@ static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) return GENMASK(4, 0); } -#define NAND_ACC_CONTROL_ECC_SHIFT 16 -#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13 - static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl) { u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f; - mask <<= NAND_ACC_CONTROL_ECC_SHIFT; + mask <<= ACC_CONTROL_ECC_SHIFT; /* v7.2 includes additional ECC levels */ - if (ctrl->nand_version >= 0x0702) - mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT; + if (ctrl->nand_version == 0x0702) + mask |= 0x7 << ACC_CONTROL_ECC_EXT_SHIFT; return mask; } @@ -905,8 +928,8 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en) if (en) { acc_control |= ecc_flags; /* enable RD/WR ECC */ - acc_control |= host->hwcfg.ecc_level - << NAND_ACC_CONTROL_ECC_SHIFT; + acc_control &= ~brcmnand_ecc_level_mask(ctrl); + acc_control |= host->hwcfg.ecc_level << ctrl->ecc_level_shift; } else { acc_control &= ~ecc_flags; /* disable RD/WR ECC */ acc_control &= ~brcmnand_ecc_level_mask(ctrl); @@ -957,6 +980,43 @@ static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val) nand_writereg(ctrl, acc_control_offs, tmp); } +static int brcmnand_get_spare_size(struct brcmnand_host *host) +{ + struct brcmnand_controller *ctrl = host->ctrl; + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, + BRCMNAND_CS_ACC_CONTROL); + u32 acc = nand_readreg(ctrl, acc_control_offs); + + return (acc & brcmnand_spare_area_mask(ctrl)); +} + +static void brcmnand_get_ecc_settings(struct brcmnand_host *host, struct nand_chip *chip) +{ + struct brcmnand_controller *ctrl = host->ctrl; + u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs, + BRCMNAND_CS_ACC_CONTROL); + bool sector_size_1k = brcmnand_get_sector_size_1k(host); + int spare_area_size, ecc_level; + u32 acc; + + spare_area_size = brcmnand_get_spare_size(host); + acc = nand_readreg(ctrl, acc_control_offs); + ecc_level = (acc & brcmnand_ecc_level_mask(ctrl)) >> ctrl->ecc_level_shift; + if (sector_size_1k) + chip->ecc.strength = ecc_level * 2; + else if (spare_area_size == 16 && ecc_level == 15) + chip->ecc.strength = 1; /* hamming */ + else + chip->ecc.strength = ecc_level; + + if (chip->ecc.size == 0) { + if (sector_size_1k) + chip->ecc.size = 1024; + else + chip->ecc.size = 512; + } +} + /*********************************************************************** * CS_NAND_SELECT ***********************************************************************/ @@ -1003,6 +1063,14 @@ static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl, } while (get_timer(base) < limit); #endif /* __UBOOT__ */ + /* + * do a final check after time out in case the CPU was busy and the driver + * did not get enough time to perform the polling to avoid false alarms + */ + val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS); + if ((val & mask) == expected_val) + return 0; + dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n", expected_val, val & mask); @@ -1318,19 +1386,33 @@ static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i, const u8 *oob, int sas, int sector_1k) { int tbytes = sas << sector_1k; - int j; + int j, k = 0; + u32 last = 0xffffffff; + u8 *plast = (u8 *)&last; /* Adjust OOB values for 1K sector size */ if (sector_1k && (i & 0x01)) tbytes = max(0, tbytes - (int)ctrl->max_oob); tbytes = min_t(int, tbytes, ctrl->max_oob); - for (j = 0; j < tbytes; j += 4) + /* + * tbytes may not be multiple of words. Make sure we don't read out of + * the boundary and stop at last word. + */ + for (j = 0; (j + 3) < tbytes; j += 4) oob_reg_write(ctrl, j, (oob[j + 0] << 24) | (oob[j + 1] << 16) | (oob[j + 2] << 8) | (oob[j + 3] << 0)); + + /* handle the remaing bytes */ + while (j < tbytes) + plast[k++] = oob[j++]; + + if (tbytes & 0x3) + oob_reg_write(ctrl, (tbytes & ~0x3), (__force u32)cpu_to_be32(last)); + return tbytes; } @@ -1781,7 +1863,7 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, { struct brcmnand_host *host = nand_get_controller_data(chip); struct brcmnand_controller *ctrl = host->ctrl; - int i, j, ret = 0; + int i, ret = 0; brcmnand_clear_ecc_addr(ctrl); @@ -1794,8 +1876,8 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, if (likely(buf)) { brcmnand_soc_data_bus_prepare(ctrl->soc, false); - for (j = 0; j < FC_WORDS; j++, buf++) - *buf = brcmnand_read_fc(ctrl, j); + brcmnand_read_data_bus(ctrl, ctrl->nand_fc, buf, FC_WORDS); + buf += FC_WORDS; brcmnand_soc_data_bus_unprepare(ctrl->soc, false); } @@ -2225,7 +2307,7 @@ static int brcmnand_set_cfg(struct brcmnand_host *host, tmp &= ~brcmnand_ecc_level_mask(ctrl); tmp &= ~brcmnand_spare_area_mask(ctrl); if (ctrl->nand_version >= 0x0302) { - tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; + tmp |= cfg->ecc_level << ctrl->ecc_level_shift; tmp |= cfg->spare_area_size; } nand_writereg(ctrl, acc_control_offs, tmp); @@ -2274,15 +2356,38 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) { struct mtd_info *mtd = nand_to_mtd(&host->chip); struct nand_chip *chip = &host->chip; + struct nand_device *nanddev = mtd_to_nanddev(mtd); + struct nand_memory_organization *memorg = nanddev_get_memorg(nanddev); struct brcmnand_controller *ctrl = host->ctrl; struct brcmnand_cfg *cfg = &host->hwcfg; - char msg[128]; u32 offs, tmp, oob_sector; + bool use_strap = false; + char msg[128]; int ret; memset(cfg, 0, sizeof(*cfg)); #ifndef __UBOOT__ + use_strap = of_property_read_bool(nand_get_flash_node(chip), + "brcm,nand-ecc-use-strap"): +#else + use_strap = ofnode_read_bool(nand_get_flash_node(chip), + "brcm,nand-ecc-use-strap"); +#endif /* __UBOOT__ */ + /* + * Either nand-ecc-xxx or brcm,nand-ecc-use-strap can be set. Error out + * if both exist. + */ + if (chip->ecc.strength && use_strap) { + dev_err(ctrl->dev, + "ECC strap and DT ECC configuration properties are mutually exclusive\n"); + return -EINVAL; + } + + if (use_strap) + brcmnand_get_ecc_settings(host, chip); + +#ifndef __UBOOT__ ret = of_property_read_u32(nand_get_flash_node(chip), "brcm,nand-oob-sector-size", &oob_sector); @@ -2291,20 +2396,25 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) "brcm,nand-oob-sector-size", &oob_sector); #endif /* __UBOOT__ */ + if (ret) { - /* Use detected size */ - cfg->spare_area_size = mtd->oobsize / - (mtd->writesize >> FC_SHIFT); + if (use_strap) + cfg->spare_area_size = brcmnand_get_spare_size(host); + else + /* Use detected size */ + cfg->spare_area_size = mtd->oobsize / + (mtd->writesize >> FC_SHIFT); } else { cfg->spare_area_size = oob_sector; } if (cfg->spare_area_size > ctrl->max_oob) cfg->spare_area_size = ctrl->max_oob; /* - * Set oobsize to be consistent with controller's spare_area_size, as - * the rest is inaccessible. + * Set mtd and memorg oobsize to be consistent with controller's + * spare_area_size, as the rest is inaccessible. */ mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT); + memorg->oobsize = mtd->oobsize; cfg->device_size = mtd->size; cfg->block_size = mtd->erasesize; @@ -2796,8 +2906,17 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc) /* Disable XOR addressing */ brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0); + /* Check if the board connects the WP pin */ +#ifndef __UBOOT__ + if (of_property_read_bool(dn, "brcm,wp-not-connected")) +#else + if (dev_read_bool(ctrl->dev, "brcm,wp-not-connected")) +#endif /* __UBOOT__ */ + wp_on = 0; + /* Read the write-protect configuration in the device tree */ - wp_on = dev_read_u32_default(dev, "write-protect", wp_on); + if (dev_read_bool(ctrl->dev, "write-protect")) + wp_on = dev_read_u32_default(dev, "write-protect", wp_on); if (ctrl->features & BRCMNAND_HAS_WP) { /* Permanently disable write protection */ diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.h b/drivers/mtd/nand/raw/brcmnand/brcmnand.h index 6946a62b067..3a1d6047136 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.h +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.h @@ -11,6 +11,8 @@ struct brcmnand_soc { void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en); void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare, bool is_param); + void (*read_data_bus)(struct brcmnand_soc *soc, void __iomem *flash_cache, + u32 *buffer, int fc_words); void *ctrl; }; diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c index c89661badbf..4430c4e93ee 100644 --- a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c @@ -152,7 +152,7 @@ static void lpc32xx_nand_init(void) &lpc32xx_nand_mlc_registers->time_reg); } -#if !defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_XPL_BUILD) /** * lpc32xx_cmd_ctrl - write command to either cmd or data register @@ -606,7 +606,7 @@ void board_nand_init(void) pr_err("nand_register returned %i", ret); } -#else /* defined(CONFIG_SPL_BUILD) */ +#else /* defined(CONFIG_XPL_BUILD) */ void nand_init(void) { @@ -770,4 +770,4 @@ unsigned int nand_page_size(void) return BYTES_PER_PAGE; } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c index 4d643bc64bc..109c31fb4d1 100644 --- a/drivers/mtd/nand/raw/lpc32xx_nand_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_nand_slc.c @@ -84,7 +84,7 @@ static struct nand_ecclayout lpc32xx_nand_oob_16 = { } }; -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) #define ECCSTEPS (CONFIG_SYS_NAND_PAGE_SIZE / CFG_SYS_NAND_ECCSIZE) /* @@ -162,7 +162,7 @@ static int lpc32xx_nand_dev_ready(struct mtd_info *mtd) return readl(&lpc32xx_nand_slc_regs->stat) & STAT_NAND_READY; } -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) /* * Prepares DMA descriptors for NAND RD/WR operations * If the size is < 256 Bytes then it is assumed to be @@ -510,7 +510,7 @@ static void lpc32xx_write_byte(struct mtd_info *mtd, uint8_t byte) */ int board_nand_init(struct nand_chip *lpc32xx_chip) { -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) int ret; /* Acquire a channel for our use */ @@ -533,7 +533,7 @@ int board_nand_init(struct nand_chip *lpc32xx_chip) lpc32xx_chip->read_byte = lpc32xx_read_byte; lpc32xx_chip->write_byte = lpc32xx_write_byte; -#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_DMA_LPC32XX) && !defined(CONFIG_XPL_BUILD) /* Hardware ECC calculation is supported when DMA driver is selected */ lpc32xx_chip->ecc.mode = NAND_ECC_HW; diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 0545c23e268..1b65c6f6443 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -414,7 +414,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd_to_nand(mtd); int ret = 0; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD int res; #endif @@ -434,7 +434,7 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) nand_release_device(mtd); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD /* Mark block bad in BBT */ if (chip->bbt) { res = nand_markbad_bbt(mtd, ofs); @@ -488,7 +488,7 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) if (!chip->bbt) return 0; /* Return info from the table */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD return nand_isreserved_bbt(mtd, ofs); #else return 0; @@ -518,7 +518,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) return chip->block_bad(mtd, ofs); /* Return info from the table */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD return nand_isbad_bbt(mtd, ofs, allowbbt); #else return 0; @@ -3729,7 +3729,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) if (!chip->read_buf || chip->read_buf == nand_read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD if (!chip->scan_bbt) chip->scan_bbt = nand_default_bbt; #endif diff --git a/drivers/mtd/nand/raw/omap_gpmc.c b/drivers/mtd/nand/raw/omap_gpmc.c index a36e2a148cc..9c704c60e8e 100644 --- a/drivers/mtd/nand/raw/omap_gpmc.c +++ b/drivers/mtd/nand/raw/omap_gpmc.c @@ -1011,7 +1011,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, return 0; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD /* * omap_nand_switch_ecc - switch the ECC operation between different engines * (h/w and s/w) and different algorithms (hamming and BCHx) @@ -1072,7 +1072,7 @@ int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) err = nand_scan_tail(mtd); return err; } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ /* * Board-specific NAND initialization. The following members of the diff --git a/drivers/mtd/nand/raw/sand_nand.c b/drivers/mtd/nand/raw/sand_nand.c index 229d7b5b65a..3678bb8a41b 100644 --- a/drivers/mtd/nand/raw/sand_nand.c +++ b/drivers/mtd/nand/raw/sand_nand.c @@ -601,7 +601,7 @@ static int sand_nand_probe(struct udevice *dev) } nand = &chip->nand; - nand->options = spl_in_proper() ? 0 : NAND_SKIP_BBTSCAN; + nand->options = not_xpl() ? 0 : NAND_SKIP_BBTSCAN; nand->flash_node = np; nand->dev_ready = sand_nand_dev_ready; nand->cmdfunc = sand_nand_command; @@ -680,7 +680,7 @@ void board_nand_init(void) log_info("Failed to get sandbox NAND: %d\n", err); } -#if IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_NAND_INIT) +#if IS_ENABLED(CONFIG_XPL_BUILD) && IS_ENABLED(CONFIG_SPL_NAND_INIT) void nand_deselect(void) { nand_chip->select_chip(nand_to_mtd(nand_chip), -1); diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile index 4dc417a5794..7f4a8514c17 100644 --- a/drivers/mtd/onenand/Makefile +++ b/drivers/mtd/onenand/Makefile @@ -3,7 +3,7 @@ # Copyright (C) 2005-2007 Samsung Electronics. # Kyungmin Park <kyungmin.park@samsung.com> -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_CMD_ONENAND) := onenand_uboot.o onenand_base.o onenand_bbt.o obj-$(CONFIG_SAMSUNG_ONENAND) += samsung.o else diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index bedc4e970e4..ca60a425ba3 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -2,7 +2,7 @@ menu "SPI Flash Support" config DM_SPI_FLASH bool "Enable Driver Model for SPI flash" - depends on DM && DM_SPI + depends on DM_SPI imply SPI_FLASH help Enable driver model for SPI flash. This SPI flash interface @@ -176,6 +176,11 @@ config SPI_FLASH_MACRONIX help Add support for various Macronix SPI flash chips (MX25Lxxx) +config SPI_FLASH_PUYA + bool "Puya Semiconductor SPI flash support" + help + Add support for various Puya Semiconductor SPI flash chips (P25xxx) + config SPI_FLASH_SILICONKAISER bool "Silicon Kaiser SPI flash support" help diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 409395382f5..44e67cd913a 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -3,12 +3,12 @@ # (C) Copyright 2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_TPL_)DM_SPI_FLASH) += sf-uclass.o +obj-$(CONFIG_$(PHASE_)DM_SPI_FLASH) += sf-uclass.o spi-nor-y := sf_probe.o spi-nor-ids.o -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o -ifeq ($(CONFIG_$(SPL_TPL_)SPI_FLASH_TINY),y) +ifeq ($(CONFIG_$(PHASE_)SPI_FLASH_TINY),y) spi-nor-y += spi-nor-tiny.o else spi-nor-y += spi-nor-core.o @@ -19,6 +19,6 @@ endif obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o -obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_MTD) += sf_mtd.o +obj-$(CONFIG_$(PHASE_)SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o -obj-$(CONFIG_$(SPL_TPL_)BOOTDEV_SPI_FLASH) += sf_bootdev.o +obj-$(CONFIG_$(PHASE_)BOOTDEV_SPI_FLASH) += sf_bootdev.o diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index 2d5a16bf6a2..e5ebc3479fb 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -138,7 +138,7 @@ static int sandbox_sf_probe(struct udevice *dev) return ret; } slave_plat = dev_get_parent_plat(dev); - cs = slave_plat->cs; + cs = slave_plat->cs[0]; debug("found at cs %d\n", cs); if (!pdata->filename) { diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index a4d15bd64aa..102a9236826 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -54,7 +54,7 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, struct udevice *bus; char *str; -#if defined(CONFIG_SPL_BUILD) && CONFIG_IS_ENABLED(USE_TINY_PRINTF) +#if defined(CONFIG_XPL_BUILD) && CONFIG_IS_ENABLED(USE_TINY_PRINTF) str = "spi_flash"; #else char name[30]; diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c index 6db24189c8e..438eb3698d5 100644 --- a/drivers/mtd/spi/sf_dataflash.c +++ b/drivers/mtd/spi/sf_dataflash.c @@ -438,7 +438,7 @@ static int add_dataflash(struct udevice *dev, char *name, int nr_pages, spi_flash->size = nr_pages * pagesize; spi_flash->erase_size = pagesize; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD printf("SPI DataFlash: Detected %s with page size ", spi_flash->name); print_size(spi_flash->page_size, ", erase size "); print_size(spi_flash->erase_size, ", total "); diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 8f7a77e7169..f5c9868bbca 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -194,27 +194,26 @@ struct sfdp_bfpt { /** * struct spi_nor_fixups - SPI NOR fixup hooks - * @default_init: called after default flash parameters init. Used to tweak - * flash parameters when information provided by the flash_info - * table is incomplete or wrong. * @post_bfpt: called after the BFPT table has been parsed - * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs - * that do not support RDSFDP). Typically used to tweak various - * parameters that could not be extracted by other means (i.e. - * when information provided by the SFDP/flash_info tables are - * incomplete or wrong). + * @post_sfdp: called after SFDP has been parsed. Typically used to tweak + * various parameters that could not be extracted by other means + * (i.e. when information provided by the SFDP tables are incomplete + * or wrong). + * @late_init: used to initialize flash parameters that are not declared in the + * JESD216 SFDP standard, or where SFDP tables not defined at all. * * Those hooks can be used to tweak the SPI NOR configuration when the SFDP * table is broken or not available. */ struct spi_nor_fixups { - void (*default_init)(struct spi_nor *nor); int (*post_bfpt)(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, const struct sfdp_bfpt *bfpt, struct spi_nor_flash_parameter *params); void (*post_sfdp)(struct spi_nor *nor, struct spi_nor_flash_parameter *params); + void (*late_init)(struct spi_nor *nor, + struct spi_nor_flash_parameter *params); }; #define SPI_NOR_SRST_SLEEP_LEN 200 @@ -467,8 +466,9 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len, } /* - * Read the status register, returning its value in the location - * Return the status register value. + * Return the status register value. If the chip is parallel, then the + * read will be striped, so we should read 2 bytes to get the sr + * register value from both of the parallel chips. * Returns negative if error occurred. */ static int read_sr(struct spi_nor *nor) @@ -500,18 +500,29 @@ static int read_sr(struct spi_nor *nor) if (spi_nor_protocol_is_dtr(nor->reg_proto)) op.data.nbytes = 2; - ret = spi_nor_read_write_reg(nor, &op, val); - if (ret < 0) { - pr_debug("error %d reading SR\n", (int)ret); - return ret; + if (nor->flags & SNOR_F_HAS_PARALLEL) { + op.data.nbytes = 2; + ret = spi_nor_read_write_reg(nor, &op, &val[0]); + if (ret < 0) { + pr_debug("error %d reading SR\n", (int)ret); + return ret; + } + val[0] |= val[1]; + } else { + ret = spi_nor_read_write_reg(nor, &op, &val[0]); + if (ret < 0) { + pr_debug("error %d reading SR\n", (int)ret); + return ret; + } } - return *val; + return val[0]; } /* - * Read the flag status register, returning its value in the location - * Return the status register value. + * Return the flag status register value. If the chip is parallel, then + * the read will be striped, so we should read 2 bytes to get the fsr + * register value from both of the parallel chips. * Returns negative if error occurred. */ static int read_fsr(struct spi_nor *nor) @@ -543,13 +554,23 @@ static int read_fsr(struct spi_nor *nor) if (spi_nor_protocol_is_dtr(nor->reg_proto)) op.data.nbytes = 2; - ret = spi_nor_read_write_reg(nor, &op, val); - if (ret < 0) { - pr_debug("error %d reading FSR\n", ret); - return ret; + if (nor->flags & SNOR_F_HAS_PARALLEL) { + op.data.nbytes = 2; + ret = spi_nor_read_write_reg(nor, &op, &val[0]); + if (ret < 0) { + pr_debug("error %d reading SR\n", (int)ret); + return ret; + } + val[0] &= val[1]; + } else { + ret = spi_nor_read_write_reg(nor, &op, &val[0]); + if (ret < 0) { + pr_debug("error %d reading FSR\n", ret); + return ret; + } } - return *val; + return val[0]; } /* @@ -573,6 +594,24 @@ static int read_cr(struct spi_nor *nor) } #endif +/** + * read_sr3() - Read status register 3 unique to newer Winbond flashes + * @nor: pointer to a 'struct spi_nor' + */ +static int read_sr3(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1); + if (ret < 0) { + dev_dbg(nor->dev, "error %d reading SR3\n", ret); + return ret; + } + + return val; +} + /* * Write status register 1 byte * Returns negative if error occurred. @@ -583,6 +622,17 @@ static int write_sr(struct spi_nor *nor, u8 val) return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1); } +/** + * write_sr3() - Write status register 3 unique to newer Winbond flashes + * @nor: pointer to a 'struct spi_nor' + * @val: value to be written into SR3 + */ +static int write_sr3(struct spi_nor *nor, u8 val) +{ + nor->cmd_buf[0] = val; + return nor->write_reg(nor, SPINOR_OP_WRSR3, nor->cmd_buf, 1); +} + /* * Set write enable latch with Write Enable command. * Returns negative if error occurred. @@ -668,12 +718,17 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, const struct flash_info *info) { + bool shift = 0; + + if (nor->flags & SNOR_F_HAS_PARALLEL) + shift = 1; + /* Do some manufacturer fixups first */ switch (JEDEC_MFR(info)) { case SNOR_MFR_SPANSION: /* No small sector erase for 4-byte command set */ nor->erase_opcode = SPINOR_OP_SE; - nor->mtd.erasesize = info->sector_size; + nor->mtd.erasesize = info->sector_size << shift; break; default: @@ -901,12 +956,32 @@ static int clean_bar(struct spi_nor *nor) static int write_bar(struct spi_nor *nor, u32 offset) { - u8 cmd, bank_sel; + u8 cmd, bank_sel, upage_curr; int ret; + struct mtd_info *mtd = &nor->mtd; + + /* Wait until previous write command is finished */ + if (spi_nor_wait_till_ready(nor)) + return 1; + + if (nor->flags & (SNOR_F_HAS_PARALLEL | SNOR_F_HAS_STACKED) && + mtd->size <= SZ_32M) + return 0; + + if (mtd->size <= SZ_16M) + return 0; + + offset = offset % (u32)mtd->size; + bank_sel = offset >> 24; + + upage_curr = nor->spi->flags & SPI_XFER_U_PAGE; + + if (!(nor->flags & SNOR_F_HAS_STACKED) && bank_sel == nor->bank_curr) + return 0; + else if (upage_curr == nor->upage_prev && bank_sel == nor->bank_curr) + return 0; - bank_sel = offset / SZ_16M; - if (bank_sel == nor->bank_curr) - goto bar_end; + nor->upage_prev = upage_curr; cmd = nor->bank_write_cmd; write_enable(nor); @@ -916,15 +991,19 @@ static int write_bar(struct spi_nor *nor, u32 offset) return ret; } -bar_end: nor->bank_curr = bank_sel; - return nor->bank_curr; + + return write_disable(nor); } static int read_bar(struct spi_nor *nor, const struct flash_info *info) { u8 curr_bank = 0; int ret; + struct mtd_info *mtd = &nor->mtd; + + if (mtd->size <= SZ_16M) + return 0; switch (JEDEC_MFR(info)) { case SNOR_MFR_SPANSION: @@ -936,15 +1015,30 @@ static int read_bar(struct spi_nor *nor, const struct flash_info *info) nor->bank_write_cmd = SPINOR_OP_WREAR; } + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_XFER_LOWER; + ret = nor->read_reg(nor, nor->bank_read_cmd, - &curr_bank, 1); + &curr_bank, 1); if (ret) { debug("SF: fail to read bank addr register\n"); return ret; } nor->bank_curr = curr_bank; - return 0; + // Make sure both chips use the same BAR + if (nor->flags & SNOR_F_HAS_PARALLEL) { + write_enable(nor); + ret = nor->write_reg(nor, nor->bank_write_cmd, &curr_bank, 1); + if (ret) + return ret; + + ret = write_disable(nor); + if (ret) + return ret; + } + + return ret; } #endif @@ -1008,8 +1102,8 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); + u32 addr, len, rem, offset, max_size; bool addr_known = false; - u32 addr, len, rem, max_size; int ret, err; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, @@ -1030,11 +1124,23 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) while (len) { schedule(); - if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc()) { + if (!IS_ENABLED(CONFIG_XPL_BUILD) && ctrlc()) { addr_known = false; ret = -EINTR; goto erase_err; } + offset = addr; + if (nor->flags & SNOR_F_HAS_PARALLEL) + offset /= 2; + + if (nor->flags & SNOR_F_HAS_STACKED) { + if (offset >= (mtd->size / 2)) { + offset = offset - (mtd->size / 2); + nor->spi->flags |= SPI_XFER_U_PAGE; + } else { + nor->spi->flags &= ~SPI_XFER_U_PAGE; + } + } #ifdef CONFIG_SPI_FLASH_BAR ret = write_bar(nor, addr); if (ret < 0) @@ -1446,6 +1552,9 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) u8 id[SPI_NOR_MAX_ID_LEN]; const struct flash_info *info; + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_XFER_LOWER; + tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); if (tmp < 0) { dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp); @@ -1470,28 +1579,67 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, { struct spi_nor *nor = mtd_to_spi_nor(mtd); int ret; + loff_t offset = from; + u32 read_len = 0; + u32 rem_bank_len = 0; + u8 bank; + bool is_ofst_odd = false; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); + if ((nor->flags & SNOR_F_HAS_PARALLEL) && (offset & 1)) { + /* We can hit this case when we use file system like ubifs */ + from--; + len++; + is_ofst_odd = true; + } + while (len) { - loff_t addr = from; - size_t read_len = len; + if (nor->addr_width == 3) { + if (nor->flags & SNOR_F_HAS_PARALLEL) { + bank = (u32)from / (SZ_16M << 0x01); + rem_bank_len = ((SZ_16M << 0x01) * + (bank + 1)) - from; + } else { + bank = (u32)from / SZ_16M; + rem_bank_len = (SZ_16M * (bank + 1)) - from; + } + } + offset = from; -#ifdef CONFIG_SPI_FLASH_BAR - u32 remain_len; + if (nor->flags & SNOR_F_HAS_STACKED) { + if (offset >= (mtd->size / 2)) { + offset = offset - (mtd->size / 2); + nor->spi->flags |= SPI_XFER_U_PAGE; + } else { + nor->spi->flags &= ~SPI_XFER_U_PAGE; + } + } - ret = write_bar(nor, addr); - if (ret < 0) - return log_ret(ret); - remain_len = (SZ_16M * (nor->bank_curr + 1)) - addr; + if (nor->flags & SNOR_F_HAS_PARALLEL) + offset /= 2; - if (len < remain_len) + if (nor->addr_width == 3) { +#ifdef CONFIG_SPI_FLASH_BAR + ret = write_bar(nor, offset); + if (ret < 0) + return log_ret(ret); +#endif + } + + if (len < rem_bank_len) read_len = len; else - read_len = remain_len; -#endif + read_len = rem_bank_len; + + if (read_len == 0) + return -EIO; - ret = nor->read(nor, addr, read_len, buf); + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto read_err; + + ret = nor->read(nor, offset, read_len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1500,8 +1648,15 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, if (ret < 0) goto read_err; - *retlen += ret; - buf += ret; + if (is_ofst_odd == true) { + memmove(buf, (buf + 1), (len - 1)); + *retlen += (ret - 1); + buf += ret - 1; + is_ofst_odd = false; + } else { + *retlen += ret; + buf += ret; + } from += ret; len -= ret; } @@ -1796,6 +1951,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_nor *nor = mtd_to_spi_nor(mtd); size_t page_offset, page_remain, i; ssize_t ret; + u32 offset; #ifdef CONFIG_SPI_FLASH_SST /* sst nor chips use AAI word program */ @@ -1805,6 +1961,27 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); + if (!len) + return 0; + + /* + * Cannot write to odd offset in parallel mode, + * so write 2 bytes first + */ + if ((nor->flags & SNOR_F_HAS_PARALLEL) && (to & 1)) { + u8 two[2] = {0xff, buf[0]}; + size_t local_retlen; + + ret = spi_nor_write(mtd, to & ~1, 2, &local_retlen, two); + if (ret < 0) + return ret; + + *retlen += 1; /* We've written only one actual byte */ + ++buf; + --len; + ++to; + } + for (i = 0; i < len; ) { ssize_t written; loff_t addr = to + i; @@ -1822,18 +1999,35 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, page_offset = do_div(aux, nor->page_size); } + offset = (to + i); + if (nor->flags & SNOR_F_HAS_PARALLEL) + offset /= 2; + + if (nor->flags & SNOR_F_HAS_STACKED) { + if (offset >= (mtd->size / 2)) { + offset = offset - (mtd->size / 2); + nor->spi->flags |= SPI_XFER_U_PAGE; + } else { + nor->spi->flags &= ~SPI_XFER_U_PAGE; + } + } + + if (nor->addr_width == 3) { +#ifdef CONFIG_SPI_FLASH_BAR + ret = write_bar(nor, offset); + if (ret < 0) + return ret; +#endif + } /* the size of data remaining on the first page */ page_remain = min_t(size_t, nor->page_size - page_offset, len - i); -#ifdef CONFIG_SPI_FLASH_BAR - ret = write_bar(nor, addr); - if (ret < 0) - return ret; -#endif + ret = spi_nor_wait_till_ready(nor); + if (ret) + goto write_err; write_enable(nor); - /* * On DTR capable flashes like Micron Xcella the writes cannot * start or end at an odd address in DTR mode. So we need to @@ -1841,7 +2035,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, * address and end address are even. */ if (spi_nor_protocol_is_dtr(nor->write_proto) && - ((addr | page_remain) & 1)) { + ((offset | page_remain) & 1)) { u_char *tmp; size_t extra_bytes = 0; @@ -1852,10 +2046,10 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } /* Prepend a 0xff byte if the start address is odd. */ - if (addr & 1) { + if (offset & 1) { tmp[0] = 0xff; memcpy(tmp + 1, buf + i, page_remain); - addr--; + offset--; page_remain++; extra_bytes++; } else { @@ -1863,13 +2057,13 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, } /* Append a 0xff byte if the end address is odd. */ - if ((addr + page_remain) & 1) { + if ((offset + page_remain) & 1) { tmp[page_remain + extra_bytes] = 0xff; extra_bytes++; page_remain++; } - ret = nor->write(nor, addr, page_remain, tmp); + ret = nor->write(nor, offset, page_remain, tmp); kfree(tmp); @@ -1882,7 +2076,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, */ written = ret - extra_bytes; } else { - ret = nor->write(nor, addr, page_remain, buf + i); + ret = nor->write(nor, offset, page_remain, buf + i); if (ret < 0) goto write_err; written = ret; @@ -1891,6 +2085,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ret = spi_nor_wait_till_ready(nor); if (ret) goto write_err; + + ret = write_disable(nor); + if (ret) + goto write_err; + *retlen += written; i += written; } @@ -1931,6 +2130,10 @@ static int macronix_quad_enable(struct spi_nor *nor) if (ret) return ret; + ret = write_disable(nor); + if (ret) + return ret; + ret = read_sr(nor); if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { dev_err(nor->dev, "Macronix Quad bit not set\n"); @@ -1992,7 +2195,7 @@ static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 addr_base, return -EINVAL; } - return 0; + return write_disable(nor); } #endif @@ -2168,6 +2371,10 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, nor->read_dummy = 8; while (len) { + /* Both chips are identical, so should be the SFDP data */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_XFER_LOWER; + ret = nor->read(nor, addr, len, (u8 *)buf); if (!ret || ret > len) { ret = -EIO; @@ -2837,13 +3044,12 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, /** * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings - * after SFDP has been parsed (is also called for SPI NORs that do not - * support RDSFDP). + * after SFDP has been parsed. * @nor: pointer to a 'struct spi_nor' * * Typically used to tweak various parameters that could not be extracted by - * other means (i.e. when information provided by the SFDP/flash_info tables - * are incomplete or wrong). + * other means (i.e. when information provided by the SFDP tables are incomplete + * or wrong). */ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, struct spi_nor_flash_parameter *params) @@ -2852,20 +3058,29 @@ static void spi_nor_post_sfdp_fixups(struct spi_nor *nor, nor->fixups->post_sfdp(nor, params); } -static void spi_nor_default_init_fixups(struct spi_nor *nor) +static void spi_nor_late_init_fixups(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { - if (nor->fixups && nor->fixups->default_init) - nor->fixups->default_init(nor); + if (nor->fixups && nor->fixups->late_init) + nor->fixups->late_init(nor, params); } static int spi_nor_init_params(struct spi_nor *nor, const struct flash_info *info, struct spi_nor_flash_parameter *params) { +#if CONFIG_IS_ENABLED(DM_SPI) && CONFIG_IS_ENABLED(SPI_ADVANCE) + struct udevice *dev = nor->spi->dev; + u64 flash_size[SNOR_FLASH_CNT_MAX] = {0}; + u32 idx = 0, i = 0; + int rc; +#endif + /* Set legacy flash parameters as default. */ memset(params, 0, sizeof(*params)); /* Set SPI NOR sizes. */ + params->writesize = 1; params->size = info->sector_size * info->n_sectors; params->page_size = info->page_size; @@ -2961,8 +3176,6 @@ static int spi_nor_init_params(struct spi_nor *nor, } } - spi_nor_default_init_fixups(nor); - /* Override the parameters with data read from SFDP tables. */ nor->addr_width = 0; nor->mtd.erasesize = 0; @@ -2978,9 +3191,66 @@ static int spi_nor_init_params(struct spi_nor *nor, } else { memcpy(params, &sfdp_params, sizeof(*params)); } + + spi_nor_post_sfdp_fixups(nor, params); + } +#if CONFIG_IS_ENABLED(DM_SPI) && CONFIG_IS_ENABLED(SPI_ADVANCE) + /* + * The flashes that are connected in stacked mode should be of same make. + * Except the flash size all other properties are identical for all the + * flashes connected in stacked mode. + * The flashes that are connected in parallel mode should be identical. + */ + while (i < SNOR_FLASH_CNT_MAX) { + rc = ofnode_read_u64_index(dev_ofnode(dev), "stacked-memories", + idx, &flash_size[i]); + if (rc == -EINVAL) { + break; + } else if (rc == -EOVERFLOW) { + idx++; + } else { + idx++; + i++; + if (!(nor->flags & SNOR_F_HAS_STACKED)) + nor->flags |= SNOR_F_HAS_STACKED; + if (!(nor->spi->flags & SPI_XFER_STACKED)) + nor->spi->flags |= SPI_XFER_STACKED; + } } - spi_nor_post_sfdp_fixups(nor, params); + i = 0; + idx = 0; + while (i < SNOR_FLASH_CNT_MAX) { + rc = ofnode_read_u64_index(dev_ofnode(dev), "parallel-memories", + idx, &flash_size[i]); + if (rc == -EINVAL) { + break; + } else if (rc == -EOVERFLOW) { + idx++; + } else { + idx++; + i++; + if (!(nor->flags & SNOR_F_HAS_PARALLEL)) + nor->flags |= SNOR_F_HAS_PARALLEL; + } + } + + if (nor->flags & (SNOR_F_HAS_STACKED | SNOR_F_HAS_PARALLEL)) { + params->size = 0; + for (idx = 0; idx < SNOR_FLASH_CNT_MAX; idx++) + params->size += flash_size[idx]; + } + /* + * In parallel-memories the erase operation is + * performed on both the flashes simultaneously + * so, double the erasesize. + */ + if (nor->flags & SNOR_F_HAS_PARALLEL) { + nor->mtd.erasesize <<= 1; + params->page_size <<= 1; + } +#endif + spi_nor_late_init_fixups(nor, params); return 0; } @@ -3294,16 +3564,54 @@ static int spi_nor_select_erase(struct spi_nor *nor, /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SPINOR_OP_BE_4K; - mtd->erasesize = 4096; + /* + * In parallel-memories the erase operation is + * performed on both the flashes simultaneously + * so, double the erasesize. + */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + mtd->erasesize = 4096 * 2; + else + mtd->erasesize = 4096; } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SPINOR_OP_BE_4K_PMC; - mtd->erasesize = 4096; + /* + * In parallel-memories the erase operation is + * performed on both the flashes simultaneously + * so, double the erasesize. + */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + mtd->erasesize = 4096 * 2; + else + mtd->erasesize = 4096; } else #endif { nor->erase_opcode = SPINOR_OP_SE; - mtd->erasesize = info->sector_size; + /* + * In parallel-memories the erase operation is + * performed on both the flashes simultaneously + * so, double the erasesize. + */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + mtd->erasesize = info->sector_size * 2; + else + mtd->erasesize = info->sector_size; + } + + if ((JEDEC_MFR(info) == SNOR_MFR_SST) && info->flags & SECT_4K) { + nor->erase_opcode = SPINOR_OP_BE_4K; + /* + * In parallel-memories the erase operation is + * performed on both the flashes simultaneously + * so, double the erasesize. + */ + if (nor->flags & SNOR_F_HAS_PARALLEL) + mtd->erasesize = 4096 * 2; + else + mtd->erasesize = 4096; } + return 0; } @@ -3376,8 +3684,10 @@ static int s25fs_s_quad_enable(struct spi_nor *nor) static int s25fs_s_erase_non_uniform(struct spi_nor *nor, loff_t addr) { + u8 opcode = nor->addr_width == 4 ? SPINOR_OP_BE_4K_4B : SPINOR_OP_BE_4K; + /* Support 8 x 4KB sectors at bottom */ - return spansion_erase_non_uniform(nor, addr, SPINOR_OP_BE_4K_4B, 0, SZ_32K); + return spansion_erase_non_uniform(nor, addr, opcode, 0, SZ_32K); } static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, @@ -3404,7 +3714,8 @@ static int s25fs_s_setup(struct spi_nor *nor, const struct flash_info *info, return spi_nor_default_setup(nor, info, params); } -static void s25fs_s_default_init(struct spi_nor *nor) +static void s25fs_s_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->setup = s25fs_s_setup; } @@ -3431,20 +3742,32 @@ static int s25fs_s_post_bfpt_fixup(struct spi_nor *nor, static void s25fs_s_post_sfdp_fixup(struct spi_nor *nor, struct spi_nor_flash_parameter *params) { - /* READ_1_1_2 is not supported */ - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; - /* READ_1_1_4 is not supported */ - params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; - /* PP_1_1_4 is not supported */ - params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + /* + * The S25FS064S(8MB) supports 1-1-2 and 1-1-4 commands, but params for + * read ops in SFDP are wrong. The other density parts do not support + * 1-1-2 and 1-1-4 commands. + */ + if (params->size == SZ_8M) { + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_2], + 0, 8, SPINOR_OP_READ_1_1_2, + SNOR_PROTO_1_1_2); + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_1_1_4], + 0, 8, SPINOR_OP_READ_1_1_4, + SNOR_PROTO_1_1_4); + } else { + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_2; + params->hwcaps.mask &= ~SNOR_HWCAPS_READ_1_1_4; + params->hwcaps.mask &= ~SNOR_HWCAPS_PP_1_1_4; + } + /* Use volatile register to enable quad */ params->quad_enable = s25fs_s_quad_enable; } static struct spi_nor_fixups s25fs_s_fixups = { - .default_init = s25fs_s_default_init, .post_bfpt = s25fs_s_post_bfpt_fixup, .post_sfdp = s25fs_s_post_sfdp_fixup, + .late_init = s25fs_s_late_init, }; static int s25_s28_mdp_ready(struct spi_nor *nor) @@ -3528,9 +3851,17 @@ static int s25_s28_setup(struct spi_nor *nor, const struct flash_info *info, return spi_nor_default_setup(nor, info, params); } -static void s25_default_init(struct spi_nor *nor) +static void s25_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; } static int s25_s28_post_bfpt_fixup(struct spi_nor *nor, @@ -3609,9 +3940,9 @@ static void s25_post_sfdp_fixup(struct spi_nor *nor, } static struct spi_nor_fixups s25_fixups = { - .default_init = s25_default_init, .post_bfpt = s25_s28_post_bfpt_fixup, .post_sfdp = s25_post_sfdp_fixup, + .late_init = s25_late_init, }; static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, @@ -3620,13 +3951,14 @@ static int s25fl256l_setup(struct spi_nor *nor, const struct flash_info *info, return -ENOTSUPP; /* Bank Address Register is not supported */ } -static void s25fl256l_default_init(struct spi_nor *nor) +static void s25fl256l_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->setup = s25fl256l_setup; } static struct spi_nor_fixups s25fl256l_fixups = { - .default_init = s25fl256l_default_init, + .late_init = s25fl256l_late_init, }; #endif @@ -3689,10 +4021,18 @@ static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor) return 0; } -static void s28hx_t_default_init(struct spi_nor *nor) +static void s28hx_t_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable; nor->setup = s25_s28_setup; + + /* + * Programming is supported only in 16-byte ECC data unit granularity. + * Byte-programming, bit-walking, or multiple program operations to the + * same ECC data unit without an erase are not allowed. + */ + params->writesize = 16; } static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, @@ -3727,9 +4067,9 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor, } static struct spi_nor_fixups s28hx_t_fixups = { - .default_init = s28hx_t_default_init, .post_sfdp = s28hx_t_post_sfdp_fixup, .post_bfpt = s25_s28_post_bfpt_fixup, + .late_init = s28hx_t_late_init, }; #endif /* CONFIG_SPI_FLASH_S28HX_T */ @@ -3781,7 +4121,8 @@ static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor) return 0; } -static void mt35xu512aba_default_init(struct spi_nor *nor) +static void mt35xu512aba_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; } @@ -3810,8 +4151,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor, } static struct spi_nor_fixups mt35xu512aba_fixups = { - .default_init = mt35xu512aba_default_init, .post_sfdp = mt35xu512aba_post_sfdp_fixup, + .late_init = mt35xu512aba_late_init, }; #endif /* CONFIG_SPI_FLASH_MT35XU */ @@ -3871,7 +4212,8 @@ static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) return 0; } -static void macronix_octal_default_init(struct spi_nor *nor) +static void macronix_octal_late_init(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) { nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; } @@ -3888,8 +4230,8 @@ static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor, } static struct spi_nor_fixups macronix_octal_fixups = { - .default_init = macronix_octal_default_init, .post_sfdp = macronix_octal_post_sfdp_fixup, + .late_init = macronix_octal_late_init, }; #endif /* CONFIG_SPI_FLASH_MACRONIX */ @@ -3925,6 +4267,9 @@ static int spi_nor_init(struct spi_nor *nor) { int err; + if (nor->flags & SNOR_F_HAS_PARALLEL) + nor->spi->flags |= SPI_NOR_ENABLE_MULTI_CS; + err = spi_nor_octal_dtr_enable(nor); if (err) { dev_dbg(nor->dev, "Octal DTR mode not supported\n"); @@ -3943,6 +4288,24 @@ static int spi_nor_init(struct spi_nor *nor) write_enable(nor); write_sr(nor, 0); spi_nor_wait_till_ready(nor); + + /* + * Some Winbond SPI NORs have special SR3 register which is + * used among other things to control whether non-standard + * "Individual Block/Sector Write Protection" (WPS bit) + * locking scheme is activated. This non-standard locking + * scheme is not supported by either U-Boot or Linux SPI + * NOR stack so make sure it is disabled, otherwise the + * SPI NOR may appear locked for no obvious reason. + */ + if (JEDEC_MFR(nor->info) == SNOR_MFR_WINBOND) { + err = read_sr3(nor); + if (err > 0 && err & SR3_WPS) { + write_enable(nor); + write_sr3(nor, err & ~SR3_WPS); + write_disable(nor); + } + } } if (nor->quad_enable) { @@ -4079,7 +4442,9 @@ void spi_nor_set_fixups(struct spi_nor *nor) #endif #if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) - nor->fixups = ¯onix_octal_fixups; + if (JEDEC_MFR(nor->info) == SNOR_MFR_MACRONIX && + nor->info->flags & SPI_NOR_OCTAL_DTR_READ) + nor->fixups = ¯onix_octal_fixups; #endif /* SPI_FLASH_MACRONIX */ } @@ -4091,6 +4456,7 @@ int spi_nor_scan(struct spi_nor *nor) struct spi_slave *spi = nor->spi; int ret; int cfi_mtd_nb = 0; + bool shift = 0; #ifdef CONFIG_FLASH_CFI_MTD cfi_mtd_nb = CFI_FLASH_BANKS; @@ -4155,7 +4521,7 @@ int spi_nor_scan(struct spi_nor *nor) mtd->dev = nor->dev; mtd->priv = nor; mtd->type = MTD_NORFLASH; - mtd->writesize = 1; + mtd->writesize = params.writesize; mtd->flags = MTD_CAP_NORFLASH; mtd->size = params.size; mtd->_erase = spi_nor_erase; @@ -4228,7 +4594,9 @@ int spi_nor_scan(struct spi_nor *nor) nor->addr_width = 3; } - if (nor->addr_width == 3 && mtd->size > SZ_16M) { + if (nor->flags & (SNOR_F_HAS_PARALLEL | SNOR_F_HAS_STACKED)) + shift = 1; + if (nor->addr_width == 3 && (mtd->size >> shift) > SZ_16M) { #ifndef CONFIG_SPI_FLASH_BAR /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; @@ -4238,6 +4606,7 @@ int spi_nor_scan(struct spi_nor *nor) #else /* Configure the BAR - discover bank cmds and read current bank */ nor->addr_width = 3; + set_4byte(nor, info, 0); ret = read_bar(nor, info); if (ret < 0) return ret; @@ -4255,6 +4624,14 @@ int spi_nor_scan(struct spi_nor *nor) if (ret) return ret; + if (nor->flags & SNOR_F_HAS_STACKED) { + nor->spi->flags |= SPI_XFER_U_PAGE; + ret = spi_nor_init(nor); + if (ret) + return ret; + nor->spi->flags &= ~SPI_XFER_U_PAGE; + } + nor->rdsr_dummy = params.rdsr_dummy; nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes; nor->name = info->name; @@ -4262,7 +4639,7 @@ int spi_nor_scan(struct spi_nor *nor) nor->erase_size = mtd->erasesize; nor->sector_size = mtd->erasesize; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD printf("SF: Detected %s with page size ", nor->name); print_size(nor->page_size, ", erase size "); print_size(nor->erase_size, ", total "); diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 88709a52b3a..91ae49c9484 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -258,7 +258,6 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx25u6435f", 0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, SECT_4K) }, { INFO("mx25u12835f", 0xc22538, 0, 64 * 1024, 256, SECT_4K) }, - { INFO("mx25u25635f", 0xc22539, 0, 64 * 1024, 512, SECT_4K) }, { INFO("mx25u51245g", 0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0) }, @@ -295,6 +294,36 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx25uw6445g", 0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, { INFO("mx25uw6345g", 0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, #endif +#ifdef CONFIG_SPI_FLASH_PUYA + /* Puya Semiconductor (Shanghai) Co., Ltd */ + { INFO + ("p25q05h", 0x856010, 0, 64 * 1024, 1, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q10h", 0x856011, 0, 64 * 1024, 2, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q20h", 0x856012, 0, 64 * 1024, 4, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q40h", 0x856013, 0, 64 * 1024, 8, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q80h", 0x856014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q16h", 0x856015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q32h", 0x856016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q64h", 0x856017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO + ("p25q128h", 0x856018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +#endif #ifdef CONFIG_SPI_FLASH_SILICONKAISER { INFO("sk25lp128", 0x257018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, @@ -329,6 +358,7 @@ const struct flash_info spi_nor_ids[] = { #ifdef CONFIG_SPI_FLASH_MT35XU { INFO("mt35xl512aba", 0x2c5a1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, { INFO("mt35xu512aba", 0x2c5b1a, 0, 128 * 1024, 512, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ) }, + { INFO("mt35xu01gaba", 0x2c5b1b, 0, 128 * 1024, 1024, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, #endif /* CONFIG_SPI_FLASH_MT35XU */ { INFO6("mt35xu01g", 0x2c5b1b, 0x104100, 128 * 1024, 1024, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, { INFO("mt35xu02g", 0x2c5b1c, 0, 128 * 1024, 2048, USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, @@ -339,9 +369,12 @@ const struct flash_info spi_nor_ids[] = { */ { INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, - { INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl256s0", 0x010219, 0x4d0080, 256 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fl256s1", 0x010219, 0x4d0180, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs064s", 0x010217, 0x4d0181, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs128s", 0x012018, 0x4d0181, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { INFO6("s25fs256s", 0x010219, 0x4d0181, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { INFO("s25fl512s_256k", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { INFO("s25fl512s_64k", 0x010220, 0x4d01, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, @@ -369,7 +402,7 @@ const struct flash_info spi_nor_ids[] = { SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_CLSR) }, { INFO6("s25hl02gt", 0x342a1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, { INFO6("s25hs512t", 0x342b1a, 0x0f0390, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_CLSR) }, @@ -377,15 +410,16 @@ const struct flash_info spi_nor_ids[] = { SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_CLSR) }, { INFO6("s25hs02gt", 0x342b1c, 0x0f0090, 256 * 1024, 1024, - SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, + SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | NO_CHIP_ERASE) }, { INFO6("s25fs256t", 0x342b19, 0x0f0890, 128 * 1024, 256, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, #ifdef CONFIG_SPI_FLASH_S28HX_T { INFO("s28hl512t", 0x345a1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, { INFO("s28hl01gt", 0x345a1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs256t", 0x345b19, 0, 256 * 1024, 128, SPI_NOR_OCTAL_DTR_READ) }, { INFO("s28hs512t", 0x345b1a, 0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ) }, { INFO("s28hs01gt", 0x345b1b, 0, 256 * 1024, 512, SPI_NOR_OCTAL_DTR_READ) }, - { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ) }, + { INFO("s28hs02gt", 0x345b1c, 0, 256 * 1024, 1024, SPI_NOR_OCTAL_DTR_READ | NO_CHIP_ERASE) }, #endif #endif #ifdef CONFIG_SPI_FLASH_SST /* SST */ @@ -430,11 +464,6 @@ const struct flash_info spi_nor_ids[] = { { INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECT_4K) }, { INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K) }, { INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { - INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) - }, { INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K) }, { INFO("w25q20cl", 0xef4012, 0, 64 * 1024, 4, SECT_4K) }, { INFO("w25q20bw", 0xef5012, 0, 64 * 1024, 4, SECT_4K) }, @@ -442,7 +471,8 @@ const struct flash_info spi_nor_ids[] = { { INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25q16dw", 0xef6015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, @@ -541,7 +571,11 @@ const struct flash_info spi_nor_ids[] = { }, { INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { + INFO("w25q16cl", 0xef4015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, { INFO("w25q32bv", 0xef4016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25q64cv", 0xef4017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index cf0d702421f..104537784ab 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -679,10 +679,8 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->bad_peb_limit = get_bad_peb_limit(ubi, max_beb_per1024); } - if (ubi->mtd->type == MTD_NORFLASH) { - ubi_assert(ubi->mtd->writesize == 1); + if (ubi->mtd->type == MTD_NORFLASH) ubi->nor_flash = 1; - } ubi->min_io_size = ubi->mtd->writesize; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 14be95b74bc..45699b4a477 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -563,7 +563,14 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) return -EROFS; } - if (ubi->nor_flash) { + /* + * If the flash is ECC-ed then we have to erase the ECC block before we + * can write to it. But the write is in preparation to an erase in the + * first place. This means we cannot zero out EC and VID before the + * erase and we just have to hope the flash starts erasing from the + * start of the page. + */ + if (ubi->nor_flash && ubi->mtd->writesize == 1) { err = nor_erase_prepare(ubi, pnum); if (err) return err; diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile index d4e24789d33..63770e12bd1 100644 --- a/drivers/mux/Makefile +++ b/drivers/mux/Makefile @@ -4,4 +4,4 @@ # Jean-Jacques Hiblot <jjhiblot@ti.com> obj-$(CONFIG_MULTIPLEXER) += mux-uclass.o -obj-$(CONFIG_$(SPL_)MUX_MMIO) += mmio.o +obj-$(CONFIG_$(XPL_)MUX_MMIO) += mmio.o diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e7d0ddfe25a..576cd2d50ad 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -48,6 +48,7 @@ config DM_DSA bool "Enable Driver Model for DSA switches" depends on DM_MDIO depends on PHY_FIXED + depends on !NET_LWIP help Enable driver model for DSA switches @@ -96,7 +97,7 @@ config DSA_SANDBOX menuconfig NETDEVICES bool "Network device support" - depends on NET + depends on NET || NET_LWIP select DM_ETH help You must select Y to enable any network device support @@ -342,6 +343,7 @@ config ESSEDMA config ETH_SANDBOX depends on SANDBOX + depends on NET default y bool "Sandbox: Mocked Ethernet driver" help @@ -350,8 +352,20 @@ config ETH_SANDBOX This driver is particularly useful in the test/dm/eth.c tests +config ETH_SANDBOX_LWIP + depends on SANDBOX + depends on NET_LWIP + default y + bool "Sandbox: Mocked Ethernet driver (for NET_LWIP)" + help + This driver is meant as a replacement for ETH_SANDBOX when + the network stack is NET_LWIP rather than NET. It currently + does nothing, i.e. it drops the sent packets and never receives + data. + config ETH_SANDBOX_RAW depends on SANDBOX + depends on NET default y bool "Sandbox: Bridge to Linux Raw Sockets" help @@ -511,11 +525,11 @@ config KS8851_MLL The Microchip KS8851 parallel bus external ethernet interface chip. config KSZ9477 - bool "Microchip KSZ9477 I2C controller driver" - depends on DM_DSA && DM_I2C + bool "Microchip KSZ9477 controller driver" + depends on DM_DSA && (DM_I2C || DM_SPI) help This driver implements a DSA switch driver for the KSZ9477 family - of GbE switches using the I2C interface. + of GbE switches using the I2C or SPI interface. config LITEETH bool "LiteX LiteEth Ethernet MAC" @@ -748,6 +762,38 @@ config TULIP help This driver supports DEC DC2114x Fast ethernet chips. +config TULIP_SUPPORT_NON_PCI + bool "No PCI controller" + depends on TULIP + default n + help + Say Y to this and you can run this driver on platforms that do not + have PCI controllers. + +config TULIP_IGNORE_TX_NO_CARRIER + bool "Ignore tx no carrier error" + depends on TULIP + default n + help + Some IP cores of dc2114x or its variants do not comply so well with + the behaviors described by the official document. A packet could be + sent successfully but reported with No Carrier error. Latest drivers + of this IP core do not detect this error anymore. Say Y to this could + disable handling of this error. + +config TULIP_MULTIPLE_TX_DESC + bool "Use multiple tx descriptors" + depends on TULIP + default n + help + Some IP cores of dc2114x or its variants do not comply so well with + the behaviors described by the official document. Originally this + driver uses only one tx descriptor and organizes it as a ring buffer, + which would lead to a problem that one packet would be sent twice. + Say Y to this could prevent this bug if you are using IP cores with + this issue, by using multiple tx descriptors and organizing them as + a real well-defined ring buffer. + config XILINX_AXIEMAC select PHYLIB select MII @@ -891,7 +937,7 @@ config FEC2_PHY_NORXERR config SYS_DPAA_QBMAN bool "Device tree fixup for QBMan on freescale SOCs" - depends on (ARM || PPC) && !SPL_BUILD + depends on ARM || PPC default y if ARCH_B4860 || \ ARCH_B4420 || \ ARCH_P1023 || \ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4946a63f80f..f5ab1f5dedf 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o obj-$(CONFIG_ETH_SANDBOX) += sandbox.o obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o +obj-$(CONFIG_ETH_SANDBOX_LWIP) += sandbox-lwip.o obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FMAN_ENET) += fm/ obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index ce028f451f1..7c0665faa8e 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include <asm/io.h> +#include <cpu_func.h> #include <dm.h> #include <malloc.h> #include <net.h> @@ -72,10 +73,20 @@ #define POLL_DEMAND 1 +#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) +#define phys_to_bus(dev, a) virt_to_phys((volatile const void *)(a)) +#else #define phys_to_bus(dev, a) dm_pci_phys_to_mem((dev), (a)) +#endif + +/* Number of TX descriptors */ +#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC) +#define NUM_TX_DESC 4 +#else +#define NUM_TX_DESC 1 +#endif #define NUM_RX_DESC PKTBUFSRX -#define NUM_TX_DESC 1 /* Number of TX descriptors */ #define RX_BUFF_SZ PKTSIZE_ALIGN #define TOUT_LOOP 1000000 @@ -89,9 +100,17 @@ struct de4x5_desc { u32 next; }; +/* Assigned for network card's ring buffer: + * Some CPU might treat these memories as cached, and changes to these memories + * won't immediately be visible to each other. It is necessary to ensure that + * these memories between the CPU and the network card are marked as uncached. + */ +static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32); +static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32); + struct dc2114x_priv { - struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32); - struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32); + struct de4x5_desc *rx_ring; /* Must be uncached to CPU */ + struct de4x5_desc *tx_ring; /* Must be uncached to CPU */ int rx_new; /* RX descriptor ring pointer */ int tx_new; /* TX descriptor ring pointer */ char rx_ring_size; @@ -271,7 +290,12 @@ static int read_srom(struct dc2114x_priv *priv, u_long ioaddr, int index) static void send_setup_frame(struct dc2114x_priv *priv) { - char setup_frame[SETUP_FRAME_LEN]; + /* We are writing setup frame and these changes should be visible to the + * network card immediately. So let's directly read/write through the + * uncached window. + */ + char __setup_frame[SETUP_FRAME_LEN] __aligned(32); + char *setup_frame = (char *)map_physmem((phys_addr_t)virt_to_phys(__setup_frame), 0, MAP_NOCACHE); char *pa = &setup_frame[0]; int i; @@ -292,8 +316,13 @@ static void send_setup_frame(struct dc2114x_priv *priv) } priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno, - (u32)&setup_frame[0])); + (phys_addr_t)&setup_frame[0])); +#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC) + priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_SET | SETUP_FRAME_LEN); + priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER); +#else priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN); +#endif priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN); dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD); @@ -307,7 +336,7 @@ static void send_setup_frame(struct dc2114x_priv *priv) } if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) != 0x7FFFFFFF) { - printf("TX error status2 = 0x%08X\n", + debug("TX error status2 = 0x%08X\n", le32_to_cpu(priv->tx_ring[priv->tx_new].status)); } @@ -332,9 +361,17 @@ static int dc21x4x_send_common(struct dc2114x_priv *priv, void *packet, int leng goto done; } + /* Packet should be visible to the network card */ + flush_dcache_range((phys_addr_t)packet, (phys_addr_t)(packet + RX_BUFF_SZ)); + priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno, - (u32)packet)); + (phys_addr_t)packet)); +#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC) + priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_LS | TD_FS | length); + priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER); +#else priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length); +#endif priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN); dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD); @@ -349,7 +386,9 @@ static int dc21x4x_send_common(struct dc2114x_priv *priv, void *packet, int leng if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) & TD_ES) { priv->tx_ring[priv->tx_new].status = 0x0; +#if !CONFIG_IS_ENABLED(TULIP_IGNORE_TX_NO_CARRIER) goto done; +#endif } status = length; @@ -398,13 +437,22 @@ static int dc21x4x_init_common(struct dc2114x_priv *priv) return -1; } - dc2114x_outl(priv, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); + /* 2024-07: + * Remove the OMR_PM flag and choose 16 perfect filtering mode since in + * modern networks there're plenty of multicasts and set ORM_PM flag will + * increase the dc2114x's workload and ask the U-Boot to handle packets + * not related to itself. And most of the time, U-Boot does not need this + * feature. + * + * A better way: let user to decide whether to have this flag. + */ + dc2114x_outl(priv, OMR_SDP | OMR_PS, DE4X5_OMR); for (i = 0; i < NUM_RX_DESC; i++) { priv->rx_ring[i].status = cpu_to_le32(R_OWN); priv->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); priv->rx_ring[i].buf = cpu_to_le32(phys_to_bus(priv->devno, - (u32)net_rx_packets[i])); + (phys_addr_t)net_rx_packets[i])); priv->rx_ring[i].next = 0; } @@ -423,9 +471,9 @@ static int dc21x4x_init_common(struct dc2114x_priv *priv) priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER); /* Tell the adapter where the TX/RX rings are located. */ - dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->rx_ring), + dc2114x_outl(priv, phys_to_bus(priv->devno, (phys_addr_t)priv->rx_ring), DE4X5_RRBA); - dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->tx_ring), + dc2114x_outl(priv, phys_to_bus(priv->devno, (phys_addr_t)priv->tx_ring), DE4X5_TRBA); start_de4x5(priv); @@ -461,21 +509,32 @@ static void read_hw_addr(struct dc2114x_priv *priv) } } +#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) static struct pci_device_id supported[] = { { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST) }, { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142) }, { } }; +#endif static int dc2114x_start(struct udevice *dev) { - struct eth_pdata *plat = dev_get_plat(dev); struct dc2114x_priv *priv = dev_get_priv(dev); + int rval; - memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr)); + if (!priv->enetaddr) { + rval = eth_env_get_enetaddr("ethaddr", priv->enetaddr); + if (!rval) { + printf("dc2114x: Err: please set a valid MAC address\n"); + return -EINVAL; + } + } + +#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) /* Ensure we're not sleeping. */ dm_pci_write_config8(dev, PCI_CFDA_PSM, WAKEUP); +#endif return dc21x4x_init_common(priv); } @@ -485,8 +544,9 @@ static void dc2114x_stop(struct udevice *dev) struct dc2114x_priv *priv = dev_get_priv(dev); dc21x4x_halt_common(priv); - +#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) dm_pci_write_config8(dev, PCI_CFDA_PSM, SLEEP); +#endif } static int dc2114x_send(struct udevice *dev, void *packet, int length) @@ -515,7 +575,8 @@ static int dc2114x_recv(struct udevice *dev, int flags, uchar **packetp) if (!ret) return 0; - *packetp = net_rx_packets[priv->rx_new]; + invalidate_dcache_range((phys_addr_t)net_rx_packets[priv->rx_new], (phys_addr_t)(net_rx_packets[priv->rx_new] + RX_BUFF_SZ)); + *packetp = (uchar *)net_rx_packets[priv->rx_new]; return ret - 4; } @@ -543,7 +604,7 @@ static int dc2114x_read_rom_hwaddr(struct udevice *dev) static int dc2114x_bind(struct udevice *dev) { - static int card_number; + static int card_number = 0; char name[16]; sprintf(name, "dc2114x#%u", card_number++); @@ -555,6 +616,8 @@ static int dc2114x_probe(struct udevice *dev) { struct eth_pdata *plat = dev_get_plat(dev); struct dc2114x_priv *priv = dev_get_priv(dev); + +#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) u16 command, status; u32 iobase; @@ -562,9 +625,6 @@ static int dc2114x_probe(struct udevice *dev) iobase &= ~0xf; debug("dc2114x: DEC 2114x PCI Device @0x%x\n", iobase); - - priv->devno = dev; - priv->enetaddr = plat->enetaddr; priv->iobase = (void __iomem *)dm_pci_mem_to_phys(dev, iobase); command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; @@ -576,10 +636,29 @@ static int dc2114x_probe(struct udevice *dev) } dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x60); +#endif + + priv->devno = dev; + priv->enetaddr = plat->enetaddr; + priv->rx_ring = (struct de4x5_desc *)map_physmem((phys_addr_t)virt_to_phys(rx_ring), 0, MAP_NOCACHE); + priv->tx_ring = (struct de4x5_desc *)map_physmem((phys_addr_t)virt_to_phys(tx_ring), 0, MAP_NOCACHE); return 0; } +#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) +static int dc2114x_of_to_plat(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_plat(dev); + struct dc2114x_priv *priv = dev_get_priv(dev); + + plat->iobase = (phys_addr_t)map_physmem((phys_addr_t)devfdt_get_addr(dev), 0, MAP_NOCACHE); + priv->iobase = (void *)plat->iobase; + + return 0; +} +#endif + static const struct eth_ops dc2114x_ops = { .start = dc2114x_start, .send = dc2114x_send, @@ -589,9 +668,23 @@ static const struct eth_ops dc2114x_ops = { .read_rom_hwaddr = dc2114x_read_rom_hwaddr, }; +#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) +static const struct udevice_id dc2114x_eth_ids[] = { + { .compatible = "dec,dmfe" }, + { .compatible = "tulip,dmfe" }, + { .compatible = "dec,dc2114x" }, + { .compatible = "tulip,dc2114x" }, + { } +}; +#endif + U_BOOT_DRIVER(eth_dc2114x) = { .name = "eth_dc2114x", .id = UCLASS_ETH, +#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) + .of_match = dc2114x_eth_ids, + .of_to_plat = dc2114x_of_to_plat, +#endif .bind = dc2114x_bind, .probe = dc2114x_probe, .ops = &dc2114x_ops, @@ -599,4 +692,6 @@ U_BOOT_DRIVER(eth_dc2114x) = { .plat_auto = sizeof(struct eth_pdata), }; +#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI) U_BOOT_PCI_DEVICE(eth_dc2114x, supported); +#endif diff --git a/drivers/net/dwc_eth_xgmac_socfpga.c b/drivers/net/dwc_eth_xgmac_socfpga.c index 270c1b0ca6c..87fb7e887e7 100644 --- a/drivers/net/dwc_eth_xgmac_socfpga.c +++ b/drivers/net/dwc_eth_xgmac_socfpga.c @@ -37,7 +37,7 @@ static int dwxgmac_socfpga_do_setphy(struct udevice *dev, u32 modereg) u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << xgmac->syscon_phy_regshift; - if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) { + if (!(IS_ENABLED(CONFIG_XPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) { u32 index = ((u64)xgmac->syscon_phy - socfpga_get_sysmgr_addr() - SYSMGR_SOC64_EMAC0) >> 2; diff --git a/drivers/net/dwmac_socfpga.c b/drivers/net/dwmac_socfpga.c index bba3fc4d34b..a9e2d8c0972 100644 --- a/drivers/net/dwmac_socfpga.c +++ b/drivers/net/dwmac_socfpga.c @@ -68,7 +68,7 @@ static int dwmac_socfpga_do_setphy(struct udevice *dev, u32 modereg) struct dwmac_socfpga_plat *pdata = dev_get_plat(dev); u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift; -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF) +#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF) u32 index = ((u64)pdata->phy_intf - socfpga_get_sysmgr_addr() - SYSMGR_SOC64_EMAC0) >> 2; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index d18a8d577ca..f64dbb7d6a1 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -678,7 +678,7 @@ static int eepro100_recv_common(struct eepro100_priv *priv, uchar **packetp) status = le16_to_cpu(desc->status); if (!(status & RFD_STATUS_C)) - return 0; + return -EAGAIN; /* Valid frame status. */ if (status & RFD_STATUS_OK) { diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c index 43baa699619..7ebbe197660 100644 --- a/drivers/net/ksz9477.c +++ b/drivers/net/ksz9477.c @@ -11,7 +11,12 @@ #include <eth_phy.h> #include <linux/delay.h> #include <miiphy.h> -#include <i2c.h> +#if CONFIG_IS_ENABLED(DM_I2C) +# include <i2c.h> +#endif +#if CONFIG_IS_ENABLED(DM_SPI) +# include <spi.h> +#endif #include <net/dsa.h> #include <asm-generic/gpio.h> @@ -71,15 +76,157 @@ #define MMD_SETUP(mode, dev) (((u16)(mode) << PORT_MMD_OP_MODE_S) | (dev)) #define REG_PORT_PHY_MMD_INDEX_DATA 0x011C +/* SPI specific define (opcodes) */ +#define KSZ_SPI_OP_RD 3 +#define KSZ_SPI_OP_WR 2 + +#define KSZ9477_SPI_ADDR_SHIFT 24 +#define KSZ9477_SPI_ADDR_ALIGN 3 +#define KSZ9477_SPI_TURNAROUND_SHIFT 5 + +/** + * struct ksz_phy_ops - low-level KSZ bus operations + */ +struct ksz_phy_ops { + /* read() - Read bytes from the device + * + * @udev: bus device + * @reg: register offset + * @val: data read + * @len: Number of bytes to read + * + * @return: 0 on success, negative on failure + */ + int (*read)(struct udevice *udev, u32 reg, u8 *val, int len); + + /* write() - Write bytes to the device + * + * @udev: bus device + * @reg: register offset + * @val: data to write + * @len: Number of bytes to write + * + * @return: 0 on success, negative on failure + */ + int (*write)(struct udevice *udev, u32 reg, u8 *val, int len); +}; + struct ksz_dsa_priv { struct udevice *dev; + struct ksz_phy_ops *phy_ops; u32 features; /* chip specific features */ }; +#if CONFIG_IS_ENABLED(DM_I2C) +static inline int ksz_i2c_read(struct udevice *dev, u32 reg, u8 *val, int len) +{ + return dm_i2c_read(dev, reg, val, len); +} + +static inline int ksz_i2c_write(struct udevice *dev, u32 reg, u8 *val, int len) +{ + return dm_i2c_write(dev, reg, val, len); +} + +static struct ksz_phy_ops phy_i2c_ops = { + .read = ksz_i2c_read, + .write = ksz_i2c_write, +}; +#endif + +#if CONFIG_IS_ENABLED(DM_SPI) +/** + * ksz_spi_xfer() - only used for 8/16/32 bits bus access + * + * @dev: The SPI slave device which will be sending/receiving the data. + * @reg: register address. + * @out: Pointer to a string of bits to send out. The bits are + * held in a byte array and are sent MSB first. + * @in: Pointer to a string of bits that will be filled in. + * @len: number of bytes to read. + * + * Return: 0 on success, not 0 on failure + */ +static int ksz_spi_xfer(struct udevice *dev, u32 reg, const u8 *out, + u8 *in, u16 len) +{ + int ret; + u32 addr = 0; + u8 opcode; + + if (in && out) { + printf("%s: can't do full duplex\n", __func__); + return -EINVAL; + } + + if (len > 4 || len == 0) { + printf("%s: only 8/16/32 bits bus access supported\n", + __func__); + return -EINVAL; + } + + ret = dm_spi_claim_bus(dev); + if (ret < 0) { + printf("%s: could not claim bus\n", __func__); + return ret; + } + + opcode = (in ? KSZ_SPI_OP_RD : KSZ_SPI_OP_WR); + + /* The actual device address space is 16 bits (A15 - A0), + * so the values of address bits A23 - A16 in the SPI + * command/address phase are “don't care”. + */ + addr |= opcode << (KSZ9477_SPI_ADDR_SHIFT + KSZ9477_SPI_TURNAROUND_SHIFT); + addr |= reg << KSZ9477_SPI_TURNAROUND_SHIFT; + + addr = __swab32(addr); + + ret = dm_spi_xfer(dev, 32, &addr, NULL, SPI_XFER_BEGIN); + if (ret) { + printf("%s ERROR: dm_spi_xfer addr (%u)\n", __func__, ret); + goto release_bus; + } + + ret = dm_spi_xfer(dev, len * 8, out, in, SPI_XFER_END); + if (ret) { + printf("%s ERROR: dm_spi_xfer data (%u)\n", __func__, ret); + goto release_bus; + } + +release_bus: + /* If an error occurred, release the chip by deasserting the CS */ + if (ret < 0) + dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END); + + dm_spi_release_bus(dev); + + return ret; +} + +static inline int ksz_spi_read(struct udevice *dev, u32 reg, u8 *val, int len) +{ + return ksz_spi_xfer(dev, reg, NULL, val, len); +} + +static inline int ksz_spi_write(struct udevice *dev, u32 reg, u8 *val, int len) +{ + return ksz_spi_xfer(dev, reg, val, NULL, len); +} + +static struct ksz_phy_ops phy_spi_ops = { + .read = ksz_spi_read, + .write = ksz_spi_write, +}; +#endif + static inline int ksz_read8(struct udevice *dev, u32 reg, u8 *val) { - int ret = dm_i2c_read(dev, reg, val, 1); + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; + + int ret = phy_ops->read(dev, reg, val, 1); dev_dbg(dev, "%s 0x%04x<<0x%02x\n", __func__, reg, *val); @@ -93,8 +240,11 @@ static inline int ksz_pread8(struct udevice *dev, int port, int reg, u8 *val) static inline int ksz_write8(struct udevice *dev, u32 reg, u8 val) { + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; + dev_dbg(dev, "%s 0x%04x>>0x%02x\n", __func__, reg, val); - return dm_i2c_write(dev, reg, &val, 1); + return phy_ops->write(dev, reg, &val, 1); } static inline int ksz_pwrite8(struct udevice *dev, int port, int reg, u8 val) @@ -104,13 +254,15 @@ static inline int ksz_pwrite8(struct udevice *dev, int port, int reg, u8 val) static inline int ksz_write16(struct udevice *dev, u32 reg, u16 val) { + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; u8 buf[2]; buf[1] = val & 0xff; buf[0] = val >> 8; dev_dbg(dev, "%s 0x%04x>>0x%04x\n", __func__, reg, val); - return dm_i2c_write(dev, reg, buf, 2); + return phy_ops->write(dev, reg, buf, 2); } static inline int ksz_pwrite16(struct udevice *dev, int port, int reg, u16 val) @@ -120,10 +272,12 @@ static inline int ksz_pwrite16(struct udevice *dev, int port, int reg, u16 val) static inline int ksz_read16(struct udevice *dev, u32 reg, u16 *val) { + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; u8 buf[2]; int ret; - ret = dm_i2c_read(dev, reg, buf, 2); + ret = phy_ops->read(dev, reg, buf, 2); *val = (buf[0] << 8) | buf[1]; dev_dbg(dev, "%s 0x%04x<<0x%04x\n", __func__, reg, *val); @@ -137,7 +291,10 @@ static inline int ksz_pread16(struct udevice *dev, int port, int reg, u16 *val) static inline int ksz_read32(struct udevice *dev, u32 reg, u32 *val) { - return dm_i2c_read(dev, reg, (u8 *)val, 4); + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; + + return phy_ops->read(dev, reg, (u8 *)val, 4); } static inline int ksz_pread32(struct udevice *dev, int port, int reg, u32 *val) @@ -147,6 +304,8 @@ static inline int ksz_pread32(struct udevice *dev, int port, int reg, u32 *val) static inline int ksz_write32(struct udevice *dev, u32 reg, u32 val) { + struct ksz_dsa_priv *priv = dev_get_priv(dev); + struct ksz_phy_ops *phy_ops = priv->phy_ops; u8 buf[4]; buf[3] = val & 0xff; @@ -155,7 +314,7 @@ static inline int ksz_write32(struct udevice *dev, u32 reg, u32 val) buf[0] = (val >> 8) & 0xff; dev_dbg(dev, "%s 0x%04x>>0x%04x\n", __func__, reg, val); - return dm_i2c_write(dev, reg, buf, 4); + return phy_ops->write(dev, reg, buf, 4); } static inline int ksz_pwrite32(struct udevice *dev, int port, int reg, u32 val) @@ -276,7 +435,7 @@ static int ksz_mdio_probe(struct udevice *dev) struct ksz_mdio_priv *priv = dev_get_priv(dev); dev_dbg(dev, "%s\n", __func__); - priv->ksz = dev_get_parent_priv(dev->parent); + priv->ksz = dev_get_priv(dev->parent); return 0; } @@ -355,12 +514,12 @@ static int ksz_port_setup(struct udevice *dev, int port, phy_interface_t interface) { struct dsa_pdata *pdata = dev_get_uclass_plat(dev); + struct ksz_dsa_priv *priv = dev_get_priv(dev); u8 data8; dev_dbg(dev, "%s P%d %s\n", __func__, port + 1, (port == pdata->cpu_port) ? "cpu" : ""); - struct ksz_dsa_priv *priv = dev_get_priv(dev); if (port != pdata->cpu_port) { if (priv->features & NEW_XMII) /* phy port: config errata and leds */ @@ -503,23 +662,59 @@ static int ksz_probe_mdio(struct udevice *dev) return 0; } -/* - * I2C driver - */ -static int ksz_i2c_probe(struct udevice *dev) +static void ksz_ops_register(struct udevice *dev, struct ksz_phy_ops *ops) +{ + struct ksz_dsa_priv *priv = dev_get_priv(dev); + + priv->phy_ops = ops; +} + +static bool dsa_ksz_check_ops(struct ksz_phy_ops *phy_ops) +{ + if (!phy_ops || !phy_ops->read || !phy_ops->write) + return false; + + return true; +} + +static int ksz_probe(struct udevice *dev) { struct dsa_pdata *pdata = dev_get_uclass_plat(dev); struct ksz_dsa_priv *priv = dev_get_priv(dev); + enum uclass_id parent_id = UCLASS_INVALID; int i, ret; u8 data8; u32 id; - dev_set_parent_priv(dev, priv); + parent_id = device_get_uclass_id(dev_get_parent(dev)); + switch (parent_id) { +#if CONFIG_IS_ENABLED(DM_I2C) + case UCLASS_I2C: { + ksz_ops_register(dev, &phy_i2c_ops); - ret = i2c_set_chip_offset_len(dev, 2); - if (ret) { - printf("i2c_set_chip_offset_len failed: %d\n", ret); - return ret; + ret = i2c_set_chip_offset_len(dev, 2); + if (ret) { + printf("i2c_set_chip_offset_len failed: %d\n", ret); + return ret; + } + break; + } +#endif +#if CONFIG_IS_ENABLED(DM_SPI) + case UCLASS_SPI: { + ksz_ops_register(dev, &phy_spi_ops); + break; + } +#endif + default: + dev_err(dev, "invalid parent bus (%s)\n", + uclass_get_name(parent_id)); + return -EINVAL; + } + + if (!dsa_ksz_check_ops(priv->phy_ops)) { + printf("Driver bug. No bus ops defined\n"); + return -EINVAL; } /* default config */ @@ -543,6 +738,9 @@ static int ksz_i2c_probe(struct udevice *dev) case 0x00956700: puts("KSZ9567R: "); break; + case 0x00989600: + puts("KSZ9896C: "); + break; case 0x00989700: puts("KSZ9897S: "); break; @@ -573,19 +771,20 @@ static int ksz_i2c_probe(struct udevice *dev) return 0; }; -static const struct udevice_id ksz_i2c_ids[] = { +static const struct udevice_id ksz_ids[] = { { .compatible = "microchip,ksz9897" }, { .compatible = "microchip,ksz9477" }, { .compatible = "microchip,ksz9567" }, { .compatible = "microchip,ksz9893" }, + { .compatible = "microchip,ksz9896" }, { } }; U_BOOT_DRIVER(ksz) = { .name = "ksz-switch", .id = UCLASS_DSA, - .of_match = ksz_i2c_ids, - .probe = ksz_i2c_probe, + .of_match = ksz_ids, + .probe = ksz_probe, .ops = &ksz_dsa_ops, .priv_auto = sizeof(struct ksz_dsa_priv), }; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a9efc509814..13e73810ad6 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -11,7 +11,7 @@ config MV88E6352_SWITCH menuconfig PHYLIB bool "Ethernet PHY (physical media interface) support" - depends on NET + depends on NET || NET_LWIP help Enable Ethernet PHY (physical media interface) support. diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index a96430cec43..4d67203ee70 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -12,6 +12,7 @@ #define PHY_ID_YT8511 0x0000010a #define PHY_ID_YT8531 0x4f51e91b +#define PHY_ID_YT8821 0x4f51ea19 #define PHY_ID_MASK GENMASK(31, 0) /* Extended Register's Address Offset Register */ @@ -102,8 +103,12 @@ #define YTPHY_SPECIFIC_STATUS_REG 0x11 #define YTPHY_DUPLEX_MASK BIT(13) #define YTPHY_DUPLEX_SHIFT 13 -#define YTPHY_SPEED_MODE_MASK GENMASK(15, 14) -#define YTPHY_SPEED_MODE_SHIFT 14 +#define YTPHY_SPEED_MASK ((0x3 << 14) | BIT(9)) +#define YTPHY_SPEED_10M ((0x0 << 14)) +#define YTPHY_SPEED_100M ((0x1 << 14)) +#define YTPHY_SPEED_1000M ((0x2 << 14)) +#define YTPHY_SPEED_10G ((0x3 << 14)) +#define YTPHY_SPEED_2500M ((0x0 << 14) | BIT(9)) #define YT8531_EXTREG_SLEEP_CONTROL1_REG 0x27 #define YT8531_ESC1R_SLEEP_SW BIT(15) @@ -131,6 +136,91 @@ #define TX_CLK_100_INVERTED BIT(4) #define TX_CLK_1000_INVERTED BIT(5) +#define YT8821_SDS_EXT_CSR_CTRL_REG 0x23 +#define YT8821_SDS_EXT_CSR_VCO_LDO_EN BIT(15) +#define YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN BIT(8) + +#define YT8821_UTP_EXT_PI_CTRL_REG 0x56 +#define YT8821_UTP_EXT_PI_RST_N_FIFO BIT(5) +#define YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE BIT(4) +#define YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE BIT(3) +#define YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE BIT(2) +#define YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE BIT(1) +#define YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE BIT(0) + +#define YT8821_UTP_EXT_VCT_CFG6_CTRL_REG 0x97 +#define YT8821_UTP_EXT_FECHO_AMP_TH_HUGE GENMASK(15, 8) + +#define YT8821_UTP_EXT_ECHO_CTRL_REG 0x336 +#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000 GENMASK(14, 8) + +#define YT8821_UTP_EXT_GAIN_CTRL_REG 0x340 +#define YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000 GENMASK(6, 0) + +#define YT8821_UTP_EXT_RPDN_CTRL_REG 0x34E +#define YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 BIT(15) +#define YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 BIT(7) +#define YT8821_UTP_EXT_RPDN_IPR_SHT_2500 GENMASK(6, 0) + +#define YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG 0x36A +#define YT8821_UTP_EXT_TH_20DB_2500 GENMASK(15, 0) + +#define YT8821_UTP_EXT_TRACE_CTRL_REG 0x372 +#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 GENMASK(14, 8) +#define YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500 GENMASK(6, 0) + +#define YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG 0x374 +#define YT8821_UTP_EXT_ALPHA_SHT_2500 GENMASK(14, 8) +#define YT8821_UTP_EXT_IPR_LNG_2500 GENMASK(6, 0) + +#define YT8821_UTP_EXT_PLL_CTRL_REG 0x450 +#define YT8821_UTP_EXT_PLL_SPARE_CFG GENMASK(7, 0) + +#define YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG 0x466 +#define YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG GENMASK(14, 8) +#define YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG GENMASK(6, 0) + +#define YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG 0x467 +#define YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG GENMASK(14, 8) +#define YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG GENMASK(6, 0) + +#define YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG 0x468 +#define YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG GENMASK(14, 8) +#define YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG GENMASK(6, 0) + +#define YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG 0x469 +#define YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG GENMASK(14, 8) +#define YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG GENMASK(6, 0) + +#define YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG 0x4B3 +#define YT8821_UTP_EXT_MU_COARSE_FR_F_FFE GENMASK(14, 12) +#define YT8821_UTP_EXT_MU_COARSE_FR_F_FBE GENMASK(10, 8) + +#define YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG 0x4B5 +#define YT8821_UTP_EXT_MU_FINE_FR_F_FFE GENMASK(14, 12) +#define YT8821_UTP_EXT_MU_FINE_FR_F_FBE GENMASK(10, 8) + +#define YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG 0x4D2 +#define YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER GENMASK(7, 4) +#define YT8821_UTP_EXT_VGA_LPF1_CAP_2500 GENMASK(3, 0) + +#define YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG 0x4D3 +#define YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER GENMASK(7, 4) +#define YT8821_UTP_EXT_VGA_LPF2_CAP_2500 GENMASK(3, 0) + +#define YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG 0x660 +#define YT8821_UTP_EXT_NFR_TX_ABILITY BIT(3) + +#define YT8821_CHIP_MODE_FORCE_BX2500 1 + +/* chip config register */ +#define YTPHY_CCR_MODE_SEL_MASK GENMASK(2, 0) + +#define YTPHY_REG_SPACE_SELECT_REG 0xA000 +#define YTPHY_RSSR_SPACE_MASK BIT(1) +#define YTPHY_RSSR_FIBER_SPACE (0x1 << 1) +#define YTPHY_RSSR_UTP_SPACE (0x0 << 1) + struct ytphy_plat_priv { u32 rx_delay_ps; u32 tx_delay_ps; @@ -295,15 +385,15 @@ static int yt8531_parse_status(struct phy_device *phydev) if (val < 0) return val; - speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT; + speed_mode = (val & YTPHY_SPEED_MASK); switch (speed_mode) { - case 2: + case YTPHY_SPEED_1000M: speed = SPEED_1000; break; - case 1: + case YTPHY_SPEED_100M: speed = SPEED_100; break; - default: + case YTPHY_SPEED_10M: speed = SPEED_10; break; } @@ -632,6 +722,398 @@ static int yt8531_probe(struct phy_device *phydev) return 0; } +static int ytphy_save_page(struct phy_device *phydev) +{ + int old_page; + + old_page = ytphy_read_ext(phydev, YTPHY_REG_SPACE_SELECT_REG); + if (old_page < 0) + return old_page; + + if ((old_page & YTPHY_RSSR_SPACE_MASK) == YTPHY_RSSR_FIBER_SPACE) + return YTPHY_RSSR_FIBER_SPACE; + + return YTPHY_RSSR_UTP_SPACE; +}; + +static int ytphy_restore_page(struct phy_device *phydev, int page, + int ret) +{ + int mask = YTPHY_RSSR_SPACE_MASK; + int set; + int r; + + if ((page & YTPHY_RSSR_SPACE_MASK) == YTPHY_RSSR_FIBER_SPACE) + set = YTPHY_RSSR_FIBER_SPACE; + else + set = YTPHY_RSSR_UTP_SPACE; + + r = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, mask, + set); + if (ret >= 0 && r < 0) + ret = r; + + return ret; +}; + +static int ytphy_write_ext(struct phy_device *phydev, u16 regnum, + u16 val) +{ + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, + YTPHY_PAGE_SELECT, regnum); + if (ret < 0) + return ret; + + return phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, val); +} + +static int yt8821_probe(struct phy_device *phydev) +{ + phydev->advertising = PHY_GBIT_FEATURES | + SUPPORTED_2500baseX_Full | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause; + phydev->supported = phydev->advertising; + + return 0; +} + +static int yt8821_serdes_init(struct phy_device *phydev) +{ + int old_page; + u16 mask; + u16 set; + int ret; + + old_page = ytphy_save_page(phydev); + if (old_page < 0) + return old_page; + + ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, + YTPHY_RSSR_SPACE_MASK, + YTPHY_RSSR_FIBER_SPACE); + if (ret < 0) + goto err_restore_page; + + ret = phy_modify(phydev, MDIO_DEVAD_NONE, MII_BMCR, + BMCR_ANENABLE, 0); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_SDS_EXT_CSR_VCO_LDO_EN | + YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN; + set = YT8821_SDS_EXT_CSR_VCO_LDO_EN; + ret = ytphy_modify_ext(phydev, YT8821_SDS_EXT_CSR_CTRL_REG, mask, + set); + +err_restore_page: + return ytphy_restore_page(phydev, old_page, ret); +} + +static int yt8821_utp_init(struct phy_device *phydev) +{ + int old_page; + u16 mask; + u16 save; + u16 set; + int ret; + + old_page = ytphy_save_page(phydev); + if (old_page < 0) + return old_page; + + ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, + YTPHY_RSSR_SPACE_MASK, + YTPHY_RSSR_UTP_SPACE); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 | + YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 | + YT8821_UTP_EXT_RPDN_IPR_SHT_2500; + set = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 | + YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500; + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_RPDN_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER | + YT8821_UTP_EXT_VGA_LPF1_CAP_2500; + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG, + mask, 0); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER | + YT8821_UTP_EXT_VGA_LPF2_CAP_2500; + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG, + mask, 0); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 | + YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500; + set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500, 0x5a) | + FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500, 0x3c); + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_TRACE_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_IPR_LNG_2500; + set = FIELD_PREP(YT8821_UTP_EXT_IPR_LNG_2500, 0x6c); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000; + set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000, 0x2a); + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_ECHO_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000; + set = FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000, 0x22); + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_GAIN_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_TH_20DB_2500; + set = FIELD_PREP(YT8821_UTP_EXT_TH_20DB_2500, 0x8000); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_MU_COARSE_FR_F_FFE | + YT8821_UTP_EXT_MU_COARSE_FR_F_FBE; + set = FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FFE, 0x7) | + FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FBE, 0x7); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_MU_FINE_FR_F_FFE | + YT8821_UTP_EXT_MU_FINE_FR_F_FBE; + set = FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FFE, 0x2) | + FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FBE, 0x2); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + /* save YT8821_UTP_EXT_PI_CTRL_REG's val for use later */ + ret = ytphy_read_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG); + if (ret < 0) + goto err_restore_page; + + save = ret; + + mask = YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE | + YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE | + YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE | + YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE | + YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE; + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG, + mask, 0); + if (ret < 0) + goto err_restore_page; + + /* restore YT8821_UTP_EXT_PI_CTRL_REG's val */ + ret = ytphy_write_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG, save); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_FECHO_AMP_TH_HUGE; + set = FIELD_PREP(YT8821_UTP_EXT_FECHO_AMP_TH_HUGE, 0x38); + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_VCT_CFG6_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_NFR_TX_ABILITY; + set = YT8821_UTP_EXT_NFR_TX_ABILITY; + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_PLL_SPARE_CFG; + set = FIELD_PREP(YT8821_UTP_EXT_PLL_SPARE_CFG, 0xe9); + ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PLL_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG | + YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG; + set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG, 0x64) | + FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG, 0x64); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG | + YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG; + set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG, 0x64) | + FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG, 0x64); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG | + YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG; + set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG, 0x64) | + FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG, 0x64); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG, + mask, set); + if (ret < 0) + goto err_restore_page; + + mask = YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG | + YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG; + set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG, 0x64) | + FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG, 0x64); + ret = ytphy_modify_ext(phydev, + YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG, + mask, set); + +err_restore_page: + return ytphy_restore_page(phydev, old_page, ret); +} + +static int yt8821_auto_sleep_config(struct phy_device *phydev, + bool enable) +{ + int old_page; + int ret; + + old_page = ytphy_save_page(phydev); + if (old_page < 0) + return old_page; + + ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, + YTPHY_RSSR_SPACE_MASK, + YTPHY_RSSR_UTP_SPACE); + if (ret < 0) + goto err_restore_page; + + ret = ytphy_modify_ext(phydev, + YT8531_EXTREG_SLEEP_CONTROL1_REG, + YT8531_ESC1R_SLEEP_SW, + enable ? 1 : 0); + +err_restore_page: + return ytphy_restore_page(phydev, old_page, ret); +} + +static int yt8821_soft_reset(struct phy_device *phydev) +{ + return ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG, + YT8531_CCR_SW_RST, 0); +} + +static int yt8821_config(struct phy_device *phydev) +{ + u8 mode = YT8821_CHIP_MODE_FORCE_BX2500; + int ret; + u16 set; + + set = FIELD_PREP(YTPHY_CCR_MODE_SEL_MASK, mode); + ret = ytphy_modify_ext(phydev, + YT8531_CHIP_CONFIG_REG, + YTPHY_CCR_MODE_SEL_MASK, + set); + if (ret < 0) + return ret; + + ret = yt8821_serdes_init(phydev); + if (ret < 0) + return ret; + + ret = yt8821_utp_init(phydev); + if (ret < 0) + return ret; + + ret = yt8821_auto_sleep_config(phydev, false); + if (ret < 0) + return ret; + + return yt8821_soft_reset(phydev); +} + +static void yt8821_parse_status(struct phy_device *phydev, int val) +{ + int speed_mode; + int speed; + + speed_mode = val & YTPHY_SPEED_MASK; + switch (speed_mode) { + case YTPHY_SPEED_2500M: + speed = SPEED_2500; + break; + case YTPHY_SPEED_1000M: + speed = SPEED_1000; + break; + case YTPHY_SPEED_100M: + speed = SPEED_100; + break; + case YTPHY_SPEED_10M: + speed = SPEED_10; + break; + } + + phydev->speed = speed; + phydev->duplex = FIELD_GET(YTPHY_DUPLEX_MASK, val); +} + +static int yt8821_startup(struct phy_device *phydev) +{ + u16 val; + int ret; + + ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, + YTPHY_RSSR_SPACE_MASK, + YTPHY_RSSR_UTP_SPACE); + if (ret) + return ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + ret = phy_read(phydev, MDIO_DEVAD_NONE, + YTPHY_SPECIFIC_STATUS_REG); + if (ret < 0) + return ret; + + val = ret; + + if (phydev->link) + yt8821_parse_status(phydev, val); + + return 0; +} + U_BOOT_PHY_DRIVER(motorcomm8511) = { .name = "YT8511 Gigabit Ethernet", .uid = PHY_ID_YT8511, @@ -652,3 +1134,14 @@ U_BOOT_PHY_DRIVER(motorcomm8531) = { .startup = &yt8531_startup, .shutdown = &genphy_shutdown, }; + +U_BOOT_PHY_DRIVER(motorcomm8821) = { + .name = "YT8821 2.5G Ethernet", + .uid = PHY_ID_YT8821, + .mask = PHY_ID_MASK, + .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS | MDIO_MMD_AN), + .probe = &yt8821_probe, + .config = &yt8821_config, + .startup = &yt8821_startup, + .shutdown = &genphy_shutdown, +}; diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 2e0afad089f..5f4b1e2d3a0 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -433,7 +433,7 @@ static int rtl8139_recv_common(struct rtl8139_priv *priv, unsigned char *rxdata, int length = 0; if (inb(priv->ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY) - return 0; + return -EAGAIN; priv->rxstatus = inw(priv->ioaddr + RTL_REG_INTRSTATUS); /* See below for the rest of the interrupt acknowledges. */ diff --git a/drivers/net/sandbox-lwip.c b/drivers/net/sandbox-lwip.c new file mode 100644 index 00000000000..3721033c310 --- /dev/null +++ b/drivers/net/sandbox-lwip.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015 National Instruments + * + * (C) Copyright 2015 + * Joe Hershberger <joe.hershberger@ni.com> + */ + +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <net.h> +#include <asm/eth.h> +#include <asm/global_data.h> +#include <asm/test.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int sb_lwip_eth_start(struct udevice *dev) +{ + debug("eth_sandbox_lwip: Start\n"); + + return 0; +} + +static int sb_lwip_eth_send(struct udevice *dev, void *packet, int length) +{ + debug("eth_sandbox_lwip: Send packet %d\n", length); + + return -ENOTSUPP; +} + +static int sb_lwip_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + return -EAGAIN; +} + +static int sb_lwip_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + return 0; +} + +static void sb_lwip_eth_stop(struct udevice *dev) +{ +} + +static int sb_lwip_eth_write_hwaddr(struct udevice *dev) +{ + return 0; +} + +static const struct eth_ops sb_eth_ops = { + .start = sb_lwip_eth_start, + .send = sb_lwip_eth_send, + .recv = sb_lwip_eth_recv, + .free_pkt = sb_lwip_eth_free_pkt, + .stop = sb_lwip_eth_stop, + .write_hwaddr = sb_lwip_eth_write_hwaddr, +}; + +static int sb_lwip_eth_remove(struct udevice *dev) +{ + return 0; +} + +static int sb_lwip_eth_of_to_plat(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id sb_eth_ids[] = { + { .compatible = "sandbox,eth" }, + { } +}; + +U_BOOT_DRIVER(eth_sandbox) = { + .name = "eth_lwip_sandbox", + .id = UCLASS_ETH, + .of_match = sb_eth_ids, + .of_to_plat = sb_lwip_eth_of_to_plat, + .remove = sb_lwip_eth_remove, + .ops = &sb_eth_ops, + .priv_auto = 0, + .plat_auto = sizeof(struct eth_pdata), +}; diff --git a/drivers/nvme/Makefile b/drivers/nvme/Makefile index fd3e68a91dc..8c32cfbfc0f 100644 --- a/drivers/nvme/Makefile +++ b/drivers/nvme/Makefile @@ -4,4 +4,4 @@ obj-y += nvme-uclass.o nvme.o nvme_show.o obj-$(CONFIG_NVME_APPLE) += nvme_apple.o -obj-$(CONFIG_$(SPL_)NVME_PCI) += nvme_pci.o +obj-$(CONFIG_$(XPL_)NVME_PCI) += nvme_pci.o diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 22a56f4ca38..876a5fa57ee 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -137,6 +137,12 @@ config PCI_GT64120 bool "GT64120 PCI support" depends on MIPS +config PCIE_CDNS_TI + bool "TI K3 PCIe support" + help + Say Y here to enable support for the Cadence PCIe Controller + on TI's K3 SoCs. + config PCI_PHYTIUM bool "Phytium PCIe support" help diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 5b2d2969802..bf361cd0fba 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o obj-$(CONFIG_PCIE_ECAM_SYNQUACER) += pcie_ecam_synquacer.o obj-$(CONFIG_PCIE_APPLE) += pcie_apple.o +obj-$(CONFIG_PCIE_CDNS_TI) += pcie_cdns_ti.o obj-$(CONFIG_PCI_FTPCI100) += pci_ftpci100.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o obj-$(CONFIG_PCI_MPC85XX) += pci_mpc85xx.o diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 6571e653049..59894d2430b 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -722,7 +722,7 @@ static bool pci_need_device_pre_reloc(struct udevice *bus, uint vendor, u32 vendev; int index; - if (spl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(PCI_PNP)) + if (xpl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(PCI_PNP)) return true; for (index = 0; @@ -798,7 +798,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, if (!(gd->flags & GD_FLG_RELOC) && !(drv->flags & DM_FLAG_PRE_RELOC) && (!CONFIG_IS_ENABLED(PCI_PNP) || - spl_phase() != PHASE_SPL)) + xpl_phase() != PHASE_SPL)) return log_msg_ret("pre", -EPERM); /* diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 78e5de937cd..2753df275ca 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -379,7 +379,7 @@ int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void)) } /* In U-Boot proper, collect the information added by SPL (see below) */ - if (IS_ENABLED(CONFIG_SPL_VIDEO) && spl_phase() > PHASE_SPL && + if (IS_ENABLED(CONFIG_SPL_VIDEO) && xpl_phase() > PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) { struct video_handoff *ho; @@ -425,7 +425,7 @@ int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void)) mode_info.vesa.bits_per_pixel); /* In SPL, store the information for use by U-Boot proper */ - if (spl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) { + if (xpl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) { struct video_handoff *ho; ho = bloblist_add(BLOBLISTT_U_BOOT_VIDEO, sizeof(*ho), 0); diff --git a/drivers/pci/pcie_cdns_ti.c b/drivers/pci/pcie_cdns_ti.c new file mode 100644 index 00000000000..41469a186a3 --- /dev/null +++ b/drivers/pci/pcie_cdns_ti.c @@ -0,0 +1,853 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com + * + * PCIe controller driver for TI's K3 SoCs with Cadence PCIe controller + * + * Ported from the Linux driver - drivers/pci/controller/cadence/pci-j721e.c + * + * Author: Siddharth Vadapalli <s-vadapalli@ti.com> + * + */ + +#include <asm/gpio.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <generic-phy.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/log2.h> +#include <power-domain.h> +#include <regmap.h> +#include <syscon.h> + +#define CDNS_PCIE_LM_BASE 0x00100000 +#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044) +#define CDNS_PCIE_LTSSM_CTRL_CAP (CDNS_PCIE_LM_BASE + 0x0054) +#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300) + +#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0) +#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0 +#define CDNS_PCIE_LM_ID_VENDOR(vid) \ + (((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK) +#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16) +#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16 +#define CDNS_PCIE_LM_ID_SUBSYS(sub) \ + (((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK) + +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \ + (((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK) + +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14) +#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \ + (((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK) + +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17) +#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18) +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19) +#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20) + +#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6 +#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7 + +#define LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) \ + (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS << (((bar) * 8) + 6)) +#define LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) \ + (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS << (((bar) * 8) + 6)) +#define LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) \ + (CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS << (((bar) * 8) + 6)) +#define LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) \ + (CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS << (((bar) * 8) + 6)) +#define LM_RC_BAR_CFG_APERTURE(bar, aperture) \ + (((aperture) - 2) << ((bar) * 8)) + +#define CDNS_PCIE_RP_BASE 0x00200000 +#define CDNS_PCIE_RP_CAP_OFFSET 0xc0 + +/* + * Address Translation Registers + */ +#define CDNS_PCIE_AT_BASE 0x00400000 + +/* Region r Outbound AXI to PCIe Address Translation Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \ + (CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \ + (((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20) +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \ + (((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK) + +/* Region r Outbound AXI to PCIe Address Translation Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \ + (CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020) + +/* Region r Outbound PCIe Descriptor Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \ + (CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2 +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6 +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa +#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb + +/* Bit 23 MUST be set in RC mode. */ +#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23) +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24) +#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \ + (((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK) + +/* Region r Outbound PCIe Descriptor Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \ + (CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0) +#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \ + ((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK) + +/* Region r AXI Region Base Address Register 0 */ +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \ + (CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020) +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK) + +/* Region r AXI Region Base Address Register 1 */ +#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \ + (CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020) + +/* Root Port BAR Inbound PCIe to AXI Address Translation Register */ +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \ + (CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \ + (((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK) +#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \ + (CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008) + +/* AXI link down register */ +#define CDNS_PCIE_AT_LINKDOWN (CDNS_PCIE_AT_BASE + 0x0824) + +#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK GENMASK(2, 1) +#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT 1 +#define CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay) \ + (((delay) << CDNS_PCIE_DETECT_QUIET_MIN_DELAY_SHIFT) & \ + CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK) + +#define CDNS_PCIE_RP_MAX_IB 0x3 + +#define LINK_TRAINING_ENABLE BIT(0) +#define LINK_WAIT_MAX_RETRIES 10 +#define LINK_WAIT_UDELAY_MAX 100000 +#define LINK_RETRAIN_MAX_RETRIES 1000 + +#define PCIE_USER_CMD_STATUS_REG_OFFSET 0x4 +#define PCIE_USER_LINK_STATUS_REG_OFFSET 0x14 +#define PCIE_USER_LINK_STATUS_MASK GENMASK(1, 0) + +#define CDNS_TI_PCIE_MODE_RC BIT(7) +#define PCIE_MODE_SEL_MASK BIT(7) +#define PCIE_GEN_SEL_MASK GENMASK(1, 0) +#define PCIE_LINK_WIDTH_MASK GENMASK(9, 8) + +enum cdns_ti_pcie_mode { + PCIE_MODE_RC, + PCIE_MODE_EP, +}; + +enum cdns_pcie_rp_bar { + RP_BAR_UNDEFINED = -1, + RP_BAR0, + RP_BAR1, + RP_NO_BAR +}; + +static u8 bar_aperture_mask[] = { + [RP_BAR0] = 0x1F, + [RP_BAR1] = 0xF, +}; + +enum link_status { + NO_RECEIVERS_DETECTED, + LINK_TRAINING_IN_PROGRESS, + LINK_UP_DL_IN_PROGRESS, + LINK_UP_DL_COMPLETED, +}; + +struct pcie_cdns_ti_data { + enum cdns_ti_pcie_mode mode; + unsigned int quirk_retrain_flag:1; + unsigned int quirk_detect_quiet_flag:1; + unsigned int max_lanes; +}; + +struct pcie_cdns_ti { + struct udevice *dev; + void __iomem *intd_cfg_base; + void __iomem *user_cfg_base; + void __iomem *reg_base; + void __iomem *cfg_base; + fdt_size_t cfg_size; + struct regmap *syscon_base; + struct pci_controller *host_bridge; + u32 device_id; + u32 max_link_speed; + u32 num_lanes; + u32 pcie_ctrl_offset; + u32 vendor_id; + u32 mode; + unsigned int quirk_retrain_flag:1; + unsigned int quirk_detect_quiet_flag:1; + bool avail_ib_bar[CDNS_PCIE_RP_MAX_IB]; + + /* IO, MEM & PREFETCH PCI regions */ + struct pci_region io; + struct pci_region mem; + struct pci_region prefetch; +}; + +/* Cadence PCIe Controller register access helpers */ +static inline void pcie_cdns_ti_writel(struct pcie_cdns_ti *pcie, u32 reg, u32 val) +{ + writel(val, pcie->reg_base + reg); +} + +static inline u32 pcie_cdns_ti_readl(struct pcie_cdns_ti *pcie, u32 reg) +{ + return readl(pcie->reg_base + reg); +} + +/* Root Port register access helpers */ +static inline void pcie_cdns_ti_rp_writeb(struct pcie_cdns_ti *pcie, + u32 reg, u8 val) +{ + void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg; + + writeb(val, addr); +} + +static inline void pcie_cdns_ti_rp_writew(struct pcie_cdns_ti *pcie, + u32 reg, u16 val) +{ + void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg; + + writew(val, addr); +} + +static inline u16 pcie_cdns_ti_rp_readw(struct pcie_cdns_ti *pcie, u32 reg) +{ + void __iomem *addr = pcie->reg_base + CDNS_PCIE_RP_BASE + reg; + + return readw(addr); +} + +/* User register access helpers */ +static inline u32 pcie_cdns_ti_user_readl(struct pcie_cdns_ti *pcie, u32 offset) +{ + return readl(pcie->user_cfg_base + offset); +} + +static inline void pcie_cdns_ti_user_writel(struct pcie_cdns_ti *pcie, u32 offset, + u32 val) +{ + writel(val, pcie->user_cfg_base + offset); +} + +void __iomem *pcie_cdns_ti_map_bus(struct pcie_cdns_ti *pcie, pci_dev_t bdf, + uint offset) +{ + int busnr, devnr, funcnr, devfn; + u32 addr0, desc0; + + busnr = PCI_BUS(bdf); + devnr = PCI_DEV(bdf); + funcnr = PCI_FUNC(bdf); + devfn = (devnr << 3) | funcnr; + + if (busnr == 0) { + if (devfn) + return NULL; + return pcie->reg_base + (offset & 0xfff); + } + + if (!(pcie_cdns_ti_readl(pcie, CDNS_PCIE_LM_BASE) & 0x1)) + return NULL; + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_LINKDOWN, 0x0); + + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) | + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) | + CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busnr); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0); + + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); + + if (busnr == 1) + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0; + else + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1; + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0); + + return pcie->cfg_base + (offset & 0xfff); +} + +static int pcie_cdns_ti_read_config(const struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct pcie_cdns_ti *pcie = dev_get_priv(bus); + void __iomem *addr; + ulong value; + + addr = pcie_cdns_ti_map_bus(pcie, bdf, offset & ~0x3); + if (!addr) { + debug("%s: bdf out of range\n", __func__); + *valuep = pci_get_ff(size); + return 0; + } + + value = readl(addr); + *valuep = pci_conv_32_to_size(value, offset, size); + + return 0; +} + +static int pcie_cdns_ti_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct pcie_cdns_ti *pcie = dev_get_priv(bus); + void __iomem *addr; + ulong prev; + + addr = pcie_cdns_ti_map_bus(pcie, bdf, offset & ~0x3); + if (!addr) { + debug("%s: bdf out of range\n", __func__); + return 0; + } + + prev = readl(addr); + value = pci_conv_size_to_32(prev, value, offset, size); + writel(value, addr); + + return 0; +} + +static int pcie_cdns_ti_ctrl_init(struct pcie_cdns_ti *pcie) +{ + struct regmap *syscon = pcie->syscon_base; + u32 val = 0; + + if (pcie->mode == PCIE_MODE_RC) + val = CDNS_TI_PCIE_MODE_RC; + + /* Set mode of operation */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_MODE_SEL_MASK, + val); + + /* Set link speed */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_GEN_SEL_MASK, + pcie->max_link_speed - 1); + + /* Set link width */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_LINK_WIDTH_MASK, + (pcie->num_lanes - 1) << 8); + return 0; +} + +static void pcie_cdns_ti_detect_quiet_quirk(struct pcie_cdns_ti *pcie) +{ + u32 delay = 0x3; + u32 ltssm_ctrl_cap; + + ltssm_ctrl_cap = pcie_cdns_ti_readl(pcie, CDNS_PCIE_LTSSM_CTRL_CAP); + ltssm_ctrl_cap = ((ltssm_ctrl_cap & + ~CDNS_PCIE_DETECT_QUIET_MIN_DELAY_MASK) | + CDNS_PCIE_DETECT_QUIET_MIN_DELAY(delay)); + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_LTSSM_CTRL_CAP, ltssm_ctrl_cap); + ltssm_ctrl_cap = pcie_cdns_ti_readl(pcie, CDNS_PCIE_LTSSM_CTRL_CAP); +} + +static void pcie_cdns_ti_start_user_link(struct pcie_cdns_ti *pcie) +{ + u32 reg; + + reg = pcie_cdns_ti_user_readl(pcie, PCIE_USER_CMD_STATUS_REG_OFFSET); + reg |= LINK_TRAINING_ENABLE; + pcie_cdns_ti_user_writel(pcie, PCIE_USER_CMD_STATUS_REG_OFFSET, reg); +} + +static bool pcie_cdns_ti_user_link_up(struct pcie_cdns_ti *pcie) +{ + u32 reg; + + reg = pcie_cdns_ti_user_readl(pcie, PCIE_USER_LINK_STATUS_REG_OFFSET); + reg &= PCIE_USER_LINK_STATUS_MASK; + if (reg == LINK_UP_DL_COMPLETED) + return true; + + return false; +} + +static int pcie_cdns_ti_host_wait_for_link(struct pcie_cdns_ti *pcie) +{ + int retries; + + for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { + if (pcie_cdns_ti_user_link_up(pcie)) { + dev_info(pcie->dev, "link up\n"); + return 0; + } + udelay(LINK_WAIT_UDELAY_MAX); + } + + dev_err(pcie->dev, "failed to bring up link\n"); + return -ETIMEDOUT; +} + +static int pcie_cdns_ti_host_training_complete(struct pcie_cdns_ti *pcie) +{ + u32 pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET; + int retries; + u16 lnk_stat; + + /* Wait for link training to complete */ + for (retries = 0; retries < LINK_RETRAIN_MAX_RETRIES; retries++) { + lnk_stat = pcie_cdns_ti_rp_readw(pcie, pcie_cap_off + + PCI_EXP_LNKSTA); + if (!(lnk_stat & PCI_EXP_LNKSTA_LT)) + break; + udelay(1000); + } + + if (!(lnk_stat & PCI_EXP_LNKSTA_LT)) + return 0; + + return -ETIMEDOUT; +} + +static int pcie_cdns_ti_retrain_link(struct pcie_cdns_ti *pcie) +{ + u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET; + u16 lnk_stat, lnk_ctl; + int ret = 0; + + lnk_cap_sls = pcie_cdns_ti_readl(pcie, (CDNS_PCIE_RP_BASE + + pcie_cap_off + + PCI_EXP_LNKCAP)); + if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB) + return ret; + + lnk_stat = pcie_cdns_ti_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA); + if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) { + lnk_ctl = pcie_cdns_ti_rp_readw(pcie, + pcie_cap_off + PCI_EXP_LNKCTL); + lnk_ctl |= PCI_EXP_LNKCTL_RL; + pcie_cdns_ti_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL, + lnk_ctl); + + ret = pcie_cdns_ti_host_training_complete(pcie); + if (ret) + return ret; + + ret = pcie_cdns_ti_host_wait_for_link(pcie); + } + return ret; +} + +static int pcie_cdns_ti_start_host_link(struct pcie_cdns_ti *pcie) +{ + int ret; + + ret = pcie_cdns_ti_host_wait_for_link(pcie); + if (!ret && pcie->quirk_retrain_flag) + ret = pcie_cdns_ti_retrain_link(pcie); + + return ret; +} + +static void pcie_cdns_ti_init_root_port(struct pcie_cdns_ti *pcie) +{ + u32 val, ctrl, id; + + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED; + val = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS | + CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE | + CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS; + pcie_cdns_ti_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, val); + + if (pcie->vendor_id != 0xffff) { + id = CDNS_PCIE_LM_ID_VENDOR(pcie->vendor_id) | + CDNS_PCIE_LM_ID_SUBSYS(pcie->vendor_id); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_LM_ID, id); + } + + if (pcie->device_id != 0xffff) + pcie_cdns_ti_rp_writew(pcie, PCI_DEVICE_ID, pcie->device_id); + + pcie_cdns_ti_rp_writeb(pcie, PCI_CLASS_REVISION, 0); + pcie_cdns_ti_rp_writeb(pcie, PCI_CLASS_PROG, 0); + pcie_cdns_ti_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI); +} + +void pcie_cdns_ti_set_outbound_region(struct pcie_cdns_ti *pcie, u8 busnr, + u8 fn, u32 r, bool is_io, u64 cpu_addr, + u64 pci_addr, u32 size) +{ + u64 sz = 1ULL << fls64(size - 1); + int nbits = ilog2(sz); + u32 addr0, addr1, desc0, desc1; + + if (nbits < 8) + nbits = 8; + + addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) | + (lower_32_bits(pci_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(pci_addr); + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1); + + if (is_io) + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO; + else + desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM; + desc1 = 0; + + desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID | + CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0); + desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr); + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1); + + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) | + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(cpu_addr); + + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1); +} + +static int pcie_cdns_ti_bar_ib_config(struct pcie_cdns_ti *pcie, + enum cdns_pcie_rp_bar bar, + u64 cpu_addr, u64 size, + unsigned long flags) +{ + u32 addr0, addr1, aperture, value; + + if (!pcie->avail_ib_bar[bar]) + return -EBUSY; + + pcie->avail_ib_bar[bar] = false; + + aperture = ilog2(size); + addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(aperture) | + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(cpu_addr); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar), addr0); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar), addr1); + + if (bar == RP_NO_BAR) + return 0; + + value = pcie_cdns_ti_readl(pcie, CDNS_PCIE_LM_RC_BAR_CFG); + value &= ~(LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar) | + LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar) | + LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar) | + LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar) | + LM_RC_BAR_CFG_APERTURE(bar, bar_aperture_mask[bar] + 2)); + if (size + cpu_addr >= SZ_4G) { + if (!(flags & IORESOURCE_PREFETCH)) + value |= LM_RC_BAR_CFG_CTRL_MEM_64BITS(bar); + value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_64BITS(bar); + } else { + if (!(flags & IORESOURCE_PREFETCH)) + value |= LM_RC_BAR_CFG_CTRL_MEM_32BITS(bar); + value |= LM_RC_BAR_CFG_CTRL_PREF_MEM_32BITS(bar); + } + + value |= LM_RC_BAR_CFG_APERTURE(bar, aperture); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value); + + return 0; +} + +static int pcie_cdns_ti_map_dma_ranges(struct pcie_cdns_ti *pcie) +{ + u32 no_bar_nbits = 32; + int ret; + + /* + * Assume that DMA-Ranges have not been specified. + * TODO: Add support for "dma-ranges". + */ + dev_read_u32(pcie->dev, "cdns,no-bar-match-nbits", + &no_bar_nbits); + ret = pcie_cdns_ti_bar_ib_config(pcie, RP_NO_BAR, 0x0, + (u64)1 << no_bar_nbits, 0); + if (ret) + dev_err(pcie->dev, "IB BAR: %d config failed\n", + RP_NO_BAR); + return ret; +} + +static int pcie_cdns_ti_init_address_translation(struct pcie_cdns_ti *pcie) +{ + struct pci_controller *hb = pcie->host_bridge; + u32 addr0, addr1, desc1, region = 1; + u64 cpu_addr = (u64)pcie->cfg_base; + int i, busnr = 0; + + /* + * Reserve region 0 for PCI configure space accesses: + * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by + * cdns_pci_map_bus(), other region registers are set here once for all. + */ + addr1 = 0; /* Should be programmed to zero. */ + desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(busnr); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1); + + addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) | + (lower_32_bits(cpu_addr) & GENMASK(31, 8)); + addr1 = upper_32_bits(cpu_addr); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0); + pcie_cdns_ti_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1); + + for (i = 0; i < hb->region_count; i++) { + if (hb->regions[i].flags == PCI_REGION_IO) { + pcie->io.phys_start = hb->regions[i].phys_start; /* IO base */ + pcie->io.bus_start = hb->regions[i].bus_start; /* IO_bus_addr */ + pcie->io.size = hb->regions[i].size; /* IO size */ + + pcie_cdns_ti_set_outbound_region(pcie, busnr, 0, region, + true, pcie->io.phys_start, + pcie->io.bus_start, + pcie->io.size); + } else { + pcie->mem.phys_start = hb->regions[i].phys_start; /* MEM base */ + pcie->mem.bus_start = hb->regions[i].bus_start; /* MEM_bus_addr */ + pcie->mem.size = hb->regions[i].size; /* MEM size */ + + pcie_cdns_ti_set_outbound_region(pcie, busnr, 0, region, + false, pcie->mem.phys_start, + pcie->mem.bus_start, + pcie->mem.size); + } + region++; + } + + return pcie_cdns_ti_map_dma_ranges(pcie); +} + +static int pcie_cdns_ti_host_init(struct pcie_cdns_ti *pcie) +{ + pcie_cdns_ti_init_root_port(pcie); + + return pcie_cdns_ti_init_address_translation(pcie); +} + +static int pcie_cdns_ti_setup_host(struct pcie_cdns_ti *pcie) +{ + enum cdns_pcie_rp_bar bar; + int ret; + + if (pcie->quirk_detect_quiet_flag) + pcie_cdns_ti_detect_quiet_quirk(pcie); + + pcie_cdns_ti_start_user_link(pcie); + + ret = pcie_cdns_ti_start_host_link(pcie); + if (ret) + return ret; + + for (bar = RP_BAR0; bar <= RP_NO_BAR; bar++) + pcie->avail_ib_bar[bar] = true; + + ret = pcie_cdns_ti_host_init(pcie); + if (ret) + return ret; + + return 0; +} + +static int pcie_cdns_ti_probe(struct udevice *dev) +{ + struct pcie_cdns_ti *pcie = dev_get_priv(dev); + struct udevice *pci_ctlr = pci_get_controller(dev); + struct pci_controller *host_bridge = dev_get_uclass_priv(pci_ctlr); + const struct pcie_cdns_ti_data *data; + struct power_domain pci_pwrdmn; + struct gpio_desc *gpiod; + struct phy serdes; + struct clk *clk; + int ret; + + pcie->dev = dev; + pcie->host_bridge = host_bridge; + + data = (struct pcie_cdns_ti_data *)dev_get_driver_data(dev); + if (!data) + return -EINVAL; + + pcie->mode = data->mode; + pcie->quirk_retrain_flag = data->quirk_retrain_flag; + pcie->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag; + + if (pcie->num_lanes > data->max_lanes) { + dev_warn(dev, "cannot support %d lanes, defaulting to %d\n", + pcie->num_lanes, data->max_lanes); + pcie->num_lanes = data->max_lanes; + } + + ret = power_domain_get_by_index(dev, &pci_pwrdmn, 0); + if (ret) { + dev_err(dev, "failed to get power domain\n"); + return ret; + } + + ret = power_domain_on(&pci_pwrdmn); + if (ret) { + dev_err(dev, "failed to power on\n"); + return ret; + } + + clk = devm_clk_get(dev, "fck"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "failed to get functional clock\n"); + return ret; + } + + ret = generic_phy_get_by_name(dev, "pcie-phy", &serdes); + if (ret) { + dev_err(dev, "unable to get serdes"); + return ret; + } + generic_phy_reset(&serdes); + generic_phy_init(&serdes); + generic_phy_power_on(&serdes); + + ret = pcie_cdns_ti_ctrl_init(pcie); + if (ret) + return ret; + + gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_IS_OUT); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get reset GPIO\n"); + return ret; + } + + if (gpiod) { + ret = dm_gpio_set_value(gpiod, 0); + udelay(200); + ret = dm_gpio_set_value(gpiod, 1); + if (ret) + return ret; + } + + ret = pcie_cdns_ti_setup_host(pcie); + if (ret) + return ret; + + return 0; +} + +static int pcie_cdns_ti_of_to_plat(struct udevice *dev) +{ + struct pcie_cdns_ti *pcie = dev_get_priv(dev); + struct regmap *syscon; + u32 offset; + int ret; + + pcie->intd_cfg_base = dev_remap_addr_name(dev, "intd_cfg"); + if (!pcie->intd_cfg_base) + return -EINVAL; + + pcie->user_cfg_base = dev_remap_addr_name(dev, "user_cfg"); + if (!pcie->user_cfg_base) + return -EINVAL; + + pcie->reg_base = dev_remap_addr_name(dev, "reg"); + if (!pcie->reg_base) + return -EINVAL; + + pcie->cfg_base = dev_remap_addr_name(dev, "cfg"); + if (!pcie->cfg_base) + return -EINVAL; + + pcie->vendor_id = 0xffff; + pcie->device_id = 0xffff; + dev_read_u32(dev, "vendor-id", &pcie->vendor_id); + dev_read_u32(dev, "device-id", &pcie->device_id); + + ret = dev_read_u32(dev, "num-lanes", &pcie->num_lanes); + if (ret) + return ret; + + ret = dev_read_u32(dev, "max-link-speed", &pcie->max_link_speed); + if (ret) + return ret; + + syscon = syscon_regmap_lookup_by_phandle(dev, "ti,syscon-pcie-ctrl"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + ret = dev_read_u32_index(dev, "ti,syscon-pcie-ctrl", 1, &offset); + if (ret) + return ret; + + pcie->syscon_base = syscon; + pcie->pcie_ctrl_offset = offset; + + return 0; +} + +static const struct dm_pci_ops pcie_cdns_ti_ops = { + .read_config = pcie_cdns_ti_read_config, + .write_config = pcie_cdns_ti_write_config, +}; + +static const struct pcie_cdns_ti_data j7200_pcie_rc_data = { + .mode = PCIE_MODE_RC, + .quirk_detect_quiet_flag = true, + .max_lanes = 2, +}; + +static const struct udevice_id pcie_cdns_ti_ids[] = { + { + .compatible = "ti,j7200-pcie-host", + .data = (ulong)&j7200_pcie_rc_data, + }, + {}, +}; + +U_BOOT_DRIVER(pcie_cdns_ti) = { + .name = "pcie_cdns_ti", + .id = UCLASS_PCI, + .of_match = pcie_cdns_ti_ids, + .ops = &pcie_cdns_ti_ops, + .of_to_plat = pcie_cdns_ti_of_to_plat, + .probe = pcie_cdns_ti_probe, + .priv_auto = sizeof(struct pcie_cdns_ti), +}; diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 7a2b764492b..c35f9294dd9 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -8,8 +8,8 @@ obj-y += marvell/ obj-y += rockchip/ obj-y += socionext/ -obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o -obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o +obj-$(CONFIG_$(XPL_)PHY) += phy-uclass.o +obj-$(CONFIG_$(XPL_)NOP_PHY) += nop-phy.o obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o obj-$(CONFIG_APPLE_ATCPHY) += phy-apple-atc.o @@ -19,7 +19,7 @@ obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o obj-$(CONFIG_BCM6368_USBH_PHY) += bcm6368-usbh-phy.o obj-$(CONFIG_BCM_SR_PCIE_PHY) += phy-bcm-sr-pcie.o obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o -obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o +obj-$(CONFIG_$(XPL_)PIPE3_PHY) += ti-pipe3-phy.o obj-$(CONFIG_AM654_PHY) += phy-ti-am654.o obj-$(CONFIG_STI_USB_PHY) += sti_usb_phy.o obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o diff --git a/drivers/phy/cadence/Makefile b/drivers/phy/cadence/Makefile index af63b32d9f5..e0da41cd7eb 100644 --- a/drivers/phy/cadence/Makefile +++ b/drivers/phy/cadence/Makefile @@ -1,2 +1,2 @@ -obj-$(CONFIG_$(SPL_)PHY_CADENCE_SIERRA) += phy-cadence-sierra.o -obj-$(CONFIG_$(SPL_)PHY_CADENCE_TORRENT) += phy-cadence-torrent.o +obj-$(CONFIG_$(XPL_)PHY_CADENCE_SIERRA) += phy-cadence-sierra.o +obj-$(CONFIG_$(XPL_)PHY_CADENCE_TORRENT) += phy-cadence-torrent.o diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 3aae1813352..5c77203d606 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -12,6 +12,12 @@ config PHY_QCOM_IPQ4019_USB help Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s. +config PHY_QCOM_QMP_UFS + tristate "Qualcomm QMP UFS PHY driver" + depends on PHY && ARCH_SNAPDRAGON + help + Enable this to support the UFS QMP PHY on various Qualcomm chipsets. + config PHY_QCOM_QUSB2 tristate "Qualcomm USB QUSB2 PHY driver" depends on PHY && ARCH_SNAPDRAGON diff --git a/drivers/phy/qcom/Makefile b/drivers/phy/qcom/Makefile index a5153061dfb..dc3ed492696 100644 --- a/drivers/phy/qcom/Makefile +++ b/drivers/phy/qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o +obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2) += phy-qcom-snps-femto-v2.o obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h new file mode 100644 index 00000000000..a0803a8783d --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v2.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V2_H_ +#define QCOM_PHY_QMP_PCS_UFS_V2_H_ + +#define QPHY_V2_PCS_UFS_PHY_START 0x000 +#define QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL 0x004 + +#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x034 +#define QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL 0x038 +#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x03c +#define QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL 0x040 + +#define QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP 0x0cc +#define QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL 0x13c +#define QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME 0x140 +#define QPHY_V2_PCS_UFS_RX_SIGDET_CTRL2 0x148 +#define QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND 0x154 + +#define QPHY_V2_PCS_UFS_READY_STATUS 0x168 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h new file mode 100644 index 00000000000..adea13c3a9e --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v3.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V3_H_ +#define QCOM_PHY_QMP_PCS_UFS_V3_H_ + +#define QPHY_V3_PCS_UFS_PHY_START 0x000 +#define QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x02c +#define QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x034 +#define QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL 0x134 +#define QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME 0x138 +#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1 0x13c +#define QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2 0x140 +#define QPHY_V3_PCS_UFS_READY_STATUS 0x160 +#define QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1 0x1bc +#define QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1 0x1c4 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h new file mode 100644 index 00000000000..a1c7d3d1715 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v4.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V4_H_ +#define QCOM_PHY_QMP_PCS_UFS_V4_H_ + +/* Only for QMP V4 PHY - UFS PCS registers */ +#define QPHY_V4_PCS_UFS_PHY_START 0x000 +#define QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V4_PCS_UFS_SW_RESET 0x008 +#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c +#define QPHY_V4_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010 +#define QPHY_V4_PCS_UFS_PLL_CNTL 0x02c +#define QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030 +#define QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038 +#define QPHY_V4_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060 +#define QPHY_V4_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 +#define QPHY_V4_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0b4 +#define QPHY_V4_PCS_UFS_DEBUG_BUS_CLKSEL 0x124 +#define QPHY_V4_PCS_UFS_LINECFG_DISABLE 0x148 +#define QPHY_V4_PCS_UFS_RX_MIN_HIBERN8_TIME 0x150 +#define QPHY_V4_PCS_UFS_RX_SIGDET_CTRL2 0x158 +#define QPHY_V4_PCS_UFS_TX_PWM_GEAR_BAND 0x160 +#define QPHY_V4_PCS_UFS_TX_HS_GEAR_BAND 0x168 +#define QPHY_V4_PCS_UFS_READY_STATUS 0x180 +#define QPHY_V4_PCS_UFS_TX_MID_TERM_CTRL1 0x1d8 +#define QPHY_V4_PCS_UFS_MULTI_LANE_CTRL1 0x1e0 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v5.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v5.h new file mode 100644 index 00000000000..07959964fcf --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v5.h @@ -0,0 +1,32 @@ +/* Only for QMP V5 PHY - UFS PCS registers */ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V5_H_ +#define QCOM_PHY_QMP_PCS_UFS_V5_H_ + +/* Only for QMP V5 PHY - UFS PCS registers */ +#define QPHY_V5_PCS_UFS_PHY_START 0x000 +#define QPHY_V5_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V5_PCS_UFS_SW_RESET 0x008 +#define QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c +#define QPHY_V5_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010 +#define QPHY_V5_PCS_UFS_PLL_CNTL 0x02c +#define QPHY_V5_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030 +#define QPHY_V5_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038 +#define QPHY_V5_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060 +#define QPHY_V5_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 +#define QPHY_V5_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0b4 +#define QPHY_V5_PCS_UFS_DEBUG_BUS_CLKSEL 0x124 +#define QPHY_V5_PCS_UFS_RX_MIN_HIBERN8_TIME 0x150 +#define QPHY_V5_PCS_UFS_RX_SIGDET_CTRL1 0x154 +#define QPHY_V5_PCS_UFS_RX_SIGDET_CTRL2 0x158 +#define QPHY_V5_PCS_UFS_TX_PWM_GEAR_BAND 0x160 +#define QPHY_V5_PCS_UFS_TX_HS_GEAR_BAND 0x168 +#define QPHY_V5_PCS_UFS_READY_STATUS 0x180 +#define QPHY_V5_PCS_UFS_TX_MID_TERM_CTRL1 0x1d8 +#define QPHY_V5_PCS_UFS_MULTI_LANE_CTRL1 0x1e0 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v6.h new file mode 100644 index 00000000000..f19f9892ed7 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-ufs-v6.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_PCS_UFS_V6_H_ +#define QCOM_PHY_QMP_PCS_UFS_V6_H_ + +/* Only for QMP V6 PHY - UFS PCS registers */ +#define QPHY_V6_PCS_UFS_PHY_START 0x000 +#define QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V6_PCS_UFS_SW_RESET 0x008 +#define QPHY_V6_PCS_UFS_TIMER_20US_CORECLK_STEPS_MSB 0x00c +#define QPHY_V6_PCS_UFS_TIMER_20US_CORECLK_STEPS_LSB 0x010 +#define QPHY_V6_PCS_UFS_PCS_CTRL1 0x020 +#define QPHY_V6_PCS_UFS_PLL_CNTL 0x02c +#define QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL 0x030 +#define QPHY_V6_PCS_UFS_TX_SMALL_AMP_DRV_LVL 0x038 +#define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060 +#define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 +#define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c +#define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158 +#define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c +#define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184 +#define QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2 0x18c +#define QPHY_V6_PCS_UFS_TX_PWM_GEAR_BAND 0x178 +#define QPHY_V6_PCS_UFS_TX_HS_GEAR_BAND 0x174 +#define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8 +#define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4 +#define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4 0x240 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5 0x244 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6 0x248 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7 0x24c + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-v2.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-v2.h new file mode 100644 index 00000000000..bf36399d005 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-v2.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_V2_H_ +#define QCOM_PHY_QMP_PCS_V2_H_ + +/* Only for QMP V2 PHY - PCS registers */ +#define QPHY_V2_PCS_SW_RESET 0x000 +#define QPHY_V2_PCS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V2_PCS_START_CONTROL 0x008 +#define QPHY_V2_PCS_TXDEEMPH_M6DB_V0 0x024 +#define QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0 0x028 +#define QPHY_V2_PCS_ENDPOINT_REFCLK_DRIVE 0x054 +#define QPHY_V2_PCS_RX_IDLE_DTCT_CNTRL 0x058 +#define QPHY_V2_PCS_POWER_STATE_CONFIG1 0x060 +#define QPHY_V2_PCS_POWER_STATE_CONFIG2 0x064 +#define QPHY_V2_PCS_POWER_STATE_CONFIG4 0x06c +#define QPHY_V2_PCS_LOCK_DETECT_CONFIG1 0x080 +#define QPHY_V2_PCS_LOCK_DETECT_CONFIG2 0x084 +#define QPHY_V2_PCS_LOCK_DETECT_CONFIG3 0x088 +#define QPHY_V2_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x0a0 +#define QPHY_V2_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x0a4 +#define QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME 0x0a8 +#define QPHY_V2_PCS_FLL_CNTRL1 0x0c0 +#define QPHY_V2_PCS_FLL_CNTRL2 0x0c4 +#define QPHY_V2_PCS_FLL_CNT_VAL_L 0x0c8 +#define QPHY_V2_PCS_FLL_CNT_VAL_H_TOL 0x0cc +#define QPHY_V2_PCS_FLL_MAN_CODE 0x0d0 +#define QPHY_V2_PCS_AUTONOMOUS_MODE_CTRL 0x0d4 +#define QPHY_V2_PCS_LFPS_RXTERM_IRQ_CLEAR 0x0d8 +#define QPHY_V2_PCS_LFPS_RXTERM_IRQ_STATUS 0x178 +#define QPHY_V2_PCS_USB_PCS_STATUS 0x17c /* USB */ +#define QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1a8 +#define QPHY_V2_PCS_OSC_DTCT_ACTIONS 0x1ac +#define QPHY_V2_PCS_RX_SIGDET_LVL 0x1d8 +#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1dc +#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1e0 + +#define QPHY_V2_PCS_PCI_PCS_STATUS 0x174 /* PCI */ + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-v3.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-v3.h new file mode 100644 index 00000000000..10dbbb00620 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-v3.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_V3_H_ +#define QCOM_PHY_QMP_PCS_V3_H_ + +/* Only for QMP V3 PHY - PCS registers */ +#define QPHY_V3_PCS_SW_RESET 0x000 +#define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004 +#define QPHY_V3_PCS_START_CONTROL 0x008 +#define QPHY_V3_PCS_TXMGN_V0 0x00c +#define QPHY_V3_PCS_TXMGN_V1 0x010 +#define QPHY_V3_PCS_TXMGN_V2 0x014 +#define QPHY_V3_PCS_TXMGN_V3 0x018 +#define QPHY_V3_PCS_TXMGN_V4 0x01c +#define QPHY_V3_PCS_TXMGN_LS 0x020 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024 +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1 0x030 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_V2 0x034 +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2 0x038 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_V3 0x03c +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3 0x040 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_V4 0x044 +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4 0x048 +#define QPHY_V3_PCS_TXDEEMPH_M6DB_LS 0x04c +#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS 0x050 +#define QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE 0x054 +#define QPHY_V3_PCS_RX_IDLE_DTCT_CNTRL 0x058 +#define QPHY_V3_PCS_RATE_SLEW_CNTRL 0x05c +#define QPHY_V3_PCS_POWER_STATE_CONFIG1 0x060 +#define QPHY_V3_PCS_POWER_STATE_CONFIG2 0x064 +#define QPHY_V3_PCS_POWER_STATE_CONFIG3 0x068 +#define QPHY_V3_PCS_POWER_STATE_CONFIG4 0x06c +#define QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L 0x070 +#define QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H 0x074 +#define QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L 0x078 +#define QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H 0x07c +#define QPHY_V3_PCS_LOCK_DETECT_CONFIG1 0x080 +#define QPHY_V3_PCS_LOCK_DETECT_CONFIG2 0x084 +#define QPHY_V3_PCS_LOCK_DETECT_CONFIG3 0x088 +#define QPHY_V3_PCS_TSYNC_RSYNC_TIME 0x08c +#define QPHY_V3_PCS_SIGDET_LOW_2_IDLE_TIME 0x090 +#define QPHY_V3_PCS_BEACON_2_IDLE_TIME_L 0x094 +#define QPHY_V3_PCS_BEACON_2_IDLE_TIME_H 0x098 +#define QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_SYSCLK 0x09c +#define QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x0a0 +#define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x0a4 +#define QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME 0x0a8 +#define QPHY_V3_PCS_LFPS_DET_HIGH_COUNT_VAL 0x0ac +#define QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK 0x0b0 +#define QPHY_V3_PCS_LFPS_TX_END_CNT_P2U3_START 0x0b4 +#define QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME 0x0b8 +#define QPHY_V3_PCS_RXEQTRAINING_RUN_TIME 0x0bc +#define QPHY_V3_PCS_TXONESZEROS_RUN_LENGTH 0x0c0 +#define QPHY_V3_PCS_FLL_CNTRL1 0x0c4 +#define QPHY_V3_PCS_FLL_CNTRL2 0x0c8 +#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc +#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0 +#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4 +#define QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL 0x0d8 +#define QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR 0x0dc +#define QPHY_V3_PCS_ARCVR_DTCT_EN_PERIOD 0x0e0 +#define QPHY_V3_PCS_ARCVR_DTCT_CM_DLY 0x0e4 +#define QPHY_V3_PCS_ALFPS_DEGLITCH_VAL 0x0e8 +#define QPHY_V3_PCS_INSIG_SW_CTRL1 0x0ec +#define QPHY_V3_PCS_INSIG_SW_CTRL2 0x0f0 +#define QPHY_V3_PCS_INSIG_SW_CTRL3 0x0f4 +#define QPHY_V3_PCS_INSIG_MX_CTRL1 0x0f8 +#define QPHY_V3_PCS_INSIG_MX_CTRL2 0x0fc +#define QPHY_V3_PCS_INSIG_MX_CTRL3 0x100 +#define QPHY_V3_PCS_OUTSIG_SW_CTRL1 0x104 +#define QPHY_V3_PCS_OUTSIG_MX_CTRL1 0x108 +#define QPHY_V3_PCS_CLK_DEBUG_BYPASS_CTRL 0x10c +#define QPHY_V3_PCS_TEST_CONTROL 0x110 +#define QPHY_V3_PCS_TEST_CONTROL2 0x114 +#define QPHY_V3_PCS_TEST_CONTROL3 0x118 +#define QPHY_V3_PCS_TEST_CONTROL4 0x11c +#define QPHY_V3_PCS_TEST_CONTROL5 0x120 +#define QPHY_V3_PCS_TEST_CONTROL6 0x124 +#define QPHY_V3_PCS_TEST_CONTROL7 0x128 +#define QPHY_V3_PCS_COM_RESET_CONTROL 0x12c +#define QPHY_V3_PCS_BIST_CTRL 0x130 +#define QPHY_V3_PCS_PRBS_POLY0 0x134 +#define QPHY_V3_PCS_PRBS_POLY1 0x138 +#define QPHY_V3_PCS_PRBS_SEED0 0x13c +#define QPHY_V3_PCS_PRBS_SEED1 0x140 +#define QPHY_V3_PCS_FIXED_PAT_CTRL 0x144 +#define QPHY_V3_PCS_FIXED_PAT0 0x148 +#define QPHY_V3_PCS_FIXED_PAT1 0x14c +#define QPHY_V3_PCS_FIXED_PAT2 0x150 +#define QPHY_V3_PCS_FIXED_PAT3 0x154 +#define QPHY_V3_PCS_COM_CLK_SWITCH_CTRL 0x158 +#define QPHY_V3_PCS_ELECIDLE_DLY_SEL 0x15c +#define QPHY_V3_PCS_SPARE1 0x160 +#define QPHY_V3_PCS_BIST_CHK_ERR_CNT_L_STATUS 0x164 +#define QPHY_V3_PCS_BIST_CHK_ERR_CNT_H_STATUS 0x168 +#define QPHY_V3_PCS_BIST_CHK_STATUS 0x16c +#define QPHY_V3_PCS_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x170 +#define QPHY_V3_PCS_PCS_STATUS 0x174 +#define QPHY_V3_PCS_PCS_STATUS2 0x178 +#define QPHY_V3_PCS_PCS_STATUS3 0x17c +#define QPHY_V3_PCS_COM_RESET_STATUS 0x180 +#define QPHY_V3_PCS_OSC_DTCT_STATUS 0x184 +#define QPHY_V3_PCS_REVISION_ID0 0x188 +#define QPHY_V3_PCS_REVISION_ID1 0x18c +#define QPHY_V3_PCS_REVISION_ID2 0x190 +#define QPHY_V3_PCS_REVISION_ID3 0x194 +#define QPHY_V3_PCS_DEBUG_BUS_0_STATUS 0x198 +#define QPHY_V3_PCS_DEBUG_BUS_1_STATUS 0x19c +#define QPHY_V3_PCS_DEBUG_BUS_2_STATUS 0x1a0 +#define QPHY_V3_PCS_DEBUG_BUS_3_STATUS 0x1a4 +#define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1a8 +#define QPHY_V3_PCS_OSC_DTCT_ACTIONS 0x1ac +#define QPHY_V3_PCS_SIGDET_CNTRL 0x1b0 +#define QPHY_V3_PCS_IDAC_CAL_CNTRL 0x1b4 +#define QPHY_V3_PCS_CMN_ACK_OUT_SEL 0x1b8 +#define QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME_SYSCLK 0x1bc +#define QPHY_V3_PCS_AUTONOMOUS_MODE_STATUS 0x1c0 +#define QPHY_V3_PCS_ENDPOINT_REFCLK_CNTRL 0x1c4 +#define QPHY_V3_PCS_EPCLK_PRE_PLL_LOCK_DLY_SYSCLK 0x1c8 +#define QPHY_V3_PCS_EPCLK_PRE_PLL_LOCK_DLY_AUXCLK 0x1cc +#define QPHY_V3_PCS_EPCLK_DLY_COUNT_VAL_L 0x1d0 +#define QPHY_V3_PCS_EPCLK_DLY_COUNT_VAL_H 0x1d4 +#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 +#define QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1dc +#define QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1e0 +#define QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL2 0x1e4 +#define QPHY_V3_PCS_RXTERMINATION_DLY_SEL 0x1e8 +#define QPHY_V3_PCS_LFPS_PER_TIMER_VAL 0x1ec +#define QPHY_V3_PCS_SIGDET_STARTUP_TIMER_VAL 0x1f0 +#define QPHY_V3_PCS_LOCK_DETECT_CONFIG4 0x1f4 +#define QPHY_V3_PCS_RX_SIGDET_DTCT_CNTRL 0x1f8 +#define QPHY_V3_PCS_PCS_STATUS4 0x1fc +#define QPHY_V3_PCS_PCS_STATUS4_CLEAR 0x200 +#define QPHY_V3_PCS_DEC_ERROR_COUNT_STATUS 0x204 +#define QPHY_V3_PCS_COMMA_POS_STATUS 0x208 +#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c +#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 +#define QPHY_V3_PCS_REFGEN_REQ_CONFIG3 0x214 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-v4.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-v4.h new file mode 100644 index 00000000000..a2c1eba2b69 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-v4.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_V4_H_ +#define QCOM_PHY_QMP_PCS_V4_H_ + +/* Only for QMP V4 PHY - USB/PCIe PCS registers */ +#define QPHY_V4_PCS_SW_RESET 0x000 +#define QPHY_V4_PCS_REVISION_ID0 0x004 +#define QPHY_V4_PCS_REVISION_ID1 0x008 +#define QPHY_V4_PCS_REVISION_ID2 0x00c +#define QPHY_V4_PCS_REVISION_ID3 0x010 +#define QPHY_V4_PCS_PCS_STATUS1 0x014 +#define QPHY_V4_PCS_PCS_STATUS2 0x018 +#define QPHY_V4_PCS_PCS_STATUS3 0x01c +#define QPHY_V4_PCS_PCS_STATUS4 0x020 +#define QPHY_V4_PCS_PCS_STATUS5 0x024 +#define QPHY_V4_PCS_PCS_STATUS6 0x028 +#define QPHY_V4_PCS_PCS_STATUS7 0x02c +#define QPHY_V4_PCS_DEBUG_BUS_0_STATUS 0x030 +#define QPHY_V4_PCS_DEBUG_BUS_1_STATUS 0x034 +#define QPHY_V4_PCS_DEBUG_BUS_2_STATUS 0x038 +#define QPHY_V4_PCS_DEBUG_BUS_3_STATUS 0x03c +#define QPHY_V4_PCS_POWER_DOWN_CONTROL 0x040 +#define QPHY_V4_PCS_START_CONTROL 0x044 +#define QPHY_V4_PCS_INSIG_SW_CTRL1 0x048 +#define QPHY_V4_PCS_INSIG_SW_CTRL2 0x04c +#define QPHY_V4_PCS_INSIG_SW_CTRL3 0x050 +#define QPHY_V4_PCS_INSIG_SW_CTRL4 0x054 +#define QPHY_V4_PCS_INSIG_SW_CTRL5 0x058 +#define QPHY_V4_PCS_INSIG_SW_CTRL6 0x05c +#define QPHY_V4_PCS_INSIG_SW_CTRL7 0x060 +#define QPHY_V4_PCS_INSIG_SW_CTRL8 0x064 +#define QPHY_V4_PCS_INSIG_MX_CTRL1 0x068 +#define QPHY_V4_PCS_INSIG_MX_CTRL2 0x06c +#define QPHY_V4_PCS_INSIG_MX_CTRL3 0x070 +#define QPHY_V4_PCS_INSIG_MX_CTRL4 0x074 +#define QPHY_V4_PCS_INSIG_MX_CTRL5 0x078 +#define QPHY_V4_PCS_INSIG_MX_CTRL7 0x07c +#define QPHY_V4_PCS_INSIG_MX_CTRL8 0x080 +#define QPHY_V4_PCS_OUTSIG_SW_CTRL1 0x084 +#define QPHY_V4_PCS_OUTSIG_MX_CTRL1 0x088 +#define QPHY_V4_PCS_CLAMP_ENABLE 0x08c +#define QPHY_V4_PCS_POWER_STATE_CONFIG1 0x090 +#define QPHY_V4_PCS_POWER_STATE_CONFIG2 0x094 +#define QPHY_V4_PCS_FLL_CNTRL1 0x098 +#define QPHY_V4_PCS_FLL_CNTRL2 0x09c +#define QPHY_V4_PCS_FLL_CNT_VAL_L 0x0a0 +#define QPHY_V4_PCS_FLL_CNT_VAL_H_TOL 0x0a4 +#define QPHY_V4_PCS_FLL_MAN_CODE 0x0a8 +#define QPHY_V4_PCS_TEST_CONTROL1 0x0ac +#define QPHY_V4_PCS_TEST_CONTROL2 0x0b0 +#define QPHY_V4_PCS_TEST_CONTROL3 0x0b4 +#define QPHY_V4_PCS_TEST_CONTROL4 0x0b8 +#define QPHY_V4_PCS_TEST_CONTROL5 0x0bc +#define QPHY_V4_PCS_TEST_CONTROL6 0x0c0 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG4 0x0d0 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG5 0x0d4 +#define QPHY_V4_PCS_LOCK_DETECT_CONFIG6 0x0d8 +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG2 0x0e0 +#define QPHY_V4_PCS_REFGEN_REQ_CONFIG3 0x0e4 +#define QPHY_V4_PCS_BIST_CTRL 0x0e8 +#define QPHY_V4_PCS_PRBS_POLY0 0x0ec +#define QPHY_V4_PCS_PRBS_POLY1 0x0f0 +#define QPHY_V4_PCS_FIXED_PAT0 0x0f4 +#define QPHY_V4_PCS_FIXED_PAT1 0x0f8 +#define QPHY_V4_PCS_FIXED_PAT2 0x0fc +#define QPHY_V4_PCS_FIXED_PAT3 0x100 +#define QPHY_V4_PCS_FIXED_PAT4 0x104 +#define QPHY_V4_PCS_FIXED_PAT5 0x108 +#define QPHY_V4_PCS_FIXED_PAT6 0x10c +#define QPHY_V4_PCS_FIXED_PAT7 0x110 +#define QPHY_V4_PCS_FIXED_PAT8 0x114 +#define QPHY_V4_PCS_FIXED_PAT9 0x118 +#define QPHY_V4_PCS_FIXED_PAT10 0x11c +#define QPHY_V4_PCS_FIXED_PAT11 0x120 +#define QPHY_V4_PCS_FIXED_PAT12 0x124 +#define QPHY_V4_PCS_FIXED_PAT13 0x128 +#define QPHY_V4_PCS_FIXED_PAT14 0x12c +#define QPHY_V4_PCS_FIXED_PAT15 0x130 +#define QPHY_V4_PCS_TXMGN_CONFIG 0x134 +#define QPHY_V4_PCS_G12S1_TXMGN_V0 0x138 +#define QPHY_V4_PCS_G12S1_TXMGN_V1 0x13c +#define QPHY_V4_PCS_G12S1_TXMGN_V2 0x140 +#define QPHY_V4_PCS_G12S1_TXMGN_V3 0x144 +#define QPHY_V4_PCS_G12S1_TXMGN_V4 0x148 +#define QPHY_V4_PCS_G12S1_TXMGN_V0_RS 0x14c +#define QPHY_V4_PCS_G12S1_TXMGN_V1_RS 0x150 +#define QPHY_V4_PCS_G12S1_TXMGN_V2_RS 0x154 +#define QPHY_V4_PCS_G12S1_TXMGN_V3_RS 0x158 +#define QPHY_V4_PCS_G12S1_TXMGN_V4_RS 0x15c +#define QPHY_V4_PCS_G3S2_TXMGN_MAIN 0x160 +#define QPHY_V4_PCS_G3S2_TXMGN_MAIN_RS 0x164 +#define QPHY_V4_PCS_G12S1_TXDEEMPH_M6DB 0x168 +#define QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB 0x16c +#define QPHY_V4_PCS_G3S2_PRE_GAIN 0x170 +#define QPHY_V4_PCS_G3S2_POST_GAIN 0x174 +#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET 0x178 +#define QPHY_V4_PCS_G3S2_PRE_GAIN_RS 0x17c +#define QPHY_V4_PCS_G3S2_POST_GAIN_RS 0x180 +#define QPHY_V4_PCS_G3S2_PRE_POST_OFFSET_RS 0x184 +#define QPHY_V4_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V4_PCS_RX_SIGDET_DTCT_CNTRL 0x18c +#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 +#define QPHY_V4_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V4_PCS_RATE_SLEW_CNTRL2 0x19c +#define QPHY_V4_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x1a0 +#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L 0x1a4 +#define QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H 0x1a8 +#define QPHY_V4_PCS_TSYNC_RSYNC_TIME 0x1ac +#define QPHY_V4_PCS_CDR_RESET_TIME 0x1b0 +#define QPHY_V4_PCS_TSYNC_DLY_TIME 0x1b4 +#define QPHY_V4_PCS_ELECIDLE_DLY_SEL 0x1b8 +#define QPHY_V4_PCS_CMN_ACK_OUT_SEL 0x1bc +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG3 0x1c8 +#define QPHY_V4_PCS_ALIGN_DETECT_CONFIG4 0x1cc +#define QPHY_V4_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V4_PCS_RX_IDLE_DTCT_CNTRL 0x1d4 +#define QPHY_V4_PCS_RX_DCC_CAL_CONFIG 0x1d8 +#define QPHY_V4_PCS_EQ_CONFIG1 0x1dc +#define QPHY_V4_PCS_EQ_CONFIG2 0x1e0 +#define QPHY_V4_PCS_EQ_CONFIG3 0x1e4 +#define QPHY_V4_PCS_EQ_CONFIG4 0x1e8 +#define QPHY_V4_PCS_EQ_CONFIG5 0x1ec + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v3.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v3.h new file mode 100644 index 00000000000..c0bd54e0e7b --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v3.h @@ -0,0 +1,111 @@ + +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_V3_H_ +#define QCOM_PHY_QMP_QSERDES_COM_V3_H_ + +/* Only for QMP V3 PHY - QSERDES COM registers */ +#define QSERDES_V3_COM_ATB_SEL1 0x000 +#define QSERDES_V3_COM_ATB_SEL2 0x004 +#define QSERDES_V3_COM_FREQ_UPDATE 0x008 +#define QSERDES_V3_COM_BG_TIMER 0x00c +#define QSERDES_V3_COM_SSC_EN_CENTER 0x010 +#define QSERDES_V3_COM_SSC_ADJ_PER1 0x014 +#define QSERDES_V3_COM_SSC_ADJ_PER2 0x018 +#define QSERDES_V3_COM_SSC_PER1 0x01c +#define QSERDES_V3_COM_SSC_PER2 0x020 +#define QSERDES_V3_COM_SSC_STEP_SIZE1 0x024 +#define QSERDES_V3_COM_SSC_STEP_SIZE2 0x028 +#define QSERDES_V3_COM_POST_DIV 0x02c +#define QSERDES_V3_COM_POST_DIV_MUX 0x030 +#define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034 +#define QSERDES_V3_COM_CLK_ENABLE1 0x038 +#define QSERDES_V3_COM_SYS_CLK_CTRL 0x03c +#define QSERDES_V3_COM_SYSCLK_BUF_ENABLE 0x040 +#define QSERDES_V3_COM_PLL_EN 0x044 +#define QSERDES_V3_COM_PLL_IVCO 0x048 +#define QSERDES_V3_COM_CMN_IETRIM 0x04c +#define QSERDES_V3_COM_CMN_IPTRIM 0x050 +#define QSERDES_V3_COM_EP_CLOCK_DETECT_CTR 0x054 +#define QSERDES_V3_COM_SYSCLK_DET_COMP_STATUS 0x058 +#define QSERDES_V3_COM_CLK_EP_DIV 0x05c +#define QSERDES_V3_COM_CP_CTRL_MODE0 0x060 +#define QSERDES_V3_COM_CP_CTRL_MODE1 0x064 +#define QSERDES_V3_COM_PLL_RCTRL_MODE0 0x068 +#define QSERDES_V3_COM_PLL_RCTRL_MODE1 0x06c +#define QSERDES_V3_COM_PLL_CCTRL_MODE0 0x070 +#define QSERDES_V3_COM_PLL_CCTRL_MODE1 0x074 +#define QSERDES_V3_COM_PLL_CNTRL 0x078 +#define QSERDES_V3_COM_BIAS_EN_CTRL_BY_PSM 0x07c +#define QSERDES_V3_COM_SYSCLK_EN_SEL 0x080 +#define QSERDES_V3_COM_CML_SYSCLK_SEL 0x084 +#define QSERDES_V3_COM_RESETSM_CNTRL 0x088 +#define QSERDES_V3_COM_RESETSM_CNTRL2 0x08c +#define QSERDES_V3_COM_LOCK_CMP_EN 0x090 +#define QSERDES_V3_COM_LOCK_CMP_CFG 0x094 +#define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098 +#define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c +#define QSERDES_V3_COM_LOCK_CMP3_MODE0 0x0a0 +#define QSERDES_V3_COM_LOCK_CMP1_MODE1 0x0a4 +#define QSERDES_V3_COM_LOCK_CMP2_MODE1 0x0a8 +#define QSERDES_V3_COM_LOCK_CMP3_MODE1 0x0ac +#define QSERDES_V3_COM_DEC_START_MODE0 0x0b0 +#define QSERDES_V3_COM_DEC_START_MODE1 0x0b4 +#define QSERDES_V3_COM_DIV_FRAC_START1_MODE0 0x0b8 +#define QSERDES_V3_COM_DIV_FRAC_START2_MODE0 0x0bc +#define QSERDES_V3_COM_DIV_FRAC_START3_MODE0 0x0c0 +#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1 0x0c4 +#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1 0x0c8 +#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1 0x0cc +#define QSERDES_V3_COM_INTEGLOOP_INITVAL 0x0d0 +#define QSERDES_V3_COM_INTEGLOOP_EN 0x0d4 +#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0 0x0d8 +#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0 0x0dc +#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1 0x0e0 +#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1 0x0e4 +#define QSERDES_V3_COM_VCOCAL_DEADMAN_CTRL 0x0e8 +#define QSERDES_V3_COM_VCO_TUNE_CTRL 0x0ec +#define QSERDES_V3_COM_VCO_TUNE_MAP 0x0f0 +#define QSERDES_V3_COM_VCO_TUNE1_MODE0 0x0f4 +#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8 +#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc +#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100 +#define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104 +#define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108 +#define QSERDES_V3_COM_VCO_TUNE_MINVAL1 0x10c +#define QSERDES_V3_COM_VCO_TUNE_MINVAL2 0x110 +#define QSERDES_V3_COM_VCO_TUNE_MAXVAL1 0x114 +#define QSERDES_V3_COM_VCO_TUNE_MAXVAL2 0x118 +#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c +#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120 +#define QSERDES_V3_COM_CMN_STATUS 0x124 +#define QSERDES_V3_COM_RESET_SM_STATUS 0x128 +#define QSERDES_V3_COM_RESTRIM_CODE_STATUS 0x12c +#define QSERDES_V3_COM_PLLCAL_CODE1_STATUS 0x130 +#define QSERDES_V3_COM_PLLCAL_CODE2_STATUS 0x134 +#define QSERDES_V3_COM_CLK_SELECT 0x138 +#define QSERDES_V3_COM_HSCLK_SEL 0x13c +#define QSERDES_V3_COM_INTEGLOOP_BINCODE_STATUS 0x140 +#define QSERDES_V3_COM_PLL_ANALOG 0x144 +#define QSERDES_V3_COM_CORECLK_DIV_MODE0 0x148 +#define QSERDES_V3_COM_CORECLK_DIV_MODE1 0x14c +#define QSERDES_V3_COM_SW_RESET 0x150 +#define QSERDES_V3_COM_CORE_CLK_EN 0x154 +#define QSERDES_V3_COM_C_READY_STATUS 0x158 +#define QSERDES_V3_COM_CMN_CONFIG 0x15c +#define QSERDES_V3_COM_CMN_RATE_OVERRIDE 0x160 +#define QSERDES_V3_COM_SVS_MODE_CLK_SEL 0x164 +#define QSERDES_V3_COM_DEBUG_BUS0 0x168 +#define QSERDES_V3_COM_DEBUG_BUS1 0x16c +#define QSERDES_V3_COM_DEBUG_BUS2 0x170 +#define QSERDES_V3_COM_DEBUG_BUS3 0x174 +#define QSERDES_V3_COM_DEBUG_BUS_SEL 0x178 +#define QSERDES_V3_COM_CMN_MISC1 0x17c +#define QSERDES_V3_COM_CMN_MISC2 0x180 +#define QSERDES_V3_COM_CMN_MODE 0x184 +#define QSERDES_V3_COM_CMN_VREG_SEL 0x188 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v4.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v4.h new file mode 100644 index 00000000000..b0e3298d990 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v4.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_V4_H_ +#define QCOM_PHY_QMP_QSERDES_COM_V4_H_ + +/* Only for QMP V4 PHY - QSERDES COM registers */ +#define QSERDES_V4_COM_ATB_SEL1 0x000 +#define QSERDES_V4_COM_ATB_SEL2 0x004 +#define QSERDES_V4_COM_FREQ_UPDATE 0x008 +#define QSERDES_V4_COM_BG_TIMER 0x00c +#define QSERDES_V4_COM_SSC_EN_CENTER 0x010 +#define QSERDES_V4_COM_SSC_ADJ_PER1 0x014 +#define QSERDES_V4_COM_SSC_ADJ_PER2 0x018 +#define QSERDES_V4_COM_SSC_PER1 0x01c +#define QSERDES_V4_COM_SSC_PER2 0x020 +#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0 0x024 +#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0 0x028 +#define QSERDES_V4_COM_SSC_STEP_SIZE3_MODE0 0x02c +#define QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1 0x030 +#define QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1 0x034 +#define QSERDES_V4_COM_SSC_STEP_SIZE3_MODE1 0x038 +#define QSERDES_V4_COM_POST_DIV 0x03c +#define QSERDES_V4_COM_POST_DIV_MUX 0x040 +#define QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN 0x044 +#define QSERDES_V4_COM_CLK_ENABLE1 0x048 +#define QSERDES_V4_COM_SYS_CLK_CTRL 0x04c +#define QSERDES_V4_COM_SYSCLK_BUF_ENABLE 0x050 +#define QSERDES_V4_COM_PLL_EN 0x054 +#define QSERDES_V4_COM_PLL_IVCO 0x058 +#define QSERDES_V4_COM_CMN_IETRIM 0x05c +#define QSERDES_V4_COM_CMN_IPTRIM 0x060 +#define QSERDES_V4_COM_EP_CLOCK_DETECT_CTRL 0x064 +#define QSERDES_V4_COM_SYSCLK_DET_COMP_STATUS 0x068 +#define QSERDES_V4_COM_CLK_EP_DIV_MODE0 0x06c +#define QSERDES_V4_COM_CLK_EP_DIV_MODE1 0x070 +#define QSERDES_V4_COM_CP_CTRL_MODE0 0x074 +#define QSERDES_V4_COM_CP_CTRL_MODE1 0x078 +#define QSERDES_V4_COM_PLL_RCTRL_MODE0 0x07c +#define QSERDES_V4_COM_PLL_RCTRL_MODE1 0x080 +#define QSERDES_V4_COM_PLL_CCTRL_MODE0 0x084 +#define QSERDES_V4_COM_PLL_CCTRL_MODE1 0x088 +#define QSERDES_V4_COM_PLL_CNTRL 0x08c +#define QSERDES_V4_COM_BIAS_EN_CTRL_BY_PSM 0x090 +#define QSERDES_V4_COM_SYSCLK_EN_SEL 0x094 +#define QSERDES_V4_COM_CML_SYSCLK_SEL 0x098 +#define QSERDES_V4_COM_RESETSM_CNTRL 0x09c +#define QSERDES_V4_COM_RESETSM_CNTRL2 0x0a0 +#define QSERDES_V4_COM_LOCK_CMP_EN 0x0a4 +#define QSERDES_V4_COM_LOCK_CMP_CFG 0x0a8 +#define QSERDES_V4_COM_LOCK_CMP1_MODE0 0x0ac +#define QSERDES_V4_COM_LOCK_CMP2_MODE0 0x0b0 +#define QSERDES_V4_COM_LOCK_CMP1_MODE1 0x0b4 +#define QSERDES_V4_COM_LOCK_CMP2_MODE1 0x0b8 +#define QSERDES_V4_COM_DEC_START_MODE0 0x0bc +#define QSERDES_V4_COM_DEC_START_MSB_MODE0 0x0c0 +#define QSERDES_V4_COM_DEC_START_MODE1 0x0c4 +#define QSERDES_V4_COM_DEC_START_MSB_MODE1 0x0c8 +#define QSERDES_V4_COM_DIV_FRAC_START1_MODE0 0x0cc +#define QSERDES_V4_COM_DIV_FRAC_START2_MODE0 0x0d0 +#define QSERDES_V4_COM_DIV_FRAC_START3_MODE0 0x0d4 +#define QSERDES_V4_COM_DIV_FRAC_START1_MODE1 0x0d8 +#define QSERDES_V4_COM_DIV_FRAC_START2_MODE1 0x0dc +#define QSERDES_V4_COM_DIV_FRAC_START3_MODE1 0x0e0 +#define QSERDES_V4_COM_INTEGLOOP_INITVAL 0x0e4 +#define QSERDES_V4_COM_INTEGLOOP_EN 0x0e8 +#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE0 0x0ec +#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0 0x0f0 +#define QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE1 0x0f4 +#define QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE1 0x0f8 +#define QSERDES_V4_COM_INTEGLOOP_P_PATH_GAIN0 0x0fc +#define QSERDES_V4_COM_INTEGLOOP_P_PATH_GAIN1 0x100 +#define QSERDES_V4_COM_VCOCAL_DEADMAN_CTRL 0x104 +#define QSERDES_V4_COM_VCO_TUNE_CTRL 0x108 +#define QSERDES_V4_COM_VCO_TUNE_MAP 0x10c +#define QSERDES_V4_COM_VCO_TUNE1_MODE0 0x110 +#define QSERDES_V4_COM_VCO_TUNE2_MODE0 0x114 +#define QSERDES_V4_COM_VCO_TUNE1_MODE1 0x118 +#define QSERDES_V4_COM_VCO_TUNE2_MODE1 0x11c +#define QSERDES_V4_COM_VCO_TUNE_INITVAL1 0x120 +#define QSERDES_V4_COM_VCO_TUNE_INITVAL2 0x124 +#define QSERDES_V4_COM_VCO_TUNE_MINVAL1 0x128 +#define QSERDES_V4_COM_VCO_TUNE_MINVAL2 0x12c +#define QSERDES_V4_COM_VCO_TUNE_MAXVAL1 0x130 +#define QSERDES_V4_COM_VCO_TUNE_MAXVAL2 0x134 +#define QSERDES_V4_COM_VCO_TUNE_TIMER1 0x138 +#define QSERDES_V4_COM_VCO_TUNE_TIMER2 0x13c +#define QSERDES_V4_COM_CMN_STATUS 0x140 +#define QSERDES_V4_COM_RESET_SM_STATUS 0x144 +#define QSERDES_V4_COM_RESTRIM_CODE_STATUS 0x148 +#define QSERDES_V4_COM_PLLCAL_CODE1_STATUS 0x14c +#define QSERDES_V4_COM_PLLCAL_CODE2_STATUS 0x150 +#define QSERDES_V4_COM_CLK_SELECT 0x154 +#define QSERDES_V4_COM_HSCLK_SEL 0x158 +#define QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL 0x15c +#define QSERDES_V4_COM_INTEGLOOP_BINCODE_STATUS 0x160 +#define QSERDES_V4_COM_PLL_ANALOG 0x164 +#define QSERDES_V4_COM_CORECLK_DIV_MODE0 0x168 +#define QSERDES_V4_COM_CORECLK_DIV_MODE1 0x16c +#define QSERDES_V4_COM_SW_RESET 0x170 +#define QSERDES_V4_COM_CORE_CLK_EN 0x174 +#define QSERDES_V4_COM_C_READY_STATUS 0x178 +#define QSERDES_V4_COM_CMN_CONFIG 0x17c +#define QSERDES_V4_COM_CMN_RATE_OVERRIDE 0x180 +#define QSERDES_V4_COM_SVS_MODE_CLK_SEL 0x184 +#define QSERDES_V4_COM_DEBUG_BUS0 0x188 +#define QSERDES_V4_COM_DEBUG_BUS1 0x18c +#define QSERDES_V4_COM_DEBUG_BUS2 0x190 +#define QSERDES_V4_COM_DEBUG_BUS3 0x194 +#define QSERDES_V4_COM_DEBUG_BUS_SEL 0x198 +#define QSERDES_V4_COM_CMN_MISC1 0x19c +#define QSERDES_V4_COM_CMN_MISC2 0x1a0 +#define QSERDES_V4_COM_CMN_MODE 0x1a4 +#define QSERDES_V4_COM_VCO_DC_LEVEL_CTRL 0x1a8 +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x1ac +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x1b0 +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x1b4 +#define QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x1b8 +#define QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL 0x1bc + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v6.h new file mode 100644 index 00000000000..328c6c0b0b0 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com-v6.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_V6_H_ +#define QCOM_PHY_QMP_QSERDES_COM_V6_H_ + +/* Only for QMP V6 PHY - QSERDES COM registers */ + +#define QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1 0x00 +#define QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1 0x04 +#define QSERDES_V6_COM_CP_CTRL_MODE1 0x10 +#define QSERDES_V6_COM_PLL_RCTRL_MODE1 0x14 +#define QSERDES_V6_COM_PLL_CCTRL_MODE1 0x18 +#define QSERDES_V6_COM_CORECLK_DIV_MODE1 0x1c +#define QSERDES_V6_COM_LOCK_CMP1_MODE1 0x20 +#define QSERDES_V6_COM_LOCK_CMP2_MODE1 0x24 +#define QSERDES_V6_COM_DEC_START_MODE1 0x28 +#define QSERDES_V6_COM_DEC_START_MSB_MODE1 0x2c +#define QSERDES_V6_COM_DIV_FRAC_START1_MODE1 0x30 +#define QSERDES_V6_COM_DIV_FRAC_START2_MODE1 0x34 +#define QSERDES_V6_COM_DIV_FRAC_START3_MODE1 0x38 +#define QSERDES_V6_COM_HSCLK_SEL_1 0x3c +#define QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE1 0x40 +#define QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE1 0x44 +#define QSERDES_V6_COM_VCO_TUNE1_MODE1 0x48 +#define QSERDES_V6_COM_VCO_TUNE2_MODE1 0x4c +#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1 0x50 +#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1 0x54 +#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0 0x58 +#define QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0 0x5c +#define QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0 0x60 +#define QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0 0x64 +#define QSERDES_V6_COM_CP_CTRL_MODE0 0x70 +#define QSERDES_V6_COM_PLL_RCTRL_MODE0 0x74 +#define QSERDES_V6_COM_PLL_CCTRL_MODE0 0x78 +#define QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0 0x7c +#define QSERDES_V6_COM_LOCK_CMP1_MODE0 0x80 +#define QSERDES_V6_COM_LOCK_CMP2_MODE0 0x84 +#define QSERDES_V6_COM_DEC_START_MODE0 0x88 +#define QSERDES_V6_COM_DEC_START_MSB_MODE0 0x8c +#define QSERDES_V6_COM_DIV_FRAC_START1_MODE0 0x90 +#define QSERDES_V6_COM_DIV_FRAC_START2_MODE0 0x94 +#define QSERDES_V6_COM_DIV_FRAC_START3_MODE0 0x98 +#define QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1 0x9c +#define QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0 0xa0 +#define QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0 0xa4 +#define QSERDES_V6_COM_VCO_TUNE1_MODE0 0xa8 +#define QSERDES_V6_COM_VCO_TUNE2_MODE0 0xac +#define QSERDES_V6_COM_BG_TIMER 0xbc +#define QSERDES_V6_COM_SSC_EN_CENTER 0xc0 +#define QSERDES_V6_COM_SSC_ADJ_PER1 0xc4 +#define QSERDES_V6_COM_SSC_PER1 0xcc +#define QSERDES_V6_COM_SSC_PER2 0xd0 +#define QSERDES_V6_COM_PLL_POST_DIV_MUX 0xd8 +#define QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN 0xdc +#define QSERDES_V6_COM_CLK_ENABLE1 0xe0 +#define QSERDES_V6_COM_SYS_CLK_CTRL 0xe4 +#define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8 +#define QSERDES_V6_COM_PLL_IVCO 0xf4 +#define QSERDES_V6_COM_PLL_IVCO_MODE1 0xf8 +#define QSERDES_V6_COM_CMN_IETRIM 0xfc +#define QSERDES_V6_COM_CMN_IPTRIM 0x100 +#define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110 +#define QSERDES_V6_COM_RESETSM_CNTRL 0x118 +#define QSERDES_V6_COM_LOCK_CMP_EN 0x120 +#define QSERDES_V6_COM_LOCK_CMP_CFG 0x124 +#define QSERDES_V6_COM_VCO_TUNE_CTRL 0x13c +#define QSERDES_V6_COM_VCO_TUNE_MAP 0x140 +#define QSERDES_V6_COM_VCO_TUNE_INITVAL2 0x148 +#define QSERDES_V6_COM_VCO_TUNE_MAXVAL2 0x158 +#define QSERDES_V6_COM_CLK_SELECT 0x164 +#define QSERDES_V6_COM_CORE_CLK_EN 0x170 +#define QSERDES_V6_COM_CMN_CONFIG_1 0x174 +#define QSERDES_V6_COM_SVS_MODE_CLK_SEL 0x17c +#define QSERDES_V6_COM_CMN_MISC_1 0x184 +#define QSERDES_V6_COM_CMN_MODE 0x188 +#define QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL 0x198 +#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_1 0x1a4 +#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_2 0x1a8 +#define QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_3 0x1ac +#define QSERDES_V6_COM_ADDITIONAL_MISC 0x1b4 +#define QSERDES_V6_COM_ADDITIONAL_MISC_2 0x1b8 +#define QSERDES_V6_COM_ADDITIONAL_MISC_3 0x1bc +#define QSERDES_V6_COM_CMN_STATUS 0x1d0 +#define QSERDES_V6_COM_C_READY_STATUS 0x1f8 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-com.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com.h new file mode 100644 index 00000000000..7fa5363feeb --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-com.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_COM_H_ +#define QCOM_PHY_QMP_QSERDES_COM_H_ + +/* Only for QMP V2 PHY - QSERDES COM registers */ +#define QSERDES_COM_ATB_SEL1 0x000 +#define QSERDES_COM_ATB_SEL2 0x004 +#define QSERDES_COM_FREQ_UPDATE 0x008 +#define QSERDES_COM_BG_TIMER 0x00c +#define QSERDES_COM_SSC_EN_CENTER 0x010 +#define QSERDES_COM_SSC_ADJ_PER1 0x014 +#define QSERDES_COM_SSC_ADJ_PER2 0x018 +#define QSERDES_COM_SSC_PER1 0x01c +#define QSERDES_COM_SSC_PER2 0x020 +#define QSERDES_COM_SSC_STEP_SIZE1 0x024 +#define QSERDES_COM_SSC_STEP_SIZE2 0x028 +#define QSERDES_COM_POST_DIV 0x02c +#define QSERDES_COM_POST_DIV_MUX 0x030 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x034 +#define QSERDES_COM_CLK_ENABLE1 0x038 +#define QSERDES_COM_SYS_CLK_CTRL 0x03c +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x040 +#define QSERDES_COM_PLL_EN 0x044 +#define QSERDES_COM_PLL_IVCO 0x048 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x04c +#define QSERDES_COM_LOCK_CMP2_MODE0 0x050 +#define QSERDES_COM_LOCK_CMP3_MODE0 0x054 +#define QSERDES_COM_LOCK_CMP1_MODE1 0x058 +#define QSERDES_COM_LOCK_CMP2_MODE1 0x05c +#define QSERDES_COM_LOCK_CMP3_MODE1 0x060 +#define QSERDES_COM_LOCK_CMP1_MODE2 0x064 +#define QSERDES_COM_CMN_RSVD0 0x064 +#define QSERDES_COM_LOCK_CMP2_MODE2 0x068 +#define QSERDES_COM_EP_CLOCK_DETECT_CTRL 0x068 +#define QSERDES_COM_LOCK_CMP3_MODE2 0x06c +#define QSERDES_COM_SYSCLK_DET_COMP_STATUS 0x06c +#define QSERDES_COM_BG_TRIM 0x070 +#define QSERDES_COM_CLK_EP_DIV 0x074 +#define QSERDES_COM_CP_CTRL_MODE0 0x078 +#define QSERDES_COM_CP_CTRL_MODE1 0x07c +#define QSERDES_COM_CP_CTRL_MODE2 0x080 +#define QSERDES_COM_CMN_RSVD1 0x080 +#define QSERDES_COM_PLL_RCTRL_MODE0 0x084 +#define QSERDES_COM_PLL_RCTRL_MODE1 0x088 +#define QSERDES_COM_PLL_RCTRL_MODE2 0x08c +#define QSERDES_COM_CMN_RSVD2 0x08c +#define QSERDES_COM_PLL_CCTRL_MODE0 0x090 +#define QSERDES_COM_PLL_CCTRL_MODE1 0x094 +#define QSERDES_COM_PLL_CCTRL_MODE2 0x098 +#define QSERDES_COM_CMN_RSVD3 0x098 +#define QSERDES_COM_PLL_CNTRL 0x09c +#define QSERDES_COM_PHASE_SEL_CTRL 0x0a0 +#define QSERDES_COM_PHASE_SEL_DC 0x0a4 +#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL 0x0a8 +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x0a8 +#define QSERDES_COM_SYSCLK_EN_SEL 0x0ac +#define QSERDES_COM_CML_SYSCLK_SEL 0x0b0 +#define QSERDES_COM_RESETSM_CNTRL 0x0b4 +#define QSERDES_COM_RESETSM_CNTRL2 0x0b8 +#define QSERDES_COM_RESTRIM_CTRL 0x0bc +#define QSERDES_COM_RESTRIM_CTRL2 0x0c0 +#define QSERDES_COM_RESCODE_DIV_NUM 0x0c4 +#define QSERDES_COM_LOCK_CMP_EN 0x0c8 +#define QSERDES_COM_LOCK_CMP_CFG 0x0cc +#define QSERDES_COM_DEC_START_MODE0 0x0d0 +#define QSERDES_COM_DEC_START_MODE1 0x0d4 +#define QSERDES_COM_DEC_START_MODE2 0x0d8 +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x0d8 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x0dc +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x0e0 +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x0e4 +#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x0e8 +#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x0ec +#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x0f0 +#define QSERDES_COM_DIV_FRAC_START1_MODE2 0x0f4 +#define QSERDES_COM_VCO_TUNE_MINVAL1 0x0f4 +#define QSERDES_COM_DIV_FRAC_START2_MODE2 0x0f8 +#define QSERDES_COM_VCO_TUNE_MINVAL2 0x0f8 +#define QSERDES_COM_DIV_FRAC_START3_MODE2 0x0fc +#define QSERDES_COM_CMN_RSVD4 0x0fc +#define QSERDES_COM_INTEGLOOP_INITVAL 0x100 +#define QSERDES_COM_INTEGLOOP_EN 0x104 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x108 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x10c +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x110 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x114 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 0x118 +#define QSERDES_COM_VCO_TUNE_MAXVAL1 0x118 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 0x11c +#define QSERDES_COM_VCO_TUNE_MAXVAL2 0x11c +#define QSERDES_COM_RES_TRIM_CONTROL2 0x120 +#define QSERDES_COM_VCO_TUNE_CTRL 0x124 +#define QSERDES_COM_VCO_TUNE_MAP 0x128 +#define QSERDES_COM_VCO_TUNE1_MODE0 0x12c +#define QSERDES_COM_VCO_TUNE2_MODE0 0x130 +#define QSERDES_COM_VCO_TUNE1_MODE1 0x134 +#define QSERDES_COM_VCO_TUNE2_MODE1 0x138 +#define QSERDES_COM_VCO_TUNE1_MODE2 0x13c +#define QSERDES_COM_VCO_TUNE_INITVAL1 0x13c +#define QSERDES_COM_VCO_TUNE2_MODE2 0x140 +#define QSERDES_COM_VCO_TUNE_INITVAL2 0x140 +#define QSERDES_COM_VCO_TUNE_TIMER1 0x144 +#define QSERDES_COM_VCO_TUNE_TIMER2 0x148 +#define QSERDES_COM_SAR 0x14c +#define QSERDES_COM_SAR_CLK 0x150 +#define QSERDES_COM_SAR_CODE_OUT_STATUS 0x154 +#define QSERDES_COM_SAR_CODE_READY_STATUS 0x158 +#define QSERDES_COM_CMN_STATUS 0x15c +#define QSERDES_COM_RESET_SM_STATUS 0x160 +#define QSERDES_COM_RESTRIM_CODE_STATUS 0x164 +#define QSERDES_COM_PLLCAL_CODE1_STATUS 0x168 +#define QSERDES_COM_PLLCAL_CODE2_STATUS 0x16c +#define QSERDES_COM_BG_CTRL 0x170 +#define QSERDES_COM_CLK_SELECT 0x174 +#define QSERDES_COM_HSCLK_SEL 0x178 +#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS 0x17c +#define QSERDES_COM_PLL_ANALOG 0x180 +#define QSERDES_COM_CORECLK_DIV 0x184 +#define QSERDES_COM_SW_RESET 0x188 +#define QSERDES_COM_CORE_CLK_EN 0x18c +#define QSERDES_COM_C_READY_STATUS 0x190 +#define QSERDES_COM_CMN_CONFIG 0x194 +#define QSERDES_COM_CMN_RATE_OVERRIDE 0x198 +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x19c +#define QSERDES_COM_DEBUG_BUS0 0x1a0 +#define QSERDES_COM_DEBUG_BUS1 0x1a4 +#define QSERDES_COM_DEBUG_BUS2 0x1a8 +#define QSERDES_COM_DEBUG_BUS3 0x1ac +#define QSERDES_COM_DEBUG_BUS_SEL 0x1b0 +#define QSERDES_COM_CMN_MISC1 0x1b4 +#define QSERDES_COM_CMN_MISC2 0x1b8 +#define QSERDES_COM_CORECLK_DIV_MODE1 0x1bc +#define QSERDES_COM_CORECLK_DIV_MODE2 0x1c0 +#define QSERDES_COM_CMN_RSVD5 0x1c4 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-pll.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-pll.h new file mode 100644 index 00000000000..231e59364e3 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-pll.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_PLL_H_ +#define QCOM_PHY_QMP_QSERDES_PLL_H_ + +/* QMP V2 PHY for PCIE gen3 ports - QSERDES PLL registers */ +#define QSERDES_PLL_BG_TIMER 0x00c +#define QSERDES_PLL_SSC_EN_CENTER 0x010 +#define QSERDES_PLL_SSC_ADJ_PER1 0x014 +#define QSERDES_PLL_SSC_ADJ_PER2 0x018 +#define QSERDES_PLL_SSC_PER1 0x01c +#define QSERDES_PLL_SSC_PER2 0x020 +#define QSERDES_PLL_SSC_STEP_SIZE1_MODE0 0x024 +#define QSERDES_PLL_SSC_STEP_SIZE2_MODE0 0x028 +#define QSERDES_PLL_SSC_STEP_SIZE1_MODE1 0x02c +#define QSERDES_PLL_SSC_STEP_SIZE2_MODE1 0x030 +#define QSERDES_PLL_BIAS_EN_CLKBUFLR_EN 0x03c +#define QSERDES_PLL_CLK_ENABLE1 0x040 +#define QSERDES_PLL_SYS_CLK_CTRL 0x044 +#define QSERDES_PLL_SYSCLK_BUF_ENABLE 0x048 +#define QSERDES_PLL_PLL_IVCO 0x050 +#define QSERDES_PLL_LOCK_CMP1_MODE0 0x054 +#define QSERDES_PLL_LOCK_CMP2_MODE0 0x058 +#define QSERDES_PLL_LOCK_CMP1_MODE1 0x060 +#define QSERDES_PLL_LOCK_CMP2_MODE1 0x064 +#define QSERDES_PLL_BG_TRIM 0x074 +#define QSERDES_PLL_CLK_EP_DIV_MODE0 0x078 +#define QSERDES_PLL_CLK_EP_DIV_MODE1 0x07c +#define QSERDES_PLL_CP_CTRL_MODE0 0x080 +#define QSERDES_PLL_CP_CTRL_MODE1 0x084 +#define QSERDES_PLL_PLL_RCTRL_MODE0 0x088 +#define QSERDES_PLL_PLL_RCTRL_MODE1 0x08c +#define QSERDES_PLL_PLL_CCTRL_MODE0 0x090 +#define QSERDES_PLL_PLL_CCTRL_MODE1 0x094 +#define QSERDES_PLL_BIAS_EN_CTRL_BY_PSM 0x0a4 +#define QSERDES_PLL_SYSCLK_EN_SEL 0x0a8 +#define QSERDES_PLL_RESETSM_CNTRL 0x0b0 +#define QSERDES_PLL_LOCK_CMP_EN 0x0c4 +#define QSERDES_PLL_DEC_START_MODE0 0x0cc +#define QSERDES_PLL_DEC_START_MODE1 0x0d0 +#define QSERDES_PLL_DIV_FRAC_START1_MODE0 0x0d8 +#define QSERDES_PLL_DIV_FRAC_START2_MODE0 0x0dc +#define QSERDES_PLL_DIV_FRAC_START3_MODE0 0x0e0 +#define QSERDES_PLL_DIV_FRAC_START1_MODE1 0x0e4 +#define QSERDES_PLL_DIV_FRAC_START2_MODE1 0x0e8 +#define QSERDES_PLL_DIV_FRAC_START3_MODE1 0x0ec +#define QSERDES_PLL_INTEGLOOP_GAIN0_MODE0 0x100 +#define QSERDES_PLL_INTEGLOOP_GAIN1_MODE0 0x104 +#define QSERDES_PLL_INTEGLOOP_GAIN0_MODE1 0x108 +#define QSERDES_PLL_INTEGLOOP_GAIN1_MODE1 0x10c +#define QSERDES_PLL_VCO_TUNE_MAP 0x120 +#define QSERDES_PLL_VCO_TUNE1_MODE0 0x124 +#define QSERDES_PLL_VCO_TUNE2_MODE0 0x128 +#define QSERDES_PLL_VCO_TUNE1_MODE1 0x12c +#define QSERDES_PLL_VCO_TUNE2_MODE1 0x130 +#define QSERDES_PLL_VCO_TUNE_TIMER1 0x13c +#define QSERDES_PLL_VCO_TUNE_TIMER2 0x140 +#define QSERDES_PLL_CLK_SELECT 0x16c +#define QSERDES_PLL_HSCLK_SEL 0x170 +#define QSERDES_PLL_CORECLK_DIV 0x17c +#define QSERDES_PLL_CORE_CLK_EN 0x184 +#define QSERDES_PLL_CMN_CONFIG 0x18c +#define QSERDES_PLL_SVS_MODE_CLK_SEL 0x194 +#define QSERDES_PLL_CORECLK_DIV_MODE1 0x1b4 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-ufs-v6.h new file mode 100644 index 00000000000..d17a5235796 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-ufs-v6.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V6_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V6_H_ + +#define QSERDES_UFS_V6_TX_RES_CODE_LANE_TX 0x28 +#define QSERDES_UFS_V6_TX_RES_CODE_LANE_RX 0x2c +#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX 0x30 +#define QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX 0x34 +#define QSERDES_UFS_V6_TX_LANE_MODE_1 0x7c +#define QSERDES_UFS_V6_TX_FR_DCC_CTRL 0x108 + +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24 +#define QSERDES_UFS_V6_RX_UCDR_SO_SATURATION 0x28 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54 +#define QSERDES_UFS_V6_RX_UCDR_PI_CTRL1 0x58 +#define QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0 0xc4 +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4 +#define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0 +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4 +#define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178 +#define QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4 0x1ac +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc +#define QSERDES_UFS_V6_RX_INTERFACE_MODE 0x1e0 +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2 0x210 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4 0x218 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6 0x220 +#define QSERDES_UFS_V6_RX_MODE_RATE2_B3 0x238 +#define QSERDES_UFS_V6_RX_MODE_RATE2_B6 0x244 +#define QSERDES_UFS_V6_RX_MODE_RATE3_B3 0x25c +#define QSERDES_UFS_V6_RX_MODE_RATE3_B4 0x260 +#define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264 +#define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B0 0x274 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B1 0x278 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B2 0x27c +#define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v3.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v3.h new file mode 100644 index 00000000000..161e6df30ea --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v3.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V3_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V3_H_ + +/* Only for QMP V3 PHY - TX registers */ +#define QSERDES_V3_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_V3_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_V3_TX_TX_EMP_POST1_LVL 0x00c +#define QSERDES_V3_TX_TX_DRV_LVL 0x01c +#define QSERDES_V3_TX_RESET_TSYNC_EN 0x024 +#define QSERDES_V3_TX_PRE_STALL_LDO_BOOST_EN 0x028 +#define QSERDES_V3_TX_TX_BAND 0x02c +#define QSERDES_V3_TX_SLEW_CNTL 0x030 +#define QSERDES_V3_TX_INTERFACE_SELECT 0x034 +#define QSERDES_V3_TX_RES_CODE_LANE_TX 0x03c +#define QSERDES_V3_TX_RES_CODE_LANE_RX 0x040 +#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX 0x044 +#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX 0x048 +#define QSERDES_V3_TX_DEBUG_BUS_SEL 0x058 +#define QSERDES_V3_TX_TRANSCEIVER_BIAS_EN 0x05c +#define QSERDES_V3_TX_HIGHZ_DRVR_EN 0x060 +#define QSERDES_V3_TX_TX_POL_INV 0x064 +#define QSERDES_V3_TX_PARRATE_REC_DETECT_IDLE_EN 0x068 +#define QSERDES_V3_TX_LANE_MODE_1 0x08c +#define QSERDES_V3_TX_LANE_MODE_2 0x090 +#define QSERDES_V3_TX_LANE_MODE_3 0x094 +#define QSERDES_V3_TX_RCV_DETECT_LVL_2 0x0a4 +#define QSERDES_V3_TX_TRAN_DRVR_EMP_EN 0x0c0 +#define QSERDES_V3_TX_TX_INTERFACE_MODE 0x0c4 +#define QSERDES_V3_TX_VMODE_CTRL1 0x0f0 + +/* Only for QMP V3 PHY - RX registers */ +#define QSERDES_V3_RX_UCDR_FO_GAIN 0x008 +#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c +#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 +#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c +#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 +#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 +#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044 +#define QSERDES_V3_RX_RX_TERM_BW 0x07c +#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc +#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0 +#define QSERDES_V3_RX_RX_EQ_GAIN2_LSB 0x0c8 +#define QSERDES_V3_RX_RX_EQ_GAIN2_MSB 0x0cc +#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d0 +#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4 +#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3 0x0d8 +#define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4 0x0dc +#define QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x0f8 +#define QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x0fc +#define QSERDES_V3_RX_SIGDET_ENABLES 0x100 +#define QSERDES_V3_RX_SIGDET_CNTRL 0x104 +#define QSERDES_V3_RX_SIGDET_LVL 0x108 +#define QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL 0x10c +#define QSERDES_V3_RX_RX_BAND 0x110 +#define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c +#define QSERDES_V3_RX_RX_MODE_00 0x164 +#define QSERDES_V3_RX_RX_MODE_01 0x168 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v4.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v4.h new file mode 100644 index 00000000000..6ee3bec9ac4 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx-v4.h @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_V4_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_V4_H_ + +/* Only for QMP V4 PHY - TX registers */ +#define QSERDES_V4_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_V4_TX_BIST_INVERT 0x004 +#define QSERDES_V4_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_V4_TX_TX_EMP_POST1_LVL 0x00c +#define QSERDES_V4_TX_TX_IDLE_LVL_LARGE_AMP 0x010 +#define QSERDES_V4_TX_TX_DRV_LVL 0x014 +#define QSERDES_V4_TX_TX_DRV_LVL_OFFSET 0x018 +#define QSERDES_V4_TX_RESET_TSYNC_EN 0x01c +#define QSERDES_V4_TX_PRE_STALL_LDO_BOOST_EN 0x020 +#define QSERDES_V4_TX_TX_BAND 0x024 +#define QSERDES_V4_TX_SLEW_CNTL 0x028 +#define QSERDES_V4_TX_INTERFACE_SELECT 0x02c +#define QSERDES_V4_TX_LPB_EN 0x030 +#define QSERDES_V4_TX_RES_CODE_LANE_TX 0x034 +#define QSERDES_V4_TX_RES_CODE_LANE_RX 0x038 +#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX 0x03c +#define QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX 0x040 +#define QSERDES_V4_TX_PERL_LENGTH1 0x044 +#define QSERDES_V4_TX_PERL_LENGTH2 0x048 +#define QSERDES_V4_TX_SERDES_BYP_EN_OUT 0x04c +#define QSERDES_V4_TX_DEBUG_BUS_SEL 0x050 +#define QSERDES_V4_TX_TRANSCEIVER_BIAS_EN 0x054 +#define QSERDES_V4_TX_HIGHZ_DRVR_EN 0x058 +#define QSERDES_V4_TX_TX_POL_INV 0x05c +#define QSERDES_V4_TX_PARRATE_REC_DETECT_IDLE_EN 0x060 +#define QSERDES_V4_TX_BIST_PATTERN1 0x064 +#define QSERDES_V4_TX_BIST_PATTERN2 0x068 +#define QSERDES_V4_TX_BIST_PATTERN3 0x06c +#define QSERDES_V4_TX_BIST_PATTERN4 0x070 +#define QSERDES_V4_TX_BIST_PATTERN5 0x074 +#define QSERDES_V4_TX_BIST_PATTERN6 0x078 +#define QSERDES_V4_TX_BIST_PATTERN7 0x07c +#define QSERDES_V4_TX_BIST_PATTERN8 0x080 +#define QSERDES_V4_TX_LANE_MODE_1 0x084 +#define QSERDES_V4_TX_LANE_MODE_2 0x088 +#define QSERDES_V4_TX_LANE_MODE_3 0x08c +#define QSERDES_V4_TX_ATB_SEL1 0x090 +#define QSERDES_V4_TX_ATB_SEL2 0x094 +#define QSERDES_V4_TX_RCV_DETECT_LVL 0x098 +#define QSERDES_V4_TX_RCV_DETECT_LVL_2 0x09c +#define QSERDES_V4_TX_PRBS_SEED1 0x0a0 +#define QSERDES_V4_TX_PRBS_SEED2 0x0a4 +#define QSERDES_V4_TX_PRBS_SEED3 0x0a8 +#define QSERDES_V4_TX_PRBS_SEED4 0x0ac +#define QSERDES_V4_TX_RESET_GEN 0x0b0 +#define QSERDES_V4_TX_RESET_GEN_MUXES 0x0b4 +#define QSERDES_V4_TX_TRAN_DRVR_EMP_EN 0x0b8 +#define QSERDES_V4_TX_TX_INTERFACE_MODE 0x0bc +#define QSERDES_V4_TX_PWM_CTRL 0x0c0 +#define QSERDES_V4_TX_PWM_ENCODED_OR_DATA 0x0c4 +#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND2 0x0c8 +#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND2 0x0cc +#define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND2 0x0d0 +#define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND2 0x0d4 +#define QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0x0d8 +#define QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0x0dc +#define QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0x0e0 +#define QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0x0e4 +#define QSERDES_V4_TX_VMODE_CTRL1 0x0e8 +#define QSERDES_V4_TX_ALOG_OBSV_BUS_CTRL_1 0x0ec +#define QSERDES_V4_TX_BIST_STATUS 0x0f0 +#define QSERDES_V4_TX_BIST_ERROR_COUNT1 0x0f4 +#define QSERDES_V4_TX_BIST_ERROR_COUNT2 0x0f8 +#define QSERDES_V4_TX_ALOG_OBSV_BUS_STATUS_1 0x0fc +#define QSERDES_V4_TX_LANE_DIG_CONFIG 0x100 +#define QSERDES_V4_TX_PI_QEC_CTRL 0x104 +#define QSERDES_V4_TX_PRE_EMPH 0x108 +#define QSERDES_V4_TX_SW_RESET 0x10c +#define QSERDES_V4_TX_DCC_OFFSET 0x110 +#define QSERDES_V4_TX_DIG_BKUP_CTRL 0x114 +#define QSERDES_V4_TX_DEBUG_BUS0 0x118 +#define QSERDES_V4_TX_DEBUG_BUS1 0x11c +#define QSERDES_V4_TX_DEBUG_BUS2 0x120 +#define QSERDES_V4_TX_DEBUG_BUS3 0x124 +#define QSERDES_V4_TX_READ_EQCODE 0x128 +#define QSERDES_V4_TX_READ_OFFSETCODE 0x12c +#define QSERDES_V4_TX_IA_ERROR_COUNTER_LOW 0x130 +#define QSERDES_V4_TX_IA_ERROR_COUNTER_HIGH 0x134 +#define QSERDES_V4_TX_VGA_READ_CODE 0x138 +#define QSERDES_V4_TX_VTH_READ_CODE 0x13c +#define QSERDES_V4_TX_DFE_TAP1_READ_CODE 0x140 +#define QSERDES_V4_TX_DFE_TAP2_READ_CODE 0x144 +#define QSERDES_V4_TX_IDAC_STATUS_I 0x148 +#define QSERDES_V4_TX_IDAC_STATUS_IBAR 0x14c +#define QSERDES_V4_TX_IDAC_STATUS_Q 0x150 +#define QSERDES_V4_TX_IDAC_STATUS_QBAR 0x154 +#define QSERDES_V4_TX_IDAC_STATUS_A 0x158 +#define QSERDES_V4_TX_IDAC_STATUS_ABAR 0x15c +#define QSERDES_V4_TX_IDAC_STATUS_SM_ON 0x160 +#define QSERDES_V4_TX_IDAC_STATUS_CAL_DONE 0x164 +#define QSERDES_V4_TX_IDAC_STATUS_SIGNERROR 0x168 +#define QSERDES_V4_TX_DCC_CAL_STATUS 0x16c + +/* Only for QMP V4 PHY - RX registers */ +#define QSERDES_V4_RX_UCDR_FO_GAIN_HALF 0x000 +#define QSERDES_V4_RX_UCDR_FO_GAIN_QUARTER 0x004 +#define QSERDES_V4_RX_UCDR_FO_GAIN 0x008 +#define QSERDES_V4_RX_UCDR_SO_GAIN_HALF 0x00c +#define QSERDES_V4_RX_UCDR_SO_GAIN_QUARTER 0x010 +#define QSERDES_V4_RX_UCDR_SO_GAIN 0x014 +#define QSERDES_V4_RX_UCDR_SVS_FO_GAIN_HALF 0x018 +#define QSERDES_V4_RX_UCDR_SVS_FO_GAIN_QUARTER 0x01c +#define QSERDES_V4_RX_UCDR_SVS_FO_GAIN 0x020 +#define QSERDES_V4_RX_UCDR_SVS_SO_GAIN_HALF 0x024 +#define QSERDES_V4_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028 +#define QSERDES_V4_RX_UCDR_SVS_SO_GAIN 0x02c +#define QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN 0x030 +#define QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 +#define QSERDES_V4_RX_UCDR_FO_TO_SO_DELAY 0x038 +#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c +#define QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040 +#define QSERDES_V4_RX_UCDR_PI_CONTROLS 0x044 +#define QSERDES_V4_RX_UCDR_PI_CTRL2 0x048 +#define QSERDES_V4_RX_UCDR_SB2_THRESH1 0x04c +#define QSERDES_V4_RX_UCDR_SB2_THRESH2 0x050 +#define QSERDES_V4_RX_UCDR_SB2_GAIN1 0x054 +#define QSERDES_V4_RX_UCDR_SB2_GAIN2 0x058 +#define QSERDES_V4_RX_AUX_CONTROL 0x05c +#define QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE 0x060 +#define QSERDES_V4_RX_RCLK_AUXDATA_SEL 0x064 +#define QSERDES_V4_RX_AC_JTAG_ENABLE 0x068 +#define QSERDES_V4_RX_AC_JTAG_INITP 0x06c +#define QSERDES_V4_RX_AC_JTAG_INITN 0x070 +#define QSERDES_V4_RX_AC_JTAG_LVL 0x074 +#define QSERDES_V4_RX_AC_JTAG_MODE 0x078 +#define QSERDES_V4_RX_AC_JTAG_RESET 0x07c +#define QSERDES_V4_RX_RX_TERM_BW 0x080 +#define QSERDES_V4_RX_RX_RCVR_IQ_EN 0x084 +#define QSERDES_V4_RX_RX_IDAC_I_DC_OFFSETS 0x088 +#define QSERDES_V4_RX_RX_IDAC_IBAR_DC_OFFSETS 0x08c +#define QSERDES_V4_RX_RX_IDAC_Q_DC_OFFSETS 0x090 +#define QSERDES_V4_RX_RX_IDAC_QBAR_DC_OFFSETS 0x094 +#define QSERDES_V4_RX_RX_IDAC_A_DC_OFFSETS 0x098 +#define QSERDES_V4_RX_RX_IDAC_ABAR_DC_OFFSETS 0x09c +#define QSERDES_V4_RX_RX_IDAC_EN 0x0a0 +#define QSERDES_V4_RX_RX_IDAC_ENABLES 0x0a4 +#define QSERDES_V4_RX_RX_IDAC_SIGN 0x0a8 +#define QSERDES_V4_RX_RX_HIGHZ_HIGHRATE 0x0ac +#define QSERDES_V4_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x0b0 +#define QSERDES_V4_RX_DFE_1 0x0b4 +#define QSERDES_V4_RX_DFE_2 0x0b8 +#define QSERDES_V4_RX_DFE_3 0x0bc +#define QSERDES_V4_RX_DFE_4 0x0c0 +#define QSERDES_V4_RX_TX_ADAPT_PRE_THRESH1 0x0c4 +#define QSERDES_V4_RX_TX_ADAPT_PRE_THRESH2 0x0c8 +#define QSERDES_V4_RX_TX_ADAPT_POST_THRESH 0x0cc +#define QSERDES_V4_RX_TX_ADAPT_MAIN_THRESH 0x0d0 +#define QSERDES_V4_RX_VGA_CAL_CNTRL1 0x0d4 +#define QSERDES_V4_RX_VGA_CAL_CNTRL2 0x0d8 +#define QSERDES_V4_RX_GM_CAL 0x0dc +#define QSERDES_V4_RX_RX_VGA_GAIN2_LSB 0x0e0 +#define QSERDES_V4_RX_RX_VGA_GAIN2_MSB 0x0e4 +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1 0x0e8 +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2 0x0ec +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3 0x0f0 +#define QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4 0x0f4 +#define QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW 0x0f8 +#define QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH 0x0fc +#define QSERDES_V4_RX_RX_IDAC_MEASURE_TIME 0x100 +#define QSERDES_V4_RX_RX_IDAC_ACCUMULATOR 0x104 +#define QSERDES_V4_RX_RX_EQ_OFFSET_LSB 0x108 +#define QSERDES_V4_RX_RX_EQ_OFFSET_MSB 0x10c +#define QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x110 +#define QSERDES_V4_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x114 +#define QSERDES_V4_RX_SIGDET_ENABLES 0x118 +#define QSERDES_V4_RX_SIGDET_CNTRL 0x11c +#define QSERDES_V4_RX_SIGDET_LVL 0x120 +#define QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL 0x124 +#define QSERDES_V4_RX_RX_BAND 0x128 +#define QSERDES_V4_RX_CDR_FREEZE_UP_DN 0x12c +#define QSERDES_V4_RX_CDR_RESET_OVERRIDE 0x130 +#define QSERDES_V4_RX_RX_INTERFACE_MODE 0x134 +#define QSERDES_V4_RX_JITTER_GEN_MODE 0x138 +#define QSERDES_V4_RX_SJ_AMP1 0x13c +#define QSERDES_V4_RX_SJ_AMP2 0x140 +#define QSERDES_V4_RX_SJ_PER1 0x144 +#define QSERDES_V4_RX_SJ_PER2 0x148 +#define QSERDES_V4_RX_PPM_OFFSET1 0x14c +#define QSERDES_V4_RX_PPM_OFFSET2 0x150 +#define QSERDES_V4_RX_SIGN_PPM_PERIOD1 0x154 +#define QSERDES_V4_RX_SIGN_PPM_PERIOD2 0x158 +#define QSERDES_V4_RX_RX_PWM_ENABLE_AND_DATA 0x15c +#define QSERDES_V4_RX_RX_PWM_GEAR1_TIMEOUT_COUNT 0x160 +#define QSERDES_V4_RX_RX_PWM_GEAR2_TIMEOUT_COUNT 0x164 +#define QSERDES_V4_RX_RX_PWM_GEAR3_TIMEOUT_COUNT 0x168 +#define QSERDES_V4_RX_RX_PWM_GEAR4_TIMEOUT_COUNT 0x16c +#define QSERDES_V4_RX_RX_MODE_00_LOW 0x170 +#define QSERDES_V4_RX_RX_MODE_00_HIGH 0x174 +#define QSERDES_V4_RX_RX_MODE_00_HIGH2 0x178 +#define QSERDES_V4_RX_RX_MODE_00_HIGH3 0x17c +#define QSERDES_V4_RX_RX_MODE_00_HIGH4 0x180 +#define QSERDES_V4_RX_RX_MODE_01_LOW 0x184 +#define QSERDES_V4_RX_RX_MODE_01_HIGH 0x188 +#define QSERDES_V4_RX_RX_MODE_01_HIGH2 0x18c +#define QSERDES_V4_RX_RX_MODE_01_HIGH3 0x190 +#define QSERDES_V4_RX_RX_MODE_01_HIGH4 0x194 +#define QSERDES_V4_RX_RX_MODE_10_LOW 0x198 +#define QSERDES_V4_RX_RX_MODE_10_HIGH 0x19c +#define QSERDES_V4_RX_RX_MODE_10_HIGH2 0x1a0 +#define QSERDES_V4_RX_RX_MODE_10_HIGH3 0x1a4 +#define QSERDES_V4_RX_RX_MODE_10_HIGH4 0x1a8 +#define QSERDES_V4_RX_PHPRE_CTRL 0x1ac +#define QSERDES_V4_RX_PHPRE_INITVAL 0x1b0 +#define QSERDES_V4_RX_DFE_EN_TIMER 0x1b4 +#define QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET 0x1b8 +#define QSERDES_V4_RX_DCC_CTRL1 0x1bc +#define QSERDES_V4_RX_DCC_CTRL2 0x1c0 +#define QSERDES_V4_RX_VTH_CODE 0x1c4 +#define QSERDES_V4_RX_VTH_MIN_THRESH 0x1c8 +#define QSERDES_V4_RX_VTH_MAX_THRESH 0x1cc +#define QSERDES_V4_RX_ALOG_OBSV_BUS_CTRL_1 0x1d0 +#define QSERDES_V4_RX_PI_CTRL1 0x1d4 +#define QSERDES_V4_RX_PI_CTRL2 0x1d8 +#define QSERDES_V4_RX_PI_QUAD 0x1dc +#define QSERDES_V4_RX_IDATA1 0x1e0 +#define QSERDES_V4_RX_IDATA2 0x1e4 +#define QSERDES_V4_RX_AUX_DATA1 0x1e8 +#define QSERDES_V4_RX_AUX_DATA2 0x1ec +#define QSERDES_V4_RX_AC_JTAG_OUTP 0x1f0 +#define QSERDES_V4_RX_AC_JTAG_OUTN 0x1f4 +#define QSERDES_V4_RX_RX_SIGDET 0x1f8 +#define QSERDES_V4_RX_ALOG_OBSV_BUS_STATUS_1 0x1fc + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx.h b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx.h new file mode 100644 index 00000000000..d20694513eb --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-qserdes-txrx.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_QSERDES_TXRX_H_ +#define QCOM_PHY_QMP_QSERDES_TXRX_H_ + +/* Only for QMP V2 PHY - TX registers */ +#define QSERDES_TX_BIST_MODE_LANENO 0x000 +#define QSERDES_TX_BIST_INVERT 0x004 +#define QSERDES_TX_CLKBUF_ENABLE 0x008 +#define QSERDES_TX_CMN_CONTROL_ONE 0x00c +#define QSERDES_TX_CMN_CONTROL_TWO 0x010 +#define QSERDES_TX_CMN_CONTROL_THREE 0x014 +#define QSERDES_TX_TX_EMP_POST1_LVL 0x018 +#define QSERDES_TX_TX_POST2_EMPH 0x01c +#define QSERDES_TX_TX_BOOST_LVL_UP_DN 0x020 +#define QSERDES_TX_HP_PD_ENABLES 0x024 +#define QSERDES_TX_TX_IDLE_LVL_LARGE_AMP 0x028 +#define QSERDES_TX_TX_DRV_LVL 0x02c +#define QSERDES_TX_TX_DRV_LVL_OFFSET 0x030 +#define QSERDES_TX_RESET_TSYNC_EN 0x034 +#define QSERDES_TX_PRE_STALL_LDO_BOOST_EN 0x038 +#define QSERDES_TX_TX_BAND 0x03c +#define QSERDES_TX_SLEW_CNTL 0x040 +#define QSERDES_TX_INTERFACE_SELECT 0x044 +#define QSERDES_TX_LPB_EN 0x048 +#define QSERDES_TX_RES_CODE_LANE_TX 0x04c +#define QSERDES_TX_RES_CODE_LANE_RX 0x050 +#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x054 +#define QSERDES_TX_PERL_LENGTH1 0x058 +#define QSERDES_TX_PERL_LENGTH2 0x05c +#define QSERDES_TX_SERDES_BYP_EN_OUT 0x060 +#define QSERDES_TX_DEBUG_BUS_SEL 0x064 +#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x068 +#define QSERDES_TX_TX_POL_INV 0x06c +#define QSERDES_TX_PARRATE_REC_DETECT_IDLE_EN 0x070 +#define QSERDES_TX_BIST_PATTERN1 0x074 +#define QSERDES_TX_BIST_PATTERN2 0x078 +#define QSERDES_TX_BIST_PATTERN3 0x07c +#define QSERDES_TX_BIST_PATTERN4 0x080 +#define QSERDES_TX_BIST_PATTERN5 0x084 +#define QSERDES_TX_BIST_PATTERN6 0x088 +#define QSERDES_TX_BIST_PATTERN7 0x08c +#define QSERDES_TX_BIST_PATTERN8 0x090 +#define QSERDES_TX_LANE_MODE 0x094 +#define QSERDES_TX_IDAC_CAL_LANE_MODE 0x098 +#define QSERDES_TX_IDAC_CAL_LANE_MODE_CONFIGURATION 0x09c +#define QSERDES_TX_ATB_SEL1 0x0a0 +#define QSERDES_TX_ATB_SEL2 0x0a4 +#define QSERDES_TX_RCV_DETECT_LVL 0x0a8 +#define QSERDES_TX_RCV_DETECT_LVL_2 0x0ac +#define QSERDES_TX_PRBS_SEED1 0x0b0 +#define QSERDES_TX_PRBS_SEED2 0x0b4 +#define QSERDES_TX_PRBS_SEED3 0x0b8 +#define QSERDES_TX_PRBS_SEED4 0x0bc +#define QSERDES_TX_RESET_GEN 0x0c0 +#define QSERDES_TX_RESET_GEN_MUXES 0x0c4 +#define QSERDES_TX_TRAN_DRVR_EMP_EN 0x0c8 +#define QSERDES_TX_TX_INTERFACE_MODE 0x0cc +#define QSERDES_TX_PWM_CTRL 0x0d0 +#define QSERDES_TX_PWM_ENCODED_OR_DATA 0x0d4 +#define QSERDES_TX_PWM_GEAR_1_DIVIDER_BAND2 0x0d8 +#define QSERDES_TX_PWM_GEAR_2_DIVIDER_BAND2 0x0dc +#define QSERDES_TX_PWM_GEAR_3_DIVIDER_BAND2 0x0e0 +#define QSERDES_TX_PWM_GEAR_4_DIVIDER_BAND2 0x0e4 +#define QSERDES_TX_PWM_GEAR_1_DIVIDER_BAND0_1 0x0e8 +#define QSERDES_TX_PWM_GEAR_2_DIVIDER_BAND0_1 0x0ec +#define QSERDES_TX_PWM_GEAR_3_DIVIDER_BAND0_1 0x0f0 +#define QSERDES_TX_PWM_GEAR_4_DIVIDER_BAND0_1 0x0f4 +#define QSERDES_TX_VMODE_CTRL1 0x0f8 +#define QSERDES_TX_VMODE_CTRL2 0x0fc +#define QSERDES_TX_TX_ALOG_INTF_OBSV_CNTL 0x100 +#define QSERDES_TX_BIST_STATUS 0x104 +#define QSERDES_TX_BIST_ERROR_COUNT1 0x108 +#define QSERDES_TX_BIST_ERROR_COUNT2 0x10c +#define QSERDES_TX_TX_ALOG_INTF_OBSV 0x110 + +/* Only for QMP V2 PHY - RX registers */ +#define QSERDES_RX_UCDR_FO_GAIN_HALF 0x000 +#define QSERDES_RX_UCDR_FO_GAIN_QUARTER 0x004 +#define QSERDES_RX_UCDR_FO_GAIN_EIGHTH 0x008 +#define QSERDES_RX_UCDR_FO_GAIN 0x00c +#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010 +#define QSERDES_RX_UCDR_SO_GAIN_QUARTER 0x014 +#define QSERDES_RX_UCDR_SO_GAIN_EIGHTH 0x018 +#define QSERDES_RX_UCDR_SO_GAIN 0x01c +#define QSERDES_RX_UCDR_SVS_FO_GAIN_HALF 0x020 +#define QSERDES_RX_UCDR_SVS_FO_GAIN_QUARTER 0x024 +#define QSERDES_RX_UCDR_SVS_FO_GAIN_EIGHTH 0x028 +#define QSERDES_RX_UCDR_SVS_FO_GAIN 0x02c +#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF 0x030 +#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER 0x034 +#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH 0x038 +#define QSERDES_RX_UCDR_SVS_SO_GAIN 0x03c +#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040 +#define QSERDES_RX_UCDR_FD_GAIN 0x044 +#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048 +#define QSERDES_RX_UCDR_FO_TO_SO_DELAY 0x04c +#define QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW 0x050 +#define QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH 0x054 +#define QSERDES_RX_UCDR_MODULATE 0x058 +#define QSERDES_RX_UCDR_PI_CONTROLS 0x05c +#define QSERDES_RX_RBIST_CONTROL 0x060 +#define QSERDES_RX_AUX_CONTROL 0x064 +#define QSERDES_RX_AUX_DATA_TCOARSE 0x068 +#define QSERDES_RX_AUX_DATA_TFINE_LSB 0x06c +#define QSERDES_RX_AUX_DATA_TFINE_MSB 0x070 +#define QSERDES_RX_RCLK_AUXDATA_SEL 0x074 +#define QSERDES_RX_AC_JTAG_ENABLE 0x078 +#define QSERDES_RX_AC_JTAG_INITP 0x07c +#define QSERDES_RX_AC_JTAG_INITN 0x080 +#define QSERDES_RX_AC_JTAG_LVL 0x084 +#define QSERDES_RX_AC_JTAG_MODE 0x088 +#define QSERDES_RX_AC_JTAG_RESET 0x08c +#define QSERDES_RX_RX_TERM_BW 0x090 +#define QSERDES_RX_RX_RCVR_IQ_EN 0x094 +#define QSERDES_RX_RX_IDAC_I_DC_OFFSETS 0x098 +#define QSERDES_RX_RX_IDAC_IBAR_DC_OFFSETS 0x09c +#define QSERDES_RX_RX_IDAC_Q_DC_OFFSETS 0x0a0 +#define QSERDES_RX_RX_IDAC_QBAR_DC_OFFSETS 0x0a4 +#define QSERDES_RX_RX_IDAC_A_DC_OFFSETS 0x0a8 +#define QSERDES_RX_RX_IDAC_ABAR_DC_OFFSETS 0x0ac +#define QSERDES_RX_RX_IDAC_EN 0x0b0 +#define QSERDES_RX_RX_IDAC_ENABLES 0x0b4 +#define QSERDES_RX_RX_IDAC_SIGN 0x0b8 +#define QSERDES_RX_RX_HIGHZ_HIGHRATE 0x0bc +#define QSERDES_RX_RX_TERM_AC_BYPASS_DC_COUPLE_OFFSET 0x0c0 +#define QSERDES_RX_RX_EQ_GAIN1_LSB 0x0c4 +#define QSERDES_RX_RX_EQ_GAIN1_MSB 0x0c8 +#define QSERDES_RX_RX_EQ_GAIN2_LSB 0x0cc +#define QSERDES_RX_RX_EQ_GAIN2_MSB 0x0d0 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 0x0d4 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d8 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x0dc +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x0e0 +#define QSERDES_RX_RX_IDAC_CAL_CONFIGURATION 0x0e4 +#define QSERDES_RX_RX_IDAC_TSETTLE_LOW 0x0e8 +#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH 0x0ec +#define QSERDES_RX_RX_IDAC_ENDSAMP_LOW 0x0f0 +#define QSERDES_RX_RX_IDAC_ENDSAMP_HIGH 0x0f4 +#define QSERDES_RX_RX_IDAC_MIDPOINT_LOW 0x0f8 +#define QSERDES_RX_RX_IDAC_MIDPOINT_HIGH 0x0fc +#define QSERDES_RX_RX_EQ_OFFSET_LSB 0x100 +#define QSERDES_RX_RX_EQ_OFFSET_MSB 0x104 +#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x108 +#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x10c +#define QSERDES_RX_SIGDET_ENABLES 0x110 +#define QSERDES_RX_SIGDET_CNTRL 0x114 +#define QSERDES_RX_SIGDET_LVL 0x118 +#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x11c +#define QSERDES_RX_RX_BAND 0x120 +#define QSERDES_RX_CDR_FREEZE_UP_DN 0x124 +#define QSERDES_RX_CDR_RESET_OVERRIDE 0x128 +#define QSERDES_RX_RX_INTERFACE_MODE 0x12c +#define QSERDES_RX_JITTER_GEN_MODE 0x130 +#define QSERDES_RX_BUJ_AMP 0x134 +#define QSERDES_RX_SJ_AMP1 0x138 +#define QSERDES_RX_SJ_AMP2 0x13c +#define QSERDES_RX_SJ_PER1 0x140 +#define QSERDES_RX_SJ_PER2 0x144 +#define QSERDES_RX_BUJ_STEP_FREQ1 0x148 +#define QSERDES_RX_BUJ_STEP_FREQ2 0x14c +#define QSERDES_RX_PPM_OFFSET1 0x150 +#define QSERDES_RX_PPM_OFFSET2 0x154 +#define QSERDES_RX_SIGN_PPM_PERIOD1 0x158 +#define QSERDES_RX_SIGN_PPM_PERIOD2 0x15c +#define QSERDES_RX_SSC_CTRL 0x160 +#define QSERDES_RX_SSC_COUNT1 0x164 +#define QSERDES_RX_SSC_COUNT2 0x168 +#define QSERDES_RX_RX_ALOG_INTF_OBSV_CNTL 0x16c +#define QSERDES_RX_RX_PWM_ENABLE_AND_DATA 0x170 +#define QSERDES_RX_RX_PWM_GEAR1_TIMEOUT_COUNT 0x174 +#define QSERDES_RX_RX_PWM_GEAR2_TIMEOUT_COUNT 0x178 +#define QSERDES_RX_RX_PWM_GEAR3_TIMEOUT_COUNT 0x17c +#define QSERDES_RX_RX_PWM_GEAR4_TIMEOUT_COUNT 0x180 +#define QSERDES_RX_PI_CTRL1 0x184 +#define QSERDES_RX_PI_CTRL2 0x188 +#define QSERDES_RX_PI_QUAD 0x18c +#define QSERDES_RX_IDATA1 0x190 +#define QSERDES_RX_IDATA2 0x194 +#define QSERDES_RX_AUX_DATA1 0x198 +#define QSERDES_RX_AUX_DATA2 0x19c +#define QSERDES_RX_AC_JTAG_OUTP 0x1a0 +#define QSERDES_RX_AC_JTAG_OUTN 0x1a4 +#define QSERDES_RX_RX_SIGDET 0x1a8 +#define QSERDES_RX_RX_VDCOFF 0x1ac +#define QSERDES_RX_IDAC_CAL_ON 0x1b0 +#define QSERDES_RX_IDAC_STATUS_I 0x1b4 +#define QSERDES_RX_IDAC_STATUS_IBAR 0x1b8 +#define QSERDES_RX_IDAC_STATUS_Q 0x1bc +#define QSERDES_RX_IDAC_STATUS_QBAR 0x1c0 +#define QSERDES_RX_IDAC_STATUS_A 0x1c4 +#define QSERDES_RX_IDAC_STATUS_ABAR 0x1c8 +#define QSERDES_RX_CALST_STATUS_I 0x1cc +#define QSERDES_RX_CALST_STATUS_Q 0x1d0 +#define QSERDES_RX_CALST_STATUS_A 0x1d4 +#define QSERDES_RX_RX_ALOG_INTF_OBSV 0x1d8 +#define QSERDES_RX_READ_EQCODE 0x1dc +#define QSERDES_RX_READ_OFFSETCODE 0x1e0 +#define QSERDES_RX_IA_ERROR_COUNTER_LOW 0x1e4 +#define QSERDES_RX_IA_ERROR_COUNTER_HIGH 0x1e8 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c new file mode 100644 index 00000000000..8908a34df54 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -0,0 +1,1116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (C) 2023-2024 Linaro Limited + * Authors: + * - Bhupesh Sharma <bhupesh.sharma@linaro.org> + * - Neil Armstrong <neil.armstrong@linaro.org> + * + * Based on Linux driver + */ + +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <generic-phy.h> +#include <malloc.h> +#include <reset.h> + +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> + +#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-ufs-v2.h" +#include "phy-qcom-qmp-pcs-ufs-v3.h" +#include "phy-qcom-qmp-pcs-ufs-v4.h" +#include "phy-qcom-qmp-pcs-ufs-v5.h" +#include "phy-qcom-qmp-pcs-ufs-v6.h" + +#include "phy-qcom-qmp-qserdes-com-v4.h" +#include "phy-qcom-qmp-qserdes-com-v6.h" +#include "phy-qcom-qmp-qserdes-txrx-v4.h" +#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h" + +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) +/* QPHY_PCS_READY_STATUS bit */ +#define PCS_READY BIT(0) + +#define PHY_INIT_COMPLETE_TIMEOUT (200 * 10000) + +struct qmp_ufs_init_tbl { + unsigned int offset; + unsigned int val; + /* + * mask of lanes for which this register is written + * for cases when second lane needs different values + */ + u8 lane_mask; +}; + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o, \ + .val = v, \ + .lane_mask = 0xff, \ + } + +#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ + { \ + .offset = o, \ + .val = v, \ + .lane_mask = l, \ + } + +/* set of registers with offsets different per-PHY */ +enum qphy_reg_layout { + /* PCS registers */ + QPHY_SW_RESET, + QPHY_START_CTRL, + QPHY_PCS_READY_STATUS, + QPHY_PCS_POWER_DOWN_CONTROL, + /* Keep last to ensure regs_layout arrays are properly initialized */ + QPHY_LAYOUT_SIZE +}; + +static const unsigned int ufsphy_v2_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V2_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V2_PCS_UFS_READY_STATUS, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const unsigned int ufsphy_v3_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V3_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V3_PCS_UFS_READY_STATUS, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const unsigned int ufsphy_v4_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V4_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V4_PCS_UFS_READY_STATUS, + [QPHY_SW_RESET] = QPHY_V4_PCS_UFS_SW_RESET, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V4_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V6_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V6_PCS_UFS_READY_STATUS, + [QPHY_SW_RESET] = QPHY_V6_PCS_UFS_SW_RESET, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL, +}; + +static const struct qmp_ufs_init_tbl sdm845_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f), +}; + +static const struct qmp_ufs_init_tbl sdm845_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_ufs_init_tbl sdm845_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07), +}; + +static const struct qmp_ufs_init_tbl sdm845_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), +}; + +static const struct qmp_ufs_init_tbl sdm845_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6e), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0x9a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xac), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xdd), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x06), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_2_DIVIDER_BAND0_1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_3_DIVIDER_BAND0_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_PWM_GEAR_4_DIVIDER_BAND0_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_TRAN_DRVR_EMP_EN, 0x0c), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_BAND, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0xf1), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_TERM_BW, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1d), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_MEASURE_TIME, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xf6), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x3d), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xe0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb1), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0xe0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0xb1), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_RX_SIGDET_CTRL2, 0x6d), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_DEBUG_BUS_CLKSEL, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_ufs_init_tbl sm8150_ufsphy_hs_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x10), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_UFS_BIST_FIXED_PAT_CTRL, 0x0a), +}; + +static const struct qmp_ufs_init_tbl sm8250_ufsphy_hs_g4_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xe5), +}; + +static const struct qmp_ufs_init_tbl sm8250_ufsphy_hs_g4_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CTRL2, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_TERM_BW, 0x6f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_MEASURE_TIME, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x2c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x6d), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x6d), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xed), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c), +}; + +static const struct qmp_ufs_init_tbl sm8550_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07), +}; + +static const struct qmp_ufs_init_tbl sm8550_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_ufs_init_tbl sm8550_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c), +}; + +static const struct qmp_ufs_init_tbl sm8550_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), + + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60), + + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60), + + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), + +}; + +static const struct qmp_ufs_init_tbl sm8550_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), +}; + +static const struct qmp_ufs_init_tbl sm8650_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO_MODE1, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07), +}; + +static const struct qmp_ufs_init_tbl sm8650_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), +}; + +static const struct qmp_ufs_init_tbl sm8650_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B2, 0x20), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_SATURATION, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0, 0xfa), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), +}; + +static const struct qmp_ufs_init_tbl sm8650_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0xc1), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5, 0x12), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6, 0x15), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7, 0x19), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), +}; + +struct qmp_ufs_offsets { + u16 serdes; + u16 pcs; + u16 tx; + u16 rx; + /* for PHYs with >= 2 lanes */ + u16 tx2; + u16 rx2; +}; + +struct qmp_ufs_cfg_tbls { + /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + const struct qmp_ufs_init_tbl *serdes; + int serdes_num; + const struct qmp_ufs_init_tbl *tx; + int tx_num; + const struct qmp_ufs_init_tbl *rx; + int rx_num; + const struct qmp_ufs_init_tbl *pcs; + int pcs_num; +}; + +/* struct qmp_ufs_cfg - per-PHY initialization config */ +struct qmp_ufs_cfg { + int lanes; + + const struct qmp_ufs_offsets *offsets; + + /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */ + const struct qmp_ufs_cfg_tbls tbls; + /* Additional sequence for HS Series B */ + const struct qmp_ufs_cfg_tbls tbls_hs_b; + /* Additional sequence for HS G4 */ + const struct qmp_ufs_cfg_tbls tbls_hs_g4; + + /* clock ids to be requested */ + const char * const *clk_list; + int num_clks; + /* regulators to be requested */ + const char * const *vreg_list; + int num_vregs; + /* resets to be requested */ + const char * const *reset_list; + int num_resets; + + /* array of registers with different offsets */ + const unsigned int *regs; + + /* true, if PCS block has no separate SW_RESET register */ + bool no_pcs_sw_reset; +}; + +struct qmp_ufs_priv { + struct phy *phy; + + void __iomem *serdes; + void __iomem *pcs; + void __iomem *pcs_misc; + void __iomem *tx; + void __iomem *rx; + void __iomem *tx2; + void __iomem *rx2; + + struct clk *clks; + unsigned int clk_count; + + struct reset_ctl *resets; + unsigned int reset_count; + + const struct qmp_ufs_cfg *cfg; + + struct udevice *dev; + + u32 mode; + u32 submode; +}; + +static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg |= val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +/* list of clocks required by phy */ +static const char * const sdm845_ufs_phy_clk_l[] = { + "ref", "ref_aux", +}; + +/* list of regulators */ +static const char * const qmp_ufs_vreg_l[] = { + "vdda-phy", "vdda-pll", +}; + +/* list of resets */ +static const char * const qmp_ufs_reset_l[] = { + "ufsphy", +}; + +static const struct qmp_ufs_offsets qmp_ufs_offsets = { + .serdes = 0, + .pcs = 0xc00, + .tx = 0x400, + .rx = 0x600, + .tx2 = 0x800, + .rx2 = 0xa00, +}; + +static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = { + .serdes = 0, + .pcs = 0x0400, + .tx = 0x1000, + .rx = 0x1200, + .tx2 = 0x1800, + .rx2 = 0x1a00, +}; + +static const struct qmp_ufs_cfg sdm845_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sdm845_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes), + .tx = sdm845_ufsphy_tx, + .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx), + .rx = sdm845_ufsphy_rx, + .rx_num = ARRAY_SIZE(sdm845_ufsphy_rx), + .pcs = sdm845_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sdm845_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sdm845_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v3_regs_layout, + + .no_pcs_sw_reset = true, +}; + +static const struct qmp_ufs_cfg sm8250_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sm8150_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8150_ufsphy_serdes), + .tx = sm8150_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8150_ufsphy_tx), + .rx = sm8150_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8150_ufsphy_rx), + .pcs = sm8150_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8150_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8150_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), + }, + .tbls_hs_g4 = { + .tx = sm8250_ufsphy_hs_g4_tx, + .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), + .rx = sm8250_ufsphy_hs_g4_rx, + .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx), + .pcs = sm8150_ufsphy_hs_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .reset_list = qmp_ufs_reset_l, + .num_resets = ARRAY_SIZE(qmp_ufs_reset_l), + .regs = ufsphy_v4_regs_layout, + + .no_pcs_sw_reset = false, +}; + +static const struct qmp_ufs_cfg sm8550_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets_v6, + + .tbls = { + .serdes = sm8550_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_serdes), + .tx = sm8550_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_tx), + .rx = sm8550_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_rx), + .pcs = sm8550_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8550_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v6_regs_layout, + + .no_pcs_sw_reset = false, +}; + +static const struct qmp_ufs_cfg sm8650_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets_v6, + + .tbls = { + .serdes = sm8650_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8650_ufsphy_serdes), + .tx = sm8650_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8650_ufsphy_tx), + .rx = sm8650_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8650_ufsphy_rx), + .pcs = sm8650_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8650_ufsphy_pcs), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v6_regs_layout, + + .no_pcs_sw_reset = false, +}; + +static void qmp_ufs_configure_lane(void __iomem *base, + const struct qmp_ufs_init_tbl tbl[], + int num, + u8 lane_mask) +{ + int i; + const struct qmp_ufs_init_tbl *t = tbl; + + if (!t) + return; + + for (i = 0; i < num; i++, t++) { + if (!(t->lane_mask & lane_mask)) + continue; + + writel(t->val, base + t->offset); + } +} + +static void qmp_ufs_configure(void __iomem *base, + const struct qmp_ufs_init_tbl tbl[], + int num) +{ + qmp_ufs_configure_lane(base, tbl, num, 0xff); +} + +static void qmp_ufs_serdes_init(struct qmp_ufs_priv *qmp, const struct qmp_ufs_cfg_tbls *tbls) +{ + void __iomem *serdes = qmp->serdes; + + qmp_ufs_configure(serdes, tbls->serdes, tbls->serdes_num); +} + +static void qmp_ufs_lanes_init(struct qmp_ufs_priv *qmp, const struct qmp_ufs_cfg_tbls *tbls) +{ + const struct qmp_ufs_cfg *cfg = qmp->cfg; + void __iomem *tx = qmp->tx; + void __iomem *rx = qmp->rx; + + qmp_ufs_configure_lane(tx, tbls->tx, tbls->tx_num, 1); + qmp_ufs_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + + if (cfg->lanes >= 2) { + qmp_ufs_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); + qmp_ufs_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); + } +} + +static void qmp_ufs_pcs_init(struct qmp_ufs_priv *qmp, const struct qmp_ufs_cfg_tbls *tbls) +{ + void __iomem *pcs = qmp->pcs; + + qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num); +} + +static void qmp_ufs_init_registers(struct qmp_ufs_priv *qmp, const struct qmp_ufs_cfg *cfg) +{ + /* We support 'PHY_MODE_UFS_HS_B' mode & 'UFS_HS_G3' submode for now. */ + qmp_ufs_serdes_init(qmp, &cfg->tbls); + qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b); + qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_g4); + qmp_ufs_lanes_init(qmp, &cfg->tbls); + qmp_ufs_pcs_init(qmp, &cfg->tbls); +} + +static int qmp_ufs_do_reset(struct qmp_ufs_priv *qmp) +{ + int i, ret; + + for (i = 0; i < qmp->reset_count; i++) { + ret = reset_assert(&qmp->resets[i]); + if (ret) + return ret; + } + + udelay(10); + + for (i = 0; i < qmp->reset_count; i++) { + ret = reset_deassert(&qmp->resets[i]); + if (ret) + return ret; + } + + udelay(50); + + return 0; +} + +static int qmp_ufs_power_on(struct phy *phy) +{ + struct qmp_ufs_priv *qmp = dev_get_priv(phy->dev); + const struct qmp_ufs_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + void __iomem *status; + unsigned int val; + int ret; + + /* Power down PHY */ + qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + + qmp_ufs_init_registers(qmp, cfg); + + if (cfg->no_pcs_sw_reset) { + ret = qmp_ufs_do_reset(qmp); + if (ret) { + dev_err(phy->dev, "qmp reset failed\n"); + return ret; + } + } + + /* Pull PHY out of reset state */ + if (!cfg->no_pcs_sw_reset) + qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* start SerDes */ + qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], SERDES_START); + + status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; + ret = readl_poll_timeout(status, val, (val & PCS_READY), PHY_INIT_COMPLETE_TIMEOUT); + if (ret) { + dev_err(phy->dev, "phy initialization timed-out\n"); + return ret; + } + + return 0; +} + +static int qmp_ufs_power_off(struct phy *phy) +{ + struct qmp_ufs_priv *qmp = dev_get_priv(phy->dev); + const struct qmp_ufs_cfg *cfg = qmp->cfg; + + /* PHY reset */ + qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* stop SerDes and Phy-Coding-Sublayer */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], + SERDES_START | PCS_START); + + /* Put PHY into POWER DOWN state: active low */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], + SW_PWRDN); + + clk_release_all(qmp->clks, qmp->clk_count); + + return 0; +} + +static int qmp_ufs_vreg_init(struct udevice *dev, struct qmp_ufs_priv *qmp) +{ + /* TOFIX: Add regulator support, but they should be voted at boot time already */ + + return 0; +} + +static int qmp_ufs_reset_init(struct udevice *dev, struct qmp_ufs_priv *qmp) +{ + const struct qmp_ufs_cfg *cfg = qmp->cfg; + int num = cfg->num_resets; + int i, ret; + + qmp->reset_count = 0; + qmp->resets = devm_kcalloc(dev, num, sizeof(*qmp->resets), GFP_KERNEL); + if (!qmp->resets) + return -ENOMEM; + + for (i = 0; i < num; i++) { + ret = reset_get_by_index(dev, i, &qmp->resets[i]); + if (ret < 0) { + dev_err(dev, "failed to get reset %d\n", i); + goto reset_get_err; + } + + ++qmp->reset_count; + } + + return 0; + +reset_get_err: + ret = reset_release_all(qmp->resets, qmp->reset_count); + if (ret) + dev_warn(dev, "failed to disable all resets\n"); + + return ret; +} + +static int qmp_ufs_clk_init(struct udevice *dev, struct qmp_ufs_priv *qmp) +{ + const struct qmp_ufs_cfg *cfg = qmp->cfg; + int num = cfg->num_clks; + int i, ret; + + qmp->clk_count = 0; + qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); + if (!qmp->clks) + return -ENOMEM; + + for (i = 0; i < num; i++) { + ret = clk_get_by_index(dev, i, &qmp->clks[i]); + if (ret < 0) + goto clk_get_err; + + ret = clk_enable(&qmp->clks[i]); + if (ret && ret != -ENOSYS) { + dev_err(dev, "failed to enable clock %d\n", i); + goto clk_get_err; + } + + ++qmp->clk_count; + } + + return 0; + +clk_get_err: + ret = clk_release_all(qmp->clks, qmp->clk_count); + if (ret) + dev_warn(dev, "failed to disable all clocks\n"); + + return ret; +} + +static int qmp_ufs_probe_generic_child(struct udevice *dev, + ofnode child) +{ + struct qmp_ufs_priv *qmp = dev_get_priv(dev); + const struct qmp_ufs_cfg *cfg = qmp->cfg; + struct resource res; + int ret; + + /* + * Get memory resources for the PHY: + * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. + * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 + * For single lane PHYs: pcs_misc (optional) -> 3. + */ + ret = ofnode_read_resource(child, 0, &res); + if (ret) { + dev_err(dev, "can't get reg property of child %s\n", + ofnode_get_name(child)); + return ret; + } + + qmp->tx = (void __iomem *)res.start; + + ret = ofnode_read_resource(child, 1, &res); + if (ret) { + dev_err(dev, "can't get reg property of child %s\n", + ofnode_get_name(child)); + return ret; + } + + qmp->rx = (void __iomem *)res.start; + + ret = ofnode_read_resource(child, 2, &res); + if (ret) { + dev_err(dev, "can't get reg property of child %s\n", + ofnode_get_name(child)); + return ret; + } + + qmp->pcs = (void __iomem *)res.start; + + if (cfg->lanes >= 2) { + ret = ofnode_read_resource(child, 3, &res); + if (ret) { + dev_err(dev, "can't get reg property of child %s\n", + ofnode_get_name(child)); + return ret; + } + + qmp->tx2 = (void __iomem *)res.start; + + ret = ofnode_read_resource(child, 4, &res); + if (ret) { + dev_err(dev, "can't get reg property of child %s\n", + ofnode_get_name(child)); + return ret; + } + + qmp->rx2 = (void __iomem *)res.start; + + ret = ofnode_read_resource(child, 5, &res); + if (ret) + qmp->pcs_misc = NULL; + } else { + ret = ofnode_read_resource(child, 3, &res); + if (ret) + qmp->pcs_misc = NULL; + } + + return 0; +} + +static int qmp_ufs_probe_dt_children(struct udevice *dev) +{ + int ret; + ofnode child; + + ofnode_for_each_subnode(child, dev_ofnode(dev)) { + ret = qmp_ufs_probe_generic_child(dev, child); + if (ret) { + dev_err(dev, "Cannot parse child %s:%d\n", + ofnode_get_name(child), ret); + return ret; + } + } + + return 0; +} + +static int qmp_ufs_probe(struct udevice *dev) +{ + struct qmp_ufs_priv *qmp = dev_get_priv(dev); + int ret; + + qmp->serdes = (void __iomem *)dev_read_addr(dev); + if (IS_ERR(qmp->serdes)) + return PTR_ERR(qmp->serdes); + + qmp->cfg = (const struct qmp_ufs_cfg *)dev_get_driver_data(dev); + if (!qmp->cfg) + return -EINVAL; + + ret = qmp_ufs_clk_init(dev, qmp); + if (ret) { + dev_err(dev, "failed to get UFS clks\n"); + return ret; + } + + ret = qmp_ufs_vreg_init(dev, qmp); + if (ret) { + dev_err(dev, "failed to get UFS voltage regulators\n"); + return ret; + } + + if (qmp->cfg->no_pcs_sw_reset) { + ret = qmp_ufs_reset_init(dev, qmp); + if (ret) { + dev_err(dev, "failed to get UFS resets\n"); + return ret; + } + } + + qmp->dev = dev; + + if (ofnode_get_child_count(dev_ofnode(dev))) { + ret = qmp_ufs_probe_dt_children(dev); + if (ret) { + dev_err(dev, "failed to get UFS dt regs\n"); + return ret; + } + } else { + const struct qmp_ufs_offsets *offs = qmp->cfg->offsets; + struct resource res; + + if (!qmp->cfg->offsets) { + dev_err(dev, "missing UFS offsets\n"); + return -EINVAL; + } + + ret = ofnode_read_resource(dev_ofnode(dev), 0, &res); + if (ret) { + dev_err(dev, "can't get reg property\n"); + return ret; + } + + qmp->serdes = (void __iomem *)res.start + offs->serdes; + qmp->pcs = (void __iomem *)res.start + offs->pcs; + qmp->tx = (void __iomem *)res.start + offs->tx; + qmp->rx = (void __iomem *)res.start + offs->rx; + + if (qmp->cfg->lanes >= 2) { + qmp->tx2 = (void __iomem *)res.start + offs->tx2; + qmp->rx2 = (void __iomem *)res.start + offs->rx2; + } + } + + return 0; +} + +static struct phy_ops qmp_ufs_ops = { + .power_on = qmp_ufs_power_on, + .power_off = qmp_ufs_power_off, +}; + +static const struct udevice_id qmp_ufs_ids[] = { + { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, + { .compatible = "qcom,sm8550-qmp-ufs-phy", .data = (ulong)&sm8550_ufsphy_cfg }, + { .compatible = "qcom,sm8650-qmp-ufs-phy", .data = (ulong)&sm8650_ufsphy_cfg }, + { } +}; + +U_BOOT_DRIVER(qcom_qmp_ufs) = { + .name = "qcom-qmp-ufs", + .id = UCLASS_PHY, + .of_match = qmp_ufs_ids, + .ops = &qmp_ufs_ops, + .probe = qmp_ufs_probe, + .priv_auto = sizeof(struct qmp_ufs_priv), +}; diff --git a/drivers/phy/qcom/phy-qcom-qmp.h b/drivers/phy/qcom/phy-qcom-qmp.h new file mode 100644 index 00000000000..99f4d447caf --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_H_ +#define QCOM_PHY_QMP_H_ + +#include "phy-qcom-qmp-qserdes-com.h" +#include "phy-qcom-qmp-qserdes-txrx.h" + +#include "phy-qcom-qmp-qserdes-com-v3.h" +#include "phy-qcom-qmp-qserdes-txrx-v3.h" + +#include "phy-qcom-qmp-qserdes-pll.h" + +#include "phy-qcom-qmp-pcs-v2.h" + +#include "phy-qcom-qmp-pcs-v3.h" + +/* Only for QMP V3 & V4 PHY - DP COM registers */ +#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 +#define QPHY_V3_DP_COM_SW_RESET 0x04 +#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 +#define QPHY_V3_DP_COM_SWI_CTRL 0x0c +#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 +#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 +#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c + +/* QSERDES V3 COM bits */ +# define QSERDES_V3_COM_BIAS_EN 0x0001 +# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 +# define QSERDES_V3_COM_CLKBUF_R_EN 0x0004 +# define QSERDES_V3_COM_CLKBUF_L_EN 0x0008 +# define QSERDES_V3_COM_EN_SYSCLK_TX_SEL 0x0010 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_L 0x0020 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_R 0x0040 + +/* QSERDES V3 TX bits */ +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN 0x0020 +# define DP_PHY_TXn_TX_DRV_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_DRV_LVL_MUX_EN 0x0020 + +/* QMP PHY - DP PHY registers */ +#define QSERDES_DP_PHY_REVISION_ID0 0x000 +#define QSERDES_DP_PHY_REVISION_ID1 0x004 +#define QSERDES_DP_PHY_REVISION_ID2 0x008 +#define QSERDES_DP_PHY_REVISION_ID3 0x00c +#define QSERDES_DP_PHY_CFG 0x010 +#define QSERDES_DP_PHY_PD_CTL 0x018 +# define DP_PHY_PD_CTL_PWRDN 0x001 +# define DP_PHY_PD_CTL_PSR_PWRDN 0x002 +# define DP_PHY_PD_CTL_AUX_PWRDN 0x004 +# define DP_PHY_PD_CTL_LANE_0_1_PWRDN 0x008 +# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 +# define DP_PHY_PD_CTL_PLL_PWRDN 0x020 +# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 +#define QSERDES_DP_PHY_MODE 0x01c +#define QSERDES_DP_PHY_AUX_CFG0 0x020 +#define QSERDES_DP_PHY_AUX_CFG1 0x024 +#define QSERDES_DP_PHY_AUX_CFG2 0x028 +#define QSERDES_DP_PHY_AUX_CFG3 0x02c +#define QSERDES_DP_PHY_AUX_CFG4 0x030 +#define QSERDES_DP_PHY_AUX_CFG5 0x034 +#define QSERDES_DP_PHY_AUX_CFG6 0x038 +#define QSERDES_DP_PHY_AUX_CFG7 0x03c +#define QSERDES_DP_PHY_AUX_CFG8 0x040 +#define QSERDES_DP_PHY_AUX_CFG9 0x044 + +/* Only for QMP V3 PHY - DP PHY registers */ +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 +# define PHY_AUX_STOP_ERR_MASK 0x01 +# define PHY_AUX_DEC_ERR_MASK 0x02 +# define PHY_AUX_SYNC_ERR_MASK 0x04 +# define PHY_AUX_ALIGN_ERR_MASK 0x08 +# define PHY_AUX_REQ_ERR_MASK 0x10 + +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c +#define QSERDES_V3_DP_PHY_AUX_BIST_CFG 0x050 + +#define QSERDES_V3_DP_PHY_VCO_DIV 0x064 +#define QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL 0x06c +#define QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL 0x088 + +#define QSERDES_V3_DP_PHY_SPARE0 0x0ac +#define DP_PHY_SPARE0_MASK 0x0f +#define DP_PHY_SPARE0_ORIENTATION_INFO_SHIFT 0x04(0x0004) + +#define QSERDES_V3_DP_PHY_STATUS 0x0c0 + +/* Only for QMP V4 PHY - DP PHY registers */ +#define QSERDES_V4_DP_PHY_CFG_1 0x014 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 +#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c +#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V4_DP_PHY_STATUS 0x0dc + +/* Only for QMP V4 PHY - PCS_MISC registers */ +#define QPHY_V4_PCS_MISC_TYPEC_CTRL 0x00 +#define QPHY_V4_PCS_MISC_TYPEC_PWRDN_CTRL 0x04 +#define QPHY_V4_PCS_MISC_PCS_MISC_CONFIG1 0x08 +#define QPHY_V4_PCS_MISC_CLAMP_ENABLE 0x0c +#define QPHY_V4_PCS_MISC_TYPEC_STATUS 0x10 +#define QPHY_V4_PCS_MISC_PLACEHOLDER_STATUS 0x14 + +/* Only for QMP V6 PHY - DP PHY registers */ +#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 +#define QSERDES_V6_DP_PHY_STATUS 0x0e4 + +#endif diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile index 873ddbf0363..699901fd15e 100644 --- a/drivers/phy/ti/Makefile +++ b/drivers/phy/ti/Makefile @@ -1 +1 @@ -obj-$(CONFIG_$(SPL_)PHY_J721E_WIZ) += phy-j721e-wiz.o +obj-$(CONFIG_$(XPL_)PHY_J721E_WIZ) += phy-j721e-wiz.o diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 6d7b7cd9051..634047a91f4 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,13 +1,13 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += pinctrl-uclass.o -obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o +obj-$(CONFIG_$(XPL_)PINCTRL_GENERIC) += pinctrl-generic.o obj-$(CONFIG_PINCTRL_APPLE) += pinctrl-apple.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-y += nxp/ -obj-$(CONFIG_$(SPL_)PINCTRL_ROCKCHIP) += rockchip/ +obj-$(CONFIG_$(XPL_)PINCTRL_ROCKCHIP) += rockchip/ obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_ATH79) += ath79/ obj-$(CONFIG_PINCTRL_INTEL) += intel/ @@ -18,7 +18,7 @@ obj-$(CONFIG_ARCH_RENESAS) += renesas/ obj-$(CONFIG_ARCH_RZN1) += renesas/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ -obj-$(CONFIG_$(SPL_)PINCTRL_TEGRA) += tegra/ +obj-$(CONFIG_$(XPL_)PINCTRL_TEGRA) += tegra/ obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ @@ -32,7 +32,7 @@ obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o -obj-$(CONFIG_$(SPL_)PINCTRL_STMFX) += pinctrl-stmfx.o +obj-$(CONFIG_$(XPL_)PINCTRL_STMFX) += pinctrl-stmfx.o obj-y += broadcom/ obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/intel/pinctrl.c b/drivers/pinctrl/intel/pinctrl.c index 6cfe83a593a..19525f82a22 100644 --- a/drivers/pinctrl/intel/pinctrl.c +++ b/drivers/pinctrl/intel/pinctrl.c @@ -273,7 +273,7 @@ static int pinctrl_configure_itss(struct udevice *dev, irq = pcr_read32(dev, PAD_CFG1_OFFSET(pad_cfg_offset)); irq &= PAD_CFG1_IRQ_MASK; if (!irq) { - if (spl_phase() > PHASE_TPL) + if (xpl_phase() > PHASE_TPL) log_err("GPIO %u doesn't support APIC routing\n", cfg->pad); @@ -315,7 +315,7 @@ static int pinctrl_pad_reset_config_override(const struct pad_community *comm, return config_value; } } - if (spl_phase() > PHASE_TPL) + if (xpl_phase() > PHASE_TPL) log_err("Logical-to-Chipset mapping not found\n"); return -ENOENT; @@ -622,7 +622,7 @@ int intel_pinctrl_of_to_plat(struct udevice *dev, struct intel_pinctrl_priv *priv = dev_get_priv(dev); if (!comm) { - if (spl_phase() > PHASE_TPL) + if (xpl_phase() > PHASE_TPL) log_err("Cannot find community for pid %d\n", pplat->pid); return -EDOM; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c index 114f2602b28..46a5b6637c9 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c @@ -749,6 +749,7 @@ U_BOOT_DRIVER(mt7622_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7622_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7622_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c index 2703e6f754c..55e49a790e4 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -1410,6 +1410,7 @@ U_BOOT_DRIVER(mt7623_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7623_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7623_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c index 45d4def316d..3b82423c145 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7629.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c @@ -413,6 +413,7 @@ U_BOOT_DRIVER(mt7629_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7629_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7629_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c index 4bc4abe6518..047e37bc9cd 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -1048,6 +1048,7 @@ U_BOOT_DRIVER(mt7981_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7981_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7981_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), .flags = DM_FLAG_PRE_RELOC, diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c index 819d64488f3..bf8cd037535 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c @@ -773,6 +773,7 @@ U_BOOT_DRIVER(mt7986_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7986_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7986_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/drivers/pinctrl/mediatek/pinctrl-mt7988.c index 03a38e83dfa..1f384e86f4e 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7988.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7988.c @@ -1269,6 +1269,7 @@ U_BOOT_DRIVER(mt7988_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt7988_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt7988_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8512.c b/drivers/pinctrl/mediatek/pinctrl-mt8512.c index bc5fb83ac68..5a8dd4ddd40 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8512.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8512.c @@ -382,6 +382,7 @@ U_BOOT_DRIVER(mt8512_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt8512_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt8512_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8516.c b/drivers/pinctrl/mediatek/pinctrl-mt8516.c index 7487d6f0605..9c25066fc2d 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8516.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8516.c @@ -388,6 +388,7 @@ U_BOOT_DRIVER(mt8516_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt8516_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt8516_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8518.c b/drivers/pinctrl/mediatek/pinctrl-mt8518.c index 66fcfdff144..333184a6bb2 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8518.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8518.c @@ -408,6 +408,7 @@ U_BOOT_DRIVER(mt8518_pinctrl) = { .id = UCLASS_PINCTRL, .of_match = mt8518_pctrl_match, .ops = &mtk_pinctrl_ops, + .bind = mtk_pinctrl_common_bind, .probe = mtk_pinctrl_mt8518_probe, .priv_auto = sizeof(struct mtk_pinctrl_priv), }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index ede3959c94f..3760c4611ce 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -671,7 +671,7 @@ const struct pinctrl_ops mtk_pinctrl_ops = { }; #if CONFIG_IS_ENABLED(DM_GPIO) || \ - (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO)) + (defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_GPIO)) static int mtk_gpio_get(struct udevice *dev, unsigned int off) { int val, err; @@ -791,11 +791,20 @@ bind: } #endif +int mtk_pinctrl_common_bind(struct udevice *dev) +{ +#if CONFIG_IS_ENABLED(DM_GPIO) || \ + (defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_GPIO)) + return mtk_gpiochip_register(dev); +#else + return 0; +#endif +} + int mtk_pinctrl_common_probe(struct udevice *dev, const struct mtk_pinctrl_soc *soc) { struct mtk_pinctrl_priv *priv = dev_get_priv(dev); - int ret = 0; u32 i = 0; fdt_addr_t addr; u32 base_calc = soc->base_calc; @@ -813,10 +822,5 @@ int mtk_pinctrl_common_probe(struct udevice *dev, priv->base[i] = (void __iomem *)addr; } -#if CONFIG_IS_ENABLED(DM_GPIO) || \ - (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO)) - ret = mtk_gpiochip_register(dev); -#endif - - return ret; + return 0; } diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h index c948b808434..15ab3c1bf07 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h @@ -241,6 +241,7 @@ extern const struct pinctrl_ops mtk_pinctrl_ops; /* A common read-modify-write helper for MediaTek chips */ void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set); void mtk_i_rmw(struct udevice *dev, u8 i, u32 reg, u32 mask, u32 set); +int mtk_pinctrl_common_bind(struct udevice *dev); int mtk_pinctrl_common_probe(struct udevice *dev, const struct mtk_pinctrl_soc *soc); diff --git a/drivers/pinctrl/nxp/pinctrl-imx.c b/drivers/pinctrl/nxp/pinctrl-imx.c index ff466c49104..b1960c56b51 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx.c +++ b/drivers/pinctrl/nxp/pinctrl-imx.c @@ -22,7 +22,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config) { struct imx_pinctrl_priv *priv = dev_get_priv(dev); struct imx_pinctrl_soc_info *info = priv->info; - int node = dev_of_offset(config); + ofnode node = dev_ofnode(config); const struct fdt_property *prop; u32 *pin_data; int npins, size, pin_size; @@ -40,7 +40,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config) else pin_size = FSL_PIN_SIZE; - prop = fdt_getprop(gd->fdt_blob, node, "fsl,pins", &size); + prop = ofnode_get_property(node, "fsl,pins", &size); if (!prop) { dev_err(dev, "No fsl,pins property in node %s\n", config->name); return -EINVAL; @@ -56,8 +56,8 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config) if (!pin_data) return -ENOMEM; - if (fdtdec_get_int_array(gd->fdt_blob, node, "fsl,pins", - pin_data, size >> 2)) { + if (ofnode_read_u32_array(node, "fsl,pins", + pin_data, size >> 2)) { dev_err(dev, "Error reading pin data.\n"); devm_kfree(dev, pin_data); return -EINVAL; @@ -202,10 +202,11 @@ int imx_pinctrl_probe(struct udevice *dev, struct imx_pinctrl_soc_info *info) { struct imx_pinctrl_priv *priv = dev_get_priv(dev); - int node = dev_of_offset(dev), ret; - struct fdtdec_phandle_args arg; + struct ofnode_phandle_args arg; + ofnode node = dev_ofnode(dev); fdt_addr_t addr; fdt_size_t size; + int ret; if (!info) { dev_err(dev, "wrong pinctrl info\n"); @@ -218,7 +219,7 @@ int imx_pinctrl_probe(struct udevice *dev, if (info->flags & IMX8_USE_SCU) return 0; - addr = devfdt_get_addr_size_index(dev, 0, &size); + addr = ofnode_get_addr_size_index(dev_ofnode(dev), 0, &size); if (addr == FDT_ADDR_T_NONE) return -EINVAL; @@ -227,22 +228,20 @@ int imx_pinctrl_probe(struct udevice *dev, return -ENOMEM; priv->info = info; - info->mux_mask = fdtdec_get_int(gd->fdt_blob, node, "fsl,mux_mask", 0); + info->mux_mask = ofnode_read_u32(node, "fsl,mux_mask", 0); /* * Refer to linux documentation for details: * Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt */ - if (fdtdec_get_bool(gd->fdt_blob, node, "fsl,input-sel")) { - ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, - node, "fsl,input-sel", + if (ofnode_read_bool(node, "fsl,input-sel")) { + ret = ofnode_parse_phandle_with_args(node, "fsl,input-sel", NULL, 0, 0, &arg); if (ret) { dev_err(dev, "iomuxc fsl,input-sel property not found\n"); return -EINVAL; } - addr = fdtdec_get_addr_size(gd->fdt_blob, arg.node, "reg", - &size); + addr = ofnode_get_addr_size(arg.node, "reg", &size); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index eada1001240..fbf0271f08a 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -39,7 +39,7 @@ struct stm32_gpio_bank { struct list_head list; }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static char pin_name[PINNAME_SIZE]; static const char * const pinmux_mode[GPIOF_COUNT] = { @@ -488,7 +488,7 @@ static struct pinctrl_ops stm32_pinctrl_ops = { #else /* PINCTRL_FULL */ .set_state_simple = stm32_pinctrl_set_state_simple, #endif /* PINCTRL_FULL */ -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD .get_pin_name = stm32_pinctrl_get_pin_name, .get_pins_count = stm32_pinctrl_get_pins_count, .get_pin_muxing = stm32_pinctrl_get_pin_muxing, diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index b326fa85140..4f93a34281d 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -55,6 +55,13 @@ config PINCTRL_QCOM_SM6115 Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_SM8150 + bool "Qualcomm SM8150 GCC" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM8150 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SM8250 bool "Qualcomm SM8250 GCC" select PINCTRL_QCOM @@ -74,6 +81,7 @@ config PINCTRL_QCOM_SM8650 select PINCTRL_QCOM help Say Y here to enable support for pinctrl on the Snapdragon SM8650 SoC, + as well as the associated GPIO driver. endmenu diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 4f1d96787be..43d0dd29222 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o +obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o obj-$(CONFIG_PINCTRL_QCOM_SM8650) += pinctrl-sm8650.o diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c new file mode 100644 index 00000000000..1fb2ffb9597 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Qualcomm SM8150 pinctrl and GPIO driver + * + * Volodymyr Babchuk <volodymyr_babchuk@epam.com> + * Copyright (c) 2024 EPAM Systems. + * + * (C) Copyright 2024 Julius Lehmann <lehmanju@devpi.de> + * + * Based on similar U-Boot drivers. Constants were taken from the Linux driver + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define WEST 0x100000 +#define EAST 0x500000 +#define NORTH 0x900000 +#define SOUTH 0xd00000 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + { "qup2", 1 }, + { "gpio", 0 }, +}; + +static const unsigned int sm8150_pin_offsets[] = { + [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, + [4] = SOUTH, [5] = SOUTH, [6] = SOUTH, [7] = SOUTH, + [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH, + [12] = NORTH, [13] = NORTH, [14] = NORTH, [15] = NORTH, + [16] = NORTH, [17] = NORTH, [18] = NORTH, [19] = NORTH, + [20] = NORTH, [21] = EAST, [22] = EAST, [23] = EAST, + [24] = EAST, [25] = EAST, [26] = EAST, [27] = EAST, + [28] = EAST, [29] = EAST, [30] = EAST, [31] = NORTH, + [32] = NORTH, [33] = NORTH, [34] = NORTH, [35] = NORTH, + [36] = NORTH, [37] = NORTH, [38] = SOUTH, [39] = NORTH, + [40] = NORTH, [41] = NORTH, [42] = NORTH, [43] = EAST, + [44] = EAST, [45] = EAST, [46] = EAST, [47] = EAST, + [48] = EAST, [49] = EAST, [50] = EAST, [51] = SOUTH, + [52] = SOUTH, [53] = SOUTH, [54] = SOUTH, [55] = SOUTH, + [56] = SOUTH, [57] = SOUTH, [58] = SOUTH, [59] = SOUTH, + [60] = SOUTH, [61] = SOUTH, [62] = SOUTH, [63] = SOUTH, + [64] = SOUTH, [65] = SOUTH, [66] = SOUTH, [67] = SOUTH, + [68] = SOUTH, [69] = SOUTH, [70] = SOUTH, [71] = SOUTH, + [72] = SOUTH, [73] = SOUTH, [74] = SOUTH, [75] = SOUTH, + [76] = SOUTH, [77] = SOUTH, [78] = SOUTH, [79] = SOUTH, + [80] = SOUTH, [81] = SOUTH, [82] = SOUTH, [83] = NORTH, + [84] = NORTH, [85] = NORTH, [86] = NORTH, [87] = EAST, + [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH, + [92] = NORTH, [93] = NORTH, [94] = NORTH, [95] = NORTH, + [96] = NORTH, [97] = NORTH, [98] = SOUTH, [99] = SOUTH, + [100] = SOUTH, [101] = SOUTH, [102] = NORTH, [103] = NORTH, + [104] = NORTH, [105] = WEST, [106] = WEST, [107] = WEST, + [108] = WEST, [109] = WEST, [110] = WEST, [111] = WEST, + [112] = WEST, [113] = WEST, [114] = SOUTH, [115] = SOUTH, + [116] = SOUTH, [117] = SOUTH, [118] = SOUTH, [119] = SOUTH, + [120] = SOUTH, [121] = SOUTH, [122] = SOUTH, [123] = SOUTH, + [124] = SOUTH, [125] = WEST, [126] = SOUTH, [127] = SOUTH, + [128] = SOUTH, [129] = SOUTH, [130] = SOUTH, [131] = SOUTH, + [132] = SOUTH, [133] = SOUTH, [134] = SOUTH, [135] = SOUTH, + [136] = SOUTH, [137] = SOUTH, [138] = SOUTH, [139] = SOUTH, + [140] = SOUTH, [141] = SOUTH, [142] = SOUTH, [143] = SOUTH, + [144] = SOUTH, [145] = SOUTH, [146] = SOUTH, [147] = SOUTH, + [148] = SOUTH, [149] = SOUTH, [150] = SOUTH, [151] = SOUTH, + [152] = SOUTH, [153] = SOUTH, [154] = SOUTH, [155] = WEST, + [156] = WEST, [157] = WEST, [158] = WEST, [159] = WEST, + [160] = WEST, [161] = WEST, [162] = WEST, [163] = WEST, + [164] = WEST, [165] = WEST, [166] = WEST, [167] = WEST, + [168] = WEST, [169] = NORTH, [170] = NORTH, [171] = NORTH, + [172] = NORTH, [173] = NORTH, [174] = NORTH, +}; + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x04, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data msm_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb6000), + [1] = SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0xb2000, 14, 6), + [2] = SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0xb2000, 11, 3), + [3] = SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0xb2000, 9, 0), +}; + +static const char *sm8150_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm8150_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 175 && selector <= 178) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 175].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static unsigned int sm8150_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm8150_data = { + .pin_data = { + .pin_offsets = sm8150_pin_offsets, + .pin_count = 179, + .special_pins_start = 175, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm8150_get_function_name, + .get_function_mux = sm8150_get_function_mux, + .get_pin_name = sm8150_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm8150-pinctrl", .data = (ulong)&sm8150_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm8150) = { + .name = "pinctrl_sm8150", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index dac24f11bc2..cab42fa64ed 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -18,8 +18,37 @@ static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); static const struct pinctrl_function msm_pinctrl_functions[] = { { "qup12", 1 }, - { "gpio", 0 }, - { "sdc2_clk", 0 } }; + { "gpio", 0 }, }; +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm8250_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", SOUTH + 0xb8000), + [1] = SDC_PINGROUP("sdc2_clk", NORTH + 0xb7000, 14, 6), + [2] = SDC_PINGROUP("sdc2_cmd", NORTH + 0xb7000, 11, 3), + [3] = SDC_PINGROUP("sdc2_data", NORTH + 0xb7000, 9, 0), +}; static const unsigned int sm8250_pin_offsets[] = { [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, [4] = NORTH, [5] = NORTH, @@ -52,7 +81,6 @@ static const unsigned int sm8250_pin_offsets[] = { [162] = WEST, [163] = WEST, [164] = WEST, [165] = WEST, [166] = WEST, [167] = WEST, [168] = WEST, [169] = WEST, [170] = WEST, [171] = WEST, [172] = WEST, [173] = WEST, [174] = WEST, [175] = WEST, [176] = WEST, [177] = WEST, [178] = WEST, [179] = WEST, - [180] = 0, [181] = 0, [182] = 0, [183] = 0, }; static const char *sm8250_get_function_name(struct udevice *dev, unsigned int selector) @@ -62,7 +90,12 @@ static const char *sm8250_get_function_name(struct udevice *dev, unsigned int se static const char *sm8250_get_pin_name(struct udevice *dev, unsigned int selector) { - snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + if (selector >= 180 && selector <= 183) + snprintf(pin_name, MAX_PIN_NAME_LEN, + sm8250_special_pins_data[selector - 180].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; } @@ -76,6 +109,7 @@ static struct msm_pinctrl_data sm8250_data = { .pin_offsets = sm8250_pin_offsets, .pin_count = ARRAY_SIZE(sm8250_pin_offsets), .special_pins_start = 180, + .special_pins_data = sm8250_special_pins_data, }, .functions_count = ARRAY_SIZE(msm_pinctrl_functions), .get_function_name = sm8250_get_function_name, diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index aa58b79c24e..2a39d1c8884 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -70,20 +70,20 @@ #define GPSR0_9 F_(MSIOF5_SYNC, IP1SR0_7_4) #define GPSR0_8 F_(MSIOF5_SS1, IP1SR0_3_0) #define GPSR0_7 F_(MSIOF5_SS2, IP0SR0_31_28) -#define GPSR0_6 F_(IRQ0, IP0SR0_27_24) -#define GPSR0_5 F_(IRQ1, IP0SR0_23_20) -#define GPSR0_4 F_(IRQ2, IP0SR0_19_16) -#define GPSR0_3 F_(IRQ3, IP0SR0_15_12) +#define GPSR0_6 F_(IRQ0_A, IP0SR0_27_24) +#define GPSR0_5 F_(IRQ1_A, IP0SR0_23_20) +#define GPSR0_4 F_(IRQ2_A, IP0SR0_19_16) +#define GPSR0_3 F_(IRQ3_A, IP0SR0_15_12) #define GPSR0_2 F_(GP0_02, IP0SR0_11_8) #define GPSR0_1 F_(GP0_01, IP0SR0_7_4) #define GPSR0_0 F_(GP0_00, IP0SR0_3_0) /* GPSR1 */ -#define GPSR1_28 F_(HTX3, IP3SR1_19_16) -#define GPSR1_27 F_(HCTS3_N, IP3SR1_15_12) -#define GPSR1_26 F_(HRTS3_N, IP3SR1_11_8) -#define GPSR1_25 F_(HSCK3, IP3SR1_7_4) -#define GPSR1_24 F_(HRX3, IP3SR1_3_0) +#define GPSR1_28 F_(HTX3_A, IP3SR1_19_16) +#define GPSR1_27 F_(HCTS3_N_A, IP3SR1_15_12) +#define GPSR1_26 F_(HRTS3_N_A, IP3SR1_11_8) +#define GPSR1_25 F_(HSCK3_A, IP3SR1_7_4) +#define GPSR1_24 F_(HRX3_A, IP3SR1_3_0) #define GPSR1_23 F_(GP1_23, IP2SR1_31_28) #define GPSR1_22 F_(AUDIO_CLKIN, IP2SR1_27_24) #define GPSR1_21 F_(AUDIO_CLKOUT, IP2SR1_23_20) @@ -121,14 +121,14 @@ #define GPSR2_11 F_(CANFD0_RX, IP1SR2_15_12) #define GPSR2_10 F_(CANFD0_TX, IP1SR2_11_8) #define GPSR2_9 F_(CAN_CLK, IP1SR2_7_4) -#define GPSR2_8 F_(TPU0TO0, IP1SR2_3_0) -#define GPSR2_7 F_(TPU0TO1, IP0SR2_31_28) +#define GPSR2_8 F_(TPU0TO0_A, IP1SR2_3_0) +#define GPSR2_7 F_(TPU0TO1_A, IP0SR2_31_28) #define GPSR2_6 F_(FXR_TXDB, IP0SR2_27_24) -#define GPSR2_5 F_(FXR_TXENB_N, IP0SR2_23_20) +#define GPSR2_5 F_(FXR_TXENB_N_A, IP0SR2_23_20) #define GPSR2_4 F_(RXDB_EXTFXR, IP0SR2_19_16) #define GPSR2_3 F_(CLK_EXTFXR, IP0SR2_15_12) #define GPSR2_2 F_(RXDA_EXTFXR, IP0SR2_11_8) -#define GPSR2_1 F_(FXR_TXENA_N, IP0SR2_7_4) +#define GPSR2_1 F_(FXR_TXENA_N_A, IP0SR2_7_4) #define GPSR2_0 F_(FXR_TXDA, IP0SR2_3_0) /* GPSR3 */ @@ -277,13 +277,13 @@ /* SR0 */ /* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_7_4 F_(0, 0) FM(MSIOF3_SS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_11_8 F_(0, 0) FM(MSIOF3_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_15_12 FM(IRQ3) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_19_16 FM(IRQ2) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_23_20 FM(IRQ1) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_27_24 FM(IRQ0) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_15_12 FM(IRQ3_A) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_19_16 FM(IRQ2_A) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_23_20 FM(IRQ1_A) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_27_24 FM(IRQ0_A) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_31_28 FM(MSIOF5_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -292,72 +292,72 @@ #define IP1SR0_11_8 FM(MSIOF5_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR0_15_12 FM(MSIOF5_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR0_19_16 FM(MSIOF5_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_23_20 FM(MSIOF2_SS2) FM(TCLK1) FM(IRQ2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_27_24 FM(MSIOF2_SS1) FM(HTX1) FM(TX1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR0_31_28 FM(MSIOF2_SYNC) FM(HRX1) FM(RX1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_23_20 FM(MSIOF2_SS2) FM(TCLK1_A) FM(IRQ2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_27_24 FM(MSIOF2_SS1) FM(HTX1_A) FM(TX1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR0_31_28 FM(MSIOF2_SYNC) FM(HRX1_A) FM(RX1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR0_3_0 FM(MSIOF2_TXD) FM(HCTS1_N) FM(CTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR0_7_4 FM(MSIOF2_SCK) FM(HRTS1_N) FM(RTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR0_11_8 FM(MSIOF2_RXD) FM(HSCK1) FM(SCK1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_3_0 FM(MSIOF2_TXD) FM(HCTS1_N_A) FM(CTS1_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_7_4 FM(MSIOF2_SCK) FM(HRTS1_N_A) FM(RTS1_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR0_11_8 FM(MSIOF2_RXD) FM(HSCK1_A) FM(SCK1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR1 */ /* IP0SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR1_3_0 FM(MSIOF1_SS2) FM(HTX3_A) FM(TX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_7_4 FM(MSIOF1_SS1) FM(HCTS3_N_A) FM(RX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_11_8 FM(MSIOF1_SYNC) FM(HRTS3_N_A) FM(RTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_15_12 FM(MSIOF1_SCK) FM(HSCK3_A) FM(CTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_19_16 FM(MSIOF1_TXD) FM(HRX3_A) FM(SCK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_3_0 FM(MSIOF1_SS2) FM(HTX3_B) FM(TX3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_7_4 FM(MSIOF1_SS1) FM(HCTS3_N_B) FM(RX3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_11_8 FM(MSIOF1_SYNC) FM(HRTS3_N_B) FM(RTS3_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_15_12 FM(MSIOF1_SCK) FM(HSCK3_B) FM(CTS3_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_19_16 FM(MSIOF1_TXD) FM(HRX3_B) FM(SCK3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR1_23_20 FM(MSIOF1_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_27_24 FM(MSIOF0_SS2) FM(HTX1_X) FM(TX1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR1_31_28 FM(MSIOF0_SS1) FM(HRX1_X) FM(RX1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_27_24 FM(MSIOF0_SS2) FM(HTX1_B) FM(TX1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR1_31_28 FM(MSIOF0_SS1) FM(HRX1_B) FM(RX1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR1_3_0 FM(MSIOF0_SYNC) FM(HCTS1_N_X) FM(CTS1_N_X) FM(CANFD5_TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_7_4 FM(MSIOF0_TXD) FM(HRTS1_N_X) FM(RTS1_N_X) FM(CANFD5_RX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_11_8 FM(MSIOF0_SCK) FM(HSCK1_X) FM(SCK1_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_3_0 FM(MSIOF0_SYNC) FM(HCTS1_N_B) FM(CTS1_N_B) FM(CANFD5_TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_7_4 FM(MSIOF0_TXD) FM(HRTS1_N_B) FM(RTS1_N_B) FM(CANFD5_RX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_11_8 FM(MSIOF0_SCK) FM(HSCK1_B) FM(SCK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR1_15_12 FM(MSIOF0_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR1_19_16 FM(HTX0) FM(TX0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_23_20 FM(HCTS0_N) FM(CTS0_N) FM(PWM8_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_27_24 FM(HRTS0_N) FM(RTS0_N) FM(PWM9_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR1_31_28 FM(HSCK0) FM(SCK0) FM(PWM0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_23_20 FM(HCTS0_N) FM(CTS0_N) FM(PWM8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_27_24 FM(HRTS0_N) FM(RTS0_N) FM(PWM9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR1_31_28 FM(HSCK0) FM(SCK0) FM(PWM0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP2SR1_3_0 FM(HRX0) FM(RX0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR1_7_4 FM(SCIF_CLK) FM(IRQ4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_11_8 FM(SSI_SCK) FM(TCLK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_15_12 FM(SSI_WS) FM(TCLK4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_19_16 FM(SSI_SD) FM(IRQ0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_23_20 FM(AUDIO_CLKOUT) FM(IRQ1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_11_8 FM(SSI_SCK) FM(TCLK3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_15_12 FM(SSI_WS) FM(TCLK4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_19_16 FM(SSI_SD) FM(IRQ0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_23_20 FM(AUDIO_CLKOUT) FM(IRQ1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR1_27_24 FM(AUDIO_CLKIN) FM(PWM3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR1_31_28 F_(0, 0) FM(TCLK2) FM(MSIOF4_SS1) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR1_31_28 F_(0, 0) FM(TCLK2_A) FM(MSIOF4_SS1) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP3SR1 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP3SR1_3_0 FM(HRX3) FM(SCK3_A) FM(MSIOF4_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_7_4 FM(HSCK3) FM(CTS3_N_A) FM(MSIOF4_SCK) FM(TPU0TO0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_11_8 FM(HRTS3_N) FM(RTS3_N_A) FM(MSIOF4_TXD) FM(TPU0TO1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_15_12 FM(HCTS3_N) FM(RX3_A) FM(MSIOF4_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP3SR1_19_16 FM(HTX3) FM(TX3_A) FM(MSIOF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_3_0 FM(HRX3_A) FM(SCK3_A) FM(MSIOF4_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_7_4 FM(HSCK3_A) FM(CTS3_N_A) FM(MSIOF4_SCK) FM(TPU0TO0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_11_8 FM(HRTS3_N_A) FM(RTS3_N_A) FM(MSIOF4_TXD) FM(TPU0TO1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_15_12 FM(HCTS3_N_A) FM(RX3_A) FM(MSIOF4_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP3SR1_19_16 FM(HTX3_A) FM(TX3_A) FM(MSIOF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR2 */ /* IP0SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR2_3_0 FM(FXR_TXDA) FM(CANFD1_TX) FM(TPU0TO2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_7_4 FM(FXR_TXENA_N) FM(CANFD1_RX) FM(TPU0TO3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_11_8 FM(RXDA_EXTFXR) FM(CANFD5_TX) FM(IRQ5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_15_12 FM(CLK_EXTFXR) FM(CANFD5_RX) FM(IRQ4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_3_0 FM(FXR_TXDA) FM(CANFD1_TX) FM(TPU0TO2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_7_4 FM(FXR_TXENA_N_A) FM(CANFD1_RX) FM(TPU0TO3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_11_8 FM(RXDA_EXTFXR) FM(CANFD5_TX_A) FM(IRQ5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_15_12 FM(CLK_EXTFXR) FM(CANFD5_RX_A) FM(IRQ4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR2_19_16 FM(RXDB_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_23_20 FM(FXR_TXENB_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_23_20 FM(FXR_TXENB_N_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR2_27_24 FM(FXR_TXDB) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR2_31_28 FM(TPU0TO1) FM(CANFD6_TX) F_(0, 0) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR2_31_28 FM(TPU0TO1_A) FM(CANFD6_TX) F_(0, 0) FM(TCLK2_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR2_3_0 FM(TPU0TO0) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2) F_(0, 0) FM(TCLK3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3) FM(PWM1_B) FM(TCLK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_31_28 FM(CANFD3_RX) F_(0, 0) FM(PWM3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR2 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -383,8 +383,8 @@ #define IP1SR3_11_8 FM(MMC_SD_CMD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_15_12 FM(SD_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_19_16 FM(SD_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR3_23_20 FM(IPC_CLKIN) FM(IPC_CLKEN_IN) FM(PWM1_A) FM(TCLK3_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR3_27_24 FM(IPC_CLKOUT) FM(IPC_CLKEN_OUT) FM(ERROROUTC_N_A) FM(TCLK4_X) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR3_23_20 FM(IPC_CLKIN) FM(IPC_CLKEN_IN) FM(PWM1_A) FM(TCLK3_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR3_27_24 FM(IPC_CLKOUT) FM(IPC_CLKEN_OUT) FM(ERROROUTC_N_A) FM(TCLK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR3_31_28 FM(QSPI0_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR3 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -720,22 +720,22 @@ static const u16 pinmux_data[] = { /* IP0SR0 */ PINMUX_IPSR_GPSR(IP0SR0_3_0, ERROROUTC_N_B), - PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_A), + PINMUX_IPSR_GPSR(IP0SR0_3_0, TCLK2_B), PINMUX_IPSR_GPSR(IP0SR0_7_4, MSIOF3_SS1), PINMUX_IPSR_GPSR(IP0SR0_11_8, MSIOF3_SS2), - PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3), + PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3_A), PINMUX_IPSR_GPSR(IP0SR0_15_12, MSIOF3_SCK), - PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2), + PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2_A), PINMUX_IPSR_GPSR(IP0SR0_19_16, MSIOF3_TXD), - PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1), + PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1_A), PINMUX_IPSR_GPSR(IP0SR0_23_20, MSIOF3_RXD), - PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0), + PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0_A), PINMUX_IPSR_GPSR(IP0SR0_27_24, MSIOF3_SYNC), PINMUX_IPSR_GPSR(IP0SR0_31_28, MSIOF5_SS2), @@ -752,75 +752,75 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR0_19_16, MSIOF5_RXD), PINMUX_IPSR_GPSR(IP1SR0_23_20, MSIOF2_SS2), - PINMUX_IPSR_GPSR(IP1SR0_23_20, TCLK1), - PINMUX_IPSR_GPSR(IP1SR0_23_20, IRQ2_A), + PINMUX_IPSR_GPSR(IP1SR0_23_20, TCLK1_A), + PINMUX_IPSR_GPSR(IP1SR0_23_20, IRQ2_B), PINMUX_IPSR_GPSR(IP1SR0_27_24, MSIOF2_SS1), - PINMUX_IPSR_GPSR(IP1SR0_27_24, HTX1), - PINMUX_IPSR_GPSR(IP1SR0_27_24, TX1), + PINMUX_IPSR_GPSR(IP1SR0_27_24, HTX1_A), + PINMUX_IPSR_GPSR(IP1SR0_27_24, TX1_A), PINMUX_IPSR_GPSR(IP1SR0_31_28, MSIOF2_SYNC), - PINMUX_IPSR_GPSR(IP1SR0_31_28, HRX1), - PINMUX_IPSR_GPSR(IP1SR0_31_28, RX1), + PINMUX_IPSR_GPSR(IP1SR0_31_28, HRX1_A), + PINMUX_IPSR_GPSR(IP1SR0_31_28, RX1_A), /* IP2SR0 */ PINMUX_IPSR_GPSR(IP2SR0_3_0, MSIOF2_TXD), - PINMUX_IPSR_GPSR(IP2SR0_3_0, HCTS1_N), - PINMUX_IPSR_GPSR(IP2SR0_3_0, CTS1_N), + PINMUX_IPSR_GPSR(IP2SR0_3_0, HCTS1_N_A), + PINMUX_IPSR_GPSR(IP2SR0_3_0, CTS1_N_A), PINMUX_IPSR_GPSR(IP2SR0_7_4, MSIOF2_SCK), - PINMUX_IPSR_GPSR(IP2SR0_7_4, HRTS1_N), - PINMUX_IPSR_GPSR(IP2SR0_7_4, RTS1_N), + PINMUX_IPSR_GPSR(IP2SR0_7_4, HRTS1_N_A), + PINMUX_IPSR_GPSR(IP2SR0_7_4, RTS1_N_A), PINMUX_IPSR_GPSR(IP2SR0_11_8, MSIOF2_RXD), - PINMUX_IPSR_GPSR(IP2SR0_11_8, HSCK1), - PINMUX_IPSR_GPSR(IP2SR0_11_8, SCK1), + PINMUX_IPSR_GPSR(IP2SR0_11_8, HSCK1_A), + PINMUX_IPSR_GPSR(IP2SR0_11_8, SCK1_A), /* IP0SR1 */ PINMUX_IPSR_GPSR(IP0SR1_3_0, MSIOF1_SS2), - PINMUX_IPSR_GPSR(IP0SR1_3_0, HTX3_A), - PINMUX_IPSR_GPSR(IP0SR1_3_0, TX3), + PINMUX_IPSR_GPSR(IP0SR1_3_0, HTX3_B), + PINMUX_IPSR_GPSR(IP0SR1_3_0, TX3_B), PINMUX_IPSR_GPSR(IP0SR1_7_4, MSIOF1_SS1), - PINMUX_IPSR_GPSR(IP0SR1_7_4, HCTS3_N_A), - PINMUX_IPSR_GPSR(IP0SR1_7_4, RX3), + PINMUX_IPSR_GPSR(IP0SR1_7_4, HCTS3_N_B), + PINMUX_IPSR_GPSR(IP0SR1_7_4, RX3_B), PINMUX_IPSR_GPSR(IP0SR1_11_8, MSIOF1_SYNC), - PINMUX_IPSR_GPSR(IP0SR1_11_8, HRTS3_N_A), - PINMUX_IPSR_GPSR(IP0SR1_11_8, RTS3_N), + PINMUX_IPSR_GPSR(IP0SR1_11_8, HRTS3_N_B), + PINMUX_IPSR_GPSR(IP0SR1_11_8, RTS3_N_B), PINMUX_IPSR_GPSR(IP0SR1_15_12, MSIOF1_SCK), - PINMUX_IPSR_GPSR(IP0SR1_15_12, HSCK3_A), - PINMUX_IPSR_GPSR(IP0SR1_15_12, CTS3_N), + PINMUX_IPSR_GPSR(IP0SR1_15_12, HSCK3_B), + PINMUX_IPSR_GPSR(IP0SR1_15_12, CTS3_N_B), PINMUX_IPSR_GPSR(IP0SR1_19_16, MSIOF1_TXD), - PINMUX_IPSR_GPSR(IP0SR1_19_16, HRX3_A), - PINMUX_IPSR_GPSR(IP0SR1_19_16, SCK3), + PINMUX_IPSR_GPSR(IP0SR1_19_16, HRX3_B), + PINMUX_IPSR_GPSR(IP0SR1_19_16, SCK3_B), PINMUX_IPSR_GPSR(IP0SR1_23_20, MSIOF1_RXD), PINMUX_IPSR_GPSR(IP0SR1_27_24, MSIOF0_SS2), - PINMUX_IPSR_GPSR(IP0SR1_27_24, HTX1_X), - PINMUX_IPSR_GPSR(IP0SR1_27_24, TX1_X), + PINMUX_IPSR_GPSR(IP0SR1_27_24, HTX1_B), + PINMUX_IPSR_GPSR(IP0SR1_27_24, TX1_B), PINMUX_IPSR_GPSR(IP0SR1_31_28, MSIOF0_SS1), - PINMUX_IPSR_GPSR(IP0SR1_31_28, HRX1_X), - PINMUX_IPSR_GPSR(IP0SR1_31_28, RX1_X), + PINMUX_IPSR_GPSR(IP0SR1_31_28, HRX1_B), + PINMUX_IPSR_GPSR(IP0SR1_31_28, RX1_B), /* IP1SR1 */ PINMUX_IPSR_GPSR(IP1SR1_3_0, MSIOF0_SYNC), - PINMUX_IPSR_GPSR(IP1SR1_3_0, HCTS1_N_X), - PINMUX_IPSR_GPSR(IP1SR1_3_0, CTS1_N_X), + PINMUX_IPSR_GPSR(IP1SR1_3_0, HCTS1_N_B), + PINMUX_IPSR_GPSR(IP1SR1_3_0, CTS1_N_B), PINMUX_IPSR_GPSR(IP1SR1_3_0, CANFD5_TX_B), PINMUX_IPSR_GPSR(IP1SR1_7_4, MSIOF0_TXD), - PINMUX_IPSR_GPSR(IP1SR1_7_4, HRTS1_N_X), - PINMUX_IPSR_GPSR(IP1SR1_7_4, RTS1_N_X), + PINMUX_IPSR_GPSR(IP1SR1_7_4, HRTS1_N_B), + PINMUX_IPSR_GPSR(IP1SR1_7_4, RTS1_N_B), PINMUX_IPSR_GPSR(IP1SR1_7_4, CANFD5_RX_B), PINMUX_IPSR_GPSR(IP1SR1_11_8, MSIOF0_SCK), - PINMUX_IPSR_GPSR(IP1SR1_11_8, HSCK1_X), - PINMUX_IPSR_GPSR(IP1SR1_11_8, SCK1_X), + PINMUX_IPSR_GPSR(IP1SR1_11_8, HSCK1_B), + PINMUX_IPSR_GPSR(IP1SR1_11_8, SCK1_B), PINMUX_IPSR_GPSR(IP1SR1_15_12, MSIOF0_RXD), @@ -829,15 +829,15 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR1_23_20, HCTS0_N), PINMUX_IPSR_GPSR(IP1SR1_23_20, CTS0_N), - PINMUX_IPSR_GPSR(IP1SR1_23_20, PWM8_A), + PINMUX_IPSR_GPSR(IP1SR1_23_20, PWM8), PINMUX_IPSR_GPSR(IP1SR1_27_24, HRTS0_N), PINMUX_IPSR_GPSR(IP1SR1_27_24, RTS0_N), - PINMUX_IPSR_GPSR(IP1SR1_27_24, PWM9_A), + PINMUX_IPSR_GPSR(IP1SR1_27_24, PWM9), PINMUX_IPSR_GPSR(IP1SR1_31_28, HSCK0), PINMUX_IPSR_GPSR(IP1SR1_31_28, SCK0), - PINMUX_IPSR_GPSR(IP1SR1_31_28, PWM0_A), + PINMUX_IPSR_GPSR(IP1SR1_31_28, PWM0), /* IP2SR1 */ PINMUX_IPSR_GPSR(IP2SR1_3_0, HRX0), @@ -847,99 +847,99 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP2SR1_7_4, IRQ4_A), PINMUX_IPSR_GPSR(IP2SR1_11_8, SSI_SCK), - PINMUX_IPSR_GPSR(IP2SR1_11_8, TCLK3), + PINMUX_IPSR_GPSR(IP2SR1_11_8, TCLK3_B), PINMUX_IPSR_GPSR(IP2SR1_15_12, SSI_WS), - PINMUX_IPSR_GPSR(IP2SR1_15_12, TCLK4), + PINMUX_IPSR_GPSR(IP2SR1_15_12, TCLK4_B), PINMUX_IPSR_GPSR(IP2SR1_19_16, SSI_SD), - PINMUX_IPSR_GPSR(IP2SR1_19_16, IRQ0_A), + PINMUX_IPSR_GPSR(IP2SR1_19_16, IRQ0_B), PINMUX_IPSR_GPSR(IP2SR1_23_20, AUDIO_CLKOUT), - PINMUX_IPSR_GPSR(IP2SR1_23_20, IRQ1_A), + PINMUX_IPSR_GPSR(IP2SR1_23_20, IRQ1_B), PINMUX_IPSR_GPSR(IP2SR1_27_24, AUDIO_CLKIN), PINMUX_IPSR_GPSR(IP2SR1_27_24, PWM3_A), - PINMUX_IPSR_GPSR(IP2SR1_31_28, TCLK2), + PINMUX_IPSR_GPSR(IP2SR1_31_28, TCLK2_A), PINMUX_IPSR_GPSR(IP2SR1_31_28, MSIOF4_SS1), PINMUX_IPSR_GPSR(IP2SR1_31_28, IRQ3_B), /* IP3SR1 */ - PINMUX_IPSR_GPSR(IP3SR1_3_0, HRX3), + PINMUX_IPSR_GPSR(IP3SR1_3_0, HRX3_A), PINMUX_IPSR_GPSR(IP3SR1_3_0, SCK3_A), PINMUX_IPSR_GPSR(IP3SR1_3_0, MSIOF4_SS2), - PINMUX_IPSR_GPSR(IP3SR1_7_4, HSCK3), + PINMUX_IPSR_GPSR(IP3SR1_7_4, HSCK3_A), PINMUX_IPSR_GPSR(IP3SR1_7_4, CTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_7_4, MSIOF4_SCK), - PINMUX_IPSR_GPSR(IP3SR1_7_4, TPU0TO0_A), + PINMUX_IPSR_GPSR(IP3SR1_7_4, TPU0TO0_B), - PINMUX_IPSR_GPSR(IP3SR1_11_8, HRTS3_N), + PINMUX_IPSR_GPSR(IP3SR1_11_8, HRTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_11_8, RTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_11_8, MSIOF4_TXD), - PINMUX_IPSR_GPSR(IP3SR1_11_8, TPU0TO1_A), + PINMUX_IPSR_GPSR(IP3SR1_11_8, TPU0TO1_B), - PINMUX_IPSR_GPSR(IP3SR1_15_12, HCTS3_N), + PINMUX_IPSR_GPSR(IP3SR1_15_12, HCTS3_N_A), PINMUX_IPSR_GPSR(IP3SR1_15_12, RX3_A), PINMUX_IPSR_GPSR(IP3SR1_15_12, MSIOF4_RXD), - PINMUX_IPSR_GPSR(IP3SR1_19_16, HTX3), + PINMUX_IPSR_GPSR(IP3SR1_19_16, HTX3_A), PINMUX_IPSR_GPSR(IP3SR1_19_16, TX3_A), PINMUX_IPSR_GPSR(IP3SR1_19_16, MSIOF4_SYNC), /* IP0SR2 */ PINMUX_IPSR_GPSR(IP0SR2_3_0, FXR_TXDA), PINMUX_IPSR_GPSR(IP0SR2_3_0, CANFD1_TX), - PINMUX_IPSR_GPSR(IP0SR2_3_0, TPU0TO2_A), + PINMUX_IPSR_GPSR(IP0SR2_3_0, TPU0TO2_B), - PINMUX_IPSR_GPSR(IP0SR2_7_4, FXR_TXENA_N), + PINMUX_IPSR_GPSR(IP0SR2_7_4, FXR_TXENA_N_A), PINMUX_IPSR_GPSR(IP0SR2_7_4, CANFD1_RX), - PINMUX_IPSR_GPSR(IP0SR2_7_4, TPU0TO3_A), + PINMUX_IPSR_GPSR(IP0SR2_7_4, TPU0TO3_B), PINMUX_IPSR_GPSR(IP0SR2_11_8, RXDA_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_11_8, CANFD5_TX), + PINMUX_IPSR_GPSR(IP0SR2_11_8, CANFD5_TX_A), PINMUX_IPSR_GPSR(IP0SR2_11_8, IRQ5), PINMUX_IPSR_GPSR(IP0SR2_15_12, CLK_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_15_12, CANFD5_RX), + PINMUX_IPSR_GPSR(IP0SR2_15_12, CANFD5_RX_A), PINMUX_IPSR_GPSR(IP0SR2_15_12, IRQ4_B), PINMUX_IPSR_GPSR(IP0SR2_19_16, RXDB_EXTFXR), - PINMUX_IPSR_GPSR(IP0SR2_23_20, FXR_TXENB_N), + PINMUX_IPSR_GPSR(IP0SR2_23_20, FXR_TXENB_N_A), PINMUX_IPSR_GPSR(IP0SR2_27_24, FXR_TXDB), - PINMUX_IPSR_GPSR(IP0SR2_31_28, TPU0TO1), + PINMUX_IPSR_GPSR(IP0SR2_31_28, TPU0TO1_A), PINMUX_IPSR_GPSR(IP0SR2_31_28, CANFD6_TX), - PINMUX_IPSR_GPSR(IP0SR2_31_28, TCLK2_B), + PINMUX_IPSR_GPSR(IP0SR2_31_28, TCLK2_C), /* IP1SR2 */ - PINMUX_IPSR_GPSR(IP1SR2_3_0, TPU0TO0), + PINMUX_IPSR_GPSR(IP1SR2_3_0, TPU0TO0_A), PINMUX_IPSR_GPSR(IP1SR2_3_0, CANFD6_RX), - PINMUX_IPSR_GPSR(IP1SR2_3_0, TCLK1_A), + PINMUX_IPSR_GPSR(IP1SR2_3_0, TCLK1_B), PINMUX_IPSR_GPSR(IP1SR2_7_4, CAN_CLK), - PINMUX_IPSR_GPSR(IP1SR2_7_4, FXR_TXENA_N_X), + PINMUX_IPSR_GPSR(IP1SR2_7_4, FXR_TXENA_N_B), PINMUX_IPSR_GPSR(IP1SR2_11_8, CANFD0_TX), - PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_X), + PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), - PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2), - PINMUX_IPSR_GPSR(IP1SR2_19_16, TCLK3_A), + PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), + PINMUX_IPSR_GPSR(IP1SR2_19_16, TCLK3_C), PINMUX_IPSR_GPSR(IP1SR2_23_20, CANFD2_RX), - PINMUX_IPSR_GPSR(IP1SR2_23_20, TPU0TO3), + PINMUX_IPSR_GPSR(IP1SR2_23_20, TPU0TO3_A), PINMUX_IPSR_GPSR(IP1SR2_23_20, PWM1_B), - PINMUX_IPSR_GPSR(IP1SR2_23_20, TCLK4_A), + PINMUX_IPSR_GPSR(IP1SR2_23_20, TCLK4_C), PINMUX_IPSR_GPSR(IP1SR2_27_24, CANFD3_TX), - PINMUX_IPSR_GPSR(IP1SR2_27_24, PWM2_B), + PINMUX_IPSR_GPSR(IP1SR2_27_24, PWM2), PINMUX_IPSR_GPSR(IP1SR2_31_28, CANFD3_RX), PINMUX_IPSR_GPSR(IP1SR2_31_28, PWM3_B), @@ -981,12 +981,12 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR3_23_20, IPC_CLKIN), PINMUX_IPSR_GPSR(IP1SR3_23_20, IPC_CLKEN_IN), PINMUX_IPSR_GPSR(IP1SR3_23_20, PWM1_A), - PINMUX_IPSR_GPSR(IP1SR3_23_20, TCLK3_X), + PINMUX_IPSR_GPSR(IP1SR3_23_20, TCLK3_A), PINMUX_IPSR_GPSR(IP1SR3_27_24, IPC_CLKOUT), PINMUX_IPSR_GPSR(IP1SR3_27_24, IPC_CLKEN_OUT), PINMUX_IPSR_GPSR(IP1SR3_27_24, ERROROUTC_N_A), - PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_X), + PINMUX_IPSR_GPSR(IP1SR3_27_24, TCLK4_A), PINMUX_IPSR_GPSR(IP1SR3_31_28, QSPI0_SSL), @@ -1533,15 +1533,14 @@ static const unsigned int canfd4_data_mux[] = { }; /* - CANFD5 ----------------------------------------------------------------- */ -static const unsigned int canfd5_data_pins[] = { - /* CANFD5_TX, CANFD5_RX */ +static const unsigned int canfd5_data_a_pins[] = { + /* CANFD5_TX_A, CANFD5_RX_A */ RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3), }; -static const unsigned int canfd5_data_mux[] = { - CANFD5_TX_MARK, CANFD5_RX_MARK, +static const unsigned int canfd5_data_a_mux[] = { + CANFD5_TX_A_MARK, CANFD5_RX_A_MARK, }; -/* - CANFD5_B ----------------------------------------------------------------- */ static const unsigned int canfd5_data_b_pins[] = { /* CANFD5_TX_B, CANFD5_RX_B */ RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 9), @@ -1601,49 +1600,48 @@ static const unsigned int hscif0_ctrl_mux[] = { }; /* - HSCIF1 ----------------------------------------------------------------- */ -static const unsigned int hscif1_data_pins[] = { - /* HRX1, HTX1 */ +static const unsigned int hscif1_data_a_pins[] = { + /* HRX1_A, HTX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), }; -static const unsigned int hscif1_data_mux[] = { - HRX1_MARK, HTX1_MARK, +static const unsigned int hscif1_data_a_mux[] = { + HRX1_A_MARK, HTX1_A_MARK, }; -static const unsigned int hscif1_clk_pins[] = { - /* HSCK1 */ +static const unsigned int hscif1_clk_a_pins[] = { + /* HSCK1_A */ RCAR_GP_PIN(0, 18), }; -static const unsigned int hscif1_clk_mux[] = { - HSCK1_MARK, +static const unsigned int hscif1_clk_a_mux[] = { + HSCK1_A_MARK, }; -static const unsigned int hscif1_ctrl_pins[] = { - /* HRTS1_N, HCTS1_N */ +static const unsigned int hscif1_ctrl_a_pins[] = { + /* HRTS1_N_A, HCTS1_N_A */ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16), }; -static const unsigned int hscif1_ctrl_mux[] = { - HRTS1_N_MARK, HCTS1_N_MARK, +static const unsigned int hscif1_ctrl_a_mux[] = { + HRTS1_N_A_MARK, HCTS1_N_A_MARK, }; -/* - HSCIF1_X---------------------------------------------------------------- */ -static const unsigned int hscif1_data_x_pins[] = { - /* HRX1_X, HTX1_X */ +static const unsigned int hscif1_data_b_pins[] = { + /* HRX1_B, HTX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), }; -static const unsigned int hscif1_data_x_mux[] = { - HRX1_X_MARK, HTX1_X_MARK, +static const unsigned int hscif1_data_b_mux[] = { + HRX1_B_MARK, HTX1_B_MARK, }; -static const unsigned int hscif1_clk_x_pins[] = { - /* HSCK1_X */ +static const unsigned int hscif1_clk_b_pins[] = { + /* HSCK1_B */ RCAR_GP_PIN(1, 10), }; -static const unsigned int hscif1_clk_x_mux[] = { - HSCK1_X_MARK, +static const unsigned int hscif1_clk_b_mux[] = { + HSCK1_B_MARK, }; -static const unsigned int hscif1_ctrl_x_pins[] = { - /* HRTS1_N_X, HCTS1_N_X */ +static const unsigned int hscif1_ctrl_b_pins[] = { + /* HRTS1_N_B, HCTS1_N_B */ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), }; -static const unsigned int hscif1_ctrl_x_mux[] = { - HRTS1_N_X_MARK, HCTS1_N_X_MARK, +static const unsigned int hscif1_ctrl_b_mux[] = { + HRTS1_N_B_MARK, HCTS1_N_B_MARK, }; /* - HSCIF2 ----------------------------------------------------------------- */ @@ -1670,49 +1668,48 @@ static const unsigned int hscif2_ctrl_mux[] = { }; /* - HSCIF3 ----------------------------------------------------------------- */ -static const unsigned int hscif3_data_pins[] = { - /* HRX3, HTX3 */ +static const unsigned int hscif3_data_a_pins[] = { + /* HRX3_A, HTX3_A */ RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28), }; -static const unsigned int hscif3_data_mux[] = { - HRX3_MARK, HTX3_MARK, +static const unsigned int hscif3_data_a_mux[] = { + HRX3_A_MARK, HTX3_A_MARK, }; -static const unsigned int hscif3_clk_pins[] = { - /* HSCK3 */ +static const unsigned int hscif3_clk_a_pins[] = { + /* HSCK3_A */ RCAR_GP_PIN(1, 25), }; -static const unsigned int hscif3_clk_mux[] = { - HSCK3_MARK, +static const unsigned int hscif3_clk_a_mux[] = { + HSCK3_A_MARK, }; -static const unsigned int hscif3_ctrl_pins[] = { - /* HRTS3_N, HCTS3_N */ +static const unsigned int hscif3_ctrl_a_pins[] = { + /* HRTS3_N_A, HCTS3_N_A */ RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 27), }; -static const unsigned int hscif3_ctrl_mux[] = { - HRTS3_N_MARK, HCTS3_N_MARK, +static const unsigned int hscif3_ctrl_a_mux[] = { + HRTS3_N_A_MARK, HCTS3_N_A_MARK, }; -/* - HSCIF3_A ----------------------------------------------------------------- */ -static const unsigned int hscif3_data_a_pins[] = { - /* HRX3_A, HTX3_A */ +static const unsigned int hscif3_data_b_pins[] = { + /* HRX3_B, HTX3_B */ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0), }; -static const unsigned int hscif3_data_a_mux[] = { - HRX3_A_MARK, HTX3_A_MARK, +static const unsigned int hscif3_data_b_mux[] = { + HRX3_B_MARK, HTX3_B_MARK, }; -static const unsigned int hscif3_clk_a_pins[] = { - /* HSCK3_A */ +static const unsigned int hscif3_clk_b_pins[] = { + /* HSCK3_B */ RCAR_GP_PIN(1, 3), }; -static const unsigned int hscif3_clk_a_mux[] = { - HSCK3_A_MARK, +static const unsigned int hscif3_clk_b_mux[] = { + HSCK3_B_MARK, }; -static const unsigned int hscif3_ctrl_a_pins[] = { - /* HRTS3_N_A, HCTS3_N_A */ +static const unsigned int hscif3_ctrl_b_pins[] = { + /* HRTS3_N_B, HCTS3_N_B */ RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 1), }; -static const unsigned int hscif3_ctrl_a_mux[] = { - HRTS3_N_A_MARK, HCTS3_N_A_MARK, +static const unsigned int hscif3_ctrl_b_mux[] = { + HRTS3_N_B_MARK, HCTS3_N_B_MARK, }; /* - I2C0 ------------------------------------------------------------------- */ @@ -1769,6 +1766,90 @@ static const unsigned int i2c5_mux[] = { SDA5_MARK, SCL5_MARK, }; +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_a_pins[] = { + /* IRQ0_A */ + RCAR_GP_PIN(0, 6), +}; +static const unsigned int intc_ex_irq0_a_mux[] = { + IRQ0_A_MARK, +}; +static const unsigned int intc_ex_irq0_b_pins[] = { + /* IRQ0_B */ + RCAR_GP_PIN(1, 20), +}; +static const unsigned int intc_ex_irq0_b_mux[] = { + IRQ0_B_MARK, +}; + +static const unsigned int intc_ex_irq1_a_pins[] = { + /* IRQ1_A */ + RCAR_GP_PIN(0, 5), +}; +static const unsigned int intc_ex_irq1_a_mux[] = { + IRQ1_A_MARK, +}; +static const unsigned int intc_ex_irq1_b_pins[] = { + /* IRQ1_B */ + RCAR_GP_PIN(1, 21), +}; +static const unsigned int intc_ex_irq1_b_mux[] = { + IRQ1_B_MARK, +}; + +static const unsigned int intc_ex_irq2_a_pins[] = { + /* IRQ2_A */ + RCAR_GP_PIN(0, 4), +}; +static const unsigned int intc_ex_irq2_a_mux[] = { + IRQ2_A_MARK, +}; +static const unsigned int intc_ex_irq2_b_pins[] = { + /* IRQ2_B */ + RCAR_GP_PIN(0, 13), +}; +static const unsigned int intc_ex_irq2_b_mux[] = { + IRQ2_B_MARK, +}; + +static const unsigned int intc_ex_irq3_a_pins[] = { + /* IRQ3_A */ + RCAR_GP_PIN(0, 3), +}; +static const unsigned int intc_ex_irq3_a_mux[] = { + IRQ3_A_MARK, +}; +static const unsigned int intc_ex_irq3_b_pins[] = { + /* IRQ3_B */ + RCAR_GP_PIN(1, 23), +}; +static const unsigned int intc_ex_irq3_b_mux[] = { + IRQ3_B_MARK, +}; + +static const unsigned int intc_ex_irq4_a_pins[] = { + /* IRQ4_A */ + RCAR_GP_PIN(1, 17), +}; +static const unsigned int intc_ex_irq4_a_mux[] = { + IRQ4_A_MARK, +}; +static const unsigned int intc_ex_irq4_b_pins[] = { + /* IRQ4_B */ + RCAR_GP_PIN(2, 3), +}; +static const unsigned int intc_ex_irq4_b_mux[] = { + IRQ4_B_MARK, +}; + +static const unsigned int intc_ex_irq5_pins[] = { + /* IRQ5 */ + RCAR_GP_PIN(2, 2), +}; +static const unsigned int intc_ex_irq5_mux[] = { + IRQ5_MARK, +}; + /* - MMC -------------------------------------------------------------------- */ static const unsigned int mmc_data_pins[] = { /* MMC_SD_D[0:3], MMC_D[4:7] */ @@ -2095,16 +2176,16 @@ static const unsigned int pcie1_clkreq_n_mux[] = { PCIE1_CLKREQ_N_MARK, }; -/* - PWM0_A ------------------------------------------------------------------- */ -static const unsigned int pwm0_a_pins[] = { - /* PWM0_A */ +/* - PWM0 ------------------------------------------------------------------- */ +static const unsigned int pwm0_pins[] = { + /* PWM0 */ RCAR_GP_PIN(1, 15), }; -static const unsigned int pwm0_a_mux[] = { - PWM0_A_MARK, +static const unsigned int pwm0_mux[] = { + PWM0_MARK, }; -/* - PWM1_A ------------------------------------------------------------------- */ +/* - PWM1 ------------------------------------------------------------------- */ static const unsigned int pwm1_a_pins[] = { /* PWM1_A */ RCAR_GP_PIN(3, 13), @@ -2113,7 +2194,6 @@ static const unsigned int pwm1_a_mux[] = { PWM1_A_MARK, }; -/* - PWM1_B ------------------------------------------------------------------- */ static const unsigned int pwm1_b_pins[] = { /* PWM1_B */ RCAR_GP_PIN(2, 13), @@ -2122,16 +2202,16 @@ static const unsigned int pwm1_b_mux[] = { PWM1_B_MARK, }; -/* - PWM2_B ------------------------------------------------------------------- */ -static const unsigned int pwm2_b_pins[] = { - /* PWM2_B */ +/* - PWM2 ------------------------------------------------------------------- */ +static const unsigned int pwm2_pins[] = { + /* PWM2 */ RCAR_GP_PIN(2, 14), }; -static const unsigned int pwm2_b_mux[] = { - PWM2_B_MARK, +static const unsigned int pwm2_mux[] = { + PWM2_MARK, }; -/* - PWM3_A ------------------------------------------------------------------- */ +/* - PWM3 ------------------------------------------------------------------- */ static const unsigned int pwm3_a_pins[] = { /* PWM3_A */ RCAR_GP_PIN(1, 22), @@ -2140,7 +2220,6 @@ static const unsigned int pwm3_a_mux[] = { PWM3_A_MARK, }; -/* - PWM3_B ------------------------------------------------------------------- */ static const unsigned int pwm3_b_pins[] = { /* PWM3_B */ RCAR_GP_PIN(2, 15), @@ -2185,22 +2264,22 @@ static const unsigned int pwm7_mux[] = { PWM7_MARK, }; -/* - PWM8_A ------------------------------------------------------------------- */ -static const unsigned int pwm8_a_pins[] = { - /* PWM8_A */ +/* - PWM8 ------------------------------------------------------------------- */ +static const unsigned int pwm8_pins[] = { + /* PWM8 */ RCAR_GP_PIN(1, 13), }; -static const unsigned int pwm8_a_mux[] = { - PWM8_A_MARK, +static const unsigned int pwm8_mux[] = { + PWM8_MARK, }; -/* - PWM9_A ------------------------------------------------------------------- */ -static const unsigned int pwm9_a_pins[] = { - /* PWM9_A */ +/* - PWM9 ------------------------------------------------------------------- */ +static const unsigned int pwm9_pins[] = { + /* PWM9 */ RCAR_GP_PIN(1, 14), }; -static const unsigned int pwm9_a_mux[] = { - PWM9_A_MARK, +static const unsigned int pwm9_mux[] = { + PWM9_MARK, }; /* - QSPI0 ------------------------------------------------------------------ */ @@ -2263,75 +2342,51 @@ static const unsigned int scif0_ctrl_mux[] = { }; /* - SCIF1 ------------------------------------------------------------------ */ -static const unsigned int scif1_data_pins[] = { - /* RX1, TX1 */ +static const unsigned int scif1_data_a_pins[] = { + /* RX1_A, TX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), }; -static const unsigned int scif1_data_mux[] = { - RX1_MARK, TX1_MARK, +static const unsigned int scif1_data_a_mux[] = { + RX1_A_MARK, TX1_A_MARK, }; -static const unsigned int scif1_clk_pins[] = { - /* SCK1 */ +static const unsigned int scif1_clk_a_pins[] = { + /* SCK1_A */ RCAR_GP_PIN(0, 18), }; -static const unsigned int scif1_clk_mux[] = { - SCK1_MARK, +static const unsigned int scif1_clk_a_mux[] = { + SCK1_A_MARK, }; -static const unsigned int scif1_ctrl_pins[] = { - /* RTS1_N, CTS1_N */ +static const unsigned int scif1_ctrl_a_pins[] = { + /* RTS1_N_A, CTS1_N_A */ RCAR_GP_PIN(0, 17), RCAR_GP_PIN(0, 16), }; -static const unsigned int scif1_ctrl_mux[] = { - RTS1_N_MARK, CTS1_N_MARK, +static const unsigned int scif1_ctrl_a_mux[] = { + RTS1_N_A_MARK, CTS1_N_A_MARK, }; -/* - SCIF1_X ------------------------------------------------------------------ */ -static const unsigned int scif1_data_x_pins[] = { - /* RX1_X, TX1_X */ +static const unsigned int scif1_data_b_pins[] = { + /* RX1_B, TX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), }; -static const unsigned int scif1_data_x_mux[] = { - RX1_X_MARK, TX1_X_MARK, +static const unsigned int scif1_data_b_mux[] = { + RX1_B_MARK, TX1_B_MARK, }; -static const unsigned int scif1_clk_x_pins[] = { - /* SCK1_X */ +static const unsigned int scif1_clk_b_pins[] = { + /* SCK1_B */ RCAR_GP_PIN(1, 10), }; -static const unsigned int scif1_clk_x_mux[] = { - SCK1_X_MARK, +static const unsigned int scif1_clk_b_mux[] = { + SCK1_B_MARK, }; -static const unsigned int scif1_ctrl_x_pins[] = { - /* RTS1_N_X, CTS1_N_X */ +static const unsigned int scif1_ctrl_b_pins[] = { + /* RTS1_N_B, CTS1_N_B */ RCAR_GP_PIN(1, 9), RCAR_GP_PIN(1, 8), }; -static const unsigned int scif1_ctrl_x_mux[] = { - RTS1_N_X_MARK, CTS1_N_X_MARK, +static const unsigned int scif1_ctrl_b_mux[] = { + RTS1_N_B_MARK, CTS1_N_B_MARK, }; /* - SCIF3 ------------------------------------------------------------------ */ -static const unsigned int scif3_data_pins[] = { - /* RX3, TX3 */ - RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), -}; -static const unsigned int scif3_data_mux[] = { - RX3_MARK, TX3_MARK, -}; -static const unsigned int scif3_clk_pins[] = { - /* SCK3 */ - RCAR_GP_PIN(1, 4), -}; -static const unsigned int scif3_clk_mux[] = { - SCK3_MARK, -}; -static const unsigned int scif3_ctrl_pins[] = { - /* RTS3_N, CTS3_N */ - RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), -}; -static const unsigned int scif3_ctrl_mux[] = { - RTS3_N_MARK, CTS3_N_MARK, -}; - -/* - SCIF3_A ------------------------------------------------------------------ */ static const unsigned int scif3_data_a_pins[] = { /* RX3_A, TX3_A */ RCAR_GP_PIN(1, 27), RCAR_GP_PIN(1, 28), @@ -2354,6 +2409,28 @@ static const unsigned int scif3_ctrl_a_mux[] = { RTS3_N_A_MARK, CTS3_N_A_MARK, }; +static const unsigned int scif3_data_b_pins[] = { + /* RX3_B, TX3_B */ + RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), +}; +static const unsigned int scif3_data_b_mux[] = { + RX3_B_MARK, TX3_B_MARK, +}; +static const unsigned int scif3_clk_b_pins[] = { + /* SCK3_B */ + RCAR_GP_PIN(1, 4), +}; +static const unsigned int scif3_clk_b_mux[] = { + SCK3_B_MARK, +}; +static const unsigned int scif3_ctrl_b_pins[] = { + /* RTS3_N_B, CTS3_N_B */ + RCAR_GP_PIN(1, 2), RCAR_GP_PIN(1, 3), +}; +static const unsigned int scif3_ctrl_b_mux[] = { + RTS3_N_B_MARK, CTS3_N_B_MARK, +}; + /* - SCIF4 ------------------------------------------------------------------ */ static const unsigned int scif4_data_pins[] = { /* RX4, TX4 */ @@ -2410,64 +2487,63 @@ static const unsigned int ssi_ctrl_mux[] = { SSI_SCK_MARK, SSI_WS_MARK, }; -/* - TPU ------------------------------------------------------------------- */ -static const unsigned int tpu_to0_pins[] = { - /* TPU0TO0 */ +/* - TPU -------------------------------------------------------------------- */ +static const unsigned int tpu_to0_a_pins[] = { + /* TPU0TO0_A */ RCAR_GP_PIN(2, 8), }; -static const unsigned int tpu_to0_mux[] = { - TPU0TO0_MARK, +static const unsigned int tpu_to0_a_mux[] = { + TPU0TO0_A_MARK, }; -static const unsigned int tpu_to1_pins[] = { - /* TPU0TO1 */ +static const unsigned int tpu_to1_a_pins[] = { + /* TPU0TO1_A */ RCAR_GP_PIN(2, 7), }; -static const unsigned int tpu_to1_mux[] = { - TPU0TO1_MARK, +static const unsigned int tpu_to1_a_mux[] = { + TPU0TO1_A_MARK, }; -static const unsigned int tpu_to2_pins[] = { - /* TPU0TO2 */ +static const unsigned int tpu_to2_a_pins[] = { + /* TPU0TO2_A */ RCAR_GP_PIN(2, 12), }; -static const unsigned int tpu_to2_mux[] = { - TPU0TO2_MARK, +static const unsigned int tpu_to2_a_mux[] = { + TPU0TO2_A_MARK, }; -static const unsigned int tpu_to3_pins[] = { - /* TPU0TO3 */ +static const unsigned int tpu_to3_a_pins[] = { + /* TPU0TO3_A */ RCAR_GP_PIN(2, 13), }; -static const unsigned int tpu_to3_mux[] = { - TPU0TO3_MARK, +static const unsigned int tpu_to3_a_mux[] = { + TPU0TO3_A_MARK, }; -/* - TPU_A ------------------------------------------------------------------- */ -static const unsigned int tpu_to0_a_pins[] = { - /* TPU0TO0_A */ +static const unsigned int tpu_to0_b_pins[] = { + /* TPU0TO0_B */ RCAR_GP_PIN(1, 25), }; -static const unsigned int tpu_to0_a_mux[] = { - TPU0TO0_A_MARK, +static const unsigned int tpu_to0_b_mux[] = { + TPU0TO0_B_MARK, }; -static const unsigned int tpu_to1_a_pins[] = { - /* TPU0TO1_A */ +static const unsigned int tpu_to1_b_pins[] = { + /* TPU0TO1_B */ RCAR_GP_PIN(1, 26), }; -static const unsigned int tpu_to1_a_mux[] = { - TPU0TO1_A_MARK, +static const unsigned int tpu_to1_b_mux[] = { + TPU0TO1_B_MARK, }; -static const unsigned int tpu_to2_a_pins[] = { - /* TPU0TO2_A */ +static const unsigned int tpu_to2_b_pins[] = { + /* TPU0TO2_B */ RCAR_GP_PIN(2, 0), }; -static const unsigned int tpu_to2_a_mux[] = { - TPU0TO2_A_MARK, +static const unsigned int tpu_to2_b_mux[] = { + TPU0TO2_B_MARK, }; -static const unsigned int tpu_to3_a_pins[] = { - /* TPU0TO3_A */ +static const unsigned int tpu_to3_b_pins[] = { + /* TPU0TO3_B */ RCAR_GP_PIN(2, 1), }; -static const unsigned int tpu_to3_a_mux[] = { - TPU0TO3_A_MARK, +static const unsigned int tpu_to3_b_mux[] = { + TPU0TO3_B_MARK, }; /* - TSN0 ------------------------------------------------ */ @@ -2580,8 +2656,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(canfd2_data), SH_PFC_PIN_GROUP(canfd3_data), SH_PFC_PIN_GROUP(canfd4_data), - SH_PFC_PIN_GROUP(canfd5_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(canfd5_data_b), /* suffix might be updated */ + SH_PFC_PIN_GROUP(canfd5_data_a), + SH_PFC_PIN_GROUP(canfd5_data_b), SH_PFC_PIN_GROUP(canfd6_data), SH_PFC_PIN_GROUP(canfd7_data), SH_PFC_PIN_GROUP(can_clk), @@ -2589,21 +2665,21 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(hscif0_data), SH_PFC_PIN_GROUP(hscif0_clk), SH_PFC_PIN_GROUP(hscif0_ctrl), - SH_PFC_PIN_GROUP(hscif1_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_data_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_clk_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif1_ctrl_x), /* suffix might be updated */ + SH_PFC_PIN_GROUP(hscif1_data_a), + SH_PFC_PIN_GROUP(hscif1_clk_a), + SH_PFC_PIN_GROUP(hscif1_ctrl_a), + SH_PFC_PIN_GROUP(hscif1_data_b), + SH_PFC_PIN_GROUP(hscif1_clk_b), + SH_PFC_PIN_GROUP(hscif1_ctrl_b), SH_PFC_PIN_GROUP(hscif2_data), SH_PFC_PIN_GROUP(hscif2_clk), SH_PFC_PIN_GROUP(hscif2_ctrl), - SH_PFC_PIN_GROUP(hscif3_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_data_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_clk_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(hscif3_ctrl_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(hscif3_data_a), + SH_PFC_PIN_GROUP(hscif3_clk_a), + SH_PFC_PIN_GROUP(hscif3_ctrl_a), + SH_PFC_PIN_GROUP(hscif3_data_b), + SH_PFC_PIN_GROUP(hscif3_clk_b), + SH_PFC_PIN_GROUP(hscif3_ctrl_b), SH_PFC_PIN_GROUP(i2c0), SH_PFC_PIN_GROUP(i2c1), @@ -2612,6 +2688,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c4), SH_PFC_PIN_GROUP(i2c5), + SH_PFC_PIN_GROUP(intc_ex_irq0_a), + SH_PFC_PIN_GROUP(intc_ex_irq0_b), + SH_PFC_PIN_GROUP(intc_ex_irq1_a), + SH_PFC_PIN_GROUP(intc_ex_irq1_b), + SH_PFC_PIN_GROUP(intc_ex_irq2_a), + SH_PFC_PIN_GROUP(intc_ex_irq2_b), + SH_PFC_PIN_GROUP(intc_ex_irq3_a), + SH_PFC_PIN_GROUP(intc_ex_irq3_b), + SH_PFC_PIN_GROUP(intc_ex_irq4_a), + SH_PFC_PIN_GROUP(intc_ex_irq4_b), + SH_PFC_PIN_GROUP(intc_ex_irq5), + BUS_DATA_PIN_GROUP(mmc_data, 1), BUS_DATA_PIN_GROUP(mmc_data, 4), BUS_DATA_PIN_GROUP(mmc_data, 8), @@ -2665,18 +2753,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(pcie0_clkreq_n), SH_PFC_PIN_GROUP(pcie1_clkreq_n), - SH_PFC_PIN_GROUP(pwm0_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm0), SH_PFC_PIN_GROUP(pwm1_a), SH_PFC_PIN_GROUP(pwm1_b), - SH_PFC_PIN_GROUP(pwm2_b), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm2), SH_PFC_PIN_GROUP(pwm3_a), SH_PFC_PIN_GROUP(pwm3_b), SH_PFC_PIN_GROUP(pwm4), SH_PFC_PIN_GROUP(pwm5), SH_PFC_PIN_GROUP(pwm6), SH_PFC_PIN_GROUP(pwm7), - SH_PFC_PIN_GROUP(pwm8_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(pwm9_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(pwm8), + SH_PFC_PIN_GROUP(pwm9), SH_PFC_PIN_GROUP(qspi0_ctrl), BUS_DATA_PIN_GROUP(qspi0_data, 2), @@ -2688,18 +2776,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(scif0_data), SH_PFC_PIN_GROUP(scif0_clk), SH_PFC_PIN_GROUP(scif0_ctrl), - SH_PFC_PIN_GROUP(scif1_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_data_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_clk_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif1_ctrl_x), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_data), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_clk), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_ctrl), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_data_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_clk_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(scif3_ctrl_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(scif1_data_a), + SH_PFC_PIN_GROUP(scif1_clk_a), + SH_PFC_PIN_GROUP(scif1_ctrl_a), + SH_PFC_PIN_GROUP(scif1_data_b), + SH_PFC_PIN_GROUP(scif1_clk_b), + SH_PFC_PIN_GROUP(scif1_ctrl_b), + SH_PFC_PIN_GROUP(scif3_data_a), + SH_PFC_PIN_GROUP(scif3_clk_a), + SH_PFC_PIN_GROUP(scif3_ctrl_a), + SH_PFC_PIN_GROUP(scif3_data_b), + SH_PFC_PIN_GROUP(scif3_clk_b), + SH_PFC_PIN_GROUP(scif3_ctrl_b), SH_PFC_PIN_GROUP(scif4_data), SH_PFC_PIN_GROUP(scif4_clk), SH_PFC_PIN_GROUP(scif4_ctrl), @@ -2709,14 +2797,14 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(ssi_data), SH_PFC_PIN_GROUP(ssi_ctrl), - SH_PFC_PIN_GROUP(tpu_to0), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to0_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to1), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to1_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to2), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to2_a), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to3), /* suffix might be updated */ - SH_PFC_PIN_GROUP(tpu_to3_a), /* suffix might be updated */ + SH_PFC_PIN_GROUP(tpu_to0_a), + SH_PFC_PIN_GROUP(tpu_to0_b), + SH_PFC_PIN_GROUP(tpu_to1_a), + SH_PFC_PIN_GROUP(tpu_to1_b), + SH_PFC_PIN_GROUP(tpu_to2_a), + SH_PFC_PIN_GROUP(tpu_to2_b), + SH_PFC_PIN_GROUP(tpu_to3_a), + SH_PFC_PIN_GROUP(tpu_to3_b), SH_PFC_PIN_GROUP(tsn0_link), SH_PFC_PIN_GROUP(tsn0_phy_int), @@ -2790,8 +2878,7 @@ static const char * const canfd4_groups[] = { }; static const char * const canfd5_groups[] = { - /* suffix might be updated */ - "canfd5_data", + "canfd5_data_a", "canfd5_data_b", }; @@ -2814,13 +2901,12 @@ static const char * const hscif0_groups[] = { }; static const char * const hscif1_groups[] = { - /* suffix might be updated */ - "hscif1_data", - "hscif1_clk", - "hscif1_ctrl", - "hscif1_data_x", - "hscif1_clk_x", - "hscif1_ctrl_x", + "hscif1_data_a", + "hscif1_clk_a", + "hscif1_ctrl_a", + "hscif1_data_b", + "hscif1_clk_b", + "hscif1_ctrl_b", }; static const char * const hscif2_groups[] = { @@ -2830,13 +2916,12 @@ static const char * const hscif2_groups[] = { }; static const char * const hscif3_groups[] = { - /* suffix might be updated */ - "hscif3_data", - "hscif3_clk", - "hscif3_ctrl", "hscif3_data_a", "hscif3_clk_a", "hscif3_ctrl_a", + "hscif3_data_b", + "hscif3_clk_b", + "hscif3_ctrl_b", }; static const char * const i2c0_groups[] = { @@ -2863,6 +2948,20 @@ static const char * const i2c5_groups[] = { "i2c5", }; +static const char * const intc_ex_groups[] = { + "intc_ex_irq0_a", + "intc_ex_irq0_b", + "intc_ex_irq1_a", + "intc_ex_irq1_b", + "intc_ex_irq2_a", + "intc_ex_irq2_b", + "intc_ex_irq3_a", + "intc_ex_irq3_b", + "intc_ex_irq4_a", + "intc_ex_irq4_b", + "intc_ex_irq5", +}; + static const char * const mmc_groups[] = { "mmc_data1", "mmc_data4", @@ -2933,8 +3032,7 @@ static const char * const pcie_groups[] = { }; static const char * const pwm0_groups[] = { - /* suffix might be updated */ - "pwm0_a", + "pwm0", }; static const char * const pwm1_groups[] = { @@ -2943,8 +3041,7 @@ static const char * const pwm1_groups[] = { }; static const char * const pwm2_groups[] = { - /* suffix might be updated */ - "pwm2_b", + "pwm2", }; static const char * const pwm3_groups[] = { @@ -2969,13 +3066,11 @@ static const char * const pwm7_groups[] = { }; static const char * const pwm8_groups[] = { - /* suffix might be updated */ - "pwm8_a", + "pwm8", }; static const char * const pwm9_groups[] = { - /* suffix might be updated */ - "pwm9_a", + "pwm9", }; static const char * const qspi0_groups[] = { @@ -2997,23 +3092,21 @@ static const char * const scif0_groups[] = { }; static const char * const scif1_groups[] = { - /* suffix might be updated */ - "scif1_data", - "scif1_clk", - "scif1_ctrl", - "scif1_data_x", - "scif1_clk_x", - "scif1_ctrl_x", + "scif1_data_a", + "scif1_clk_a", + "scif1_ctrl_a", + "scif1_data_b", + "scif1_clk_b", + "scif1_ctrl_b", }; static const char * const scif3_groups[] = { - /* suffix might be updated */ - "scif3_data", - "scif3_clk", - "scif3_ctrl", "scif3_data_a", "scif3_clk_a", "scif3_ctrl_a", + "scif3_data_b", + "scif3_clk_b", + "scif3_ctrl_b", }; static const char * const scif4_groups[] = { @@ -3036,15 +3129,14 @@ static const char * const ssi_groups[] = { }; static const char * const tpu_groups[] = { - /* suffix might be updated */ - "tpu_to0", "tpu_to0_a", - "tpu_to1", + "tpu_to0_b", "tpu_to1_a", - "tpu_to2", + "tpu_to1_b", "tpu_to2_a", - "tpu_to3", + "tpu_to2_b", "tpu_to3_a", + "tpu_to3_b", }; static const char * const tsn0_groups[] = { @@ -3087,6 +3179,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c4), SH_PFC_FUNCTION(i2c5), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(mmc), SH_PFC_FUNCTION(msiof0), diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c index 2f09e767288..bfabf0c379a 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779h0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c @@ -77,10 +77,10 @@ #define GPSR0_9 F_(MSIOF5_SYNC, IP1SR0_7_4) #define GPSR0_8 F_(MSIOF5_SS1, IP1SR0_3_0) #define GPSR0_7 F_(MSIOF5_SS2, IP0SR0_31_28) -#define GPSR0_6 F_(IRQ0, IP0SR0_27_24) -#define GPSR0_5 F_(IRQ1, IP0SR0_23_20) -#define GPSR0_4 F_(IRQ2, IP0SR0_19_16) -#define GPSR0_3 F_(IRQ3, IP0SR0_15_12) +#define GPSR0_6 F_(IRQ0_A, IP0SR0_27_24) +#define GPSR0_5 F_(IRQ1_A, IP0SR0_23_20) +#define GPSR0_4 F_(IRQ2_A, IP0SR0_19_16) +#define GPSR0_3 F_(IRQ3_A, IP0SR0_15_12) #define GPSR0_2 F_(GP0_02, IP0SR0_11_8) #define GPSR0_1 F_(GP0_01, IP0SR0_7_4) #define GPSR0_0 F_(GP0_00, IP0SR0_3_0) @@ -261,15 +261,16 @@ #define GPSR7_1 F_(AVB0_AVTP_CAPTURE, IP0SR7_7_4) #define GPSR7_0 F_(AVB0_AVTP_PPS, IP0SR7_3_0) + /* SR0 */ /* IP0SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP0SR0_3_0 F_(0, 0) FM(ERROROUTC_N_B) FM(TCLK2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_7_4 F_(0, 0) FM(MSIOF3_SS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_11_8 F_(0, 0) FM(MSIOF3_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_15_12 FM(IRQ3) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_19_16 FM(IRQ2) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_23_20 FM(IRQ1) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR0_27_24 FM(IRQ0) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_15_12 FM(IRQ3_A) FM(MSIOF3_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_19_16 FM(IRQ2_A) FM(MSIOF3_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_23_20 FM(IRQ1_A) FM(MSIOF3_RXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR0_27_24 FM(IRQ0_A) FM(MSIOF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR0_31_28 FM(MSIOF5_SS2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR0 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -673,16 +674,16 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR0_11_8, MSIOF3_SS2), - PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3), + PINMUX_IPSR_GPSR(IP0SR0_15_12, IRQ3_A), PINMUX_IPSR_GPSR(IP0SR0_15_12, MSIOF3_SCK), - PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2), + PINMUX_IPSR_GPSR(IP0SR0_19_16, IRQ2_A), PINMUX_IPSR_GPSR(IP0SR0_19_16, MSIOF3_TXD), - PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1), + PINMUX_IPSR_GPSR(IP0SR0_23_20, IRQ1_A), PINMUX_IPSR_GPSR(IP0SR0_23_20, MSIOF3_RXD), - PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0), + PINMUX_IPSR_GPSR(IP0SR0_27_24, IRQ0_A), PINMUX_IPSR_GPSR(IP0SR0_27_24, MSIOF3_SYNC), PINMUX_IPSR_GPSR(IP0SR0_31_28, MSIOF5_SS2), @@ -1237,6 +1238,30 @@ static const unsigned int avb0_mdio_pins[] = { static const unsigned int avb0_mdio_mux[] = { AVB0_MDC_MARK, AVB0_MDIO_MARK, }; +static const unsigned int avb0_mii_pins[] = { + /* + * AVB0_MII_TD0, AVB0_MII_TD1, AVB0_MII_TD2, + * AVB0_MII_TD3, AVB0_MII_RD0, AVB0_MII_RD1, + * AVB0_MII_RD2, AVB0_MII_RD3, AVB0_MII_TXC, + * AVB0_MII_TX_EN, AVB0_MII_TX_ER, AVB0_MII_RXC, + * AVB0_MII_RX_DV, AVB0_MII_RX_ER, AVB0_MII_CRS, + * AVB0_MII_COL + */ + RCAR_GP_PIN(7, 11), RCAR_GP_PIN(7, 7), RCAR_GP_PIN(7, 6), + RCAR_GP_PIN(7, 3), RCAR_GP_PIN(7, 18), RCAR_GP_PIN(7, 17), + RCAR_GP_PIN(7, 12), RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 15), + RCAR_GP_PIN(7, 16), RCAR_GP_PIN(7, 4), RCAR_GP_PIN(7, 19), + RCAR_GP_PIN(7, 20), RCAR_GP_PIN(7, 2), RCAR_GP_PIN(7, 1), + RCAR_GP_PIN(7, 0), +}; +static const unsigned int avb0_mii_mux[] = { + AVB0_MII_TD0_MARK, AVB0_MII_TD1_MARK, AVB0_MII_TD2_MARK, + AVB0_MII_TD3_MARK, AVB0_MII_RD0_MARK, AVB0_MII_RD1_MARK, + AVB0_MII_RD2_MARK, AVB0_MII_RD3_MARK, AVB0_MII_TXC_MARK, + AVB0_MII_TX_EN_MARK, AVB0_MII_TX_ER_MARK, AVB0_MII_RXC_MARK, + AVB0_MII_RX_DV_MARK, AVB0_MII_RX_ER_MARK, AVB0_MII_CRS_MARK, + AVB0_MII_COL_MARK, +}; static const unsigned int avb0_rgmii_pins[] = { /* * AVB0_TX_CTL, AVB0_TXC, AVB0_TD0, AVB0_TD1, AVB0_TD2, AVB0_TD3, @@ -1315,6 +1340,30 @@ static const unsigned int avb1_mdio_pins[] = { static const unsigned int avb1_mdio_mux[] = { AVB1_MDC_MARK, AVB1_MDIO_MARK, }; +static const unsigned int avb1_mii_pins[] = { + /* + * AVB1_MII_TD0, AVB1_MII_TD1, AVB1_MII_TD2, + * AVB1_MII_TD3, AVB1_MII_RD0, AVB1_MII_RD1, + * AVB1_MII_RD2, AVB1_MII_RD3, AVB1_MII_TXC, + * AVB1_MII_TX_EN, AVB1_MII_TX_ER, AVB1_MII_RXC, + * AVB1_MII_RX_DV, AVB1_MII_RX_ER, AVB1_MII_CRS, + * AVB1_MII_COL + */ + RCAR_GP_PIN(6, 13), RCAR_GP_PIN(6, 12), RCAR_GP_PIN(6, 16), + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(6, 15), RCAR_GP_PIN(6, 14), + RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 19), RCAR_GP_PIN(6, 6), + RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 4), RCAR_GP_PIN(6, 8), + RCAR_GP_PIN(6, 9), RCAR_GP_PIN(6, 5), RCAR_GP_PIN(6, 11), + RCAR_GP_PIN(6, 10), +}; +static const unsigned int avb1_mii_mux[] = { + AVB1_MII_TD0_MARK, AVB1_MII_TD1_MARK, AVB1_MII_TD2_MARK, + AVB1_MII_TD3_MARK, AVB1_MII_RD0_MARK, AVB1_MII_RD1_MARK, + AVB1_MII_RD2_MARK, AVB1_MII_RD3_MARK, AVB1_MII_TXC_MARK, + AVB1_MII_TX_EN_MARK, AVB1_MII_TX_ER_MARK, AVB1_MII_RXC_MARK, + AVB1_MII_RX_DV_MARK, AVB1_MII_RX_ER_MARK, AVB1_MII_CRS_MARK, + AVB1_MII_COL_MARK, +}; static const unsigned int avb1_rgmii_pins[] = { /* * AVB1_TX_CTL, AVB1_TXC, AVB1_TD0, AVB1_TD1, AVB1_TD2, AVB1_TD3, @@ -1510,7 +1559,7 @@ static const unsigned int hscif0_ctrl_mux[] = { HRTS0_N_MARK, HCTS0_N_MARK, }; -/* - HSCIF1_A ----------------------------------------------------------------- */ +/* - HSCIF1 ------------------------------------------------------------------- */ static const unsigned int hscif1_data_a_pins[] = { /* HRX1_A, HTX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), @@ -1533,7 +1582,6 @@ static const unsigned int hscif1_ctrl_a_mux[] = { HRTS1_N_A_MARK, HCTS1_N_A_MARK, }; -/* - HSCIF1_B ---------------------------------------------------------------- */ static const unsigned int hscif1_data_b_pins[] = { /* HRX1_B, HTX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), @@ -1579,7 +1627,7 @@ static const unsigned int hscif2_ctrl_mux[] = { HRTS2_N_MARK, HCTS2_N_MARK, }; -/* - HSCIF3_A ----------------------------------------------------------------- */ +/* - HSCIF3 ------------------------------------------------------------------- */ static const unsigned int hscif3_data_a_pins[] = { /* HRX3_A, HTX3_A */ RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 28), @@ -1602,7 +1650,6 @@ static const unsigned int hscif3_ctrl_a_mux[] = { HRTS3_N_A_MARK, HCTS3_N_A_MARK, }; -/* - HSCIF3_B ----------------------------------------------------------------- */ static const unsigned int hscif3_data_b_pins[] = { /* HRX3_B, HTX3_B */ RCAR_GP_PIN(1, 4), RCAR_GP_PIN(1, 0), @@ -1661,6 +1708,90 @@ static const unsigned int i2c3_mux[] = { SDA3_MARK, SCL3_MARK, }; +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_a_pins[] = { + /* IRQ0_A */ + RCAR_GP_PIN(0, 6), +}; +static const unsigned int intc_ex_irq0_a_mux[] = { + IRQ0_A_MARK, +}; +static const unsigned int intc_ex_irq0_b_pins[] = { + /* IRQ0_B */ + RCAR_GP_PIN(1, 20), +}; +static const unsigned int intc_ex_irq0_b_mux[] = { + IRQ0_B_MARK, +}; + +static const unsigned int intc_ex_irq1_a_pins[] = { + /* IRQ1_A */ + RCAR_GP_PIN(0, 5), +}; +static const unsigned int intc_ex_irq1_a_mux[] = { + IRQ1_A_MARK, +}; +static const unsigned int intc_ex_irq1_b_pins[] = { + /* IRQ1_B */ + RCAR_GP_PIN(1, 21), +}; +static const unsigned int intc_ex_irq1_b_mux[] = { + IRQ1_B_MARK, +}; + +static const unsigned int intc_ex_irq2_a_pins[] = { + /* IRQ2_A */ + RCAR_GP_PIN(0, 4), +}; +static const unsigned int intc_ex_irq2_a_mux[] = { + IRQ2_A_MARK, +}; +static const unsigned int intc_ex_irq2_b_pins[] = { + /* IRQ2_B */ + RCAR_GP_PIN(0, 13), +}; +static const unsigned int intc_ex_irq2_b_mux[] = { + IRQ2_B_MARK, +}; + +static const unsigned int intc_ex_irq3_a_pins[] = { + /* IRQ3_A */ + RCAR_GP_PIN(0, 3), +}; +static const unsigned int intc_ex_irq3_a_mux[] = { + IRQ3_A_MARK, +}; +static const unsigned int intc_ex_irq3_b_pins[] = { + /* IRQ3_B */ + RCAR_GP_PIN(1, 23), +}; +static const unsigned int intc_ex_irq3_b_mux[] = { + IRQ3_B_MARK, +}; + +static const unsigned int intc_ex_irq4_a_pins[] = { + /* IRQ4_A */ + RCAR_GP_PIN(1, 17), +}; +static const unsigned int intc_ex_irq4_a_mux[] = { + IRQ4_A_MARK, +}; +static const unsigned int intc_ex_irq4_b_pins[] = { + /* IRQ4_B */ + RCAR_GP_PIN(2, 3), +}; +static const unsigned int intc_ex_irq4_b_mux[] = { + IRQ4_B_MARK, +}; + +static const unsigned int intc_ex_irq5_pins[] = { + /* IRQ5 */ + RCAR_GP_PIN(2, 2), +}; +static const unsigned int intc_ex_irq5_mux[] = { + IRQ5_MARK, +}; + /* - MMC -------------------------------------------------------------------- */ static const unsigned int mmc_data_pins[] = { /* MMC_SD_D[0:3], MMC_D[4:7] */ @@ -1978,7 +2109,7 @@ static const unsigned int pcie0_clkreq_n_mux[] = { PCIE0_CLKREQ_N_MARK, }; -/* - PWM0_A ------------------------------------------------------------------- */ +/* - PWM0 --------------------------------------------------------------------- */ static const unsigned int pwm0_a_pins[] = { /* PWM0_A */ RCAR_GP_PIN(1, 15), @@ -1987,7 +2118,6 @@ static const unsigned int pwm0_a_mux[] = { PWM0_A_MARK, }; -/* - PWM0_B ------------------------------------------------------------------- */ static const unsigned int pwm0_b_pins[] = { /* PWM0_B */ RCAR_GP_PIN(1, 14), @@ -1996,7 +2126,7 @@ static const unsigned int pwm0_b_mux[] = { PWM0_B_MARK, }; -/* - PWM1_A ------------------------------------------------------------------- */ +/* - PWM1 --------------------------------------------------------------------- */ static const unsigned int pwm1_a_pins[] = { /* PWM1_A */ RCAR_GP_PIN(3, 13), @@ -2005,7 +2135,6 @@ static const unsigned int pwm1_a_mux[] = { PWM1_A_MARK, }; -/* - PWM1_B ------------------------------------------------------------------- */ static const unsigned int pwm1_b_pins[] = { /* PWM1_B */ RCAR_GP_PIN(2, 13), @@ -2014,7 +2143,6 @@ static const unsigned int pwm1_b_mux[] = { PWM1_B_MARK, }; -/* - PWM1_C ------------------------------------------------------------------- */ static const unsigned int pwm1_c_pins[] = { /* PWM1_C */ RCAR_GP_PIN(2, 17), @@ -2023,7 +2151,7 @@ static const unsigned int pwm1_c_mux[] = { PWM1_C_MARK, }; -/* - PWM2_A ------------------------------------------------------------------- */ +/* - PWM2 --------------------------------------------------------------------- */ static const unsigned int pwm2_a_pins[] = { /* PWM2_A */ RCAR_GP_PIN(3, 14), @@ -2032,7 +2160,6 @@ static const unsigned int pwm2_a_mux[] = { PWM2_A_MARK, }; -/* - PWM2_B ------------------------------------------------------------------- */ static const unsigned int pwm2_b_pins[] = { /* PWM2_B */ RCAR_GP_PIN(2, 14), @@ -2041,7 +2168,6 @@ static const unsigned int pwm2_b_mux[] = { PWM2_B_MARK, }; -/* - PWM2_C ------------------------------------------------------------------- */ static const unsigned int pwm2_c_pins[] = { /* PWM2_C */ RCAR_GP_PIN(2, 19), @@ -2050,7 +2176,7 @@ static const unsigned int pwm2_c_mux[] = { PWM2_C_MARK, }; -/* - PWM3_A ------------------------------------------------------------------- */ +/* - PWM3 --------------------------------------------------------------------- */ static const unsigned int pwm3_a_pins[] = { /* PWM3_A */ RCAR_GP_PIN(4, 14), @@ -2059,7 +2185,6 @@ static const unsigned int pwm3_a_mux[] = { PWM3_A_MARK, }; -/* - PWM3_B ------------------------------------------------------------------- */ static const unsigned int pwm3_b_pins[] = { /* PWM3_B */ RCAR_GP_PIN(2, 15), @@ -2068,7 +2193,6 @@ static const unsigned int pwm3_b_mux[] = { PWM3_B_MARK, }; -/* - PWM3_C ------------------------------------------------------------------- */ static const unsigned int pwm3_c_pins[] = { /* PWM3_C */ RCAR_GP_PIN(1, 22), @@ -2145,7 +2269,7 @@ static const unsigned int scif0_ctrl_mux[] = { RTS0_N_MARK, CTS0_N_MARK, }; -/* - SCIF1_A ------------------------------------------------------------------ */ +/* - SCIF1 -------------------------------------------------------------------- */ static const unsigned int scif1_data_a_pins[] = { /* RX1_A, TX1_A */ RCAR_GP_PIN(0, 15), RCAR_GP_PIN(0, 14), @@ -2168,7 +2292,6 @@ static const unsigned int scif1_ctrl_a_mux[] = { RTS1_N_A_MARK, CTS1_N_A_MARK, }; -/* - SCIF1_B ------------------------------------------------------------------ */ static const unsigned int scif1_data_b_pins[] = { /* RX1_B, TX1_B */ RCAR_GP_PIN(1, 7), RCAR_GP_PIN(1, 6), @@ -2191,7 +2314,7 @@ static const unsigned int scif1_ctrl_b_mux[] = { RTS1_N_B_MARK, CTS1_N_B_MARK, }; -/* - SCIF3_A ------------------------------------------------------------------ */ +/* - SCIF3 -------------------------------------------------------------------- */ static const unsigned int scif3_data_a_pins[] = { /* RX3_A, TX3_A */ RCAR_GP_PIN(1, 27), RCAR_GP_PIN(1, 28), @@ -2214,7 +2337,6 @@ static const unsigned int scif3_ctrl_a_mux[] = { RTS3_N_A_MARK, CTS3_N_A_MARK, }; -/* - SCIF3_B ------------------------------------------------------------------ */ static const unsigned int scif3_data_b_pins[] = { /* RX3_B, TX3_B */ RCAR_GP_PIN(1, 1), RCAR_GP_PIN(1, 0), @@ -2293,7 +2415,7 @@ static const unsigned int ssi_ctrl_mux[] = { SSI_SCK_MARK, SSI_WS_MARK, }; -/* - TPU_A ------------------------------------------------------------------- */ +/* - TPU --------------------------------------------------------------------- */ static const unsigned int tpu_to0_a_pins[] = { /* TPU0TO0_A */ RCAR_GP_PIN(2, 8), @@ -2323,7 +2445,6 @@ static const unsigned int tpu_to3_a_mux[] = { TPU0TO3_A_MARK, }; -/* - TPU_B ------------------------------------------------------------------- */ static const unsigned int tpu_to0_b_pins[] = { /* TPU0TO0_B */ RCAR_GP_PIN(1, 25), @@ -2361,6 +2482,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb0_magic), SH_PFC_PIN_GROUP(avb0_phy_int), SH_PFC_PIN_GROUP(avb0_mdio), + SH_PFC_PIN_GROUP(avb0_mii), SH_PFC_PIN_GROUP(avb0_rgmii), SH_PFC_PIN_GROUP(avb0_txcrefclk), SH_PFC_PIN_GROUP(avb0_avtp_pps), @@ -2371,6 +2493,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(avb1_magic), SH_PFC_PIN_GROUP(avb1_phy_int), SH_PFC_PIN_GROUP(avb1_mdio), + SH_PFC_PIN_GROUP(avb1_mii), SH_PFC_PIN_GROUP(avb1_rgmii), SH_PFC_PIN_GROUP(avb1_txcrefclk), SH_PFC_PIN_GROUP(avb1_avtp_pps), @@ -2417,6 +2540,18 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(i2c2), SH_PFC_PIN_GROUP(i2c3), + SH_PFC_PIN_GROUP(intc_ex_irq0_a), + SH_PFC_PIN_GROUP(intc_ex_irq0_b), + SH_PFC_PIN_GROUP(intc_ex_irq1_a), + SH_PFC_PIN_GROUP(intc_ex_irq1_b), + SH_PFC_PIN_GROUP(intc_ex_irq2_a), + SH_PFC_PIN_GROUP(intc_ex_irq2_b), + SH_PFC_PIN_GROUP(intc_ex_irq3_a), + SH_PFC_PIN_GROUP(intc_ex_irq3_b), + SH_PFC_PIN_GROUP(intc_ex_irq4_a), + SH_PFC_PIN_GROUP(intc_ex_irq4_b), + SH_PFC_PIN_GROUP(intc_ex_irq5), + BUS_DATA_PIN_GROUP(mmc_data, 1), BUS_DATA_PIN_GROUP(mmc_data, 4), BUS_DATA_PIN_GROUP(mmc_data, 8), @@ -2533,6 +2668,7 @@ static const char * const avb0_groups[] = { "avb0_magic", "avb0_phy_int", "avb0_mdio", + "avb0_mii", "avb0_rgmii", "avb0_txcrefclk", "avb0_avtp_pps", @@ -2545,6 +2681,7 @@ static const char * const avb1_groups[] = { "avb1_magic", "avb1_phy_int", "avb1_mdio", + "avb1_mii", "avb1_rgmii", "avb1_txcrefclk", "avb1_avtp_pps", @@ -2630,6 +2767,20 @@ static const char * const i2c3_groups[] = { "i2c3", }; +static const char * const intc_ex_groups[] = { + "intc_ex_irq0_a", + "intc_ex_irq0_b", + "intc_ex_irq1_a", + "intc_ex_irq1_b", + "intc_ex_irq2_a", + "intc_ex_irq2_b", + "intc_ex_irq3_a", + "intc_ex_irq3_b", + "intc_ex_irq4_a", + "intc_ex_irq4_b", + "intc_ex_irq5", +}; + static const char * const mmc_groups[] = { "mmc_data1", "mmc_data4", @@ -2814,6 +2965,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(i2c2), SH_PFC_FUNCTION(i2c3), + SH_PFC_FUNCTION(intc_ex), + SH_PFC_FUNCTION(mmc), SH_PFC_FUNCTION(msiof0), diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile index a4a12069b36..1503153ddc9 100644 --- a/drivers/pinctrl/starfive/Makefile +++ b/drivers/pinctrl/starfive/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # Core -obj-$(CONFIG_$(SPL_TPL_)PINCTRL_STARFIVE) += pinctrl-starfive.o +obj-$(CONFIG_$(PHASE_)PINCTRL_STARFIVE) += pinctrl-starfive.o # SoC Drivers -obj-$(CONFIG_$(SPL_TPL_)PINCTRL_STARFIVE_JH7110) += pinctrl-jh7110-sys.o pinctrl-jh7110-aon.o +obj-$(CONFIG_$(PHASE_)PINCTRL_STARFIVE_JH7110) += pinctrl-jh7110-sys.o pinctrl-jh7110-aon.o diff --git a/drivers/pinctrl/tegra/Makefile b/drivers/pinctrl/tegra/Makefile index 75d3cabc62b..b1dda417475 100644 --- a/drivers/pinctrl/tegra/Makefile +++ b/drivers/pinctrl/tegra/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD ifdef CONFIG_TEGRA20 obj-y += pinctrl-tegra20.o else diff --git a/drivers/pinctrl/tegra/funcmux-tegra30.c b/drivers/pinctrl/tegra/funcmux-tegra30.c index e31b859beb8..5d3403ae441 100644 --- a/drivers/pinctrl/tegra/funcmux-tegra30.c +++ b/drivers/pinctrl/tegra/funcmux-tegra30.c @@ -33,6 +33,22 @@ int funcmux_select(enum periph_id id, int config) break; } break; + case PERIPH_ID_UART5: + switch (config) { + case FUNCMUX_UART5_SDMMC1: + pinmux_set_func(PMUX_PINGRP_SDMMC1_DAT3_PY4, + PMUX_FUNC_UARTE); + pinmux_set_func(PMUX_PINGRP_SDMMC1_DAT2_PY5, + PMUX_FUNC_UARTE); + + pinmux_set_io(PMUX_PINGRP_SDMMC1_DAT3_PY4, PMUX_PIN_OUTPUT); + pinmux_set_io(PMUX_PINGRP_SDMMC1_DAT2_PY5, PMUX_PIN_INPUT); + + pinmux_tristate_disable(PMUX_PINGRP_SDMMC1_DAT3_PY4); + pinmux_tristate_disable(PMUX_PINGRP_SDMMC1_DAT2_PY5); + break; + } + break; /* Add other periph IDs here as needed */ diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h index 5951835d6e8..da7bb4f6377 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier.h +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h @@ -126,7 +126,7 @@ struct uniphier_pinctrl_socdata { #define __UNIPHIER_PINMUX_FUNCTION(func) #func -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD /* * a tricky way to drop unneeded *_pins and *_muxvals arrays from SPL, * suppressing "defined but not used" warnings. diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 6f7e6fb0a6b..3f4d56f5139 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -3,13 +3,13 @@ # Copyright (c) 2009 Wind River Systems, Inc. # Tom Rix <Tom.Rix at windriver.com> -obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += acpi_pmc/ -obj-$(CONFIG_$(SPL_TPL_)POWER_DOMAIN) += domain/ +obj-$(CONFIG_$(PHASE_)ACPI_PMC) += acpi_pmc/ +obj-$(CONFIG_$(PHASE_)POWER_DOMAIN) += domain/ obj-y += pmic/ obj-y += regulator/ obj-$(CONFIG_AXP221_POWER) += axp221.o -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_AXP152_POWER) += axp152.o obj-$(CONFIG_AXP209_POWER) += axp209.o obj-$(CONFIG_AXP305_POWER) += axp_spl.o @@ -23,9 +23,9 @@ obj-$(CONFIG_SY8106A_POWER) += sy8106a.o obj-$(CONFIG_TPS6586X_POWER) += tps6586x.o obj-$(CONFIG_TWL4030_POWER) += twl4030.o obj-$(CONFIG_PALMAS_POWER) += palmas.o -obj-$(CONFIG_$(SPL_TPL_)POWER_LEGACY) += power_core.o +obj-$(CONFIG_$(PHASE_)POWER_LEGACY) += power_core.o obj-$(CONFIG_DIALOG_POWER) += power_dialog.o obj-$(CONFIG_POWER_FSL) += power_fsl.o -obj-$(CONFIG_$(SPL_TPL_)POWER_I2C) += power_i2c.o +obj-$(CONFIG_$(PHASE_)POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o obj-$(CONFIG_POWER_MT6323) += mt6323.o diff --git a/drivers/power/acpi_pmc/Makefile b/drivers/power/acpi_pmc/Makefile index 0db52a65824..3259b397a9a 100644 --- a/drivers/power/acpi_pmc/Makefile +++ b/drivers/power/acpi_pmc/Makefile @@ -3,4 +3,4 @@ # Copyright 2019 Google LLC obj-y += acpi-pmc-uclass.o -obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o +obj-$(CONFIG_$(PHASE_)ACPI_PMC_SANDBOX) += sandbox.o pmc_emul.o diff --git a/drivers/power/acpi_pmc/acpi-pmc-uclass.c b/drivers/power/acpi_pmc/acpi-pmc-uclass.c index c289cede15b..1e94104091e 100644 --- a/drivers/power/acpi_pmc/acpi-pmc-uclass.c +++ b/drivers/power/acpi_pmc/acpi-pmc-uclass.c @@ -60,7 +60,7 @@ int pmc_gpe_init(struct udevice *dev) * are different and if they aren't, use the reset values. */ if (dw[0] == dw[1] || dw[1] == dw[2]) { - if (spl_phase() > PHASE_TPL) + if (xpl_phase() > PHASE_TPL) log_info("PMC: Using default GPE route"); gpio_cfg = readl(upriv->gpe_cfg); for (i = 0; i < upriv->gpe0_count; i++) diff --git a/drivers/power/axp809.c b/drivers/power/axp809.c index 9e38e1a7450..ec3eca1ac4b 100644 --- a/drivers/power/axp809.c +++ b/drivers/power/axp809.c @@ -93,7 +93,7 @@ int axp_set_dcdc4(unsigned int mvolt) return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1, AXP809_OUTPUT_CTRL1_DCDC4_EN); - ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg); + ret = pmic_bus_write(AXP809_DCDC4_CTRL, cfg); if (ret) return ret; diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index 2daab73eb75..110646c503a 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2016, NVIDIA CORPORATION. # -obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o +obj-$(CONFIG_$(XPL_)POWER_DOMAIN) += power-domain-uclass.o obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index 8b6870c8646..c22fbe60675 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -456,25 +456,22 @@ static int imx8m_power_domain_of_xlate(struct power_domain *power_domain, static int imx8m_power_domain_bind(struct udevice *dev) { - int offset; + ofnode subnode; const char *name; int ret = 0; - offset = dev_of_offset(dev); - for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; - offset = fdt_next_subnode(gd->fdt_blob, offset)) { + ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { /* Bind the subnode to this driver */ - name = fdt_get_name(gd->fdt_blob, offset, NULL); + name = ofnode_get_name(subnode); /* Descend into 'pgc' subnode */ if (!strstr(name, "power-domain")) { - offset = fdt_first_subnode(gd->fdt_blob, offset); - name = fdt_get_name(gd->fdt_blob, offset, NULL); + subnode = ofnode_first_subnode(subnode); + name = ofnode_get_name(subnode); } - ret = device_bind_with_driver_data(dev, dev->driver, name, dev->driver_data, - offset_to_ofnode(offset), + subnode, NULL); if (ret == -ENODEV) @@ -514,8 +511,7 @@ static int imx8m_power_domain_of_to_plat(struct udevice *dev) struct imx_pgc_domain_data *domain_data = (struct imx_pgc_domain_data *)dev_get_driver_data(dev); - pdata->resource_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "reg", -1); + pdata->resource_id = ofnode_read_u32_default(dev_ofnode(dev), "reg", -1); pdata->domain = &domain_data->domains[pdata->resource_id]; pdata->regs = domain_data->pgc_regs; pdata->base = dev_read_addr_ptr(dev->parent); diff --git a/drivers/power/domain/meson-ee-pwrc.c b/drivers/power/domain/meson-ee-pwrc.c index 20e9f32b381..4d9f3bba644 100644 --- a/drivers/power/domain/meson-ee-pwrc.c +++ b/drivers/power/domain/meson-ee-pwrc.c @@ -60,6 +60,7 @@ struct meson_ee_pwrc_domain_desc { unsigned int mem_pd_count; struct meson_ee_pwrc_mem_domain *mem_pd; bool (*get_power)(struct power_domain *power_domain); + bool enabled; }; struct meson_ee_pwrc_domain_data { @@ -306,6 +307,8 @@ static int meson_ee_pwrc_off(struct power_domain *power_domain) clk_disable_bulk(&priv->clks); } + pwrc_domain->enabled = false; + return 0; } @@ -317,6 +320,9 @@ static int meson_ee_pwrc_on(struct power_domain *power_domain) pwrc_domain = &priv->data->domains[power_domain->id]; + if (pwrc_domain->enabled) + return 0; + if (pwrc_domain->top_pd) regmap_update_bits(priv->regmap_ao, pwrc_domain->top_pd->sleep_reg, @@ -347,8 +353,13 @@ static int meson_ee_pwrc_on(struct power_domain *power_domain) return ret; } - if (pwrc_domain->clk_names_count) - return clk_enable_bulk(&priv->clks); + if (pwrc_domain->clk_names_count) { + ret = clk_enable_bulk(&priv->clks); + if (ret) + return ret; + } + + pwrc_domain->enabled = true; return 0; } diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 562c1a3b122..bbcbcee4c35 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -394,6 +394,7 @@ config SPL_PMIC_LP87565 config PMIC_TPS65941 bool "Enable driver for Texas Instruments TPS65941 PMIC" + depends on DM_PMIC help The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. This driver binds the pmic children. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index a2d59deeed8..bc138f563ff 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -3,34 +3,34 @@ # Copyright (C) 2012 Samsung Electronics # Lukasz Majewski <l.majewski@samsung.com> -obj-$(CONFIG_$(SPL_TPL_)DM_PMIC) += pmic-uclass.o -obj-$(CONFIG_$(SPL_)DM_PMIC_FAN53555) += fan53555.o -obj-$(CONFIG_$(SPL_)DM_PMIC_DA9063) += da9063.o -obj-$(CONFIG_$(SPL_)DM_PMIC_MAX77663) += max77663.o +obj-$(CONFIG_$(PHASE_)DM_PMIC) += pmic-uclass.o +obj-$(CONFIG_$(XPL_)DM_PMIC_FAN53555) += fan53555.o +obj-$(CONFIG_$(XPL_)DM_PMIC_DA9063) += da9063.o +obj-$(CONFIG_$(XPL_)DM_PMIC_MAX77663) += max77663.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o -obj-$(CONFIG_$(SPL_)DM_PMIC_BD71837) += bd71837.o -obj-$(CONFIG_$(SPL_)DM_PMIC_MP5416) += mp5416.o -obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o -obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o +obj-$(CONFIG_$(XPL_)DM_PMIC_BD71837) += bd71837.o +obj-$(CONFIG_$(XPL_)DM_PMIC_MP5416) += mp5416.o +obj-$(CONFIG_$(XPL_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(XPL_)DM_PMIC_PCA9450) += pca9450.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_AB8500) += ab8500.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o -obj-$(CONFIG_$(SPL_)PMIC_AXP) += axp.o +obj-$(CONFIG_$(XPL_)PMIC_AXP) += axp.o obj-$(CONFIG_PMIC_MAX8997) += max8997.o obj-$(CONFIG_PMIC_QCOM) += pmic_qcom.o -obj-$(CONFIG_$(SPL_TPL_)PMIC_RK8XX) += rk8xx.o -obj-$(CONFIG_$(SPL_)PMIC_RN5T567) += rn5t567.o +obj-$(CONFIG_$(PHASE_)PMIC_RK8XX) += rk8xx.o +obj-$(CONFIG_$(XPL_)PMIC_RN5T567) += rn5t567.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o -obj-$(CONFIG_$(SPL_)DM_PMIC_TPS80031) += tps80031.o -obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o -obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o -obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o +obj-$(CONFIG_$(XPL_)DM_PMIC_TPS80031) += tps80031.o +obj-$(CONFIG_$(XPL_)PMIC_PALMAS) += palmas.o +obj-$(CONFIG_$(XPL_)PMIC_LP873X) += lp873x.o +obj-$(CONFIG_$(XPL_)PMIC_LP87565) += lp87565.o obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o obj-$(CONFIG_PMIC_TPS65217) += pmic_tps65217.o obj-$(CONFIG_PMIC_TPS65219) += tps65219.o @@ -38,7 +38,7 @@ obj-$(CONFIG_PMIC_TPS65941) += tps65941.o obj-$(CONFIG_PMIC_RAA215300) += raa215300.o obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o -ifeq ($(CONFIG_$(SPL_)POWER_LEGACY),y) +ifeq ($(CONFIG_$(XPL_)POWER_LEGACY),y) obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o @@ -47,5 +47,5 @@ obj-$(CONFIG_POWER_HI6553) += pmic_hi6553.o obj-$(CONFIG_POWER_MC34VR500) += pmic_mc34vr500.o endif -obj-$(CONFIG_$(SPL_)POWER_TPS62362) += pmic_tps62362.o +obj-$(CONFIG_$(XPL_)POWER_TPS62362) += pmic_tps62362.o obj-$(CONFIG_SPL_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/da9063.c b/drivers/power/pmic/da9063.c index 7bd3df39142..59c65702863 100644 --- a/drivers/power/pmic/da9063.c +++ b/drivers/power/pmic/da9063.c @@ -7,6 +7,9 @@ #include <fdtdec.h> #include <errno.h> #include <dm.h> +#include <dm/device-internal.h> +#include <dm/device_compat.h> +#include <dm/lists.h> #include <i2c.h> #include <log.h> #include <linux/printk.h> @@ -86,6 +89,7 @@ static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len) static int da9063_bind(struct udevice *dev) { ofnode regulators_node; + struct driver *drv; int children; regulators_node = dev_read_subnode(dev, "regulators"); @@ -101,8 +105,12 @@ static int da9063_bind(struct udevice *dev) if (!children) debug("%s: %s - no child found\n", __func__, dev->name); - /* Always return success for this device */ - return 0; + drv = lists_driver_lookup_name("da9063-wdt"); + if (!drv) + return 0; + + return device_bind_with_driver_data(dev, drv, "da9063-wdt", dev->driver_data, + dev_ofnode(dev), &dev); } static int da9063_probe(struct udevice *dev) diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index 07af6273d8a..9d875f8bdbe 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -42,7 +42,7 @@ static int pca9450_write(struct udevice *dev, uint reg, const uint8_t *buff, int len) { if (dm_i2c_write(dev, reg, buff, len)) { - pr_err("write error to device: %p register: %#x!", dev, reg); + pr_err("write error to device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -53,7 +53,7 @@ static int pca9450_read(struct udevice *dev, uint reg, uint8_t *buff, int len) { if (dm_i2c_read(dev, reg, buff, len)) { - pr_err("read error from device: %p register: %#x!", dev, reg); + pr_err("read error from device: %p register: %#x!\n", dev, reg); return -EIO; } @@ -121,6 +121,7 @@ static const struct udevice_id pca9450_ids[] = { { .compatible = "nxp,pca9450b", .data = NXP_CHIP_TYPE_PCA9450BC, }, { .compatible = "nxp,pca9450c", .data = NXP_CHIP_TYPE_PCA9450BC, }, { .compatible = "nxp,pca9451a", .data = NXP_CHIP_TYPE_PCA9451A, }, + { .compatible = "nxp,pca9452", .data = NXP_CHIP_TYPE_PCA9452, }, { } }; diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index 4d5a5ceafad..a14555cf472 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -237,7 +237,7 @@ static int rk8xx_bind(struct udevice *dev) if (!children) debug("%s: %s - no child found\n", __func__, dev->name); - if (IS_ENABLED(CONFIG_SPL_BUILD) && + if (IS_ENABLED(CONFIG_XPL_BUILD) && IS_ENABLED(CONFIG_ROCKCHIP_RK8XX_DISABLE_BOOT_ON_POWERON)) dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); @@ -331,7 +331,7 @@ static int rk8xx_probe(struct udevice *dev) pmic_reg_read(dev, init_data[i].reg)); } - if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { printf("PMIC: RK%x ", show_variant); if (on_source && off_source) printf("(on=0x%02x, off=0x%02x)", diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index c99a0c27b33..f0415fbd172 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -91,7 +91,7 @@ static int stpmic1_bind(struct udevice *dev) dev_dbg(dev, "no child found\n"); #endif /* DM_REGULATOR */ - if (!IS_ENABLED(CONFIG_SPL_BUILD)) { + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { ret = device_bind_driver(dev, "stpmic1-nvm", "stpmic1-nvm", NULL); if (ret) @@ -124,7 +124,7 @@ U_BOOT_DRIVER(pmic_stpmic1) = { .ops = &stpmic1_ops, }; -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static int stpmic1_nvm_rw(struct udevice *dev, u8 addr, u8 *buf, int buf_len, enum pmic_nvm_op op) { @@ -230,7 +230,7 @@ U_BOOT_DRIVER(stpmic1_nvm) = { .id = UCLASS_MISC, .ops = &stpmic1_nvm_ops, }; -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ #ifdef CONFIG_SYSRESET static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) diff --git a/drivers/power/power_core.c b/drivers/power/power_core.c index 1caf9f09346..61b2fe5f54a 100644 --- a/drivers/power/power_core.c +++ b/drivers/power/power_core.c @@ -78,7 +78,7 @@ struct pmic *pmic_get(const char *s) return NULL; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD static int pmic_dump(struct pmic *p) { int i, ret; diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 54db0885657..ca6c89d13b5 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -4,41 +4,41 @@ # Przemyslaw Marczak <p.marczak@samsung.com> # -obj-$(CONFIG_$(SPL_)DM_REGULATOR) += regulator-uclass.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR) += regulator-uclass.o obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o obj-$(CONFIG_REGULATOR_AS3722) += as3722_regulator.o -obj-$(CONFIG_$(SPL_)REGULATOR_AXP) += axp_regulator.o -obj-$(CONFIG_$(SPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_MAX77663) += max77663_regulator.o +obj-$(CONFIG_$(XPL_)REGULATOR_AXP) += axp_regulator.o +obj-$(CONFIG_$(XPL_)REGULATOR_AXP_USB_POWER) += axp_usb_power.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_DA9063) += da9063.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_MAX77663) += max77663_regulator.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o -obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_BD71837) += bd71837.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_PCA9450) += pca9450.o -obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o +obj-$(CONFIG_$(XPL_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_BD71837) += bd71837.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_PCA9450) += pca9450.o +obj-$(CONFIG_$(XPL_)REGULATOR_PWM) += pwm_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_FAN53555) += fan53555.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_COMMON) += regulator_common.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o -obj-$(CONFIG_$(SPL_TPL_)REGULATOR_RK8XX) += rk8xx.o +obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS6287X) += tps6287x_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS80031) += tps80031_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS6287X) += tps6287x_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_TPS80031) += tps80031_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_STPMIC1) += stpmic1.o obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o -obj-$(CONFIG_$(SPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o +obj-$(CONFIG_$(XPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o diff --git a/drivers/power/regulator/pca9450.c b/drivers/power/regulator/pca9450.c index 9faf1eab5f9..a2a34244723 100644 --- a/drivers/power/regulator/pca9450.c +++ b/drivers/power/regulator/pca9450.c @@ -71,6 +71,10 @@ static struct pca9450_vrange pca9450_buck123_vranges[] = { PCA_RANGE(600000, 12500, 0, 0x7f), }; +static struct pca9450_vrange pca9450_trim_buck13_vranges[] = { + PCA_RANGE(650000, 12500, 0, 0x7f), +}; + static struct pca9450_vrange pca9450_buck456_vranges[] = { PCA_RANGE(600000, 25000, 0, 0x70), PCA_RANGE(3400000, 0, 0x71, 0x7f), @@ -105,12 +109,18 @@ static struct pca9450_plat pca9450_reg_data[] = { PCA_DATA("BUCK1", PCA9450_BUCK1CTRL, HW_STATE_CONTROL, PCA9450_BUCK1OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, pca9450_buck123_vranges), + PCA_DATA("BUCK1_TRIM", PCA9450_BUCK1CTRL, HW_STATE_CONTROL, + PCA9450_BUCK1OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_trim_buck13_vranges), PCA_DATA("BUCK2", PCA9450_BUCK2CTRL, HW_STATE_CONTROL, PCA9450_BUCK2OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, pca9450_buck123_vranges), PCA_DATA("BUCK3", PCA9450_BUCK3CTRL, HW_STATE_CONTROL, PCA9450_BUCK3OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, pca9450_buck123_vranges), + PCA_DATA("BUCK3_TRIM", PCA9450_BUCK3CTRL, HW_STATE_CONTROL, + PCA9450_BUCK3OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_trim_buck13_vranges), /* Bucks 4-6 which do not support dynamic voltage scaling */ PCA_DATA("BUCK4", PCA9450_BUCK4CTRL, HW_STATE_CONTROL, PCA9450_BUCK4OUT, PCA9450_DVS_BUCK_RUN_MASK, @@ -271,20 +281,38 @@ static int pca9450_set_value(struct udevice *dev, int uvolt) static int pca9450_regulator_probe(struct udevice *dev) { struct pca9450_plat *plat = dev_get_plat(dev); - int i, type; + int i, type, ret; + unsigned int val; + bool pmic_trim = false; type = dev_get_driver_data(dev_get_parent(dev)); if (type != NXP_CHIP_TYPE_PCA9450A && type != NXP_CHIP_TYPE_PCA9450BC && - type != NXP_CHIP_TYPE_PCA9451A) { + type != NXP_CHIP_TYPE_PCA9451A && type != NXP_CHIP_TYPE_PCA9452) { debug("Unknown PMIC type\n"); return -EINVAL; } + ret = pmic_reg_read(dev->parent, PCA9450_PWR_CTRL); + if (ret < 0) + return ret; + + val = ret; + + if ((type == NXP_CHIP_TYPE_PCA9451A || type == NXP_CHIP_TYPE_PCA9452) && + (val & PCA9450_REG_PWRCTRL_TOFF_DEB)) + pmic_trim = true; + for (i = 0; i < ARRAY_SIZE(pca9450_reg_data); i++) { if (strcmp(dev->name, pca9450_reg_data[i].name)) continue; + if (pmic_trim && (!strcmp(pca9450_reg_data[i].name, "BUCK1") || + !strcmp(pca9450_reg_data[i].name, "BUCK3"))) { + *plat = pca9450_reg_data[i + 1]; + return 0; + } + /* PCA9450B/PCA9450C uses BUCK1 and BUCK3 in dual-phase */ if (type == NXP_CHIP_TYPE_PCA9450BC && !strcmp(pca9450_reg_data[i].name, "BUCK3")) { @@ -299,6 +327,12 @@ static int pca9450_regulator_probe(struct udevice *dev) continue; } + if (type == NXP_CHIP_TYPE_PCA9452 && + (!strcmp(pca9450_reg_data[i].name, "BUCK3") || + !strcmp(pca9450_reg_data[i].name, "LDO2"))) { + continue; + } + *plat = pca9450_reg_data[i]; return 0; diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index 375d06e3207..368675ebb9f 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -16,7 +16,7 @@ #include <power/pmic.h> #include <power/regulator.h> -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD #define ENABLE_DRIVER #endif diff --git a/drivers/power/sy8106a.c b/drivers/power/sy8106a.c index fb6028de71a..d9a2b6904b0 100644 --- a/drivers/power/sy8106a.c +++ b/drivers/power/sy8106a.c @@ -10,7 +10,7 @@ #define SY8106A_VOUT1_SEL 1 #define SY8106A_VOUT1_SEL_ENABLE (1 << 7) -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static u8 sy8106a_mvolt_to_cfg(int mvolt, int min, int max, int div) { if (mvolt < min) diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile index fdb2e78ec9e..f92e86eaa3f 100644 --- a/drivers/ram/Makefile +++ b/drivers/ram/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2015 Google, Inc # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # -obj-$(CONFIG_$(SPL_TPL_)DM) += ram-uclass.o +obj-$(CONFIG_$(PHASE_)DM) += ram-uclass.o obj-$(CONFIG_MPC83XX_SDRAM) += mpc83xx_sdram.o obj-$(CONFIG_SANDBOX) += sandbox_ram.o obj-$(CONFIG_STM32MP1_DDR) += stm32mp1/ @@ -20,7 +20,7 @@ obj-$(CONFIG_K3_DDRSS) += k3-ddrss/ obj-$(CONFIG_IMXRT_SDRAM) += imxrt_sdram.o obj-$(CONFIG_RAM_SIFIVE) += sifive/ -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_STARFIVE_DDR) += starfive/ endif diff --git a/drivers/ram/mediatek/ddr3-mt7629.c b/drivers/ram/mediatek/ddr3-mt7629.c index c27c4593b9d..e9791697066 100644 --- a/drivers/ram/mediatek/ddr3-mt7629.c +++ b/drivers/ram/mediatek/ddr3-mt7629.c @@ -233,7 +233,7 @@ struct mtk_ddr3_priv { struct clk mem_mux; }; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static int mtk_ddr3_rank_size_detect(struct udevice *dev) { struct mtk_ddr3_priv *priv = dev_get_priv(dev); @@ -697,7 +697,7 @@ static int mtk_ddr3_probe(struct udevice *dev) if (priv->dramc_ao == FDT_ADDR_T_NONE) return -EINVAL; -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD int ret; ret = clk_get_by_index(dev, 0, &priv->phy); diff --git a/drivers/ram/rockchip/sdram_rk3188.c b/drivers/ram/rockchip/sdram_rk3188.c index 618bce5c9f4..ffff7d55f33 100644 --- a/drivers/ram/rockchip/sdram_rk3188.c +++ b/drivers/ram/rockchip/sdram_rk3188.c @@ -84,7 +84,7 @@ const int ddrconf_table[] = { #define DQS_GATE_TRAINING_ERROR_RANK0 (1 << 4) #define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4) -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static void copy_to_reg(u32 *dest, const u32 *src, u32 n) { int i; @@ -851,7 +851,7 @@ static int rk3188_dmc_of_to_plat(struct udevice *dev) return 0; } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ #if CONFIG_IS_ENABLED(OF_PLATDATA) static int conv_of_plat(struct udevice *dev) @@ -878,7 +878,7 @@ static int conv_of_plat(struct udevice *dev) static int rk3188_dmc_probe(struct udevice *dev) { -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD struct rk3188_sdram_params *plat = dev_get_plat(dev); struct regmap *map; struct udevice *dev_clk; @@ -888,7 +888,7 @@ static int rk3188_dmc_probe(struct udevice *dev) priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD #if CONFIG_IS_ENABLED(OF_PLATDATA) ret = conv_of_plat(dev); if (ret) @@ -950,12 +950,12 @@ U_BOOT_DRIVER(rockchip_rk3188_dmc) = { .id = UCLASS_RAM, .of_match = rk3188_dmc_ids, .ops = &rk3188_dmc_ops, -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD .of_to_plat = rk3188_dmc_of_to_plat, #endif .probe = rk3188_dmc_probe, .priv_auto = sizeof(struct dram_info), -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD .plat_auto = sizeof(struct rk3188_sdram_params), #endif }; diff --git a/drivers/ram/rockchip/sdram_rk3288.c b/drivers/ram/rockchip/sdram_rk3288.c index c9f61e933e9..25ceab98ee9 100644 --- a/drivers/ram/rockchip/sdram_rk3288.c +++ b/drivers/ram/rockchip/sdram_rk3288.c @@ -84,7 +84,7 @@ const int ddrconf_table[] = { #define DQS_GATE_TRAINING_ERROR_RANK1 (2 << 4) #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) static void copy_to_reg(u32 *dest, const u32 *src, u32 n) { int i; @@ -1013,7 +1013,7 @@ static int rk3288_dmc_of_to_plat(struct udevice *dev) return 0; } -#endif /* CONFIG_SPL_BUILD */ +#endif /* CONFIG_XPL_BUILD */ #if CONFIG_IS_ENABLED(OF_PLATDATA) static int conv_of_plat(struct udevice *dev) @@ -1041,7 +1041,7 @@ static int conv_of_plat(struct udevice *dev) static int rk3288_dmc_probe(struct udevice *dev) { #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) struct rk3288_sdram_params *plat = dev_get_plat(dev); struct udevice *dev_clk; struct regmap *map; @@ -1051,7 +1051,7 @@ static int rk3288_dmc_probe(struct udevice *dev) priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) #if CONFIG_IS_ENABLED(OF_PLATDATA) ret = conv_of_plat(dev); if (ret) @@ -1119,13 +1119,13 @@ U_BOOT_DRIVER(rockchip_rk3288_dmc) = { .of_match = rk3288_dmc_ids, .ops = &rk3288_dmc_ops, #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) .of_to_plat = rk3288_dmc_of_to_plat, #endif .probe = rk3288_dmc_probe, .priv_auto = sizeof(struct dram_info), #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) .plat_auto = sizeof(struct rk3288_sdram_params), #endif }; diff --git a/drivers/ram/rockchip/sdram_rk3399.c b/drivers/ram/rockchip/sdram_rk3399.c index 45270e27184..6fa8f268770 100644 --- a/drivers/ram/rockchip/sdram_rk3399.c +++ b/drivers/ram/rockchip/sdram_rk3399.c @@ -193,10 +193,10 @@ struct io_setting { */ static bool phase_sdram_init(void) { - return spl_phase() == PHASE_TPL || + return xpl_phase() == PHASE_TPL || (!IS_ENABLED(CONFIG_TPL) && !IS_ENABLED(CONFIG_ROCKCHIP_EXTERNAL_TPL) && - !spl_in_proper()); + !not_xpl()); } static struct io_setting * @@ -3196,7 +3196,7 @@ U_BOOT_DRIVER(dmc_rk3399) = { .probe = rk3399_dmc_probe, .priv_auto = sizeof(struct dram_info), #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) .plat_auto = sizeof(struct rockchip_dmc_plat), #endif }; diff --git a/drivers/ram/rockchip/sdram_rv1126.c b/drivers/ram/rockchip/sdram_rv1126.c index 4fbb088a8d9..b371f597d23 100644 --- a/drivers/ram/rockchip/sdram_rv1126.c +++ b/drivers/ram/rockchip/sdram_rv1126.c @@ -34,7 +34,7 @@ struct dram_info { #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) void __iomem *pctl; void __iomem *phy; struct rv1126_cru *cru; @@ -49,7 +49,7 @@ struct dram_info { }; #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) #define GRF_BASE_ADDR 0xfe000000 #define PMU_GRF_BASE_ADDR 0xfe020000 @@ -3507,7 +3507,7 @@ error: static int rv1126_dmc_probe(struct udevice *dev) { #if defined(CONFIG_TPL_BUILD) || \ - (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD)) + (!defined(CONFIG_TPL) && defined(CONFIG_XPL_BUILD)) if (rv1126_dmc_init(dev)) return 0; #else diff --git a/drivers/ram/sifive/sifive_ddr.c b/drivers/ram/sifive/sifive_ddr.c index bd2f438d727..c555d2af2d0 100644 --- a/drivers/ram/sifive/sifive_ddr.c +++ b/drivers/ram/sifive/sifive_ddr.c @@ -91,7 +91,7 @@ struct sifive_ddr_info { u32 *physical_filter_ctrl; }; -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_XPL_BUILD) struct sifive_ddr_params { struct sifive_ddrctl pctl_regs; struct sifive_ddrphy phy_regs; @@ -337,7 +337,7 @@ static int sifive_ddr_probe(struct udevice *dev) priv->info.base = gd->ram_base; priv->info.size = gd->ram_size; -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_XPL_BUILD) int ret; u32 clock = 0; @@ -404,7 +404,7 @@ U_BOOT_DRIVER(sifive_ddr) = { .ops = &sifive_ddr_ops, .probe = sifive_ddr_probe, .priv_auto = sizeof(struct sifive_ddr_info), -#if defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_XPL_BUILD) .plat_auto = sizeof(struct sifive_dmc_plat), #endif }; diff --git a/drivers/ram/starfive/Makefile b/drivers/ram/starfive/Makefile index 1df42c377bd..f1567b04b4c 100644 --- a/drivers/ram/starfive/Makefile +++ b/drivers/ram/starfive/Makefile @@ -2,10 +2,10 @@ # # Copyright (c) 2022 StarFive, Inc # -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_STARFIVE_DDR) += ddrphy_start.o obj-$(CONFIG_SPL_STARFIVE_DDR) += ddrphy_train.o obj-$(CONFIG_SPL_STARFIVE_DDR) += starfive_ddr.o obj-$(CONFIG_SPL_STARFIVE_DDR) += ddrphy_utils.o obj-$(CONFIG_SPL_STARFIVE_DDR) += ddrcsr_boot.o -endif
\ No newline at end of file +endif diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index debc458c0e2..e9cd6229ec4 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -371,7 +371,7 @@ static int stm32mp1_ddr_probe(struct udevice *dev) priv->info.base = STM32_DDR_BASE; - if (IS_ENABLED(CONFIG_SPL_BUILD)) { + if (IS_ENABLED(CONFIG_XPL_BUILD)) { priv->info.size = 0; ret = stm32mp1_ddr_setup(dev); diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index e09ed1aa4d4..801b0965e4f 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -4,7 +4,7 @@ # Texas Instruments Incorporated - https://www.ti.com/ # -obj-$(CONFIG_$(SPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o +obj-$(CONFIG_$(XPL_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o # Remote proc drivers - Please keep this list alphabetically sorted. obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 2eb639e4a65..d99a78c9828 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -32,4 +32,4 @@ obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o obj-$(CONFIG_RESET_DRA7) += reset-dra7.o obj-$(CONFIG_RESET_AT91) += reset-at91.o -obj-$(CONFIG_$(SPL_TPL_)RESET_JH7110) += reset-jh7110.o +obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 866437fd24f..76d108080d9 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -46,7 +46,7 @@ struct socfpga_reset_data { */ static bool socfpga_reset_keep_enabled(void) { -#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT) +#if !defined(CONFIG_XPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT) const char *env_str; long val; diff --git a/drivers/rng/Makefile b/drivers/rng/Makefile index 30553c9d6e9..30c58272d41 100644 --- a/drivers/rng/Makefile +++ b/drivers/rng/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2019, Linaro Limited # -obj-$(CONFIG_$(SPL_TPL_)DM_RNG) += rng-uclass.o +obj-$(CONFIG_$(PHASE_)DM_RNG) += rng-uclass.o obj-$(CONFIG_RNG_MESON) += meson-rng.o obj-$(CONFIG_RNG_SANDBOX) += sandbox_rng.o obj-$(CONFIG_RNG_MSM) += msm_rng.o diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 03a424c31a5..99b5a2a346a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -4,7 +4,7 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. #ccflags-y += -DDEBUG -obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o +obj-$(CONFIG_$(PHASE_)DM_RTC) += rtc-uclass.o obj-$(CONFIG_RTC_ARMADA38X) += armada38x.o obj-$(CONFIG_RTC_DAVINCI) += davinci.o @@ -17,7 +17,7 @@ obj-$(CONFIG_RTC_DS3232) += ds3232.o obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o obj-$(CONFIG_RTC_GOLDFISH) += goldfish_rtc.o obj-$(CONFIG_RTC_HT1380) += ht1380.o -obj-$(CONFIG_$(SPL_TPL_)RTC_SANDBOX) += i2c_rtc_emul.o +obj-$(CONFIG_$(PHASE_)RTC_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_ISL1208) += isl1208.o obj-$(CONFIG_RTC_M41T62) += m41t62.o obj-$(CONFIG_RTC_MAX313XX) += max313xx.o @@ -37,6 +37,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o obj-$(CONFIG_RTC_S35392A) += s35392a.o obj-$(CONFIG_RTC_STM32) += stm32_rtc.o -obj-$(CONFIG_$(SPL_TPL_)RTC_SANDBOX) += sandbox_rtc.o +obj-$(CONFIG_$(PHASE_)RTC_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_ABX80X) += abx80x.o obj-$(CONFIG_RTC_ZYNQMP) += zynqmp_rtc.o diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 628be4c89fb..b76de1b22a8 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -3,16 +3,16 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o ifdef CONFIG_SCSI -obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += scsi_bootdev.o +obj-$(CONFIG_$(PHASE_)BOOTSTD) += scsi_bootdev.o obj-$(CONFIG_SANDBOX) += sandbox_scsi.o obj-$(CONFIG_SANDBOX) += scsi_emul.o endif endif -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD ifdef CONFIG_SPL_SATA obj-$(CONFIG_SCSI) += scsi.o scsi-uclass.o endif diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 78810f98367..ebe692a9963 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -3,7 +3,7 @@ # (C) Copyright 2006-2009 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifeq ($(CONFIG_$(SPL_TPL_)DM_SERIAL),y) +ifeq ($(CONFIG_$(PHASE_)DM_SERIAL),y) obj-y += serial-uclass.o else obj-y += serial.o @@ -11,7 +11,7 @@ endif obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o -obj-$(CONFIG_$(SPL_)SYS_NS16550_SERIAL) += serial_ns16550.o +obj-$(CONFIG_$(XPL_)SYS_NS16550_SERIAL) += serial_ns16550.o obj-$(CONFIG_ALTERA_UART) += altera_uart.o obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o @@ -63,7 +63,7 @@ obj-$(CONFIG_XEN_SERIAL) += serial_xen.o obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o -ifndef CONFIG_SPL_BUILD +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_USB_TTY) += usbtty.o endif obj-$(CONFIG_UART4_SERIAL) += serial_adi_uart4.o diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index 7e45a80969e..0b35582aaa4 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -218,7 +218,7 @@ static const struct dm_serial_ops atmel_serial_ops = { .setbrg = atmel_serial_setbrg, }; -#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_CLK) +#if defined(CONFIG_XPL_BUILD) && !defined(CONFIG_SPL_CLK) static int atmel_serial_enable_clk(struct udevice *dev) { struct atmel_serial_priv *priv = dev_get_priv(dev); diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 6fcb5b523ac..3f6860f3916 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -227,7 +227,7 @@ static void ns16550_setbrg(struct ns16550 *com_port, int baud_divisor) void ns16550_init(struct ns16550 *com_port, int baud_divisor) { -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_OMAP34XX) +#if defined(CONFIG_XPL_BUILD) && defined(CONFIG_OMAP34XX) /* * On some OMAP3/OMAP4 devices when UART3 is configured for boot mode * before SPL starts only THRE bit is set. We have to empty the @@ -303,7 +303,7 @@ void ns16550_putc(struct ns16550 *com_port, char c) char ns16550_getc(struct ns16550 *com_port) { while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) { -#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_TTY) +#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_TTY) extern void usbtty_poll(void); usbtty_poll(); #endif @@ -473,7 +473,7 @@ static int ns16550_serial_getinfo(struct udevice *dev, struct ns16550_plat *plat = com_port->plat; /* save code size */ - if (!spl_in_proper()) + if (!not_xpl()) return -ENOSYS; info->type = SERIAL_CHIP_16550_COMPATIBLE; @@ -555,7 +555,7 @@ int ns16550_serial_of_to_plat(struct udevice *dev) struct clk clk; int err; - addr = spl_in_proper() ? dev_read_addr_size(dev, &size) : + addr = not_xpl() ? dev_read_addr_size(dev, &size) : dev_read_addr(dev); err = ns16550_serial_assign_base(plat, addr, size); if (err && !device_is_on_pci_bus(dev)) @@ -565,19 +565,19 @@ int ns16550_serial_of_to_plat(struct udevice *dev) plat->reg_shift = dev_read_u32_default(dev, "reg-shift", 0); plat->reg_width = dev_read_u32_default(dev, "reg-io-width", 1); - err = clk_get_by_index(dev, 0, &clk); - if (!err) { - err = clk_get_rate(&clk); - if (!IS_ERR_VALUE(err)) - plat->clock = err; - } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) { - debug("ns16550 failed to get clock\n"); - return err; - } - if (!plat->clock) - plat->clock = dev_read_u32_default(dev, "clock-frequency", - CFG_SYS_NS16550_CLK); + plat->clock = dev_read_u32_default(dev, "clock-frequency", 0); + if (!plat->clock) { + err = clk_get_by_index(dev, 0, &clk); + if (!err) { + err = clk_get_rate(&clk); + if (!IS_ERR_VALUE(err)) + plat->clock = err; + } else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) { + debug("ns16550 failed to get clock\n"); + return err; + } + } if (!plat->clock) plat->clock = CFG_SYS_NS16550_CLK; if (!plat->clock) { diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 84f02f7ac76..a08678dde4e 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -18,6 +18,7 @@ #include <dm/lists.h> #include <dm/device-internal.h> #include <dm/of_access.h> +#include <linux/build_bug.h> #include <linux/delay.h> DECLARE_GLOBAL_DATA_PTR; @@ -101,7 +102,7 @@ static void serial_find_console_or_panic(void) } } } - if (!IS_ENABLED(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(OF_CONTROL) || + if (!IS_ENABLED(CONFIG_XPL_BUILD) || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) { /* * Try to use CONFIG_CONS_INDEX if available (it is numbered @@ -328,11 +329,15 @@ static int __serial_tstc(struct udevice *dev) static int _serial_tstc(struct udevice *dev) { struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); + uint wr, avail; - /* Read all available chars into the RX buffer */ - while (__serial_tstc(dev)) { - upriv->buf[upriv->wr_ptr++] = __serial_getc(dev); - upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; + BUILD_BUG_ON_NOT_POWER_OF_2(CONFIG_SERIAL_RX_BUFFER_SIZE); + + /* Read all available chars into the RX buffer while there's room */ + avail = CONFIG_SERIAL_RX_BUFFER_SIZE - (upriv->wr_ptr - upriv->rd_ptr); + while (avail-- && __serial_tstc(dev)) { + wr = upriv->wr_ptr++ % CONFIG_SERIAL_RX_BUFFER_SIZE; + upriv->buf[wr] = __serial_getc(dev); } return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0; @@ -342,12 +347,13 @@ static int _serial_getc(struct udevice *dev) { struct serial_dev_priv *upriv = dev_get_uclass_priv(dev); char val; + uint rd; if (upriv->rd_ptr == upriv->wr_ptr) return __serial_getc(dev); - val = upriv->buf[upriv->rd_ptr++]; - upriv->rd_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE; + rd = upriv->rd_ptr++ % CONFIG_SERIAL_RX_BUFFER_SIZE; + val = upriv->buf[rd]; return val; } @@ -582,11 +588,6 @@ static int serial_post_probe(struct udevice *dev) sdev.getc = serial_stub_getc; sdev.tstc = serial_stub_tstc; -#if CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) - /* Allocate the RX buffer */ - upriv->buf = malloc(CONFIG_SERIAL_RX_BUFFER_SIZE); -#endif - stdio_register_dev(&sdev, &upriv->sdev); #endif return 0; diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index dc4bb06fa99..e10ca6eef76 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -315,7 +315,7 @@ static struct serial_device *get_current(void) /* We must have a console device */ if (!dev) { -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD puts("Cannot find console\n"); hang(); #else diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 801b7645afa..734780a124a 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -117,7 +117,7 @@ static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, u8 reg_width, writeb(val % 16, &uart->rest.value); } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD int s5p_serial_setbrg(struct udevice *dev, int baudrate) { struct s5p_serial_plat *plat = dev_get_plat(dev); diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c index 55f13c00ddf..b74712f3eeb 100644 --- a/drivers/serial/serial_zynq.c +++ b/drivers/serial/serial_zynq.c @@ -152,7 +152,7 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate) return 0; } -#if !defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_XPL_BUILD) static int zynq_serial_setconfig(struct udevice *dev, uint serial_config) { struct zynq_uart_plat *plat = dev_get_plat(dev); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index cd785aefd56..fa817ec4883 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -20,6 +20,12 @@ menuconfig SPI if SPI +config SPI_ADVANCE + bool "Enable the advance feature" + help + Enable the SPI advance feature support. By default this is disabled. + If you intend to use the advance feature support you should enable. + config DM_SPI bool "Enable Driver Model for SPI drivers" depends on DM @@ -93,6 +99,7 @@ config ATMEL_QSPI config ATMEL_SPI bool "Atmel SPI driver" + depends on ARCH_AT91 default y if ARCH_AT91 help This enables driver for the Atmel SPI Controller, present on @@ -126,6 +133,7 @@ config BCM63XX_SPI config BCMSTB_SPI bool "BCMSTB SPI driver" + depends on ARCH_BCMSTB help Enable the Broadcom set-top box SPI driver. This driver can be used to access the SPI flash on platforms embedding this @@ -164,6 +172,7 @@ config CADENCE_OSPI_VERSAL config CF_SPI bool "ColdFire SPI driver" + depends on M68K help Enable the ColdFire SPI driver. This driver can be used on some m68k SoCs. @@ -191,6 +200,7 @@ config DESIGNWARE_SPI config EXYNOS_SPI bool "Samsung Exynos SPI driver" + depends on ARCH_EXYNOS help Enable the Samsung Exynos SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Samsung @@ -198,6 +208,7 @@ config EXYNOS_SPI config FSL_DSPI bool "Freescale DSPI driver" + depends on FSL_LAYERSCAPE || ARCH_VF610 || ARCH_LS1021A || ARCH_LS1028A help Enable the Freescale DSPI driver. This driver can be used to access the SPI NOR flash and SPI Data flash on platforms embedding @@ -228,6 +239,7 @@ config GXP_SPI config ICH_SPI bool "Intel ICH SPI driver" + depends on X86 help Enable the Intel ICH SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Intel @@ -241,6 +253,7 @@ config IPROC_QSPI config KIRKWOOD_SPI bool "Marvell Kirkwood SPI Driver" + depends on ARCH_KIRKWOOD || ARCH_MVEBU help Enable support for SPI on various Marvell SoCs, such as Kirkwood and Armada 375. @@ -276,6 +289,7 @@ config MPC8XX_SPI config MPC8XXX_SPI bool "MPC8XXX SPI Driver" + depends on MPC83xx || MPC85xx help Enable support for SPI on the MPC8XXX PowerPC SoCs. @@ -335,6 +349,7 @@ config MVEBU_A3700_SPI config MXS_SPI bool "MXS SPI Driver" + depends on MACH_IMX help Enable the MXS SPI controller driver. This driver can be used on the i.MX23 and i.MX28 SoCs. @@ -416,6 +431,7 @@ config RENESAS_RPC_SPI config ROCKCHIP_SFC bool "Rockchip SFC Driver" + select BOUNCE_BUFFER help Enable the Rockchip SFC Driver for SPI NOR flash. This device is a limited purpose SPI controller for driving NOR flash on certain @@ -520,6 +536,7 @@ config STM32_SPI config TEGRA114_SPI bool "nVidia Tegra114 SPI driver" + depends on ARCH_TEGRA help Enable the nVidia Tegra114 SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this nVidia Tegra114 @@ -530,6 +547,7 @@ config TEGRA114_SPI config TEGRA20_SFLASH bool "nVidia Tegra20 Serial Flash controller driver" + depends on ARCH_TEGRA help Enable the nVidia Tegra20 Serial Flash controller driver. This driver can be used to access the SPI NOR flash on platforms embedding this @@ -537,6 +555,7 @@ config TEGRA20_SFLASH config TEGRA20_SLINK bool "nVidia Tegra20/Tegra30 SLINK driver" + depends on ARCH_TEGRA help Enable the nVidia Tegra20/Tegra30 SLINK driver. This driver can be used to access the SPI NOR flash on platforms embedding this @@ -544,6 +563,7 @@ config TEGRA20_SLINK config TEGRA210_QSPI bool "nVidia Tegra210 QSPI driver" + depends on ARCH_TEGRA help Enable the Tegra Quad-SPI (QSPI) driver for T210. This driver be used to access SPI chips on platforms embedding this @@ -552,6 +572,7 @@ config TEGRA210_QSPI config TI_QSPI bool "TI QSPI driver" imply TI_EDMA3 + depends on ARCH_OMAP2PLUS help Enable the TI Quad-SPI (QSPI) driver for DRA7xx and AM43xx evms. This driver support spi flash single, quad and memory reads. @@ -607,12 +628,14 @@ config FSL_ESPI config SH_QSPI bool "Renesas Quad SPI driver" + depends on ARCH_RENESAS help Enable the Renesas Quad SPI controller driver. This driver can be used on Renesas SoCs. config MXC_SPI bool "MXC SPI Driver" + depends on MACH_IMX help Enable the MXC SPI controller driver. This driver can be used on various i.MX SoCs such as i.MX31/35/51/6/7. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 32d7bf7237a..7051e2a00c6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -4,7 +4,7 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. # There are many options which enable SPI, so make this library available -ifdef CONFIG_$(SPL_TPL_)DM_SPI +ifdef CONFIG_$(PHASE_)DM_SPI obj-y += spi-uclass.o obj-$(CONFIG_CADENCE_QSPI) += cadence_qspi.o cadence_qspi_apb.o obj-$(CONFIG_CADENCE_OSPI_VERSAL) += cadence_ospi_versal.o diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c index 8e227d187b0..dafaf1130bb 100644 --- a/drivers/spi/altera_spi.c +++ b/drivers/spi/altera_spi.c @@ -95,7 +95,7 @@ static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen, uint32_t reg, data, start; debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, - dev_seq(bus), slave_plat->cs, bitlen, bytes, flags); + dev_seq(bus), slave_plat->cs[0], bitlen, bytes, flags); if (bitlen == 0) goto done; @@ -110,7 +110,7 @@ static int altera_spi_xfer(struct udevice *dev, unsigned int bitlen, readl(®s->rxdata); if (flags & SPI_XFER_BEGIN) - spi_cs_activate(dev, slave_plat->cs); + spi_cs_activate(dev, slave_plat->cs[0]); while (bytes--) { if (txp) diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c index 2178534baf0..72b612c6560 100644 --- a/drivers/spi/atcspi200_spi.c +++ b/drivers/spi/atcspi200_spi.c @@ -319,7 +319,7 @@ static int atcspi200_spi_claim_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct nds_spi_slave *ns = dev_get_priv(bus); - if (slave_plat->cs >= ns->num_cs) { + if (slave_plat->cs[0] >= ns->num_cs) { printf("Invalid SPI chipselect\n"); return -EINVAL; } diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c index fb2d77d7d4a..b0ed14f0cfc 100644 --- a/drivers/spi/ath79_spi.c +++ b/drivers/spi/ath79_spi.c @@ -73,7 +73,7 @@ static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen, if (restbits) bytes++; - out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs)); + out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs[0])); while (bytes > 0) { bytes--; curbyte = 0; diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 79f01001318..aaf3eddae42 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -125,7 +125,7 @@ static int atmel_spi_claim_bus(struct udevice *dev) struct atmel_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); struct at91_spi *reg_base = bus_plat->regs; - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; u32 freq = priv->freq; u32 scbr, csrx, mode; @@ -174,7 +174,7 @@ static void atmel_spi_cs_activate(struct udevice *dev) struct udevice *bus = dev_get_parent(dev); struct atmel_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) return; @@ -189,7 +189,7 @@ static void atmel_spi_cs_deactivate(struct udevice *dev) struct udevice *bus = dev_get_parent(dev); struct atmel_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) return; diff --git a/drivers/spi/bcm63xx_hsspi.c b/drivers/spi/bcm63xx_hsspi.c index 1aa43fd3a23..e9f0b343abb 100644 --- a/drivers/spi/bcm63xx_hsspi.c +++ b/drivers/spi/bcm63xx_hsspi.c @@ -174,7 +174,7 @@ static void bcm63xx_hsspi_activate_cs(struct bcm63xx_hsspi_priv *priv, set = DIV_ROUND_UP(2048, set); set &= SPI_PFL_CLK_FREQ_MASK; set |= SPI_PFL_CLK_RSTLOOP_MASK; - writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs)); + writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs[0])); /* profile signal */ set = 0; @@ -192,29 +192,29 @@ static void bcm63xx_hsspi_activate_cs(struct bcm63xx_hsspi_priv *priv, if (speed > SPI_MAX_SYNC_CLOCK) set |= SPI_PFL_SIG_ASYNCIN_MASK; - clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set); + clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs[0]), clr, set); /* global control */ set = 0; clr = 0; if (priv->xfer_mode == HSSPI_XFER_MODE_PREPEND) { - if (priv->cs_pols & BIT(plat->cs)) - set |= BIT(plat->cs); + if (priv->cs_pols & BIT(plat->cs[0])) + set |= BIT(plat->cs[0]); else - clr |= BIT(plat->cs); + clr |= BIT(plat->cs[0]); } else { /* invert cs polarity */ - if (priv->cs_pols & BIT(plat->cs)) - clr |= BIT(plat->cs); + if (priv->cs_pols & BIT(plat->cs[0])) + clr |= BIT(plat->cs[0]); else - set |= BIT(plat->cs); + set |= BIT(plat->cs[0]); /* invert dummy cs polarity */ - if (priv->cs_pols & BIT(!plat->cs)) - clr |= BIT(!plat->cs); + if (priv->cs_pols & BIT(!plat->cs[0])) + clr |= BIT(!plat->cs[0]); else - set |= BIT(!plat->cs); + set |= BIT(!plat->cs[0]); } clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set); @@ -290,7 +290,7 @@ static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_by if (plat->mode & SPI_3WIRE) val |= SPI_PFL_MODE_3WIRE_MASK; - writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs)); + writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0])); /* transfer loop */ while (data_bytes > 0) { @@ -310,9 +310,9 @@ static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_by /* issue the transfer */ val = SPI_CMD_OP_START; - val |= (plat->cs << SPI_CMD_PFL_SHIFT) & + val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) & SPI_CMD_PFL_MASK; - val |= (!plat->cs << SPI_CMD_SLAVE_SHIFT) & + val |= (!plat->cs[0] << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; writel(val, priv->regs + SPI_CMD_REG); @@ -450,7 +450,7 @@ static int bcm63xx_hsspi_xfer_prepend(struct udevice *dev, unsigned int data_byt } } val |= (priv->prepend_cnt << SPI_PFL_MODE_PREPCNT_SHIFT); - writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs)); + writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0])); /* set fifo operation */ val = opcode | (data_bytes & HSSPI_FIFO_OP_BYTES_MASK); @@ -459,9 +459,9 @@ static int bcm63xx_hsspi_xfer_prepend(struct udevice *dev, unsigned int data_byt /* issue the transfer */ val = SPI_CMD_OP_START; - val |= (plat->cs << SPI_CMD_PFL_SHIFT) & + val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) & SPI_CMD_PFL_MASK; - val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & + val |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; writel(val, priv->regs + SPI_CMD_REG); @@ -537,16 +537,16 @@ static int bcm63xx_hsspi_child_pre_probe(struct udevice *dev) struct spi_slave *slave = dev_get_parent_priv(dev); /* check cs */ - if (plat->cs >= priv->num_cs) { - printf("no cs %u\n", plat->cs); + if (plat->cs[0] >= priv->num_cs) { + printf("no cs %u\n", plat->cs[0]); return -ENODEV; } /* cs polarity */ if (plat->mode & SPI_CS_HIGH) - priv->cs_pols |= BIT(plat->cs); + priv->cs_pols |= BIT(plat->cs[0]); else - priv->cs_pols &= ~BIT(plat->cs); + priv->cs_pols &= ~BIT(plat->cs[0]); /* * set the max read/write size to make sure each xfer are within the diff --git a/drivers/spi/bcm63xx_spi.c b/drivers/spi/bcm63xx_spi.c index 595b41c8ab8..e02ec7e8bd7 100644 --- a/drivers/spi/bcm63xx_spi.c +++ b/drivers/spi/bcm63xx_spi.c @@ -275,7 +275,7 @@ static int bcm63xx_spi_xfer(struct udevice *dev, unsigned int bitlen, /* issue the transfer */ cmd = SPI_CMD_OP_START; - cmd |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; + cmd |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; cmd |= (priv->tx_bytes << SPI_CMD_PREPEND_SHIFT); if (plat->mode & SPI_3WIRE) cmd |= SPI_CMD_3WIRE_MASK; @@ -353,8 +353,8 @@ static int bcm63xx_spi_child_pre_probe(struct udevice *dev) struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); /* check cs */ - if (plat->cs >= priv->num_cs) { - printf("no cs %u\n", plat->cs); + if (plat->cs[0] >= priv->num_cs) { + printf("no cs %u\n", plat->cs[0]); return -ENODEV; } diff --git a/drivers/spi/bcmbca_hsspi.c b/drivers/spi/bcmbca_hsspi.c index eff9e1117d3..209ca713279 100644 --- a/drivers/spi/bcmbca_hsspi.c +++ b/drivers/spi/bcmbca_hsspi.c @@ -155,7 +155,7 @@ static void bcmbca_hsspi_setup_clock(struct bcmbca_hsspi_priv *priv, set = DIV_ROUND_UP(2048, set); set &= SPI_PFL_CLK_FREQ_MASK; set |= SPI_PFL_CLK_RSTLOOP_MASK; - writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs)); + writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs[0])); /* profile signal */ set = 0; @@ -173,16 +173,16 @@ static void bcmbca_hsspi_setup_clock(struct bcmbca_hsspi_priv *priv, if (priv->speed > SPI_MAX_SYNC_CLOCK) set |= SPI_PFL_SIG_ASYNCIN_MASK; - clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set); + clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs[0]), clr, set); /* global control */ set = 0; clr = 0; - if (priv->cs_pols & BIT(plat->cs)) - set |= BIT(plat->cs); + if (priv->cs_pols & BIT(plat->cs[0])) + set |= BIT(plat->cs[0]); else - clr |= BIT(plat->cs); + clr |= BIT(plat->cs[0]); clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set); } @@ -194,7 +194,7 @@ static void bcmbca_hsspi_activate_cs(struct bcmbca_hsspi_priv *priv, /* set the override bit */ val = readl(priv->spim_ctrl); - val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT); + val |= BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT); writel(val, priv->spim_ctrl); } @@ -205,7 +205,7 @@ static void bcmbca_hsspi_deactivate_cs(struct bcmbca_hsspi_priv *priv, /* clear the cs override bit */ val = readl(priv->spim_ctrl); - val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT); + val &= ~BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT); writel(val, priv->spim_ctrl); } @@ -250,7 +250,7 @@ static int bcmbca_hsspi_xfer(struct udevice *dev, unsigned int bitlen, if (plat->mode & SPI_3WIRE) val |= SPI_PFL_MODE_3WIRE_MASK; - writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs)); + writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs[0])); /* transfer loop */ while (data_bytes > 0) { @@ -276,9 +276,9 @@ static int bcmbca_hsspi_xfer(struct udevice *dev, unsigned int bitlen, /* issue the transfer */ val = SPI_CMD_OP_START; - val |= (plat->cs << SPI_CMD_PFL_SHIFT) & + val |= (plat->cs[0] << SPI_CMD_PFL_SHIFT) & SPI_CMD_PFL_MASK; - val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) & + val |= (plat->cs[0] << SPI_CMD_SLAVE_SHIFT) & SPI_CMD_SLAVE_MASK; writel(val, priv->regs + SPI_CMD_REG); @@ -326,22 +326,22 @@ static int bcmbca_hsspi_child_pre_probe(struct udevice *dev) u32 val; /* check cs */ - if (plat->cs >= priv->num_cs) { - dev_err(dev, "no cs %u\n", plat->cs); + if (plat->cs[0] >= priv->num_cs) { + dev_err(dev, "no cs %u\n", plat->cs[0]); return -EINVAL; } /* cs polarity */ if (plat->mode & SPI_CS_HIGH) - priv->cs_pols |= BIT(plat->cs); + priv->cs_pols |= BIT(plat->cs[0]); else - priv->cs_pols &= ~BIT(plat->cs); + priv->cs_pols &= ~BIT(plat->cs[0]); /* set the polarity to spim cs register */ val = readl(priv->spim_ctrl); - val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); - if (priv->cs_pols & BIT(plat->cs)) - val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); + val &= ~BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); + if (priv->cs_pols & BIT(plat->cs[0])) + val |= BIT(plat->cs[0] + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT); writel(val, priv->spim_ctrl); return 0; diff --git a/drivers/spi/ca_sflash.c b/drivers/spi/ca_sflash.c index a99a8a4485a..db32e39add2 100644 --- a/drivers/spi/ca_sflash.c +++ b/drivers/spi/ca_sflash.c @@ -10,6 +10,7 @@ #include <malloc.h> #include <clk.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <fdtdec.h> #include <linux/compat.h> diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c index 8234468b1d4..84077c01d83 100644 --- a/drivers/spi/cf_spi.c +++ b/drivers/spi/cf_spi.c @@ -123,7 +123,7 @@ static int coldfire_spi_claim_bus(struct udevice *dev) /* Clear FIFO and resume transfer */ clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF); - dspi_chip_select(slave_plat->cs); + dspi_chip_select(slave_plat->cs[0]); return 0; } @@ -139,7 +139,7 @@ static int coldfire_spi_release_bus(struct udevice *dev) /* Clear FIFO */ clrbits_be32(&dspi->mcr, DSPI_MCR_CTXF | DSPI_MCR_CRXF); - dspi_chip_unselect(slave_plat->cs); + dspi_chip_unselect(slave_plat->cs[0]); return 0; } @@ -168,7 +168,7 @@ static int coldfire_spi_xfer(struct udevice *dev, unsigned int bitlen, if ((flags & SPI_XFER_BEGIN) == SPI_XFER_BEGIN) ctrl |= DSPI_TFR_CONT; - ctrl = setup_ctrl(ctrl, slave_plat->cs); + ctrl = setup_ctrl(ctrl, slave_plat->cs[0]); if (len > 1) { int tmp_len = len - 1; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 19bd06cf872..eeac1339c23 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -329,13 +329,13 @@ static int davinci_spi_claim_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct davinci_spi_slave *ds = dev_get_priv(bus); - if (slave_plat->cs >= ds->num_cs) { + if (slave_plat->cs[0] >= ds->num_cs) { printf("Invalid SPI chipselect\n"); return -EINVAL; } ds->half_duplex = slave_plat->mode & SPI_PREAMBLE; - return __davinci_spi_claim_bus(ds, slave_plat->cs); + return __davinci_spi_claim_bus(ds, slave_plat->cs[0]); } static int davinci_spi_release_bus(struct udevice *dev) @@ -354,11 +354,11 @@ static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen, struct udevice *bus = dev->parent; struct davinci_spi_slave *ds = dev_get_priv(bus); - if (slave->cs >= ds->num_cs) { + if (slave->cs[0] >= ds->num_cs) { printf("Invalid SPI chipselect\n"); return -EINVAL; } - ds->cur_cs = slave->cs; + ds->cur_cs = slave->cs[0]; return __davinci_spi_xfer(ds, bitlen, dout, din, flags); } diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 6bd48b1b373..b520c727900 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -219,7 +219,7 @@ static int dw_spi_dwc_init(struct udevice *bus, struct dw_spi_priv *priv) static int request_gpio_cs(struct udevice *bus) { -#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_XPL_BUILD) struct dw_spi_priv *priv = dev_get_priv(bus); int ret; @@ -482,7 +482,7 @@ static int poll_transfer(struct dw_spi_priv *priv) */ __weak void external_cs_manage(struct udevice *dev, bool on) { -#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_SPL_BUILD) +#if CONFIG_IS_ENABLED(DM_GPIO) && !defined(CONFIG_XPL_BUILD) struct dw_spi_priv *priv = dev_get_priv(dev->parent); if (!dm_gpio_is_valid(&priv->cs_gpio)) diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index 1d4d90ce5aa..f2393c041f4 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -452,9 +452,9 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev) unsigned char pcssck = 0, cssck = 0; unsigned char pasc = 0, asc = 0; - if (slave_plat->cs >= priv->num_chipselect) { + if (slave_plat->cs[0] >= priv->num_chipselect) { debug("DSPI invalid chipselect number %d(max %d)!\n", - slave_plat->cs, priv->num_chipselect - 1); + slave_plat->cs[0], priv->num_chipselect - 1); return -EINVAL; } @@ -469,12 +469,12 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev) /* Set After SCK delay scale values */ ns_delay_scale(&pasc, &asc, sck_cs_delay, priv->bus_clk); - priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE | + priv->ctar_val[slave_plat->cs[0]] = DSPI_CTAR_DEFAULT_VALUE | DSPI_CTAR_PCSSCK(pcssck) | DSPI_CTAR_PASC(pasc); debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n", - slave_plat->cs, slave_plat->max_hz, slave_plat->mode); + slave_plat->cs[0], slave_plat->max_hz, slave_plat->mode); return 0; } @@ -527,13 +527,13 @@ static int fsl_dspi_claim_bus(struct udevice *dev) priv = dev_get_priv(bus); /* processor special preparation work */ - cpu_dspi_claim_bus(dev_seq(bus), slave_plat->cs); + cpu_dspi_claim_bus(dev_seq(bus), slave_plat->cs[0]); /* configure transfer mode */ - fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs, priv->mode); + fsl_dspi_cfg_ctar_mode(priv, slave_plat->cs[0], priv->mode); /* configure active state of CSX */ - fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs, + fsl_dspi_cfg_cs_active_state(priv, slave_plat->cs[0], priv->mode); fsl_dspi_clr_fifo(priv); @@ -559,7 +559,7 @@ static int fsl_dspi_release_bus(struct udevice *dev) dspi_halt(priv, 1); /* processor special release work */ - cpu_dspi_release_bus(dev_seq(bus), slave_plat->cs); + cpu_dspi_release_bus(dev_seq(bus), slave_plat->cs[0]); return 0; } @@ -615,7 +615,7 @@ static int fsl_dspi_xfer(struct udevice *dev, unsigned int bitlen, bus = dev->parent; priv = dev_get_priv(bus); - return dspi_xfer(priv, slave_plat->cs, bitlen, dout, din, flags); + return dspi_xfer(priv, slave_plat->cs[0], bitlen, dout, din, flags); } static int fsl_dspi_set_speed(struct udevice *bus, uint speed) diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index 2638ed25200..7ed35aa3e66 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -513,8 +513,8 @@ static int fsl_espi_child_pre_probe(struct udevice *dev) struct udevice *bus = dev->parent; struct fsl_spi_slave *fsl = dev_get_priv(bus); - debug("%s cs %u\n", __func__, slave_plat->cs); - fsl->cs = slave_plat->cs; + debug("%s cs %u\n", __func__, slave_plat->cs[0]); + fsl->cs = slave_plat->cs[0]; return 0; } diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 8a0a53cb372..c7f554826c3 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -510,10 +510,10 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave) struct dm_spi_slave_plat *plat = dev_get_parent_plat(slave->dev); - if (q->selected == plat->cs) + if (q->selected == plat->cs[0]) return; - q->selected = plat->cs; + q->selected = plat->cs[0]; fsl_qspi_invalidate(q); } diff --git a/drivers/spi/gxp_spi.c b/drivers/spi/gxp_spi.c index 70d76ac66ad..3ee369c5a03 100644 --- a/drivers/spi/gxp_spi.c +++ b/drivers/spi/gxp_spi.c @@ -87,7 +87,7 @@ static int gxp_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *do value = readl(priv->base + OFFSET_SPIMCFG); value &= ~(1 << 24); /* set chipselect */ - value |= (slave_plat->cs << 24); + value |= (slave_plat->cs[0] << 24); /* addr reg and addr size */ if (len >= 4) { diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index e48ca65fe72..2264ca83d66 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -779,7 +779,7 @@ static int ich_init_controller(struct udevice *dev, struct ich_spi_plat *plat, struct ich_spi_priv *ctlr) { - if (spl_phase() == PHASE_TPL) { + if (xpl_phase() == PHASE_TPL) { struct ich_spi_plat *plat = dev_get_plat(dev); int ret; @@ -867,7 +867,7 @@ static int ich_spi_probe(struct udevice *dev) if (ret) return ret; - if (spl_phase() == PHASE_TPL) { + if (xpl_phase() == PHASE_TPL) { /* Cache the BIOS to speed things up */ ret = ich_cache_bios_region(dev); if (ret) diff --git a/drivers/spi/mpc8xx_spi.c b/drivers/spi/mpc8xx_spi.c index 7e72fb9e23d..51cc487271d 100644 --- a/drivers/spi/mpc8xx_spi.c +++ b/drivers/spi/mpc8xx_spi.c @@ -148,7 +148,7 @@ static void mpc8xx_spi_cs_activate(struct udevice *dev) struct mpc8xx_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev); - dm_gpio_set_value(&priv->gpios[platdata->cs], 1); + dm_gpio_set_value(&priv->gpios[platdata->cs[0]], 1); } static void mpc8xx_spi_cs_deactivate(struct udevice *dev) @@ -156,7 +156,7 @@ static void mpc8xx_spi_cs_deactivate(struct udevice *dev) struct mpc8xx_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *platdata = dev_get_parent_plat(dev); - dm_gpio_set_value(&priv->gpios[platdata->cs], 0); + dm_gpio_set_value(&priv->gpios[platdata->cs[0]], 0); } static int mpc8xx_spi_xfer_one(struct udevice *dev, size_t count, diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index cd624f4d6f0..b34e1c2129c 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -113,7 +113,7 @@ static void mpc8xxx_spi_cs_activate(struct udevice *dev) struct mpc8xxx_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); - dm_gpio_set_value(&priv->gpios[plat->cs], 1); + dm_gpio_set_value(&priv->gpios[plat->cs[0]], 1); } static void mpc8xxx_spi_cs_deactivate(struct udevice *dev) @@ -121,7 +121,7 @@ static void mpc8xxx_spi_cs_deactivate(struct udevice *dev) struct mpc8xxx_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); - dm_gpio_set_value(&priv->gpios[plat->cs], 0); + dm_gpio_set_value(&priv->gpios[plat->cs[0]], 0); } static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen, @@ -137,10 +137,10 @@ static int mpc8xxx_spi_xfer(struct udevice *dev, uint bitlen, ulong type = dev_get_driver_data(bus); debug("%s: slave %s:%u dout %08X din %08X bitlen %u\n", __func__, - bus->name, plat->cs, (uint)dout, (uint)din, bitlen); - if (plat->cs >= priv->cs_count) { + bus->name, plat->cs[0], (uint)dout, (uint)din, bitlen); + if (plat->cs[0] >= priv->cs_count) { dev_err(dev, "chip select index %d too large (cs_count=%d)\n", - plat->cs, priv->cs_count); + plat->cs[0], priv->cs_count); return -EINVAL; } if (bitlen % 8) { diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c index ad4daeba3cd..75ab4ab1dda 100644 --- a/drivers/spi/mscc_bb_spi.c +++ b/drivers/spi/mscc_bb_spi.c @@ -123,11 +123,11 @@ int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen, u8 *rxd = din; debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen %u\n", - dev->parent->name, dev->name, plat->cs, plat->mode, dout, + dev->parent->name, dev->name, plat->cs[0], plat->mode, dout, din, bitlen); if (flags & SPI_XFER_BEGIN) - mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs); + mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs[0]); count = bitlen / 8; for (i = 0; i < count; i++) { diff --git a/drivers/spi/mtk_spim.c b/drivers/spi/mtk_spim.c index b360eca2b91..b66bcfc4233 100644 --- a/drivers/spi/mtk_spim.c +++ b/drivers/spi/mtk_spim.c @@ -18,7 +18,6 @@ #include <dm/devres.h> #include <dm/pinctrl.h> #include <linux/bitops.h> -#include <linux/completion.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/iopoll.h> diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index e7c393ae188..9ab39a188b2 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -135,7 +135,7 @@ static void mxc_spi_cs_activate(struct mxc_spi_slave *mxcs) struct udevice *dev = mxcs->dev; struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs])) return; @@ -153,7 +153,7 @@ static void mxc_spi_cs_deactivate(struct mxc_spi_slave *mxcs) struct udevice *dev = mxcs->dev; struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; if (!dm_gpio_is_valid(&mxcs->cs_gpios[cs])) return; @@ -632,7 +632,7 @@ static int mxc_spi_claim_bus(struct udevice *dev) mxcs->dev = dev; - return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs); + return mxc_spi_claim_bus_internal(mxcs, slave_plat->cs[0]); } static int mxc_spi_release_bus(struct udevice *dev) diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c index 73c506442ae..7b8271c8bbc 100644 --- a/drivers/spi/npcm_fiu_spi.c +++ b/drivers/spi/npcm_fiu_spi.c @@ -203,7 +203,7 @@ static int npcm_fiu_spi_xfer(struct udevice *dev, unsigned int bitlen, int len; if (flags & SPI_XFER_BEGIN) - activate_cs(regs, slave_plat->cs); + activate_cs(regs, slave_plat->cs[0]); while (bytes) { len = (bytes > CHUNK_SIZE) ? CHUNK_SIZE : bytes; @@ -222,7 +222,7 @@ static int npcm_fiu_spi_xfer(struct udevice *dev, unsigned int bitlen, } if (flags & SPI_XFER_END) - deactivate_cs(regs, slave_plat->cs); + deactivate_cs(regs, slave_plat->cs[0]); return ret; } @@ -325,9 +325,9 @@ static int npcm_fiu_exec_op(struct spi_slave *slave, bytes = op->data.nbytes; addr = (u32)op->addr.val; if (!bytes) { - activate_cs(regs, slave_plat->cs); + activate_cs(regs, slave_plat->cs[0]); ret = npcm_fiu_uma_operation(priv, op, addr, NULL, NULL, 0, false); - deactivate_cs(regs, slave_plat->cs); + deactivate_cs(regs, slave_plat->cs[0]); return ret; } @@ -339,9 +339,9 @@ static int npcm_fiu_exec_op(struct spi_slave *slave, * Use HW-control CS for read to avoid clock and timing issues. */ if (op->data.dir == SPI_MEM_DATA_OUT) - activate_cs(regs, slave_plat->cs); + activate_cs(regs, slave_plat->cs[0]); else - writel(FIELD_PREP(UMA_CTS_DEV_NUM_MASK, slave_plat->cs) | UMA_CTS_SW_CS, + writel(FIELD_PREP(UMA_CTS_DEV_NUM_MASK, slave_plat->cs[0]) | UMA_CTS_SW_CS, ®s->uma_cts); while (bytes) { len = (bytes > CHUNK_SIZE) ? CHUNK_SIZE : bytes; @@ -361,7 +361,7 @@ static int npcm_fiu_exec_op(struct spi_slave *slave, rx += len; } if (op->data.dir == SPI_MEM_DATA_OUT) - deactivate_cs(regs, slave_plat->cs); + deactivate_cs(regs, slave_plat->cs[0]); return 0; } diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index fefdaaa9e90..7489c896f9d 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -962,7 +962,7 @@ static int nxp_fspi_claim_bus(struct udevice *dev) bus = dev->parent; f = dev_get_priv(bus); - nxp_fspi_select_mem(f, slave_plat->cs); + nxp_fspi_select_mem(f, slave_plat->cs[0]); return 0; } diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c index 4bc38beaa68..0e6e0f7dbe7 100644 --- a/drivers/spi/octeon_spi.c +++ b/drivers/spi/octeon_spi.c @@ -93,7 +93,7 @@ static u64 octeon_spi_set_mpicfg(struct udevice *dev) if (max_speed > OCTEON_SPI_MAX_CLOCK_HZ) max_speed = OCTEON_SPI_MAX_CLOCK_HZ; - debug("\n slave params %d %d %d\n", slave->cs, + debug("\n slave params %d %d %d\n", slave->cs[0], slave->max_hz, slave->mode); cpha = !!(slave->mode & SPI_CPHA); cpol = !!(slave->mode & SPI_CPOL); diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 3d82fc74ff5..35bd8766097 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -393,7 +393,7 @@ static int omap3_spi_claim_bus(struct udevice *dev) struct omap3_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - priv->cs = slave_plat->cs; + priv->cs = slave_plat->cs[0]; if (!priv->freq) priv->freq = slave_plat->max_hz; @@ -422,7 +422,7 @@ static int omap3_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) struct omap3_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - priv->cs = slave_plat->cs; + priv->cs = slave_plat->cs[0]; priv->wordlen = wordlen; _omap3_spi_set_wordlen(priv); diff --git a/drivers/spi/pic32_spi.c b/drivers/spi/pic32_spi.c index e11ae7fc7a4..c4b31dc2a61 100644 --- a/drivers/spi/pic32_spi.c +++ b/drivers/spi/pic32_spi.c @@ -247,7 +247,7 @@ static int pic32_spi_xfer(struct udevice *slave, unsigned int bitlen, slave_plat = dev_get_parent_plat(slave); debug("spi_xfer: bus:%i cs:%i flags:%lx\n", - dev_seq(bus), slave_plat->cs, flags); + dev_seq(bus), slave_plat->cs[0], flags); debug("msg tx %p, rx %p submitted of %d byte(s)\n", tx_buf, rx_buf, len); diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 4571dc9f9b6..2c3d70ba715 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -444,7 +444,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Assert CS before transfer */ if (flags & SPI_XFER_BEGIN) - spi_cs_activate(dev, slave_plat->cs); + spi_cs_activate(dev, slave_plat->cs[0]); /* * To ensure fast loading of firmware images (e.g. full U-Boot @@ -507,7 +507,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen, /* Deassert CS after transfer */ if (flags & SPI_XFER_END) - spi_cs_deactivate(dev, slave_plat->cs); + spi_cs_deactivate(dev, slave_plat->cs[0]); rkspi_enable_chip(regs, false); if (!out) diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c index 596c22aa010..73738ab26d3 100644 --- a/drivers/spi/rockchip_sfc.c +++ b/drivers/spi/rockchip_sfc.c @@ -229,7 +229,7 @@ static int rockchip_sfc_ofdata_to_platdata(struct udevice *bus) sfc->regbase = dev_read_addr_ptr(bus); sfc->use_dma = !dev_read_bool(bus, "rockchip,sfc-no-dma"); - if (IS_ENABLED(CONFIG_SPL_BUILD) && sfc->use_dma) + if (IS_ENABLED(CONFIG_XPL_BUILD) && sfc->use_dma) sfc->use_dma = !dev_read_bool(bus, "u-boot,spl-sfc-no-dma"); #if CONFIG_IS_ENABLED(CLK) @@ -409,7 +409,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, /* set the Controller */ ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; - cmd |= plat->cs << SFC_CMD_CS_SHIFT; + cmd |= plat->cs[0] << SFC_CMD_CS_SHIFT; dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", op->addr.nbytes, op->addr.buswidth, diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 12320367e97..ca29cfd7c88 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -192,7 +192,7 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz) if (found) { hclk_div = hclk_masks[i] << 8; - priv->flashes[slave_plat->cs].max_freq = hclk_clk / (i + 1); + priv->flashes[slave_plat->cs[0]].max_freq = hclk_clk / (i + 1); } dev_dbg(dev, "found: %s, hclk: %d, max_clk: %d\n", found ? "yes" : "no", @@ -200,7 +200,7 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz) if (found) { dev_dbg(dev, "h_div: %d (mask %x), speed: %d\n", - i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq); + i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq); } return hclk_div; @@ -311,7 +311,7 @@ static u32 ast2500_get_clk_setting(struct udevice *dev, uint max_hz) for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) { if (hclk_clk / (i + 1) <= max_hz) { found = true; - priv->flashes[slave_plat->cs].max_freq = + priv->flashes[slave_plat->cs[0]].max_freq = hclk_clk / (i + 1); break; } @@ -325,7 +325,7 @@ static u32 ast2500_get_clk_setting(struct udevice *dev, uint max_hz) for (i = 0; i < ARRAY_SIZE(hclk_masks); i++) { if (hclk_clk / ((i + 1) * 4) <= max_hz) { found = true; - priv->flashes[slave_plat->cs].max_freq = + priv->flashes[slave_plat->cs[0]].max_freq = hclk_clk / ((i + 1) * 4); break; } @@ -340,7 +340,7 @@ end: if (found) { dev_dbg(dev, "h_div: %d (mask %x), speed: %d\n", - i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq); + i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq); } return hclk_div; @@ -456,7 +456,7 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz) if (found) { hclk_div = ((j << 24) | hclk_masks[i] << 8); - priv->flashes[slave_plat->cs].max_freq = + priv->flashes[slave_plat->cs[0]].max_freq = hclk_clk / (i + 1 + j * 16); break; } @@ -467,7 +467,7 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz) if (found) { dev_dbg(dev, "base_clk: %d, h_div: %d (mask %x), speed: %d\n", - j, i + 1, hclk_masks[i], priv->flashes[slave_plat->cs].max_freq); + j, i + 1, hclk_masks[i], priv->flashes[slave_plat->cs[0]].max_freq); } return hclk_div; @@ -588,7 +588,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave, struct udevice *bus = dev->parent; struct aspeed_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; u32 ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs]; u32 ce_ctrl_val; struct aspeed_spi_flash *flash = &priv->flashes[cs]; @@ -668,7 +668,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) const struct aspeed_spi_info *info = priv->info; struct spi_mem_op op_tmpl = desc->info.op_tmpl; u32 i; - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; u32 cmd_io_conf; u32 ce_ctrl_reg; @@ -725,7 +725,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, struct udevice *dev = desc->slave->dev; struct aspeed_spi_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; int ret; dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n", @@ -750,7 +750,7 @@ static struct aspeed_spi_flash *aspeed_spi_get_flash(struct udevice *dev) struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); struct aspeed_spi_plat *plat = dev_get_plat(bus); struct aspeed_spi_priv *priv = dev_get_priv(bus); - u32 cs = slave_plat->cs; + u32 cs = slave_plat->cs[0]; if (cs >= plat->max_cs) { dev_err(dev, "invalid CS %u\n", cs); @@ -1068,10 +1068,10 @@ static int aspeed_spi_claim_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); struct aspeed_spi_priv *priv = dev_get_priv(dev->parent); - struct aspeed_spi_flash *flash = &priv->flashes[slave_plat->cs]; + struct aspeed_spi_flash *flash = &priv->flashes[slave_plat->cs[0]]; u32 clk_setting; - dev_dbg(bus, "%s: claim bus CS%u\n", bus->name, slave_plat->cs); + dev_dbg(bus, "%s: claim bus CS%u\n", bus->name, slave_plat->cs[0]); if (flash->max_freq == 0) { clk_setting = priv->info->get_clk_setting(dev, slave_plat->max_hz); @@ -1089,7 +1089,7 @@ static int aspeed_spi_release_bus(struct udevice *dev) struct udevice *bus = dev->parent; struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - dev_dbg(bus, "%s: release bus CS%u\n", bus->name, slave_plat->cs); + dev_dbg(bus, "%s: release bus CS%u\n", bus->name, slave_plat->cs[0]); if (!aspeed_spi_get_flash(dev)) return -ENODEV; diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index b98bcd9b6ba..3835865ea7d 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -366,8 +366,8 @@ static int mxic_spi_mem_exec_op(struct spi_slave *slave, nio = 2; writel(HC_CFG_NIO(nio) | - HC_CFG_TYPE(slave_plat->cs, HC_CFG_TYPE_SPI_NOR) | - HC_CFG_SLV_ACT(slave_plat->cs) | HC_CFG_IDLE_SIO_LVL(1) | + HC_CFG_TYPE(slave_plat->cs[0], HC_CFG_TYPE_SPI_NOR) | + HC_CFG_SLV_ACT(slave_plat->cs[0]) | HC_CFG_IDLE_SIO_LVL(1) | HC_CFG_MAN_CS_EN, priv->regs + HC_CFG); writel(HC_EN_BIT, priv->regs + HC_EN); @@ -396,7 +396,7 @@ static int mxic_spi_mem_exec_op(struct spi_slave *slave, ss_ctrl |= OP_READ; } - writel(ss_ctrl, priv->regs + SS_CTRL(slave_plat->cs)); + writel(ss_ctrl, priv->regs + SS_CTRL(slave_plat->cs[0])); writel(readl(priv->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT, priv->regs + HC_CFG); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 836c550b0bb..dc001e6e4cc 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -718,7 +718,7 @@ static int qup_spi_xfer(struct udevice *dev, unsigned int bitlen, if (ret != 0) return ret; - ret = qup_spi_set_cs(bus, slave_plat->cs, false); + ret = qup_spi_set_cs(bus, slave_plat->cs[0], false); if (ret != 0) return ret; } @@ -736,7 +736,7 @@ static int qup_spi_xfer(struct udevice *dev, unsigned int bitlen, } if (flags & SPI_XFER_END) { - ret = qup_spi_set_cs(bus, slave_plat->cs, true); + ret = qup_spi_set_cs(bus, slave_plat->cs[0], true); if (ret != 0) return ret; } diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 0c8666c05f9..15407d482c9 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -108,13 +108,13 @@ static void sifive_spi_prep_device(struct sifive_spi *spi, { /* Update the chip select polarity */ if (slave_plat->mode & SPI_CS_HIGH) - spi->cs_inactive &= ~BIT(slave_plat->cs); + spi->cs_inactive &= ~BIT(slave_plat->cs[0]); else - spi->cs_inactive |= BIT(slave_plat->cs); + spi->cs_inactive |= BIT(slave_plat->cs[0]); writel(spi->cs_inactive, spi->regs + SIFIVE_SPI_REG_CSDEF); /* Select the correct device */ - writel(slave_plat->cs, spi->regs + SIFIVE_SPI_REG_CSID); + writel(slave_plat->cs[0], spi->regs + SIFIVE_SPI_REG_CSID); } static int sifive_spi_set_cs(struct sifive_spi *spi, diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c index fc82791006e..364ba4b3a97 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -497,7 +497,7 @@ static int f_ospi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) int err = 0; slave_plat = dev_get_parent_plat(slave->dev); - ospi->chip_select = slave_plat->cs; + ospi->chip_select = slave_plat->cs[0]; switch (op->data.dir) { case SPI_MEM_DATA_IN: diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index 88550b8ea84..e00532a371b 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -360,7 +360,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, } if (flags & SPI_XFER_BEGIN) - sun4i_spi_set_cs(bus, slave_plat->cs, true); + sun4i_spi_set_cs(bus, slave_plat->cs[0], true); /* Reset FIFOs */ setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) | @@ -391,7 +391,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, false, SUN4I_SPI_TIMEOUT_MS, false); if (ret < 0) { printf("ERROR: sun4i_spi: Timeout transferring data\n"); - sun4i_spi_set_cs(bus, slave_plat->cs, false); + sun4i_spi_set_cs(bus, slave_plat->cs[0], false); return ret; } @@ -402,7 +402,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, } if (flags & SPI_XFER_END) - sun4i_spi_set_cs(bus, slave_plat->cs, false); + sun4i_spi_set_cs(bus, slave_plat->cs[0], false); return 0; } diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c index eb522fd7b3d..a3c0ad17121 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -193,12 +193,12 @@ static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx) /* if nothing to do */ if (slave_plat->mode == priv->mode && rwflag == priv->rwflag && - slave_plat->cs == priv->cs && + slave_plat->cs[0] == priv->cs && slave_plat->max_hz == priv->speed) return; priv->rwflag = rwflag; - priv->cs = slave_plat->cs; + priv->cs = slave_plat->cs[0]; priv->mode = slave_plat->mode; priv->speed = slave_plat->max_hz; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 6e281725239..36b7d383aa9 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -224,7 +224,7 @@ int spi_chip_select(struct udevice *dev) { struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); - return plat ? plat->cs : -ENOENT; + return plat ? plat->cs[0] : -ENOENT; } int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) @@ -261,8 +261,8 @@ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) struct dm_spi_slave_plat *plat; plat = dev_get_parent_plat(dev); - dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs); - if (plat->cs == cs) { + dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs[0]); + if (plat->cs[0] == cs) { *devp = dev; return 0; } @@ -415,7 +415,7 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, return ret; } plat = dev_get_parent_plat(dev); - plat->cs = cs; + plat->cs[0] = cs; if (speed) { plat->max_hz = speed; } else { @@ -446,6 +446,12 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, slave = dev_get_parent_priv(dev); bus_data = dev_get_uclass_priv(bus); +#if CONFIG_IS_ENABLED(SPI_ADVANCE) + if ((dev_read_bool(dev, "parallel-memories")) && !slave->multi_cs_cap) { + dev_err(dev, "controller doesn't support multi CS\n"); + return -EINVAL; + } +#endif /* * In case the operation speed is not yet established by * dm_spi_claim_bus() ensure the bus is configured properly. @@ -509,7 +515,21 @@ int spi_slave_of_to_plat(struct udevice *dev, struct dm_spi_slave_plat *plat) int mode = 0; int value; - plat->cs = dev_read_u32_default(dev, "reg", -1); +#if CONFIG_IS_ENABLED(SPI_ADVANCE) + int ret; + + ret = dev_read_u32_array(dev, "reg", plat->cs, SPI_CS_CNT_MAX); + + if (ret == -EOVERFLOW || ret == -FDT_ERR_BADLAYOUT) { + dev_read_u32(dev, "reg", &plat->cs[0]); + } else { + dev_err(dev, "has no valid 'reg' property (%d)\n", ret); + return ret; + } +#else + plat->cs[0] = dev_read_u32_default(dev, "reg", -1); +#endif + plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency", SPI_DEFAULT_SPEED_HZ); if (dev_read_bool(dev, "spi-cpol")) @@ -538,7 +558,7 @@ int spi_slave_of_to_plat(struct udevice *dev, struct dm_spi_slave_plat *plat) mode |= SPI_TX_OCTAL; break; default: - warn_non_spl("spi-tx-bus-width %d not supported\n", value); + warn_non_xpl("spi-tx-bus-width %d not supported\n", value); break; } @@ -556,7 +576,7 @@ int spi_slave_of_to_plat(struct udevice *dev, struct dm_spi_slave_plat *plat) mode |= SPI_RX_OCTAL; break; default: - warn_non_spl("spi-rx-bus-width %d not supported\n", value); + warn_non_xpl("spi-rx-bus-width %d not supported\n", value); break; } diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 2812a4da411..3216ec8010e 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -394,7 +394,7 @@ static int stm32_qspi_claim_bus(struct udevice *dev) { struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - int slave_cs = slave_plat->cs; + int slave_cs = slave_plat->cs[0]; if (slave_cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index 97b83b17167..a1f31cf653c 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -434,7 +434,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, slave_plat = dev_get_parent_plat(slave); if (flags & SPI_XFER_BEGIN) - stm32_spi_set_cs(bus, slave_plat->cs, false); + stm32_spi_set_cs(bus, slave_plat->cs[0], false); /* Be sure to have data in fifo before starting data transfer */ if (priv->tx_buf) @@ -485,7 +485,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, stm32_spi_stopxfer(bus); if (flags & SPI_XFER_END) - stm32_spi_set_cs(bus, slave_plat->cs, true); + stm32_spi_set_cs(bus, slave_plat->cs[0], true); return xfer_status; } diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index a16412ec6fb..1f2494e592c 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -163,7 +163,7 @@ static int ti_qspi_xfer(struct udevice *dev, unsigned int bitlen, uchar *rxp = din; uint status; int timeout; - unsigned int cs = slave->cs; + unsigned int cs = slave->cs[0]; bus = dev->parent; priv = dev_get_priv(bus); @@ -344,7 +344,7 @@ static int ti_qspi_exec_mem_op(struct spi_slave *slave, if (from + op->data.nbytes > priv->mmap_size) return -ENOTSUPP; - ti_qspi_setup_mmap_read(priv, slave_plat->cs, op->cmd.opcode, + ti_qspi_setup_mmap_read(priv, slave_plat->cs[0], op->cmd.opcode, op->data.buswidth, op->addr.nbytes, op->dummy.nbytes); @@ -363,7 +363,7 @@ static int ti_qspi_claim_bus(struct udevice *dev) bus = dev->parent; priv = dev_get_priv(bus); - if (slave_plat->cs > priv->num_cs) { + if (slave_plat->cs[0] > priv->num_cs) { debug("invalid qspi chip select\n"); return -EINVAL; } @@ -371,13 +371,13 @@ static int ti_qspi_claim_bus(struct udevice *dev) writel(MM_SWITCH, &priv->base->memswitch); if (priv->ctrl_mod_mmap) ti_qspi_ctrl_mode_mmap(priv->ctrl_mod_mmap, - slave_plat->cs, true); + slave_plat->cs[0], true); writel(priv->dc, &priv->base->dc); writel(0, &priv->base->cmd); writel(0, &priv->base->data); - priv->dc <<= slave_plat->cs * 8; + priv->dc <<= slave_plat->cs[0] * 8; writel(priv->dc, &priv->base->dc); return 0; @@ -395,12 +395,12 @@ static int ti_qspi_release_bus(struct udevice *dev) writel(~MM_SWITCH, &priv->base->memswitch); if (priv->ctrl_mod_mmap) ti_qspi_ctrl_mode_mmap(priv->ctrl_mod_mmap, - slave_plat->cs, false); + slave_plat->cs[0], false); writel(0, &priv->base->dc); writel(0, &priv->base->cmd); writel(0, &priv->base->data); - writel(0, TI_QSPI_SETUP_REG(priv, slave_plat->cs)); + writel(0, TI_QSPI_SETUP_REG(priv, slave_plat->cs[0])); return 0; } diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 0e7fa3a4525..b2af17ebae9 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -291,7 +291,7 @@ static void xilinx_spi_startup_block(struct udevice *dev) * Perform a dummy read as a work around for * the startup block issue. */ - spi_cs_activate(dev, slave_plat->cs); + spi_cs_activate(dev, slave_plat->cs[0]); txp = 0x9f; start_transfer(dev, (void *)&txp, NULL, 1); @@ -306,7 +306,7 @@ static int xilinx_spi_xfer(struct udevice *dev, unsigned int bitlen, struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); int ret; - spi_cs_activate(dev, slave_plat->cs); + spi_cs_activate(dev, slave_plat->cs[0]); ret = start_transfer(dev, dout, din, bitlen / 8); spi_cs_deactivate(dev); return ret; @@ -331,7 +331,7 @@ static int xilinx_spi_mem_exec_op(struct spi_slave *spi, startup++; } - spi_cs_activate(spi->dev, slave_plat->cs); + spi_cs_activate(spi->dev, slave_plat->cs[0]); if (op->cmd.opcode) { ret = start_transfer(spi->dev, (void *)&op->cmd.opcode, diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index b71b9a6fd6c..4aad3248d9e 100644 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2013 Xilinx, Inc. + * (C) Copyright 2013 - 2022, Xilinx, Inc. * (C) Copyright 2015 Jagan Teki <jteki@openedev.com> + * (C) Copyright 2023, Advanced Micro Devices, Inc. * * Xilinx Zynq Quad-SPI(QSPI) controller driver (master mode only) */ @@ -12,10 +13,12 @@ #include <log.h> #include <malloc.h> #include <spi.h> +#include <spi_flash.h> #include <asm/global_data.h> #include <asm/io.h> #include <linux/bitops.h> #include <spi-mem.h> +#include "../mtd/spi/sf_internal.h" DECLARE_GLOBAL_DATA_PTR; @@ -41,6 +44,21 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_QSPI_TXD_00_01_OFFSET 0x80 /* Transmit 1-byte inst */ #define ZYNQ_QSPI_TXD_00_10_OFFSET 0x84 /* Transmit 2-byte inst */ #define ZYNQ_QSPI_TXD_00_11_OFFSET 0x88 /* Transmit 3-byte inst */ +#define ZYNQ_QSPI_FR_QOUT_CODE 0x6B /* read instruction code */ + +#define QSPI_SELECT_LOWER_CS BIT(0) +#define QSPI_SELECT_UPPER_CS BIT(1) + +/* + * QSPI Linear Configuration Register + * + * It is named Linear Configuration but it controls other modes when not in + * linear mode also. + */ +#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK 0x40000000 /* QSPI Enable Bit Mask */ +#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK 0x20000000 /* QSPI Enable Bit Mask */ +#define ZYNQ_QSPI_LCFG_U_PAGE 0x10000000 /* QSPI Upper memory set */ +#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8 #define ZYNQ_QSPI_TXFIFO_THRESHOLD 1 /* Tx FIFO threshold level*/ #define ZYNQ_QSPI_RXFIFO_THRESHOLD 32 /* Rx FIFO threshold level */ @@ -100,7 +118,11 @@ struct zynq_qspi_priv { int bytes_to_transfer; int bytes_to_receive; unsigned int is_inst; + unsigned int is_parallel; + unsigned int is_stacked; + unsigned int u_page; unsigned cs_change:1; + unsigned is_strip:1; }; static int zynq_qspi_of_to_plat(struct udevice *bus) @@ -111,7 +133,6 @@ static int zynq_qspi_of_to_plat(struct udevice *bus) plat->regs = (struct zynq_qspi_regs *)fdtdec_get_addr(blob, node, "reg"); - return 0; } @@ -146,6 +167,9 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) /* Disable Interrupts */ writel(ZYNQ_QSPI_IXR_ALL_MASK, ®s->idr); + /* Disable linear mode as the boot loader may have used it */ + writel(0x0, ®s->lqspicfg); + /* Clear the TX and RX threshold reg */ writel(ZYNQ_QSPI_TXFIFO_THRESHOLD, ®s->txftr); writel(ZYNQ_QSPI_RXFIFO_THRESHOLD, ®s->rxftr); @@ -163,12 +187,11 @@ static void zynq_qspi_init_hw(struct zynq_qspi_priv *priv) confr |= ZYNQ_QSPI_CR_IFMODE_MASK | ZYNQ_QSPI_CR_MCS_MASK | ZYNQ_QSPI_CR_PCS_MASK | ZYNQ_QSPI_CR_FW_MASK | ZYNQ_QSPI_CR_MSTREN_MASK; - writel(confr, ®s->cr); - /* Disable the LQSPI feature */ - confr = readl(®s->lqspicfg); - confr &= ~ZYNQ_QSPI_LQSPICFG_LQMODE_MASK; - writel(confr, ®s->lqspicfg); + if (priv->is_stacked) + confr |= 0x10; + + writel(confr, ®s->cr); /* Enable SPI */ writel(ZYNQ_QSPI_ENR_SPI_EN_MASK, ®s->enr); @@ -180,6 +203,7 @@ static int zynq_qspi_child_pre_probe(struct udevice *bus) struct zynq_qspi_priv *priv = dev_get_priv(bus->parent); priv->max_hz = slave->max_hz; + slave->multi_cs_cap = true; return 0; } @@ -362,8 +386,8 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size) unsigned len, offset; struct zynq_qspi_regs *regs = priv->regs; static const unsigned offsets[4] = { - ZYNQ_QSPI_TXD_00_00_OFFSET, ZYNQ_QSPI_TXD_00_01_OFFSET, - ZYNQ_QSPI_TXD_00_10_OFFSET, ZYNQ_QSPI_TXD_00_11_OFFSET }; + ZYNQ_QSPI_TXD_00_01_OFFSET, ZYNQ_QSPI_TXD_00_10_OFFSET, + ZYNQ_QSPI_TXD_00_11_OFFSET, ZYNQ_QSPI_TXD_00_00_OFFSET }; while ((fifocount < size) && (priv->bytes_to_transfer > 0)) { @@ -385,7 +409,11 @@ static void zynq_qspi_fill_tx_fifo(struct zynq_qspi_priv *priv, u32 size) return; len = priv->bytes_to_transfer; zynq_qspi_write_data(priv, &data, len); - offset = (priv->rx_buf) ? offsets[0] : offsets[len]; + if ((priv->is_parallel || priv->is_stacked) && + !priv->is_inst && (len % 2)) + len++; + offset = (priv->rx_buf) ? + offsets[3] : offsets[len - 1]; writel(data, ®s->cr + (offset / 4)); } } @@ -490,6 +518,7 @@ static int zynq_qspi_irq_poll(struct zynq_qspi_priv *priv) */ static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv) { + static u8 current_u_page; u32 data = 0; struct zynq_qspi_regs *regs = priv->regs; @@ -499,6 +528,34 @@ static int zynq_qspi_start_transfer(struct zynq_qspi_priv *priv) priv->bytes_to_transfer = priv->len; priv->bytes_to_receive = priv->len; + if (priv->is_parallel) + writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK | + ZYNQ_QSPI_LCFG_SEP_BUS_MASK | + (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) | + ZYNQ_QSPI_FR_QOUT_CODE), ®s->lqspicfg); + + if (priv->is_inst && priv->is_stacked && current_u_page != priv->u_page) { + if (priv->u_page) { + /* Configure two memories on shared bus + * by enabling upper mem + */ + writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK | + ZYNQ_QSPI_LCFG_U_PAGE | + (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) | + ZYNQ_QSPI_FR_QOUT_CODE), + ®s->lqspicfg); + } else { + /* Configure two memories on shared bus + * by enabling lower mem + */ + writel((ZYNQ_QSPI_LCFG_TWO_MEM_MASK | + (1 << ZYNQ_QSPI_LCFG_DUMMY_SHIFT) | + ZYNQ_QSPI_FR_QOUT_CODE), + ®s->lqspicfg); + } + current_u_page = priv->u_page; + } + if (priv->len < 4) zynq_qspi_fill_tx_fifo(priv, priv->len); else @@ -585,20 +642,21 @@ static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen, struct zynq_qspi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - priv->cs = slave_plat->cs; + priv->cs = slave_plat->cs[0]; priv->tx_buf = dout; priv->rx_buf = din; priv->len = bitlen / 8; - debug("zynq_qspi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n", - dev_seq(bus), slave_plat->cs, bitlen, priv->len, flags); + debug("zynq_qspi_xfer: bus:%i cs[0]:%i bitlen:%i len:%i flags:%lx\n", + dev_seq(bus), slave_plat->cs[0], bitlen, priv->len, flags); /* * Festering sore. * Assume that the beginning of a transfer with bits to * transmit must contain a device command. */ - if (dout && flags & SPI_XFER_BEGIN) + if ((dout && flags & SPI_XFER_BEGIN) || + (flags & SPI_XFER_END && !priv->is_strip)) priv->is_inst = 1; else priv->is_inst = 0; @@ -608,6 +666,11 @@ static int zynq_qspi_xfer(struct udevice *dev, unsigned int bitlen, else priv->cs_change = 0; + if (flags & SPI_XFER_U_PAGE) + priv->u_page = 1; + else + priv->u_page = 0; + zynq_qspi_transfer(priv); return 0; @@ -671,14 +734,35 @@ static int zynq_qspi_set_mode(struct udevice *bus, uint mode) return 0; } +static bool update_stripe(const struct spi_mem_op *op) +{ + if (op->cmd.opcode == SPINOR_OP_BE_4K || + op->cmd.opcode == SPINOR_OP_CHIP_ERASE || + op->cmd.opcode == SPINOR_OP_SE || + op->cmd.opcode == SPINOR_OP_WREAR || + op->cmd.opcode == SPINOR_OP_WRSR + ) + return false; + + return true; +} + static int zynq_qspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { + struct udevice *bus = slave->dev->parent; + struct zynq_qspi_priv *priv = dev_get_priv(bus); int op_len, pos = 0, ret, i; unsigned int flag = 0; const u8 *tx_buf = NULL; u8 *rx_buf = NULL; + if ((slave->flags & QSPI_SELECT_LOWER_CS) && + (slave->flags & QSPI_SELECT_UPPER_CS)) + priv->is_parallel = true; + if (slave->flags & SPI_XFER_STACKED) + priv->is_stacked = true; + if (op->data.nbytes) { if (op->data.dir == SPI_MEM_DATA_IN) rx_buf = op->data.buf.in; @@ -703,6 +787,9 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, if (op->dummy.nbytes) memset(op_buf + pos, 0xff, op->dummy.nbytes); + if (slave->flags & SPI_XFER_U_PAGE) + flag |= SPI_XFER_U_PAGE; + /* 1st transfer: opcode + address + dummy cycles */ /* Make sure to set END bit if no tx or rx data messages follow */ if (!tx_buf && !rx_buf) @@ -713,6 +800,9 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, if (ret) return ret; + if (priv->is_parallel) + priv->is_strip = update_stripe(op); + /* 2nd transfer: rx or tx data path */ if (tx_buf || rx_buf) { ret = zynq_qspi_xfer(slave->dev, op->data.nbytes * 8, tx_buf, @@ -721,6 +811,9 @@ static int zynq_qspi_exec_op(struct spi_slave *slave, return ret; } + priv->is_parallel = false; + priv->is_stacked = false; + slave->flags &= ~SPI_XFER_MASK; spi_release_bus(slave); return 0; diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index d15d91a1d24..37fa12b96b5 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -240,15 +240,15 @@ static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen, u8 *rx_buf = din, buf; u32 ts, status; - debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n", - dev_seq(bus), slave_plat->cs, bitlen, len, flags); + debug("spi_xfer: bus:%i cs[0]:%i bitlen:%i len:%i flags:%lx\n", + dev_seq(bus), slave_plat->cs[0], bitlen, len, flags); if (bitlen % 8) { debug("spi_xfer: Non byte aligned SPI transfer\n"); return -1; } - priv->cs = slave_plat->cs; + priv->cs = slave_plat->cs[0]; if (flags & SPI_XFER_BEGIN) spi_cs_activate(dev); diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index ae795e50b0a..1d19b2606c5 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2018 Xilinx - * + * (C) Copyright 2013 - 2022, Xilinx, Inc. + * (C) Copyright 2023, Advanced Micro Devices, Inc. * Xilinx ZynqMP Generic Quad-SPI(QSPI) controller driver(master mode only) */ @@ -24,6 +24,8 @@ #include <linux/bitops.h> #include <linux/err.h> #include <linux/sizes.h> +#include <linux/mtd/spi-nor.h> +#include "../mtd/spi/sf_internal.h" #include <zynqmp_firmware.h> #define GQSPI_GFIFO_STRT_MODE_MASK BIT(29) @@ -87,6 +89,9 @@ #define SPI_XFER_ON_LOWER 1 #define SPI_XFER_ON_UPPER 2 +#define GQSPI_SELECT_LOWER_CS BIT(0) +#define GQSPI_SELECT_UPPER_CS BIT(1) + #define GQSPI_DMA_ALIGN 0x4 #define GQSPI_MAX_BAUD_RATE_VAL 7 #define GQSPI_DFLT_BAUD_RATE_VAL 2 @@ -183,13 +188,14 @@ struct zynqmp_qspi_priv { int bytes_to_transfer; int bytes_to_receive; const struct spi_mem_op *op; + unsigned int is_parallel; + unsigned int u_page; + unsigned int bus; + unsigned int stripe; + unsigned int flags; + u32 max_hz; }; -__weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) -{ - return 0; -} - static int zynqmp_qspi_of_to_plat(struct udevice *bus) { struct zynqmp_qspi_plat *plat = dev_get_plat(bus); @@ -234,8 +240,30 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv) { u32 gqspi_fifo_reg = 0; - gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | - GQSPI_GFIFO_CS_LOWER; + if (priv->is_parallel) { + if (priv->bus == SPI_XFER_ON_BOTH) + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | + GQSPI_GFIFO_UP_BUS | + GQSPI_GFIFO_CS_UPPER | + GQSPI_GFIFO_CS_LOWER; + else if (priv->bus == SPI_XFER_ON_LOWER) + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | + GQSPI_GFIFO_CS_UPPER | + GQSPI_GFIFO_CS_LOWER; + else if (priv->bus == SPI_XFER_ON_UPPER) + gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS | + GQSPI_GFIFO_CS_LOWER | + GQSPI_GFIFO_CS_UPPER; + else + debug("Wrong Bus selection:0x%x\n", priv->bus); + } else { + if (priv->u_page) + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | + GQSPI_GFIFO_CS_UPPER; + else + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS | + GQSPI_GFIFO_CS_LOWER; + } return gqspi_fifo_reg; } @@ -295,8 +323,15 @@ static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on) gqspi_fifo_reg |= GQSPI_SPI_MODE_SPI | GQSPI_IMD_DATA_CS_ASSERT; } else { - gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS; - gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT; + if (priv->is_parallel) { + gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS | + GQSPI_GFIFO_LOW_BUS; + } else if (priv->u_page) { + gqspi_fifo_reg = GQSPI_GFIFO_UP_BUS; + } else { + gqspi_fifo_reg = GQSPI_GFIFO_LOW_BUS; + gqspi_fifo_reg |= GQSPI_IMD_DATA_CS_DEASSERT; + } } zynqmp_qspi_fill_gen_fifo(priv, gqspi_fifo_reg); @@ -367,12 +402,13 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed) log_debug("%s, Speed: %d, Max: %d\n", __func__, speed, plat->frequency); - if (speed > plat->frequency) - speed = plat->frequency; + /* + * If speed == 0 or speed > max freq, then set speed to highest + */ + if (!speed || speed > priv->max_hz) + speed = priv->max_hz; if (plat->speed_hz != speed) { - /* Set the clock frequency */ - /* If speed == 0, default to lowest speed */ while ((baud_rate_val < 8) && ((plat->frequency / (2 << baud_rate_val)) > speed)) @@ -394,6 +430,18 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed) return 0; } +static int zynqmp_qspi_child_pre_probe(struct udevice *bus) +{ + struct spi_slave *slave = dev_get_parent_priv(bus); + struct zynqmp_qspi_priv *priv = dev_get_priv(bus->parent); + + slave->multi_cs_cap = true; + slave->bytemode = SPI_4BYTE_MODE; + priv->max_hz = slave->max_hz; + + return 0; +} + static int zynqmp_qspi_probe(struct udevice *bus) { struct zynqmp_qspi_plat *plat = dev_get_plat(bus); @@ -458,12 +506,17 @@ static int zynqmp_qspi_set_mode(struct udevice *bus, uint mode) static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size) { - u32 data; + u32 data, ier; int ret = 0; struct zynqmp_qspi_regs *regs = priv->regs; u32 *buf = (u32 *)priv->tx_buf; u32 len = size; + /* Enable interrupts */ + ier = readl(®s->ier); + ier |= GQSPI_IXR_ALL_MASK | GQSPI_IXR_TXFIFOEMPTY_MASK; + writel(ier, ®s->ier); + while (size) { ret = wait_for_bit_le32(®s->isr, GQSPI_IXR_TXNFULL_MASK, 1, GQSPI_TIMEOUT, 1); @@ -586,6 +639,9 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth); gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_GFIFO_DATA_XFR_MASK; + if (priv->stripe) + gen_fifo_cmd |= GQSPI_GFIFO_STRIPE_MASK; + while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); @@ -720,6 +776,9 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth); gen_fifo_cmd |= GQSPI_GFIFO_RX | GQSPI_GFIFO_DATA_XFR_MASK; + if (priv->stripe) + gen_fifo_cmd |= GQSPI_GFIFO_STRIPE_MASK; + /* * Check if receive buffer is aligned to 4 byte and length * is multiples of four byte as we are using dma to receive. @@ -760,6 +819,33 @@ static int zynqmp_qspi_release_bus(struct udevice *dev) return 0; } +static bool zynqmp_qspi_update_stripe(const struct spi_mem_op *op) +{ + /* + * This is a list of opcodes for which we must not use striped access + * even in dual parallel mode, but instead broadcast the same data to + * both chips. This is primarily erase commands and writing some + * registers. + */ + switch (op->cmd.opcode) { + case SPINOR_OP_BE_4K: + case SPINOR_OP_BE_32K: + case SPINOR_OP_CHIP_ERASE: + case SPINOR_OP_SE: + case SPINOR_OP_BE_32K_4B: + case SPINOR_OP_SE_4B: + case SPINOR_OP_BE_4K_4B: + case SPINOR_OP_WRSR: + case SPINOR_OP_WREAR: + case SPINOR_OP_BRWR: + return false; + case SPINOR_OP_WRSR2: + return op->addr.nbytes != 0; + default: + return true; + } +} + static int zynqmp_qspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { @@ -771,6 +857,25 @@ static int zynqmp_qspi_exec_op(struct spi_slave *slave, priv->rx_buf = op->data.buf.in; priv->len = op->data.nbytes; + if (slave->flags & SPI_XFER_U_PAGE) + priv->u_page = 1; + else + priv->u_page = 0; + + if ((slave->flags & GQSPI_SELECT_LOWER_CS) && + (slave->flags & GQSPI_SELECT_UPPER_CS)) + priv->is_parallel = true; + + priv->stripe = 0; + priv->bus = 0; + + if (priv->is_parallel) { + if (slave->flags & SPI_XFER_MASK) + priv->bus = (slave->flags & SPI_XFER_MASK) >> 8; + if (zynqmp_qspi_update_stripe(op)) + priv->stripe = 1; + } + zynqmp_qspi_chipselect(priv, 1); /* Send opcode, addr, dummy */ @@ -784,6 +889,9 @@ static int zynqmp_qspi_exec_op(struct spi_slave *slave, zynqmp_qspi_chipselect(priv, 0); + priv->is_parallel = false; + slave->flags &= ~SPI_XFER_MASK; + return ret; } @@ -814,4 +922,5 @@ U_BOOT_DRIVER(zynqmp_qspi) = { .plat_auto = sizeof(struct zynqmp_qspi_plat), .priv_auto = sizeof(struct zynqmp_qspi_priv), .probe = zynqmp_qspi_probe, + .child_pre_probe = zynqmp_qspi_child_pre_probe, }; diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index a6a0584585c..796fc9effa5 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -2,7 +2,7 @@ # # (C) Copyright 2016 Cadence Design Systems Inc. -obj-$(CONFIG_$(SPL_TPL_)SYSRESET) += sysreset-uclass.o +obj-$(CONFIG_$(PHASE_)SYSRESET) += sysreset-uclass.o obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o obj-$(CONFIG_ARCH_STI) += sysreset_sti.o @@ -10,24 +10,24 @@ obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o obj-$(CONFIG_SYSRESET_CV1800B) += sysreset_cv1800b.o obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_MAX77663) += sysreset_max77663.o +obj-$(CONFIG_$(PHASE_)SYSRESET_MAX77663) += sysreset_max77663.o obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_PALMAS) += sysreset_palmas.o +obj-$(CONFIG_$(PHASE_)SYSRESET_PALMAS) += sysreset_palmas.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o obj-$(CONFIG_SYSRESET_TEGRA) += sysreset_tegra.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS65910) += sysreset_tps65910.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_TPS80031) += sysreset_tps80031.o +obj-$(CONFIG_$(PHASE_)SYSRESET_TPS65910) += sysreset_tps65910.o +obj-$(CONFIG_$(PHASE_)SYSRESET_TPS80031) += sysreset_tps80031.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o obj-$(CONFIG_SYSRESET_RESETCTL) += sysreset_resetctl.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_AT91) += sysreset_at91.o -obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o +obj-$(CONFIG_$(PHASE_)SYSRESET_AT91) += sysreset_at91.o +obj-$(CONFIG_$(PHASE_)SYSRESET_X86) += sysreset_x86.o obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o obj-$(CONFIG_SYSRESET_QCOM_PSHOLD) += sysreset_qcom-pshold.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index d30b008bf9a..536ac727142 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -102,7 +102,7 @@ void sysreset_walk_halt(enum sysreset_t type) mdelay(100); /* Still no reset? Give up */ - if (spl_phase() <= PHASE_SPL) + if (xpl_phase() <= PHASE_SPL) log_err("no sysreset\n"); else log_err("System reset not supported on this platform\n"); diff --git a/drivers/sysreset/sysreset_ast.c b/drivers/sysreset/sysreset_ast.c index ef09440bbef..4e15ebd53cc 100644 --- a/drivers/sysreset/sysreset_ast.c +++ b/drivers/sysreset/sysreset_ast.c @@ -33,7 +33,7 @@ static int ast_sysreset_request(struct udevice *dev, enum sysreset_t type) return -EPROTONOSUPPORT; } -#if !defined(CONFIG_SPL_BUILD) +#if !defined(CONFIG_XPL_BUILD) ret = wdt_expire_now(wdt, reset_mode); if (ret) { debug("Sysreset failed: %d", ret); diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index fec4af392e6..7a847e8388b 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -5,14 +5,14 @@ obj-y += timer-uclass.o obj-$(CONFIG_ADI_SC5XX_TIMER) += adi_sc5xx_timer.o obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o -obj-$(CONFIG_$(SPL_)ANDES_PLMT_TIMER) += andes_plmt_timer.o +obj-$(CONFIG_$(XPL_)ANDES_PLMT_TIMER) += andes_plmt_timer.o obj-$(CONFIG_ARC_TIMER) += arc_timer.o obj-$(CONFIG_ARM_TWD_TIMER) += arm_twd_timer.o obj-$(CONFIG_AST_TIMER) += ast_timer.o obj-$(CONFIG_AST_IBEX_TIMER) += ast_ibex_timer.o obj-$(CONFIG_ATCPIT100_TIMER) += atcpit100_timer.o -obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o -obj-$(CONFIG_$(SPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o +obj-$(CONFIG_$(XPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o +obj-$(CONFIG_$(XPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o obj-$(CONFIG_FTTMR010_TIMER) += fttmr010_timer.o @@ -27,7 +27,7 @@ obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_SANDBOX_TIMER) += sandbox_timer.o obj-$(CONFIG_SP804_TIMER) += sp804_timer.o -obj-$(CONFIG_$(SPL_)RISCV_ACLINT) += riscv_aclint_timer.o +obj-$(CONFIG_$(XPL_)RISCV_ACLINT) += riscv_aclint_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_STM32_TIMER) += stm32_timer.o obj-$(CONFIG_TEGRA_TIMER) += tegra-timer.o diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 80c084f380d..dd16ab320b2 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -83,7 +83,7 @@ static unsigned long cpu_mhz_from_cpuid(void) if (cpuid_eax(0) < 0x16) return 0; - return cpuid_eax(0x16); + return cpuid_eax(0x15); } /* @@ -299,10 +299,19 @@ static unsigned long __maybe_unused quick_pit_calibrate(void) if (!pit_expect_msb(0xff-i, &delta, &d2)) break; + delta -= tsc; + + /* + * Extrapolate the error and fail fast if the error will + * never be below 500 ppm. + */ + if (i == 1 && + d1 + d2 >= (delta * MAX_QUICK_PIT_ITERATIONS) >> 11) + return 0; + /* * Iterate until the error is less than 500 ppm */ - delta -= tsc; if (d1+d2 >= delta >> 11) continue; @@ -403,6 +412,10 @@ static void tsc_timer_ensure_setup(bool early) if (!gd->arch.clock_rate) { unsigned long fast_calibrate; + /* deal with this being called before x86_cpu_init_f() */ + if (!gd->arch.x86_vendor) + x86_get_identity_for_timer(); + /** * There is no obvious way to obtain this information from EFI * boot services. This value was measured on a Framework Laptop @@ -438,6 +451,7 @@ static void tsc_timer_ensure_setup(bool early) return; done: + fast_calibrate = min(fast_calibrate, 4000UL); if (!gd->arch.clock_rate) gd->arch.clock_rate = fast_calibrate * 1000000; } diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 9540fd7fe78..76e516dbbaf 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. -obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-uclass.o +obj-$(CONFIG_$(PHASE_)TPM) += tpm-uclass.o obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_TIS_INFINEON) += tpm_tis_infineon.o @@ -10,7 +10,7 @@ obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o sandbox_common.o obj-$(CONFIG_TPM_ST33ZP24_I2C) += tpm_tis_st33zp24_i2c.o obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o -obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o +obj-$(CONFIG_$(PHASE_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_core.o tpm2_tis_spi.o obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 7da46faed6b..b08ca08b07c 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -26,6 +26,13 @@ config UFS_PCI If unsure, say N. +config QCOM_UFS + bool "Qualcomm Host Controller driver for UFS" + depends on UFS && ARCH_SNAPDRAGON + help + This selects the platform driver for the UFS host + controller present on Qualcomm Snapdragon SoCs. + config TI_J721E_UFS bool "Glue Layer driver for UFS on TI J721E devices" help @@ -41,4 +48,12 @@ config UFS_RENESAS UFS host on Renesas needs some vendor specific configuration before accessing the hardware. +config UFS_AMD_VERSAL2 + bool "AMD Versal Gen 2 UFS controller platform driver" + depends on UFS && ZYNQMP_FIRMWARE + help + This selects the AMD specific additions to UFSHCD platform driver. + UFS host on AMD needs some vendor specific configuration before accessing + the hardware. + endmenu diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile index 67c42621aba..2a378e45111 100644 --- a/drivers/ufs/Makefile +++ b/drivers/ufs/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o +obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o obj-$(CONFIG_UFS_PCI) += ufs-pci.o obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o +obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c new file mode 100644 index 00000000000..bfd844e4193 --- /dev/null +++ b/drivers/ufs/ufs-amd-versal2.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Advanced Micro Devices, Inc. + */ + +#include <clk.h> +#include <dm.h> +#include <ufs.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <zynqmp_firmware.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/time.h> +#include <reset.h> + +#include "ufs.h" +#include "ufshcd-dwc.h" +#include "ufshci-dwc.h" + +#define VERSAL2_UFS_DEVICE_ID 4 + +#define SRAM_CSR_INIT_DONE_MASK BIT(0) +#define SRAM_CSR_EXT_LD_DONE_MASK BIT(1) +#define SRAM_CSR_BYPASS_MASK BIT(2) + +#define MPHY_FAST_RX_AFE_CAL BIT(2) +#define MPHY_FW_CALIB_CFG_VAL BIT(8) + +#define TX_RX_CFG_RDY_MASK GENMASK(3, 0) + +#define TIMEOUT_MICROSEC 1000000L + +#define IOCTL_UFS_TXRX_CFGRDY_GET 40 +#define IOCTL_UFS_SRAM_CSR_SEL 41 + +#define PM_UFS_SRAM_CSR_WRITE 0 +#define PM_UFS_SRAM_CSR_READ 1 + +struct ufs_versal2_priv { + struct ufs_hba *hba; + struct reset_ctl *rstc; + struct reset_ctl *rstphy; + u32 phy_mode; + u32 host_clk; + u32 pd_dev_id; + u8 attcompval0; + u8 attcompval1; + u8 ctlecompval0; + u8 ctlecompval1; +}; + +static int ufs_versal2_phy_reg_write(struct ufs_hba *hba, u32 addr, u32 val) +{ + static struct ufshcd_dme_attr_val phy_write_attrs[] = { + { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGWRLSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGWRMSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGRDWRSEL), 1, DME_LOCAL }, + { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } + }; + + phy_write_attrs[0].mib_val = (u8)addr; + phy_write_attrs[1].mib_val = (u8)(addr >> 8); + phy_write_attrs[2].mib_val = (u8)val; + phy_write_attrs[3].mib_val = (u8)(val >> 8); + + return ufshcd_dwc_dme_set_attrs(hba, phy_write_attrs, ARRAY_SIZE(phy_write_attrs)); +} + +static int ufs_versal2_phy_reg_read(struct ufs_hba *hba, u32 addr, u32 *val) +{ + u32 mib_val; + int ret; + static struct ufshcd_dme_attr_val phy_read_attrs[] = { + { UIC_ARG_MIB(CBCREGADDRLSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGADDRMSB), 0, DME_LOCAL }, + { UIC_ARG_MIB(CBCREGRDWRSEL), 0, DME_LOCAL }, + { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } + }; + + phy_read_attrs[0].mib_val = (u8)addr; + phy_read_attrs[1].mib_val = (u8)(addr >> 8); + + ret = ufshcd_dwc_dme_set_attrs(hba, phy_read_attrs, ARRAY_SIZE(phy_read_attrs)); + if (ret) + return ret; + + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDLSB), &mib_val); + if (ret) + return ret; + + *val = mib_val; + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(CBCREGRDMSB), &mib_val); + if (ret) + return ret; + + *val |= (mib_val << 8); + + return 0; +} + +int versal2_pm_ufs_get_txrx_cfgrdy(u32 node_id, u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_TXRX_CFGRDY_GET, + 0, 0, ret_payload); + *value = ret_payload[1]; + + return ret; +} + +int versal2_pm_ufs_sram_csr_sel(u32 node_id, u32 type, u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + if (type == PM_UFS_SRAM_CSR_READ) { + ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL, + type, 0, ret_payload); + *value = ret_payload[1]; + } else { + ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL, + type, *value, 0); + } + + return ret; +} + +static int ufs_versal2_enable_phy(struct ufs_hba *hba) +{ + u32 offset, reg; + int ret; + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0); + if (ret) + return ret; + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1); + if (ret) + return ret; + + /* Check Tx/Rx FSM states */ + for (offset = 0; offset < 2; offset++) { + u32 time_left, mibsel; + + time_left = TIMEOUT_MICROSEC; + mibsel = UIC_ARG_MIB_SEL(MTX_FSM_STATE, UIC_ARG_MPHY_TX_GEN_SEL_INDEX(offset)); + do { + ret = ufshcd_dme_get(hba, mibsel, ®); + if (ret) + return ret; + + if (reg == TX_STATE_HIBERN8 || reg == TX_STATE_SLEEP || + reg == TX_STATE_LSBURST) + break; + + time_left--; + mdelay(5); + } while (time_left); + + if (!time_left) { + dev_err(hba->dev, "Invalid Tx FSM state.\n"); + return -ETIMEDOUT; + } + + time_left = TIMEOUT_MICROSEC; + mibsel = UIC_ARG_MIB_SEL(MRX_FSM_STATE, UIC_ARG_MPHY_RX_GEN_SEL_INDEX(offset)); + do { + ret = ufshcd_dme_get(hba, mibsel, ®); + if (ret) + return ret; + + if (reg == RX_STATE_HIBERN8 || reg == RX_STATE_SLEEP || + reg == RX_STATE_LSBURST) + break; + + time_left--; + mdelay(5); + } while (time_left); + + if (!time_left) { + dev_err(hba->dev, "Invalid Rx FSM state.\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int ufs_versal2_setup_phy(struct ufs_hba *hba) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + int ret; + u32 reg; + + /* Bypass RX-AFE offset calibrations (ATT/CTLE) */ + ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(0), ®); + if (ret) + return ret; + + reg |= MPHY_FAST_RX_AFE_CAL; + ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(0), reg); + if (ret) + return ret; + + ret = ufs_versal2_phy_reg_read(hba, FAST_FLAGS(1), ®); + if (ret) + return ret; + + reg |= MPHY_FAST_RX_AFE_CAL; + ret = ufs_versal2_phy_reg_write(hba, FAST_FLAGS(1), reg); + if (ret) + return ret; + + /* Program ATT and CTLE compensation values */ + if (priv->attcompval0) { + ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(0), priv->attcompval0); + if (ret) + return ret; + } + + if (priv->attcompval1) { + ret = ufs_versal2_phy_reg_write(hba, RX_AFE_ATT_IDAC(1), priv->attcompval1); + if (ret) + return ret; + } + + if (priv->ctlecompval0) { + ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(0), priv->ctlecompval0); + if (ret) + return ret; + } + + if (priv->ctlecompval1) { + ret = ufs_versal2_phy_reg_write(hba, RX_AFE_CTLE_IDAC(1), priv->ctlecompval1); + if (ret) + return ret; + } + + ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(0), ®); + if (ret) + return ret; + + reg |= MPHY_FW_CALIB_CFG_VAL; + ret = ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(0), reg); + if (ret) + return ret; + + ret = ufs_versal2_phy_reg_read(hba, FW_CALIB_CCFG(1), ®); + if (ret) + return ret; + + reg |= MPHY_FW_CALIB_CFG_VAL; + return ufs_versal2_phy_reg_write(hba, FW_CALIB_CCFG(1), reg); +} + +static int ufs_versal2_phy_init(struct ufs_hba *hba) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + u32 reg, time_left; + int ret; + static const struct ufshcd_dme_attr_val rmmi_attrs[] = { + { UIC_ARG_MIB(CBREFCLKCTRL2), CBREFREFCLK_GATE_OVR_EN, DME_LOCAL }, + { UIC_ARG_MIB(CBCRCTRL), 1, DME_LOCAL }, + { UIC_ARG_MIB(CBC10DIRECTCONF2), 1, DME_LOCAL }, + { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } + }; + + /* Wait for Tx/Rx config_rdy */ + time_left = TIMEOUT_MICROSEC; + do { + time_left--; + ret = versal2_pm_ufs_get_txrx_cfgrdy(priv->pd_dev_id, ®); + if (ret) + return ret; + + reg &= TX_RX_CFG_RDY_MASK; + if (!reg) + break; + + mdelay(5); + } while (time_left); + + if (!time_left) { + dev_err(hba->dev, "Tx/Rx configuration signal busy.\n"); + return -ETIMEDOUT; + } + + ret = ufshcd_dwc_dme_set_attrs(hba, rmmi_attrs, ARRAY_SIZE(rmmi_attrs)); + if (ret) + return ret; + + /* DeAssert PHY reset */ + ret = reset_deassert(priv->rstphy); + if (ret) { + dev_err(hba->dev, "ufsphy reset deassert failed\n"); + return ret; + } + + /* Wait for SRAM init done */ + time_left = TIMEOUT_MICROSEC; + do { + time_left--; + ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, + PM_UFS_SRAM_CSR_READ, ®); + if (ret) + return ret; + + reg &= SRAM_CSR_INIT_DONE_MASK; + if (reg) + break; + + mdelay(5); + } while (time_left); + + if (!time_left) { + dev_err(hba->dev, "SRAM initialization failed.\n"); + return -ETIMEDOUT; + } + + ret = ufs_versal2_setup_phy(hba); + if (ret) + return ret; + + return ufs_versal2_enable_phy(hba); +} + +static int ufs_versal2_init(struct ufs_hba *hba) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + struct clk clk; + unsigned long core_clk_rate = 0; + int ret = 0; + + priv->phy_mode = UFSHCD_DWC_PHY_MODE_ROM; + priv->pd_dev_id = VERSAL2_UFS_DEVICE_ID; + + ret = clk_get_by_name(hba->dev, "core_clk", &clk); + if (ret) { + dev_err(hba->dev, "failed to get core_clk clock\n"); + return ret; + } + + core_clk_rate = clk_get_rate(&clk); + if (IS_ERR_VALUE(core_clk_rate)) { + dev_err(hba->dev, "%s: unable to find core_clk rate\n", + __func__); + return core_clk_rate; + } + priv->host_clk = core_clk_rate; + + priv->rstc = devm_reset_control_get(hba->dev, "ufshc-rst"); + if (IS_ERR(priv->rstc)) { + dev_err(hba->dev, "failed to get reset ctl: ufshc-rst\n"); + return PTR_ERR(priv->rstc); + } + priv->rstphy = devm_reset_control_get(hba->dev, "ufsphy-rst"); + if (IS_ERR(priv->rstphy)) { + dev_err(hba->dev, "failed to get reset ctl: ufsphy-rst\n"); + return PTR_ERR(priv->rstphy); + } + + return ret; +} + +static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + u32 sram_csr; + int ret; + + switch (status) { + case PRE_CHANGE: + /* Assert RST_UFS Reset for UFS block in PMX_IOU */ + ret = reset_assert(priv->rstc); + if (ret) { + dev_err(hba->dev, "ufshc reset assert failed, err = %d\n", ret); + return ret; + } + + /* Assert PHY reset */ + ret = reset_assert(priv->rstphy); + if (ret) { + dev_err(hba->dev, "ufsphy reset assert failed, err = %d\n", ret); + return ret; + } + + ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, + PM_UFS_SRAM_CSR_READ, &sram_csr); + if (ret) + return ret; + + if (!priv->phy_mode) { + sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK; + sram_csr |= SRAM_CSR_BYPASS_MASK; + } else { + dev_err(hba->dev, "Invalid phy-mode %d.\n", priv->phy_mode); + return -EINVAL; + } + + ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, + PM_UFS_SRAM_CSR_WRITE, &sram_csr); + if (ret) + return ret; + + /* De Assert RST_UFS Reset for UFS block in PMX_IOU */ + ret = reset_deassert(priv->rstc); + if (ret) + dev_err(hba->dev, "ufshc reset deassert failed, err = %d\n", ret); + + break; + case POST_CHANGE: + ret = ufs_versal2_phy_init(hba); + if (ret) + dev_err(hba->dev, "Phy init failed (%d)\n", ret); + + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_versal2_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); + int ret = 0; + + switch (status) { + case PRE_CHANGE: + if (priv->host_clk) { + u32 core_clk_div = priv->host_clk / TIMEOUT_MICROSEC; + + ufshcd_writel(hba, core_clk_div, DWC_UFS_REG_HCLKDIV); + } + break; + case POST_CHANGE: + ret = ufshcd_dwc_link_startup_notify(hba, status); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static struct ufs_hba_ops ufs_versal2_hba_ops = { + .init = ufs_versal2_init, + .link_startup_notify = ufs_versal2_link_startup_notify, + .hce_enable_notify = ufs_versal2_hce_enable_notify, +}; + +static int ufs_versal2_probe(struct udevice *dev) +{ + int ret; + + /* Perform generic probe */ + ret = ufshcd_probe(dev, &ufs_versal2_hba_ops); + if (ret) + dev_err(dev, "ufshcd_probe() failed %d\n", ret); + + return ret; +} + +static int ufs_versal2_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + + return ufs_scsi_bind(dev, &scsi_dev); +} + +static const struct udevice_id ufs_versal2_ids[] = { + { + .compatible = "amd,versal2-ufs", + }, + {}, +}; + +U_BOOT_DRIVER(ufs_versal2_pltfm) = { + .name = "ufs-versal2-pltfm", + .id = UCLASS_UFS, + .of_match = ufs_versal2_ids, + .probe = ufs_versal2_probe, + .bind = ufs_versal2_bind, +}; diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c new file mode 100644 index 00000000000..843585726c7 --- /dev/null +++ b/drivers/ufs/ufs-qcom.c @@ -0,0 +1,670 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. + * Copyright (C) 2023-2024 Linaro Limited + * Authors: + * - Bhupesh Sharma <bhupesh.sharma@linaro.org> + * - Neil Armstrong <neil.armstrong@linaro.org> + * + * Based on Linux driver + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <generic-phy.h> +#include <ufs.h> +#include <asm/gpio.h> + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> + +#include "ufs.h" +#include "ufs-qcom.h" + +#define ceil(freq, div) ((freq) % (div) == 0 ? ((freq) / (div)) : ((freq) / (div) + 1)) + +static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable); + +static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv) +{ + int err; + + if (priv->is_clks_enabled) + return 0; + + err = clk_enable_bulk(&priv->clks); + if (err) + return err; + + priv->is_clks_enabled = true; + + return 0; +} + +static int ufs_qcom_init_clks(struct ufs_qcom_priv *priv) +{ + int err; + struct udevice *dev = priv->hba->dev; + + err = clk_get_bulk(dev, &priv->clks); + if (err) + return err; + + return 0; +} + +static int ufs_qcom_check_hibern8(struct ufs_hba *hba) +{ + int err, retry_count = 50; + u32 tx_fsm_val = 0; + + do { + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); + if (err || tx_fsm_val == TX_FSM_HIBERN8) + break; + + /* max. 200us */ + udelay(200); + retry_count--; + } while (retry_count != 0); + + /* Check the state again */ + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); + + if (err) { + dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", + __func__, err); + } else if (tx_fsm_val != TX_FSM_HIBERN8) { + err = tx_fsm_val; + dev_err(hba->dev, "%s: invalid TX_FSM_STATE = %d\n", + __func__, err); + } + + return err; +} + +static void ufs_qcom_select_unipro_mode(struct ufs_qcom_priv *priv) +{ + ufshcd_rmwl(priv->hba, QUNIPRO_SEL, QUNIPRO_SEL, REG_UFS_CFG1); + + if (priv->hw_ver.major >= 0x05) + ufshcd_rmwl(priv->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0); +} + +/* + * ufs_qcom_reset - reset host controller and PHY + */ +static int ufs_qcom_reset(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + int ret; + + ret = reset_assert(&priv->core_reset); + if (ret) { + dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n", + __func__, ret); + return ret; + } + + /* + * The hardware requirement for delay between assert/deassert + * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to + * ~125us (4/32768). To be on the safe side add 200us delay. + */ + udelay(210); + + ret = reset_deassert(&priv->core_reset); + if (ret) + dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", + __func__, ret); + + udelay(1100); + + return 0; +} + +/** + * ufs_qcom_advertise_quirks - advertise the known QCOM UFS controller quirks + * @hba: host controller instance + * + * QCOM UFS host controller might have some non standard behaviours (quirks) + * than what is specified by UFSHCI specification. Advertise all such + * quirks to standard UFS host controller driver so standard takes them into + * account. + */ +static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + + if (priv->hw_ver.major == 0x2) + hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; + + if (priv->hw_ver.major > 0x3) + hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; +} + +/** + * ufs_qcom_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * @status: PRE_CHANGE or POST_CHANGE notify + * + * Returns 0 on success, non-zero on failure. + */ +static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, + enum ufs_notify_change_status status) +{ + switch (status) { + case PRE_CHANGE: + if (!on) + /* disable device ref_clk */ + ufs_qcom_dev_ref_clk_ctrl(hba, false); + break; + case POST_CHANGE: + if (on) + /* enable the device ref clock for HS mode*/ + ufs_qcom_dev_ref_clk_ctrl(hba, true); + break; + } + + return 0; +} + +static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + + /* + * TOFIX: v4 controllers *should* be able to support HS Gear 4 + * but so far pwr_mode switch is failing on v4 controllers and HS Gear 4. + * only enable HS Gear > 3 for Controlers major version 5 and later. + */ + if (priv->hw_ver.major > 0x4) + return UFS_QCOM_MAX_GEAR(ufshcd_readl(hba, REG_UFS_PARAM0)); + + /* Default is HS-G3 */ + return UFS_HS_G3; +} + +static int ufs_get_max_pwr_mode(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + u32 max_gear = ufs_qcom_get_hs_gear(hba); + + max_pwr_info->info.gear_rx = min(max_pwr_info->info.gear_rx, max_gear); + /* Qualcomm UFS only support symmetric Gear */ + max_pwr_info->info.gear_tx = max_pwr_info->info.gear_rx; + + if (priv->hw_ver.major >= 0x4 && max_pwr_info->info.gear_rx > UFS_HS_G3) + ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + PA_INITIAL_ADAPT); + + dev_info(hba->dev, "Max HS Gear: %d\n", max_pwr_info->info.gear_rx); + + return 0; +} + +static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + struct phy phy; + int ret; + + /* Reset UFS Host Controller and PHY */ + ret = ufs_qcom_reset(hba); + if (ret) + dev_warn(hba->dev, "%s: host reset returned %d\n", + __func__, ret); + + /* get phy */ + ret = generic_phy_get_by_name(hba->dev, "ufsphy", &phy); + if (ret) { + dev_warn(hba->dev, "%s: Unable to get QMP ufs phy, ret = %d\n", + __func__, ret); + return ret; + } + + /* phy initialization */ + ret = generic_phy_init(&phy); + if (ret) { + dev_err(hba->dev, "%s: phy init failed, ret = %d\n", + __func__, ret); + return ret; + } + + /* power on phy */ + ret = generic_phy_power_on(&phy); + if (ret) { + dev_err(hba->dev, "%s: phy power on failed, ret = %d\n", + __func__, ret); + goto out_disable_phy; + } + + ufs_qcom_select_unipro_mode(priv); + + return 0; + +out_disable_phy: + generic_phy_exit(&phy); + + return ret; +} + +/* + * The UTP controller has a number of internal clock gating cells (CGCs). + * Internal hardware sub-modules within the UTP controller control the CGCs. + * Hardware CGCs disable the clock to inactivate UTP sub-modules not involved + * in a specific operation, UTP controller CGCs are by default disabled and + * this function enables them (after every UFS link startup) to save some power + * leakage. + */ +static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) +{ + ufshcd_rmwl(hba, REG_UFS_CFG2_CGC_EN_ALL, REG_UFS_CFG2_CGC_EN_ALL, + REG_UFS_CFG2); + + /* Ensure that HW clock gating is enabled before next operations */ + ufshcd_readl(hba, REG_UFS_CFG2); +} + +static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + int err; + + switch (status) { + case PRE_CHANGE: + ufs_qcom_power_up_sequence(hba); + /* + * The PHY PLL output is the source of tx/rx lane symbol + * clocks, hence, enable the lane clocks only after PHY + * is initialized. + */ + err = ufs_qcom_enable_clks(priv); + break; + case POST_CHANGE: + /* check if UFS PHY moved from DISABLED to HIBERN8 */ + err = ufs_qcom_check_hibern8(hba); + ufs_qcom_enable_hw_clk_gating(hba); + break; + default: + dev_err(hba->dev, "%s: invalid status %d\n", __func__, status); + err = -EINVAL; + break; + } + + return err; +} + +/* Look for the maximum core_clk_unipro clock value */ +static u32 ufs_qcom_get_core_clk_unipro_max_freq(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + ofnode node = dev_ofnode(priv->hba->dev); + struct ofnode_phandle_args opp_table; + int pos, ret; + u32 clk = 0; + + /* Get core_clk_unipro clock index */ + pos = ofnode_stringlist_search(node, "clock-names", "core_clk_unipro"); + if (pos < 0) + goto fallback; + + /* Try parsing the opps */ + if (!ofnode_parse_phandle_with_args(node, "required-opps", + NULL, 0, 0, &opp_table) && + ofnode_device_is_compatible(opp_table.node, "operating-points-v2")) { + ofnode opp_node; + + ofnode_for_each_subnode(opp_node, opp_table.node) { + u64 opp_clk; + /* opp-hw contains the OPP frequency */ + ret = ofnode_read_u64_index(opp_node, "opp-hz", pos, &opp_clk); + if (ret) + continue; + + /* We don't handle larger clock values, ignore */ + if (opp_clk > U32_MAX) + continue; + + /* Only keep the largest value */ + if (opp_clk > clk) + clk = opp_clk; + } + + /* If we get a valid clock, return it or check legacy*/ + if (clk) + return clk; + } + + /* Legacy freq-table-hz has a pair of u32 per clocks entry, min then max */ + if (!ofnode_read_u32_index(node, "freq-table-hz", pos * 2 + 1, &clk) && + clk > 0) + return clk; + +fallback: + /* default for backwards compatibility */ + return UNIPRO_CORE_CLK_FREQ_150_MHZ * 1000 * 1000; +}; + +static int ufs_qcom_set_clk_40ns_cycles(struct ufs_hba *hba, + u32 cycles_in_1us) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + u32 cycles_in_40ns; + int err; + u32 reg; + + /* + * UFS host controller V4.0.0 onwards needs to program + * PA_VS_CORE_CLK_40NS_CYCLES attribute per programmed + * frequency of unipro core clk of UFS host controller. + */ + if (priv->hw_ver.major < 4) + return 0; + + /* + * Generic formulae for cycles_in_40ns = (freq_unipro/25) is not + * applicable for all frequencies. For ex: ceil(37.5 MHz/25) will + * be 2 and ceil(403 MHZ/25) will be 17 whereas Hardware + * specification expect to be 16. Hence use exact hardware spec + * mandated value for cycles_in_40ns instead of calculating using + * generic formulae. + */ + switch (cycles_in_1us) { + case UNIPRO_CORE_CLK_FREQ_403_MHZ: + cycles_in_40ns = 16; + break; + case UNIPRO_CORE_CLK_FREQ_300_MHZ: + cycles_in_40ns = 12; + break; + case UNIPRO_CORE_CLK_FREQ_201_5_MHZ: + cycles_in_40ns = 8; + break; + case UNIPRO_CORE_CLK_FREQ_150_MHZ: + cycles_in_40ns = 6; + break; + case UNIPRO_CORE_CLK_FREQ_100_MHZ: + cycles_in_40ns = 4; + break; + case UNIPRO_CORE_CLK_FREQ_75_MHZ: + cycles_in_40ns = 3; + break; + case UNIPRO_CORE_CLK_FREQ_37_5_MHZ: + cycles_in_40ns = 2; + break; + default: + dev_err(hba->dev, "UNIPRO clk freq %u MHz not supported\n", + cycles_in_1us); + return -EINVAL; + } + + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), ®); + if (err) + return err; + + reg &= ~PA_VS_CORE_CLK_40NS_CYCLES_MASK; + reg |= cycles_in_40ns; + + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CORE_CLK_40NS_CYCLES), reg); +} + +static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + u32 core_clk_ctrl_reg; + u32 cycles_in_1us; + int err; + + cycles_in_1us = ceil(ufs_qcom_get_core_clk_unipro_max_freq(hba), + (1000 * 1000)); + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + &core_clk_ctrl_reg); + if (err) + return err; + + /* Bit mask is different for UFS host controller V4.0.0 onwards */ + if (priv->hw_ver.major >= 4) { + core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK_V4; + core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK_V4, cycles_in_1us); + } else { + core_clk_ctrl_reg &= ~CLK_1US_CYCLES_MASK; + core_clk_ctrl_reg |= FIELD_PREP(CLK_1US_CYCLES_MASK, cycles_in_1us); + } + + /* Clear CORE_CLK_DIV_EN */ + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; + + err = ufshcd_dme_set(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + core_clk_ctrl_reg); + if (err) + return err; + + /* Configure unipro core clk 40ns attribute */ + return ufs_qcom_set_clk_40ns_cycles(hba, cycles_in_1us); +} + +static u32 ufs_qcom_get_local_unipro_ver(struct ufs_hba *hba) +{ + /* HCI version 1.0 and 1.1 supports UniPro 1.41 */ + switch (hba->version) { + case UFSHCI_VERSION_10: + case UFSHCI_VERSION_11: + return UFS_UNIPRO_VER_1_41; + + case UFSHCI_VERSION_20: + case UFSHCI_VERSION_21: + default: + return UFS_UNIPRO_VER_1_6; + } +} + +static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + int err = 0; + + switch (status) { + case PRE_CHANGE: + err = ufs_qcom_set_core_clk_ctrl(hba); + if (err) + dev_err(hba->dev, "cfg core clk ctrl failed\n"); + /* + * Some UFS devices (and may be host) have issues if LCC is + * enabled. So we are setting PA_Local_TX_LCC_Enable to 0 + * before link startup which will make sure that both host + * and device TX LCC are disabled once link startup is + * completed. + */ + if (ufs_qcom_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41) + err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + + break; + default: + break; + } + + return err; +} + +static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + + if (enable ^ priv->is_dev_ref_clk_enabled) { + u32 temp = readl_relaxed(hba->mmio_base + REG_UFS_CFG1); + + if (enable) + temp |= BIT(26); + else + temp &= ~BIT(26); + + /* + * If we are here to disable this clock it might be immediately + * after entering into hibern8 in which case we need to make + * sure that device ref_clk is active for specific time after + * hibern8 enter. + */ + if (!enable) + udelay(10); + + writel_relaxed(temp, hba->mmio_base + REG_UFS_CFG1); + + /* + * Make sure the write to ref_clk reaches the destination and + * not stored in a Write Buffer (WB). + */ + readl(hba->mmio_base + REG_UFS_CFG1); + + /* + * If we call hibern8 exit after this, we need to make sure that + * device ref_clk is stable for at least 1us before the hibern8 + * exit command. + */ + if (enable) + udelay(1); + + priv->is_dev_ref_clk_enabled = enable; + } +} + +/** + * ufs_qcom_init - bind phy with controller + * @hba: host controller instance + * + * Powers up PHY enabling clocks and regulators. + * + * Returns -EPROBE_DEFER if binding fails, returns negative error + * on phy power up failure and returns zero on success. + */ +static int ufs_qcom_init(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + int err; + + priv->hba = hba; + + /* setup clocks */ + ufs_qcom_setup_clocks(hba, true, PRE_CHANGE); + + if (priv->hw_ver.major >= 0x4) + ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + PA_NO_ADAPT); + + ufs_qcom_setup_clocks(hba, true, POST_CHANGE); + + ufs_qcom_get_controller_revision(hba, &priv->hw_ver.major, + &priv->hw_ver.minor, + &priv->hw_ver.step); + dev_info(hba->dev, "Qcom UFS HC version: %d.%d.%d\n", + priv->hw_ver.major, + priv->hw_ver.minor, + priv->hw_ver.step); + + err = ufs_qcom_init_clks(priv); + if (err) { + dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err); + return err; + } + + ufs_qcom_advertise_quirks(hba); + ufs_qcom_setup_clocks(hba, true, POST_CHANGE); + + return 0; +} + +/** + * ufs_qcom_device_reset() - toggle the (optional) device reset line + * @hba: per-adapter instance + * + * Toggles the (optional) reset line to reset the attached device. + */ +static int ufs_qcom_device_reset(struct ufs_hba *hba) +{ + struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + + if (!dm_gpio_is_valid(&priv->reset)) + return 0; + + /* + * The UFS device shall detect reset pulses of 1us, sleep for 10us to + * be on the safe side. + */ + dm_gpio_set_value(&priv->reset, true); + udelay(10); + + dm_gpio_set_value(&priv->reset, false); + udelay(10); + + return 0; +} + +static struct ufs_hba_ops ufs_qcom_hba_ops = { + .init = ufs_qcom_init, + .get_max_pwr_mode = ufs_get_max_pwr_mode, + .hce_enable_notify = ufs_qcom_hce_enable_notify, + .link_startup_notify = ufs_qcom_link_startup_notify, + .device_reset = ufs_qcom_device_reset, +}; + +static int ufs_qcom_probe(struct udevice *dev) +{ + struct ufs_qcom_priv *priv = dev_get_priv(dev); + int ret; + + /* get resets */ + ret = reset_get_by_name(dev, "rst", &priv->core_reset); + if (ret) { + dev_err(dev, "failed to get reset, ret:%d\n", ret); + return ret; + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset, GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "Warning: cannot get reset GPIO\n"); + } + + ret = ufshcd_probe(dev, &ufs_qcom_hba_ops); + if (ret) { + dev_err(dev, "ufshcd_probe() failed, ret:%d\n", ret); + return ret; + } + + return 0; +} + +static int ufs_qcom_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + + return ufs_scsi_bind(dev, &scsi_dev); +} + +static const struct udevice_id ufs_qcom_ids[] = { + { .compatible = "qcom,ufshc" }, + {}, +}; + +U_BOOT_DRIVER(qcom_ufshcd) = { + .name = "qcom-ufshcd", + .id = UCLASS_UFS, + .of_match = ufs_qcom_ids, + .probe = ufs_qcom_probe, + .bind = ufs_qcom_bind, + .priv_auto = sizeof(struct ufs_qcom_priv), +}; diff --git a/drivers/ufs/ufs-qcom.h b/drivers/ufs/ufs-qcom.h new file mode 100644 index 00000000000..de957ae60f3 --- /dev/null +++ b/drivers/ufs/ufs-qcom.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + */ + +#ifndef UFS_QCOM_H_ +#define UFS_QCOM_H_ + +#include <reset.h> +#include <linux/bitfield.h> + +#define MPHY_TX_FSM_STATE 0x41 +#define TX_FSM_HIBERN8 0x1 +#define DEFAULT_CLK_RATE_HZ 1000000 + +#define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28) +#define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) +#define UFS_HW_VER_STEP_MASK GENMASK(15, 0) + +/* QCOM UFS host controller vendor specific registers */ +enum { + REG_UFS_SYS1CLK_1US = 0xC0, + REG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4, + REG_UFS_LOCAL_PORT_ID_REG = 0xC8, + REG_UFS_PA_ERR_CODE = 0xCC, + /* On older UFS revisions, this register is called "RETRY_TIMER_REG" */ + REG_UFS_PARAM0 = 0xD0, + /* On older UFS revisions, this register is called "REG_UFS_PA_LINK_STARTUP_TIMER" */ + REG_UFS_CFG0 = 0xD8, + REG_UFS_CFG1 = 0xDC, + REG_UFS_CFG2 = 0xE0, + REG_UFS_HW_VERSION = 0xE4, + + UFS_TEST_BUS = 0xE8, + UFS_TEST_BUS_CTRL_0 = 0xEC, + UFS_TEST_BUS_CTRL_1 = 0xF0, + UFS_TEST_BUS_CTRL_2 = 0xF4, + UFS_UNIPRO_CFG = 0xF8, + + /* + * QCOM UFS host controller vendor specific registers + * added in HW Version 3.0.0 + */ + UFS_AH8_CFG = 0xFC, + + REG_UFS_CFG3 = 0x271C, +}; + +/* bit definitions for REG_UFS_CFG0 register */ +#define QUNIPRO_G4_SEL BIT(5) + +/* bit definitions for REG_UFS_CFG1 register */ +#define QUNIPRO_SEL BIT(0) +#define UFS_PHY_SOFT_RESET BIT(1) +#define UTP_DBG_RAMS_EN BIT(17) +#define TEST_BUS_EN BIT(18) +#define TEST_BUS_SEL GENMASK(22, 19) +#define UFS_REG_TEST_BUS_EN BIT(30) + +#define UFS_PHY_RESET_ENABLE 1 +#define UFS_PHY_RESET_DISABLE 0 + +/* bit definitions for REG_UFS_CFG2 register */ +#define UAWM_HW_CGC_EN BIT(0) +#define UARM_HW_CGC_EN BIT(1) +#define TXUC_HW_CGC_EN BIT(2) +#define RXUC_HW_CGC_EN BIT(3) +#define DFC_HW_CGC_EN BIT(4) +#define TRLUT_HW_CGC_EN BIT(5) +#define TMRLUT_HW_CGC_EN BIT(6) +#define OCSC_HW_CGC_EN BIT(7) + +/* bit definitions for REG_UFS_PARAM0 */ +#define MAX_HS_GEAR_MASK GENMASK(6, 4) +#define UFS_QCOM_MAX_GEAR(x) FIELD_GET(MAX_HS_GEAR_MASK, (x)) + +/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */ +#define TEST_BUS_SUB_SEL_MASK GENMASK(4, 0) /* All XXX_SEL fields are 5 bits wide */ + +#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ + TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ + DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ + TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN) + +/* bit offset */ +#define OFFSET_CLK_NS_REG 0xa + +/* bit masks */ +#define MASK_TX_SYMBOL_CLK_1US_REG GENMASK(9, 0) +#define MASK_CLK_NS_REG GENMASK(23, 10) + +/* QUniPro Vendor specific attributes */ +#define PA_VS_CONFIG_REG1 0x9000 +#define DME_VS_CORE_CLK_CTRL 0xD002 +/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ +#define CLK_1US_CYCLES_MASK_V4 GENMASK(27, 16) +#define CLK_1US_CYCLES_MASK GENMASK(7, 0) +#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) +#define PA_VS_CORE_CLK_40NS_CYCLES 0x9007 +#define PA_VS_CORE_CLK_40NS_CYCLES_MASK GENMASK(6, 0) + +/* QCOM UFS host controller core clk frequencies */ +#define UNIPRO_CORE_CLK_FREQ_37_5_MHZ 38 +#define UNIPRO_CORE_CLK_FREQ_75_MHZ 75 +#define UNIPRO_CORE_CLK_FREQ_100_MHZ 100 +#define UNIPRO_CORE_CLK_FREQ_150_MHZ 150 +#define UNIPRO_CORE_CLK_FREQ_300_MHZ 300 +#define UNIPRO_CORE_CLK_FREQ_201_5_MHZ 202 +#define UNIPRO_CORE_CLK_FREQ_403_MHZ 403 + +static inline void +ufs_qcom_get_controller_revision(struct ufs_hba *hba, + u8 *major, u16 *minor, u16 *step) +{ + u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION); + + *major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, ver); + *minor = FIELD_GET(UFS_HW_VER_MINOR_MASK, ver); + *step = FIELD_GET(UFS_HW_VER_STEP_MASK, ver); +}; + +/* Host controller hardware version: major.minor.step */ +struct ufs_hw_version { + u16 step; + u16 minor; + u8 major; +}; + +struct gpio_desc; + +struct ufs_qcom_priv { + struct phy *generic_phy; + struct ufs_hba *hba; + + struct clk_bulk clks; + bool is_clks_enabled; + + struct ufs_hw_version hw_ver; + + /* Reset control of HCI */ + struct reset_ctl core_reset; + + struct gpio_desc reset; + + bool is_dev_ref_clk_enabled; +}; + +#endif /* UFS_QCOM_H_ */ diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index be64bf971f1..f7d8c40c448 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -125,6 +125,11 @@ static void ufshcd_print_pwr_info(struct ufs_hba *hba) hba->pwr_info.hs_rate); } +static void ufshcd_device_reset(struct ufs_hba *hba) +{ + ufshcd_vops_device_reset(hba); +} + /** * ufshcd_ready_for_uic_cmd - Check if controller is ready * to accept UIC commands @@ -433,6 +438,12 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba) REG_UTP_TASK_REQ_LIST_BASE_H); /* + * Make sure base address and interrupt setup are updated before + * enabling the run/stop registers below. + */ + wmb(); + + /* * UCRDY, UTMRLDY and UTRLRDY bits must be 1 */ reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS); @@ -456,9 +467,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) { int ret; int retries = DME_LINKSTARTUP_RETRIES; - bool link_startup_again = true; -link_startup: do { ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); @@ -484,12 +493,6 @@ link_startup: /* failed to get the link up... retire */ goto out; - if (link_startup_again) { - link_startup_again = false; - retries = DME_LINKSTARTUP_RETRIES; - goto link_startup; - } - /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ ufshcd_init_pwr_info(hba); @@ -504,6 +507,8 @@ link_startup: if (ret) goto out; + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); ret = ufshcd_make_hba_operational(hba); out: if (ret) @@ -633,7 +638,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Transfer Request Descriptor * Should be aligned to 1k boundary. */ - hba->utrdl = memalign(1024, sizeof(struct utp_transfer_req_desc)); + hba->utrdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_req_desc), + ARCH_DMA_MINALIGN)); if (!hba->utrdl) { dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); return -ENOMEM; @@ -642,7 +649,9 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) /* Allocate one Command Descriptor * Should be aligned to 1k boundary. */ - hba->ucdl = memalign(1024, sizeof(struct utp_transfer_cmd_desc)); + hba->ucdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_cmd_desc), + ARCH_DMA_MINALIGN)); if (!hba->ucdl) { dev_err(hba->dev, "Command descriptor memory allocation failed\n"); return -ENOMEM; @@ -692,18 +701,29 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) } /** - * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache + * ufshcd_cache_flush - Flush cache + * + * Flush cache in aligned address..address+size range. + */ +static void ufshcd_cache_flush(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + + flush_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_cache_invalidate - Invalidate cache * - * Flush and invalidate cache in aligned address..address+size range. - * The invalidation is in place to avoid stale data in cache. + * Invalidate cache in aligned address..address+size range. */ -static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size) +static void ufshcd_cache_invalidate(void *addr, unsigned long size) { - uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); - unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN); + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); - flush_dcache_range(aaddr, aaddr + asize); - invalidate_dcache_range(aaddr, aaddr + asize); + invalidate_dcache_range(start_addr, end_addr); } /** @@ -750,7 +770,7 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, req_desc->prd_table_length = 0; - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); } static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, @@ -781,13 +801,13 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, /* Copy the Descriptor */ if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { memcpy(ucd_req_ptr + 1, query->descriptor, len); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); } else { - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); } memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) @@ -805,8 +825,8 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } /** @@ -844,6 +864,9 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + /* Make sure doorbell reg is updated before reading interrupt status */ + wmb(); + start = get_timer(0); do { intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); @@ -873,6 +896,8 @@ static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) */ static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) { + ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); + return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; } @@ -884,6 +909,8 @@ static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) { struct utp_transfer_req_desc *req_desc = hba->utrdl; + ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; } @@ -1433,8 +1460,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); } static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, @@ -1449,7 +1476,6 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) { struct utp_transfer_req_desc *req_desc = hba->utrdl; struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; - uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1); ulong datalen = pccb->datalen; int table_length; u8 *buf; @@ -1457,19 +1483,10 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) if (!datalen) { req_desc->prd_table_length = 0; - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); return; } - if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */ - flush_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); - } - - /* In any case, invalidate cache to avoid stale data in it. */ - invalidate_dcache_range(aaddr, aaddr + - ALIGN(datalen, ARCH_DMA_MINALIGN)); - table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); buf = pccb->pdata; i = table_length; @@ -1483,8 +1500,8 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1); req_desc->prd_table_length = table_length; - ufshcd_cache_flush_and_invalidate(prd_table, sizeof(*prd_table) * table_length); - ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc)); + ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); } static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) @@ -1498,8 +1515,12 @@ static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); prepare_prdt_table(hba, pccb); + ufshcd_cache_flush(pccb->pdata, pccb->datalen); + ufshcd_send_command(hba, TASK_TAG); + ufshcd_cache_invalidate(pccb->pdata, pccb->datalen); + ocs = ufshcd_get_tr_ocs(hba); switch (ocs) { case OCS_SUCCESS: @@ -1723,7 +1744,7 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) } hba->max_pwr_info.is_valid = true; - return 0; + return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info); } static int ufshcd_change_power_mode(struct ufs_hba *hba, @@ -1901,7 +1922,7 @@ int ufs_start(struct ufs_hba *hba) return ret; } - printf("Device at %s up at:", hba->dev->name); + debug("UFS Device %s is up!\n", hba->dev->name); ufshcd_print_pwr_info(hba); } @@ -1953,7 +1974,8 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) hba->version != UFSHCI_VERSION_20 && hba->version != UFSHCI_VERSION_21 && hba->version != UFSHCI_VERSION_30 && - hba->version != UFSHCI_VERSION_31) + hba->version != UFSHCI_VERSION_31 && + hba->version != UFSHCI_VERSION_40) dev_err(hba->dev, "invalid UFS version 0x%x\n", hba->version); @@ -1979,6 +2001,11 @@ int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) REG_INTERRUPT_STATUS); ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); + mb(); + + /* Reset the attached device */ + ufshcd_device_reset(hba); + err = ufshcd_hba_enable(hba); if (err) { dev_err(hba->dev, "Host controller enable failed\n"); diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 43042c294bb..00ecca350c3 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -3,6 +3,7 @@ #define __UFS_H #include <linux/types.h> +#include <asm/io.h> #include "unipro.h" struct udevice; @@ -695,11 +696,177 @@ struct ufs_dev_cmd { struct ufs_hba_ops { int (*init)(struct ufs_hba *hba); + int (*get_max_pwr_mode)(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info); int (*hce_enable_notify)(struct ufs_hba *hba, enum ufs_notify_change_status); int (*link_startup_notify)(struct ufs_hba *hba, enum ufs_notify_change_status); int (*phy_initialization)(struct ufs_hba *hba); + int (*device_reset)(struct ufs_hba *hba); +}; + +enum ufshcd_quirks { + /* Interrupt aggregation support is broken */ + UFSHCD_QUIRK_BROKEN_INTR_AGGR = 1 << 0, + + /* + * delay before each dme command is required as the unipro + * layer has shown instabilities + */ + UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS = 1 << 1, + + /* + * If UFS host controller is having issue in processing LCC (Line + * Control Command) coming from device then enable this quirk. + * When this quirk is enabled, host controller driver should disable + * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE + * attribute of device to 0). + */ + UFSHCD_QUIRK_BROKEN_LCC = 1 << 2, + + /* + * The attribute PA_RXHSUNTERMCAP specifies whether or not the + * inbound Link supports unterminated line in HS mode. Setting this + * attribute to 1 fixes moving to HS gear. + */ + UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP = 1 << 3, + + /* + * This quirk needs to be enabled if the host controller only allows + * accessing the peer dme attributes in AUTO mode (FAST AUTO or + * SLOW AUTO). + */ + UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE = 1 << 4, + + /* + * This quirk needs to be enabled if the host controller doesn't + * advertise the correct version in UFS_VER register. If this quirk + * is enabled, standard UFS host driver will call the vendor specific + * ops (get_ufs_hci_version) to get the correct version. + */ + UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION = 1 << 5, + + /* + * Clear handling for transfer/task request list is just opposite. + */ + UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR = 1 << 6, + + /* + * This quirk needs to be enabled if host controller doesn't allow + * that the interrupt aggregation timer and counter are reset by s/w. + */ + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR = 1 << 7, + + /* + * This quirks needs to be enabled if host controller cannot be + * enabled via HCE register. + */ + UFSHCI_QUIRK_BROKEN_HCE = 1 << 8, + + /* + * This quirk needs to be enabled if the host controller regards + * resolution of the values of PRDTO and PRDTL in UTRD as byte. + */ + UFSHCD_QUIRK_PRDT_BYTE_GRAN = 1 << 9, + + /* + * This quirk needs to be enabled if the host controller reports + * OCS FATAL ERROR with device error through sense data + */ + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR = 1 << 10, + + /* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it doesn't work. + */ + UFSHCD_QUIRK_BROKEN_AUTO_HIBERN8 = 1 << 11, + + /* + * This quirk needs to disable manual flush for write booster + */ + UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL = 1 << 12, + + /* + * This quirk needs to disable unipro timeout values + * before power mode change + */ + UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING = 1 << 13, + + /* + * This quirk needs to be enabled if the host controller does not + * support UIC command + */ + UFSHCD_QUIRK_BROKEN_UIC_CMD = 1 << 15, + + /* + * This quirk needs to be enabled if the host controller cannot + * support physical host configuration. + */ + UFSHCD_QUIRK_SKIP_PH_CONFIGURATION = 1 << 16, + + /* + * This quirk needs to be enabled if the host controller has + * 64-bit addressing supported capability but it doesn't work. + */ + UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS = 1 << 17, + + /* + * This quirk needs to be enabled if the host controller has + * auto-hibernate capability but it's FASTAUTO only. + */ + UFSHCD_QUIRK_HIBERN_FASTAUTO = 1 << 18, + + /* + * This quirk needs to be enabled if the host controller needs + * to reinit the device after switching to maximum gear. + */ + UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH = 1 << 19, + + /* + * Some host raises interrupt (per queue) in addition to + * CQES (traditional) when ESI is disabled. + * Enable this quirk will disable CQES and use per queue interrupt. + */ + UFSHCD_QUIRK_MCQ_BROKEN_INTR = 1 << 20, + + /* + * Some host does not implement SQ Run Time Command (SQRTC) register + * thus need this quirk to skip related flow. + */ + UFSHCD_QUIRK_MCQ_BROKEN_RTC = 1 << 21, + + /* + * This quirk needs to be enabled if the host controller supports inline + * encryption but it needs to initialize the crypto capabilities in a + * nonstandard way and/or needs to override blk_crypto_ll_ops. If + * enabled, the standard code won't initialize the blk_crypto_profile; + * ufs_hba_variant_ops::init() must do it instead. + */ + UFSHCD_QUIRK_CUSTOM_CRYPTO_PROFILE = 1 << 22, + + /* + * This quirk needs to be enabled if the host controller supports inline + * encryption but does not support the CRYPTO_GENERAL_ENABLE bit, i.e. + * host controller initialization fails if that bit is set. + */ + UFSHCD_QUIRK_BROKEN_CRYPTO_ENABLE = 1 << 23, + + /* + * This quirk needs to be enabled if the host controller driver copies + * cryptographic keys into the PRDT in order to send them to hardware, + * and therefore the PRDT should be zeroized after each request (as per + * the standard best practice for managing keys). + */ + UFSHCD_QUIRK_KEYS_IN_PRDT = 1 << 24, + + /* + * This quirk indicates that the controller reports the value 1 (not + * supported) in the Legacy Single DoorBell Support (LSDBS) bit of the + * Controller Capabilities register although it supports the legacy + * single doorbell mode. + */ + UFSHCD_QUIRK_BROKEN_LSDBS_CAP = 1 << 25, }; struct ufs_hba { @@ -710,27 +877,7 @@ struct ufs_hba { u32 capabilities; u32 version; u32 intr_mask; - u32 quirks; -/* - * If UFS host controller is having issue in processing LCC (Line - * Control Command) coming from device then enable this quirk. - * When this quirk is enabled, host controller driver should disable - * the LCC transmission on UFS device (by clearing TX_LCC_ENABLE - * attribute of device to 0). - */ -#define UFSHCD_QUIRK_BROKEN_LCC BIT(0) - -/* - * This quirk needs to be enabled if the host controller has - * 64-bit addressing supported capability but it doesn't work. - */ -#define UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS BIT(1) - -/* - * This quirk needs to be enabled if the host controller has - * auto-hibernate capability but it's FASTAUTO only. - */ -#define UFSHCD_QUIRK_HIBERN_FASTAUTO BIT(2) + enum ufshcd_quirks quirks; /* Virtual memory reference */ struct utp_transfer_cmd_desc *ucdl; @@ -758,6 +905,15 @@ static inline int ufshcd_ops_init(struct ufs_hba *hba) return 0; } +static inline int ufshcd_ops_get_max_pwr_mode(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info) +{ + if (hba->ops && hba->ops->get_max_pwr_mode) + return hba->ops->get_max_pwr_mode(hba, max_pwr_info); + + return 0; +} + static inline int ufshcd_ops_hce_enable_notify(struct ufs_hba *hba, bool status) { @@ -776,6 +932,14 @@ static inline int ufshcd_ops_link_startup_notify(struct ufs_hba *hba, return 0; } +static inline int ufshcd_vops_device_reset(struct ufs_hba *hba) +{ + if (hba->ops && hba->ops->device_reset) + return hba->ops->device_reset(hba); + + return 0; +} + /* Controller UFSHCI version */ enum { UFSHCI_VERSION_10 = 0x00010000, /* 1.0 */ @@ -784,6 +948,7 @@ enum { UFSHCI_VERSION_21 = 0x00000210, /* 2.1 */ UFSHCI_VERSION_30 = 0x00000300, /* 3.0 */ UFSHCI_VERSION_31 = 0x00000310, /* 3.1 */ + UFSHCI_VERSION_40 = 0x00000400, /* 4.0 */ }; /* Interrupt disable masks */ @@ -921,6 +1086,23 @@ enum { #define ufshcd_readl(hba, reg) \ readl((hba)->mmio_base + (reg)) +/** + * ufshcd_rmwl - perform read/modify/write for a controller register + * @hba: per adapter instance + * @mask: mask to apply on read value + * @val: actual value to write + * @reg: register address + */ +static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) +{ + u32 tmp; + + tmp = ufshcd_readl(hba, reg); + tmp &= ~mask; + tmp |= (val & mask); + ufshcd_writel(hba, tmp, reg); +} + /* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */ #define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT 0x1 diff --git a/drivers/ufs/ufshcd-dwc.c b/drivers/ufs/ufshcd-dwc.c new file mode 100644 index 00000000000..3f62e59a060 --- /dev/null +++ b/drivers/ufs/ufshcd-dwc.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + */ +#include <clk.h> +#include <dm.h> +#include <ufs.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/time.h> + +#include "ufs.h" +#include "ufshci-dwc.h" +#include "ufshcd-dwc.h" + +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, + const struct ufshcd_dme_attr_val *v, int n) +{ + int ret = 0; + int attr_node = 0; + + for (attr_node = 0; attr_node < n; attr_node++) { + ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel, + ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer); + if (ret) + return ret; + } + + return 0; +} + +/** + * ufshcd_dwc_program_clk_div() - program clock divider. + * @hba: Private Structure pointer + * @divider_val: clock divider value to be programmed + * + */ +static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) +{ + ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV); +} + +/** + * ufshcd_dwc_link_is_up() - check if link is up. + * @hba: private structure pointer + * + * Return: 0 on success, non-zero value on failure. + */ +static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) +{ + int dme_result = 0; + + ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result); + + if (dme_result == UFSHCD_LINK_IS_UP) + return 0; + + return 1; +} + +/** + * ufshcd_dwc_connection_setup() - configure unipro attributes. + * @hba: pointer to drivers private data + * + * This function configures both the local side (host) and the peer side + * (device) unipro attributes to establish the connection to application/ + * cport. + * This function is not required if the hardware is properly configured to + * have this connection setup on reset. But invoking this function does no + * harm and should be fine even working with any ufs device. + * + * Return: 0 on success non-zero value on failure. + */ +static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) +{ + static const struct ufshcd_dme_attr_val setup_attrs[] = { + { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL }, + { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_LOCAL }, + { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_LOCAL }, + { UIC_ARG_MIB(T_CPORTMODE), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_LOCAL }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_PEER }, + { UIC_ARG_MIB(N_DEVICEID), 1, DME_PEER }, + { UIC_ARG_MIB(N_DEVICEID_VALID), 1, DME_PEER }, + { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_PEER }, + { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_PEER }, + { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_PEER }, + { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_PEER }, + { UIC_ARG_MIB(T_CPORTMODE), 1, DME_PEER }, + { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_PEER } + }; + return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, ARRAY_SIZE(setup_attrs)); +} + +/** + * ufshcd_dwc_link_startup_notify() - program clock divider. + * @hba: private structure pointer + * @status: Callback notify status + * + * Return: 0 on success, non-zero value on failure. + */ +int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + int err = 0; + + if (status == PRE_CHANGE) { + ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125); + } else { /* POST_CHANGE */ + err = ufshcd_dwc_link_is_up(hba); + if (err) { + dev_err(hba->dev, "Link is not up\n"); + return err; + } + + err = ufshcd_dwc_connection_setup(hba); + if (err) + dev_err(hba->dev, "Connection setup failed (%d)\n", + err); + } + + return err; +} diff --git a/drivers/ufs/ufshcd-dwc.h b/drivers/ufs/ufshcd-dwc.h new file mode 100644 index 00000000000..fc1bcca8ccb --- /dev/null +++ b/drivers/ufs/ufshcd-dwc.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto <jpinto@synopsys.com> + */ + +#ifndef _UFSHCD_DWC_H +#define _UFSHCD_DWC_H + +/* PHY modes */ +#define UFSHCD_DWC_PHY_MODE_ROM 0 + +/* RMMI Attributes */ +#define CBREFCLKCTRL2 0x8132 +#define CBCRCTRL 0x811F +#define CBC10DIRECTCONF2 0x810E +#define CBCREGADDRLSB 0x8116 +#define CBCREGADDRMSB 0x8117 +#define CBCREGWRLSB 0x8118 +#define CBCREGWRMSB 0x8119 +#define CBCREGRDLSB 0x811A +#define CBCREGRDMSB 0x811B +#define CBCREGRDWRSEL 0x811C + +#define CBREFREFCLK_GATE_OVR_EN BIT(7) + +/* M-PHY Attributes */ +#define MTX_FSM_STATE 0x41 +#define MRX_FSM_STATE 0xC1 + +/* M-PHY registers */ +#define FAST_FLAGS(n) (0x401C + ((n) * 0x100)) +#define RX_AFE_ATT_IDAC(n) (0x4000 + ((n) * 0x100)) +#define RX_AFE_CTLE_IDAC(n) (0x4001 + ((n) * 0x100)) +#define FW_CALIB_CCFG(n) (0x404D + ((n) * 0x100)) + +/* Tx/Rx FSM state */ +enum rx_fsm_state { + RX_STATE_DISABLED = 0, + RX_STATE_HIBERN8 = 1, + RX_STATE_SLEEP = 2, + RX_STATE_STALL = 3, + RX_STATE_LSBURST = 4, + RX_STATE_HSBURST = 5, +}; + +enum tx_fsm_state { + TX_STATE_DISABLED = 0, + TX_STATE_HIBERN8 = 1, + TX_STATE_SLEEP = 2, + TX_STATE_STALL = 3, + TX_STATE_LSBURST = 4, + TX_STATE_HSBURST = 5, +}; + +struct ufshcd_dme_attr_val { + u32 attr_sel; + u32 mib_val; + u8 peer; +}; + +int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status); +int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, + const struct ufshcd_dme_attr_val *v, int n); +#endif /* End of Header */ diff --git a/drivers/ufs/ufshci-dwc.h b/drivers/ufs/ufshci-dwc.h new file mode 100644 index 00000000000..9e24c230c64 --- /dev/null +++ b/drivers/ufs/ufshci-dwc.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * UFS Host driver for Synopsys Designware Core + * + * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) + * + * Authors: Joao Pinto <jpinto@synopsys.com> + */ + +#ifndef _UFSHCI_DWC_H +#define _UFSHCI_DWC_H + +/* DWC HC UFSHCI specific Registers */ +enum dwc_specific_registers { + DWC_UFS_REG_HCLKDIV = 0xFC, +}; + +/* Clock Divider Values: Hex equivalent of frequency in MHz */ +enum clk_div_values { + DWC_UFS_REG_HCLKDIV_DIV_62_5 = 0x3e, + DWC_UFS_REG_HCLKDIV_DIV_125 = 0x7d, + DWC_UFS_REG_HCLKDIV_DIV_200 = 0xc8, +}; + +/* Selector Index */ +enum selector_index { + SELIND_LN0_TX = 0x00, + SELIND_LN1_TX = 0x01, + SELIND_LN0_RX = 0x04, + SELIND_LN1_RX = 0x05, +}; +#endif diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h index b30b17fa5ad..6df953e6e60 100644 --- a/drivers/ufs/unipro.h +++ b/drivers/ufs/unipro.h @@ -140,6 +140,12 @@ #define PA_SLEEPNOCONFIGTIME 0x15A2 #define PA_STALLNOCONFIGTIME 0x15A3 #define PA_SAVECONFIGTIME 0x15A4 +#define PA_TXHSADAPTTYPE 0x15D4 + +/* Adapt type for PA_TXHSADAPTTYPE attribute */ +#define PA_REFRESH_ADAPT 0x00 +#define PA_INITIAL_ADAPT 0x01 +#define PA_NO_ADAPT 0x03 #define PA_TACTIVATE_TIME_UNIT_US 10 #define PA_HIBERN8_TIME_UNIT_US 100 @@ -148,6 +154,7 @@ #define VS_MPHYCFGUPDT 0xD085 #define VS_DEBUGOMC 0xD09E #define VS_POWERSTATE 0xD083 +#define VS_MPHYDISABLE 0xD0C1 #define PA_GRANULARITY_MIN_VAL 1 #define PA_GRANULARITY_MAX_VAL 6 diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 311aaa7e67f..960b6a906ac 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -85,6 +85,8 @@ source "drivers/usb/emul/Kconfig" source "drivers/usb/phy/Kconfig" +source "drivers/usb/tcpm/Kconfig" + source "drivers/usb/ulpi/Kconfig" if USB_HOST diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile index 18d7190755d..d6047856091 100644 --- a/drivers/usb/cdns3/Makefile +++ b/drivers/usb/cdns3/Makefile @@ -4,8 +4,8 @@ cdns3-y := core.o drd.o obj-$(CONFIG_USB_CDNS3) += cdns3.o -cdns3-$(CONFIG_$(SPL_)USB_CDNS3_GADGET) += gadget.o ep0.o +cdns3-$(CONFIG_$(XPL_)USB_CDNS3_GADGET) += gadget.o ep0.o -cdns3-$(CONFIG_$(SPL_)USB_CDNS3_HOST) += host.o +cdns3-$(CONFIG_$(XPL_)USB_CDNS3_HOST) += host.o obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index cbe06a9e7b6..4cfd38ec245 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -149,7 +149,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns) dr_mode = best_dr_mode; -#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_XPL_BUILD) if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { ret = cdns3_host_init(cdns); if (ret) { @@ -412,7 +412,7 @@ int cdns3_bind(struct udevice *parent) switch (dr_mode) { #if defined(CONFIG_SPL_USB_HOST) || \ - (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) + (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST)) case USB_DR_MODE_HOST: debug("%s: dr_mode: HOST\n", __func__); driver = "cdns-usb3-host"; @@ -498,7 +498,7 @@ int dm_usb_gadget_handle_interrupts(struct udevice *dev) #endif #if defined(CONFIG_SPL_USB_HOST) || \ - (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) + (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST)) static int cdns3_host_probe(struct udevice *dev) { struct cdns3_host_priv *priv = dev_get_priv(dev); diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index ac7e469469a..a30c40ef80e 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1637,6 +1637,14 @@ void cdns3_ep_config(struct cdns3_endpoint *priv_ep) else priv_ep->trb_burst_size = 16; + /* + * The Endpoint is configured to handle a maximum packet size of + * max_packet_size. Hence, set priv_ep->endpoint.maxpacket to + * max_packet_size. This is necessary to ensure that the TD_SIZE + * is calculated correctly in cdns3_ep_run_transfer(). + */ + priv_ep->endpoint.maxpacket = max_packet_size; + ret = cdns3_ep_onchip_buffer_reserve(priv_dev, buffering + 1, !!priv_ep->dir); if (ret) { diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile index 2e9353b76a6..11cc4657a0f 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -3,7 +3,7 @@ # (C) Copyright 2016 Freescale Semiconductor, Inc. # -obj-$(CONFIG_$(SPL_)DM_USB) += common.o +obj-$(CONFIG_$(XPL_)DM_USB) += common.o obj-$(CONFIG_USB_ISP1760) += usb_urb.o obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index a46b6824ab7..a085c9d4628 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -6,11 +6,11 @@ dwc3-y := core.o obj-$(CONFIG_USB_DWC3_GADGET) += gadget.o ep0.o -obj-$(CONFIG_$(SPL_)USB_DWC3_AM62) += dwc3-am62.o +obj-$(CONFIG_$(XPL_)USB_DWC3_AM62) += dwc3-am62.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o obj-$(CONFIG_USB_DWC3_MESON_GXL) += dwc3-meson-gxl.o -obj-$(CONFIG_$(SPL_)USB_DWC3_GENERIC) += dwc3-generic.o +obj-$(CONFIG_$(XPL_)USB_DWC3_GENERIC) += dwc3-generic.o obj-$(CONFIG_USB_DWC3_UNIPHIER) += dwc3-uniphier.o obj-$(CONFIG_USB_DWC3_LAYERSCAPE) += dwc3-layerscape.o obj-$(CONFIG_USB_DWC3_PHY_OMAP) += ti_usb_phy.o diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7374ce950da..b572ea340c8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -670,6 +670,7 @@ struct dwc3_scratchpad_array { * @ep0_trb: dma address of ep0_trb * @ep0_usb_req: dummy req used while handling STD USB requests * @ep0_bounce_addr: dma address of ep0_bounce + * @setup_buf_addr: dma address of setup_buf * @scratch_addr: dma address of scratchbuf * @lock: for synchronizing * @dev: pointer to our struct device @@ -757,6 +758,7 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; + dma_addr_t setup_buf_addr; struct dwc3_request ep0_usb_req; /* device lock */ diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index a9ba315463c..2ab41cbae45 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -246,12 +246,12 @@ static int dwc3_generic_host_probe(struct udevice *dev) return rc; rc = device_get_supply_regulator(dev, "vbus-supply", &priv->vbus_supply); - if (rc) + if (rc && rc != -ENOSYS) debug("%s: No vbus regulator found: %d\n", dev->name, rc); - /* Only returns an error if regulator is valid and failed to enable due to a driver issue */ + /* Does not return an error if regulator is invalid - but does so when DM_REGULATOR is disabled */ rc = regulator_set_enable_if_allowed(priv->vbus_supply, true); - if (rc) + if (rc && rc != -ENOSYS) return rc; hccr = (struct xhci_hccr *)priv->gen_priv.base; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 24f516a131b..531f0b522af 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -380,7 +380,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = sizeof(*response_pkt); - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); @@ -662,7 +662,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dep = dwc->eps[0]; dwc->ep0_usb_req.dep = dep; dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; - dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.buf = (void *)dwc->setup_buf_addr; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); @@ -742,6 +742,8 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, if (!dwc->gadget_driver) goto out; + dwc3_invalidate_cache((uintptr_t)ctrl, sizeof(*ctrl)); + len = le16_to_cpu(ctrl->wLength); if (!len) { dwc->three_stage_setup = false; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fe33e307d3e..e5a383407a2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2534,6 +2534,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) while (left > 0) { union dwc3_event event; + dwc3_invalidate_cache((uintptr_t)evt->buf, evt->length); + event.raw = *(u32 *) (evt->buf + evt->lpos); dwc3_process_event_entry(dwc, &event); @@ -2653,8 +2655,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, - DWC3_EP0_BOUNCE_SIZE); + dwc->setup_buf = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE, + (unsigned long *)&dwc->setup_buf_addr); if (!dwc->setup_buf) { ret = -ENOMEM; goto err2; @@ -2701,7 +2703,7 @@ err4: dma_free_coherent(dwc->ep0_bounce); err3: - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); err2: dma_free_coherent(dwc->ep0_trb); @@ -2723,7 +2725,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->ep0_bounce); - kfree(dwc->setup_buf); + dma_free_coherent(dwc->setup_buf); dma_free_coherent(dwc->ep0_trb); diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 04791d4c9be..c1ab0288142 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -50,6 +50,17 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) static inline void dwc3_flush_cache(uintptr_t addr, int length) { - flush_dcache_range(addr, addr + ROUND(length, CACHELINE_SIZE)); + uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE); + + flush_dcache_range((unsigned long)start_addr, (unsigned long)end_addr); +} + +static inline void dwc3_invalidate_cache(uintptr_t addr, int length) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(CACHELINE_SIZE - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + length, CACHELINE_SIZE); + + invalidate_dcache_range((unsigned long)start_addr, (unsigned long)end_addr); } #endif /* __DRIVERS_USB_DWC3_IO_H */ diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index f20a16e3e7d..010084ef7f3 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -114,6 +114,15 @@ config USB_GADGET_DWC2_OTG driver to operate in Peripheral mode. This option requires USB_GADGET to be enabled. +config USB_RENESAS_USBHS + bool "Renesas RCar USB2.0 HS controller (gadget mode)" + select USB_GADGET_DUALSPEED + help + The Renesas Rcar USB 2.0 high-speed gadget controller + integrated into Salvator and Kingfisher boards. Select this + option if you want the driver to operate in Peripheral mode. + This option requires USB_GADGET to be enabled. + if USB_GADGET_DWC2_OTG config USB_GADGET_DWC2_OTG_PHY @@ -224,7 +233,7 @@ endif # USB_GADGET_DOWNLOAD config USB_ETHER bool "USB Ethernet Gadget" - depends on NET + depends on NET || NET_LWIP default y if ARCH_SUNXI && USB_MUSB_GADGET help Creates an Ethernet network device through a USB peripheral diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 6abcce0d9c7..4bda224ff1a 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,11 +3,11 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-$(CONFIG_$(SPL_TPL_)USB_GADGET) += epautoconf.o config.o usbstring.o -obj-$(CONFIG_$(SPL_TPL_)USB_ETHER) += epautoconf.o config.o usbstring.o ether.o -obj-$(CONFIG_$(SPL_TPL_)USB_ETH_RNDIS) += rndis.o +obj-$(CONFIG_$(PHASE_)USB_GADGET) += epautoconf.o config.o usbstring.o +obj-$(CONFIG_$(PHASE_)USB_ETHER) += epautoconf.o config.o usbstring.o ether.o +obj-$(CONFIG_$(PHASE_)USB_ETH_RNDIS) += rndis.o -ifdef CONFIG_SPL_BUILD +ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_USB_GADGET) += g_dnl.o obj-$(CONFIG_SPL_DFU) += f_dfu.o obj-$(CONFIG_SPL_USB_SDP_SUPPORT) += f_sdp.o @@ -21,7 +21,8 @@ obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o -ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_USB_RENESAS_USBHS) += rcar/ +ifndef CONFIG_XPL_BUILD obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_DFU_OVER_USB) += f_dfu.o diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 5d62eb475d0..36934b1bcf7 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -411,7 +411,7 @@ static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request *req) return; } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD env_set_hex("filesize", sdp->dnl_bytes); #endif printf("done\n"); @@ -736,7 +736,7 @@ static u32 sdp_jump_imxheader(void *address) return 0; } -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD static ulong sdp_load_read(struct spl_load_info *load, ulong sector, ulong count, void *buf) { @@ -825,7 +825,7 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image, /* If imx header fails, try some U-Boot specific headers */ if (status) { -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) sdp_func->jmp_address = (u32)search_container_header((ulong)sdp_func->jmp_address, sdp_func->dnl_bytes); else if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) @@ -907,7 +907,7 @@ static void sdp_handle_out_ep(void) } } -#ifndef CONFIG_SPL_BUILD +#ifndef CONFIG_XPL_BUILD int sdp_handle(struct udevice *udc) #else int spl_sdp_handle(struct udevice *udc, struct spl_image_info *spl_image, @@ -928,7 +928,7 @@ int spl_sdp_handle(struct udevice *udc, struct spl_image_info *spl_image, schedule(); dm_usb_gadget_handle_interrupts(udc); -#ifdef CONFIG_SPL_BUILD +#ifdef CONFIG_XPL_BUILD flag = sdp_handle_in_ep(spl_image, bootdev); #else flag = sdp_handle_in_ep(NULL, NULL); diff --git a/drivers/usb/gadget/rcar/Makefile b/drivers/usb/gadget/rcar/Makefile new file mode 100644 index 00000000000..676f39c8e24 --- /dev/null +++ b/drivers/usb/gadget/rcar/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_USB_RENESAS_USBHS) += \ + common.o \ + fifo.o \ + mod.o \ + mod_gadget.o \ + pipe.o diff --git a/drivers/usb/gadget/rcar/common.c b/drivers/usb/gadget/rcar/common.c new file mode 100644 index 00000000000..2ba022a3f2c --- /dev/null +++ b/drivers/usb/gadget/rcar/common.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <generic-phy.h> +#include <linux/err.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <usb.h> + +#include "common.h" + +/* + * image of renesas_usbhs + * + * ex) gadget case + + * mod.c + * mod_gadget.c + * mod_host.c pipe.c fifo.c + * + * +-------+ +-----------+ + * | pipe0 |------>| fifo pio | + * +------------+ +-------+ +-----------+ + * | mod_gadget |=====> | pipe1 |--+ + * +------------+ +-------+ | +-----------+ + * | pipe2 | | +-| fifo dma0 | + * +------------+ +-------+ | | +-----------+ + * | mod_host | | pipe3 |<-|--+ + * +------------+ +-------+ | +-----------+ + * | .... | +--->| fifo dma1 | + * | .... | +-----------+ + */ + +/* + * common functions + */ +u16 usbhs_read(struct usbhs_priv *priv, u32 reg) +{ + return ioread16(priv->base + reg); +} + +void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data) +{ + iowrite16(data, priv->base + reg); +} + +void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data) +{ + u16 val = usbhs_read(priv, reg); + + val &= ~mask; + val |= data & mask; + + usbhs_write(priv, reg, val); +} + +/* + * syscfg functions + */ +static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) +{ + usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0); +} + +void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) +{ + u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; + u16 val = DCFM | DRPD | HSE | USBE; + + /* + * if enable + * + * - select Host mode + * - D+ Line/D- Line Pull-down + */ + usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); +} + +void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) +{ + u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; + u16 val = HSE | USBE; + + /* + * if enable + * + * - select Function mode + * - D+ Line Pull-up is disabled + * When D+ Line Pull-up is enabled, + * calling usbhs_sys_function_pullup(,1) + */ + usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); +} + +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable) +{ + usbhs_bset(priv, SYSCFG, DPRPU, enable ? DPRPU : 0); +} + +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) +{ + usbhs_write(priv, TESTMODE, mode); +} + +/* + * frame functions + */ +int usbhs_frame_get_num(struct usbhs_priv *priv) +{ + return usbhs_read(priv, FRMNUM) & FRNM_MASK; +} + +/* + * usb request functions + */ +void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) +{ + u16 val; + + val = usbhs_read(priv, USBREQ); + req->bRequest = (val >> 8) & 0xFF; + req->bRequestType = (val >> 0) & 0xFF; + + req->wValue = cpu_to_le16(usbhs_read(priv, USBVAL)); + req->wIndex = cpu_to_le16(usbhs_read(priv, USBINDX)); + req->wLength = cpu_to_le16(usbhs_read(priv, USBLENG)); +} + +void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) +{ + usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); + usbhs_write(priv, USBVAL, le16_to_cpu(req->wValue)); + usbhs_write(priv, USBINDX, le16_to_cpu(req->wIndex)); + usbhs_write(priv, USBLENG, le16_to_cpu(req->wLength)); + + usbhs_bset(priv, DCPCTR, SUREQ, SUREQ); +} + +/* + * bus/vbus functions + */ +void usbhs_bus_send_sof_enable(struct usbhs_priv *priv) +{ + u16 status = usbhs_read(priv, DVSTCTR) & (USBRST | UACT); + + if (status != USBRST) { + struct device *dev = usbhs_priv_to_dev(priv); + dev_err(dev, "usbhs should be reset\n"); + } + + usbhs_bset(priv, DVSTCTR, (USBRST | UACT), UACT); +} + +void usbhs_bus_send_reset(struct usbhs_priv *priv) +{ + usbhs_bset(priv, DVSTCTR, (USBRST | UACT), USBRST); +} + +int usbhs_bus_get_speed(struct usbhs_priv *priv) +{ + u16 dvstctr = usbhs_read(priv, DVSTCTR); + + switch (RHST & dvstctr) { + case RHST_LOW_SPEED: + return USB_SPEED_LOW; + case RHST_FULL_SPEED: + return USB_SPEED_FULL; + case RHST_HIGH_SPEED: + return USB_SPEED_HIGH; + } + + return USB_SPEED_UNKNOWN; +} + +static void usbhsc_bus_init(struct usbhs_priv *priv) +{ + usbhs_write(priv, DVSTCTR, 0); +} + +/* + * device configuration + */ +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, + u16 upphub, u16 hubport, u16 speed) +{ + struct device *dev = usbhs_priv_to_dev(priv); + u16 usbspd = 0; + u32 reg = DEVADD0 + (2 * devnum); + + if (devnum > 10) { + dev_err(dev, "cannot set speed to unknown device %d\n", devnum); + return -EIO; + } + + if (upphub > 0xA) { + dev_err(dev, "unsupported hub number %d\n", upphub); + return -EIO; + } + + switch (speed) { + case USB_SPEED_LOW: + usbspd = USBSPD_SPEED_LOW; + break; + case USB_SPEED_FULL: + usbspd = USBSPD_SPEED_FULL; + break; + case USB_SPEED_HIGH: + usbspd = USBSPD_SPEED_HIGH; + break; + default: + dev_err(dev, "unsupported speed %d\n", speed); + return -EIO; + } + + usbhs_write(priv, reg, UPPHUB(upphub) | + HUBPORT(hubport)| + USBSPD(usbspd)); + + return 0; +} + +/* + * interrupt functions + */ +void usbhs_xxxsts_clear(struct usbhs_priv *priv, u16 sts_reg, u16 bit) +{ + u16 pipe_mask = (u16)GENMASK(usbhs_get_dparam(priv, pipe_size), 0); + + usbhs_write(priv, sts_reg, ~(1 << bit) & pipe_mask); +} + +/* + * local functions + */ +static void usbhsc_set_buswait(struct usbhs_priv *priv) +{ + int wait = usbhs_get_dparam(priv, buswait_bwait); + + /* set bus wait if platform have */ + if (wait) + usbhs_bset(priv, BUSWAIT, 0x000F, wait); +} + +/* + * platform default param + */ + +/* commonly used on newer SH-Mobile and R-Car SoCs */ +static struct renesas_usbhs_driver_pipe_config usbhsc_new_pipe[] = { + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_CONTROL, 64, 0x00, false), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x08, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_ISOC, 1024, 0x28, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x48, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x58, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x68, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x04, false), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x05, false), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_INT, 64, 0x06, false), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x78, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x88, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0x98, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xa8, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xb8, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xc8, true), + RENESAS_USBHS_PIPE(USB_ENDPOINT_XFER_BULK, 512, 0xd8, true), +}; + +#define LPSTS 0x102 +#define LPSTS_SUSPM BIT(14) + +#define UGCTRL2 0x184 +#define UGCTRL2_RESERVED_3 BIT(0) +#define UGCTRL2_USB0SEL_EHCI 0x10 +#define UGCTRL2_USB0SEL_HSUSB 0x20 +#define UGCTRL2_USB0SEL_OTG 0x30 +#define UGCTRL2_USB0SEL_MASK 0x30 +#define UGCTRL2_VBUSSEL BIT(10) + +struct usbhs_priv_otg_data { + void __iomem *base; + void __iomem *phybase; + + struct platform_device usbhs_dev; + struct usbhs_priv usbhs_priv; + + struct phy phy; +}; + +static int usbhs_rcar3_power_ctrl(struct usbhs_priv *priv, bool enable) +{ + if (enable) { + writel(UGCTRL2_USB0SEL_OTG | UGCTRL2_VBUSSEL | UGCTRL2_RESERVED_3, + priv->base + UGCTRL2); + + usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); + /* The controller on R-Car Gen3 needs to wait up to 90 usec */ + udelay(90); + + usbhs_sys_clock_ctrl(priv, enable); + } else { + usbhs_sys_clock_ctrl(priv, enable); + + usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0); + } + + return 0; +} + +void usbhsc_hotplug(struct usbhs_priv *priv) +{ + int ret; + + ret = usbhs_mod_change(priv, USBHS_GADGET); + if (ret < 0) + return; + + usbhs_rcar3_power_ctrl(priv, true); + + /* bus init */ + usbhsc_set_buswait(priv); + usbhsc_bus_init(priv); + + /* module start */ + usbhs_mod_call(priv, start, priv); +} + +#define USB2_OBINTSTA 0x604 +#define USB2_OBINT_SESSVLDCHG BIT(12) +#define USB2_OBINT_IDDIGCHG BIT(11) + +static int usbhs_udc_otg_gadget_handle_interrupts(struct udevice *dev) +{ + struct usbhs_priv_otg_data *priv = dev_get_priv(dev); + const u32 status = readl(priv->phybase + USB2_OBINTSTA); + + /* We don't have a good way to forward IRQ to PHY yet */ + if (status & (USB2_OBINT_SESSVLDCHG | USB2_OBINT_IDDIGCHG)) { + writel(USB2_OBINT_SESSVLDCHG | USB2_OBINT_IDDIGCHG, + priv->phybase + USB2_OBINTSTA); + generic_phy_set_mode(&priv->phy, PHY_MODE_USB_OTG, 0); + } + + usbhs_interrupt(0, &priv->usbhs_priv); + + return 0; +} + +static int usbhs_probe(struct usbhs_priv *priv) +{ + int ret; + + priv->dparam.type = USBHS_TYPE_RCAR_GEN3; + priv->dparam.pio_dma_border = 64; + priv->dparam.pipe_configs = usbhsc_new_pipe; + priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe); + + /* call pipe and module init */ + ret = usbhs_pipe_probe(priv); + if (ret < 0) + return ret; + + ret = usbhs_fifo_probe(priv); + if (ret < 0) + goto probe_end_pipe_exit; + + ret = usbhs_mod_probe(priv); + if (ret < 0) + goto probe_end_fifo_exit; + + usbhs_sys_clock_ctrl(priv, 0); + + usbhs_rcar3_power_ctrl(priv, true); + usbhs_mod_autonomy_mode(priv); + usbhsc_hotplug(priv); + + return ret; + +probe_end_fifo_exit: + usbhs_fifo_remove(priv); +probe_end_pipe_exit: + usbhs_pipe_remove(priv); + return ret; +} + +static int usbhs_udc_otg_probe(struct udevice *dev) +{ + struct usbhs_priv_otg_data *priv = dev_get_priv(dev); + struct usb_gadget *gadget; + struct clk_bulk clk_bulk; + int ret = -EINVAL; + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_bulk(dev, &clk_bulk); + if (ret) + return ret; + + ret = clk_enable_bulk(&clk_bulk); + if (ret) + return ret; + + clrsetbits_le32(priv->base + UGCTRL2, UGCTRL2_USB0SEL_MASK, UGCTRL2_USB0SEL_EHCI); + clrsetbits_le16(priv->base + LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); + + ret = generic_setup_phy(dev, &priv->phy, 0, PHY_MODE_USB_OTG, 1); + if (ret) + goto err_clk; + + priv->phybase = dev_read_addr_ptr(priv->phy.dev); + + priv->usbhs_priv.pdev = &priv->usbhs_dev; + priv->usbhs_priv.base = priv->base; + priv->usbhs_dev.dev.driver_data = &priv->usbhs_priv; + ret = usbhs_probe(&priv->usbhs_priv); + if (ret < 0) + goto err_phy; + + gadget = usbhsg_get_gadget(&priv->usbhs_priv); + gadget->is_dualspeed = 1; + gadget->is_otg = 0; + gadget->is_a_peripheral = 0; + gadget->b_hnp_enable = 0; + gadget->a_hnp_support = 0; + gadget->a_alt_hnp_support = 0; + + return usb_add_gadget_udc((struct device *)dev, gadget); + +err_phy: + generic_shutdown_phy(&priv->phy); +err_clk: + clk_disable_bulk(&clk_bulk); + return ret; +} + +static int usbhs_udc_otg_remove(struct udevice *dev) +{ + struct usbhs_priv_otg_data *priv = dev_get_priv(dev); + + usbhs_rcar3_power_ctrl(&priv->usbhs_priv, false); + usbhs_mod_remove(&priv->usbhs_priv); + usbhs_fifo_remove(&priv->usbhs_priv); + usbhs_pipe_remove(&priv->usbhs_priv); + + generic_shutdown_phy(&priv->phy); + + return dm_scan_fdt_dev(dev); +} + +static const struct udevice_id usbhs_udc_otg_ids[] = { + { .compatible = "renesas,rcar-gen3-usbhs" }, + {}, +}; + +static const struct usb_gadget_generic_ops usbhs_udc_otg_ops = { + .handle_interrupts = usbhs_udc_otg_gadget_handle_interrupts, +}; + +U_BOOT_DRIVER(usbhs_udc_otg) = { + .name = "usbhs-udc-otg", + .id = UCLASS_USB_GADGET_GENERIC, + .ops = &usbhs_udc_otg_ops, + .of_match = usbhs_udc_otg_ids, + .probe = usbhs_udc_otg_probe, + .remove = usbhs_udc_otg_remove, + .priv_auto = sizeof(struct usbhs_priv_otg_data), +}; diff --git a/drivers/usb/gadget/rcar/common.h b/drivers/usb/gadget/rcar/common.h new file mode 100644 index 00000000000..544cfd77cdf --- /dev/null +++ b/drivers/usb/gadget/rcar/common.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#ifndef RENESAS_USB_DRIVER_H +#define RENESAS_USB_DRIVER_H + +#include <dm/device.h> +#include <dm/device_compat.h> +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/io.h> +#include "renesas_usb.h" + +struct usbhs_priv; + +#include "mod.h" +#include "pipe.h" + +/* + * + * register define + * + */ +#define SYSCFG 0x0000 +#define BUSWAIT 0x0002 +#define DVSTCTR 0x0008 +#define TESTMODE 0x000C +#define CFIFO 0x0014 +#define CFIFOSEL 0x0020 +#define CFIFOCTR 0x0022 +#define D0FIFO 0x0100 +#define D0FIFOSEL 0x0028 +#define D0FIFOCTR 0x002A +#define D1FIFO 0x0120 +#define D1FIFOSEL 0x002C +#define D1FIFOCTR 0x002E +#define INTENB0 0x0030 +#define INTENB1 0x0032 +#define BRDYENB 0x0036 +#define NRDYENB 0x0038 +#define BEMPENB 0x003A +#define INTSTS0 0x0040 +#define INTSTS1 0x0042 +#define BRDYSTS 0x0046 +#define NRDYSTS 0x0048 +#define BEMPSTS 0x004A +#define FRMNUM 0x004C +#define USBREQ 0x0054 /* USB request type register */ +#define USBVAL 0x0056 /* USB request value register */ +#define USBINDX 0x0058 /* USB request index register */ +#define USBLENG 0x005A /* USB request length register */ +#define DCPCFG 0x005C +#define DCPMAXP 0x005E +#define DCPCTR 0x0060 +#define PIPESEL 0x0064 +#define PIPECFG 0x0068 +#define PIPEBUF 0x006A +#define PIPEMAXP 0x006C +#define PIPEPERI 0x006E +#define PIPEnCTR 0x0070 +#define PIPE1TRE 0x0090 +#define PIPE1TRN 0x0092 +#define PIPE2TRE 0x0094 +#define PIPE2TRN 0x0096 +#define PIPE3TRE 0x0098 +#define PIPE3TRN 0x009A +#define PIPE4TRE 0x009C +#define PIPE4TRN 0x009E +#define PIPE5TRE 0x00A0 +#define PIPE5TRN 0x00A2 +#define PIPEBTRE 0x00A4 +#define PIPEBTRN 0x00A6 +#define PIPECTRE 0x00A8 +#define PIPECTRN 0x00AA +#define PIPEDTRE 0x00AC +#define PIPEDTRN 0x00AE +#define PIPEETRE 0x00B0 +#define PIPEETRN 0x00B2 +#define PIPEFTRE 0x00B4 +#define PIPEFTRN 0x00B6 +#define PIPE9TRE 0x00B8 +#define PIPE9TRN 0x00BA +#define PIPEATRE 0x00BC +#define PIPEATRN 0x00BE +#define DEVADD0 0x00D0 /* Device address n configuration */ +#define DEVADD1 0x00D2 +#define DEVADD2 0x00D4 +#define DEVADD3 0x00D6 +#define DEVADD4 0x00D8 +#define DEVADD5 0x00DA +#define DEVADD6 0x00DC +#define DEVADD7 0x00DE +#define DEVADD8 0x00E0 +#define DEVADD9 0x00E2 +#define DEVADDA 0x00E4 +#define D2FIFOSEL 0x00F0 /* for R-Car Gen2 */ +#define D2FIFOCTR 0x00F2 /* for R-Car Gen2 */ +#define D3FIFOSEL 0x00F4 /* for R-Car Gen2 */ +#define D3FIFOCTR 0x00F6 /* for R-Car Gen2 */ +#define SUSPMODE 0x0102 /* for RZ/A */ + +/* SYSCFG */ +#define SCKE (1 << 10) /* USB Module Clock Enable */ +#define CNEN (1 << 8) /* Single-ended receiver operation Enable */ +#define HSE (1 << 7) /* High-Speed Operation Enable */ +#define DCFM (1 << 6) /* Controller Function Select */ +#define DRPD (1 << 5) /* D+ Line/D- Line Resistance Control */ +#define DPRPU (1 << 4) /* D+ Line Resistance Control */ +#define USBE (1 << 0) /* USB Module Operation Enable */ +#define UCKSEL (1 << 2) /* Clock Select for RZ/A1 */ +#define UPLLE (1 << 1) /* USB PLL Enable for RZ/A1 */ + +/* DVSTCTR */ +#define EXTLP (1 << 10) /* Controls the EXTLP pin output state */ +#define PWEN (1 << 9) /* Controls the PWEN pin output state */ +#define USBRST (1 << 6) /* Bus Reset Output */ +#define UACT (1 << 4) /* USB Bus Enable */ +#define RHST (0x7) /* Reset Handshake */ +#define RHST_LOW_SPEED 1 /* Low-speed connection */ +#define RHST_FULL_SPEED 2 /* Full-speed connection */ +#define RHST_HIGH_SPEED 3 /* High-speed connection */ + +/* CFIFOSEL */ +#define DREQE (1 << 12) /* DMA Transfer Request Enable */ +#define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */ + +/* CFIFOCTR */ +#define BVAL (1 << 15) /* Buffer Memory Enable Flag */ +#define BCLR (1 << 14) /* CPU buffer clear */ +#define FRDY (1 << 13) /* FIFO Port Ready */ +#define DTLN_MASK (0x0FFF) /* Receive Data Length */ + +/* INTENB0 */ +#define VBSE (1 << 15) /* Enable IRQ VBUS_0 and VBUSIN_0 */ +#define RSME (1 << 14) /* Enable IRQ Resume */ +#define SOFE (1 << 13) /* Enable IRQ Frame Number Update */ +#define DVSE (1 << 12) /* Enable IRQ Device State Transition */ +#define CTRE (1 << 11) /* Enable IRQ Control Stage Transition */ +#define BEMPE (1 << 10) /* Enable IRQ Buffer Empty */ +#define NRDYE (1 << 9) /* Enable IRQ Buffer Not Ready Response */ +#define BRDYE (1 << 8) /* Enable IRQ Buffer Ready */ + +/* INTENB1 */ +#define BCHGE (1 << 14) /* USB Bus Change Interrupt Enable */ +#define DTCHE (1 << 12) /* Disconnection Detect Interrupt Enable */ +#define ATTCHE (1 << 11) /* Connection Detect Interrupt Enable */ +#define EOFERRE (1 << 6) /* EOF Error Detect Interrupt Enable */ +#define SIGNE (1 << 5) /* Setup Transaction Error Interrupt Enable */ +#define SACKE (1 << 4) /* Setup Transaction ACK Interrupt Enable */ + +/* INTSTS0 */ +#define VBINT (1 << 15) /* VBUS0_0 and VBUS1_0 Interrupt Status */ +#define DVST (1 << 12) /* Device State Transition Interrupt Status */ +#define CTRT (1 << 11) /* Control Stage Interrupt Status */ +#define BEMP (1 << 10) /* Buffer Empty Interrupt Status */ +#define BRDY (1 << 8) /* Buffer Ready Interrupt Status */ +#define VBSTS (1 << 7) /* VBUS_0 and VBUSIN_0 Input Status */ +#define VALID (1 << 3) /* USB Request Receive */ + +#define DVSQ_MASK (0x7 << 4) /* Device State */ +#define POWER_STATE (0 << 4) +#define DEFAULT_STATE (1 << 4) +#define ADDRESS_STATE (2 << 4) +#define CONFIGURATION_STATE (3 << 4) +#define SUSPENDED_STATE (4 << 4) + +#define CTSQ_MASK (0x7) /* Control Transfer Stage */ +#define IDLE_SETUP_STAGE 0 /* Idle stage or setup stage */ +#define READ_DATA_STAGE 1 /* Control read data stage */ +#define READ_STATUS_STAGE 2 /* Control read status stage */ +#define WRITE_DATA_STAGE 3 /* Control write data stage */ +#define WRITE_STATUS_STAGE 4 /* Control write status stage */ +#define NODATA_STATUS_STAGE 5 /* Control write NoData status stage */ +#define SEQUENCE_ERROR 6 /* Control transfer sequence error */ + +/* INTSTS1 */ +#define OVRCR (1 << 15) /* OVRCR Interrupt Status */ +#define BCHG (1 << 14) /* USB Bus Change Interrupt Status */ +#define DTCH (1 << 12) /* USB Disconnection Detect Interrupt Status */ +#define ATTCH (1 << 11) /* ATTCH Interrupt Status */ +#define EOFERR (1 << 6) /* EOF Error Detect Interrupt Status */ +#define SIGN (1 << 5) /* Setup Transaction Error Interrupt Status */ +#define SACK (1 << 4) /* Setup Transaction ACK Response Interrupt Status */ + +/* PIPECFG */ +/* DCPCFG */ +#define TYPE_NONE (0 << 14) /* Transfer Type */ +#define TYPE_BULK (1 << 14) +#define TYPE_INT (2 << 14) +#define TYPE_ISO (3 << 14) +#define BFRE (1 << 10) /* BRDY Interrupt Operation Spec. */ +#define DBLB (1 << 9) /* Double Buffer Mode */ +#define SHTNAK (1 << 7) /* Pipe Disable in Transfer End */ +#define DIR_OUT (1 << 4) /* Transfer Direction */ + +/* PIPEMAXP */ +/* DCPMAXP */ +#define DEVSEL_MASK (0xF << 12) /* Device Select */ +#define DCP_MAXP_MASK (0x7F) +#define PIPE_MAXP_MASK (0x7FF) + +/* PIPEBUF */ +#define BUFSIZE_SHIFT 10 +#define BUFSIZE_MASK (0x1F << BUFSIZE_SHIFT) +#define BUFNMB_MASK (0xFF) + +/* PIPEnCTR */ +/* DCPCTR */ +#define BSTS (1 << 15) /* Buffer Status */ +#define SUREQ (1 << 14) /* Sending SETUP Token */ +#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */ +#define CSSTS (1 << 12) /* CSSTS Status */ +#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ +#define SQCLR (1 << 8) /* Toggle Bit Clear */ +#define SQSET (1 << 7) /* Toggle Bit Set */ +#define SQMON (1 << 6) /* Toggle Bit Check */ +#define PBUSY (1 << 5) /* Pipe Busy */ +#define PID_MASK (0x3) /* Response PID */ +#define PID_NAK 0 +#define PID_BUF 1 +#define PID_STALL10 2 +#define PID_STALL11 3 + +#define CCPL (1 << 2) /* Control Transfer End Enable */ + +/* PIPEnTRE */ +#define TRENB (1 << 9) /* Transaction Counter Enable */ +#define TRCLR (1 << 8) /* Transaction Counter Clear */ + +/* FRMNUM */ +#define FRNM_MASK (0x7FF) + +/* DEVADDn */ +#define UPPHUB(x) (((x) & 0xF) << 11) /* HUB Register */ +#define HUBPORT(x) (((x) & 0x7) << 8) /* HUB Port for Target Device */ +#define USBSPD(x) (((x) & 0x3) << 6) /* Device Transfer Rate */ +#define USBSPD_SPEED_LOW 0x1 +#define USBSPD_SPEED_FULL 0x2 +#define USBSPD_SPEED_HIGH 0x3 + +/* SUSPMODE */ +#define SUSPM (1 << 14) /* SuspendM Control */ + +/* + * struct + */ +struct usbhs_priv { + void __iomem *base; + struct renesas_usbhs_driver_param dparam; + struct platform_device *pdev; + + /* + * module control + */ + struct usbhs_mod_info mod_info; + + /* + * pipe control + */ + struct usbhs_pipe_info pipe_info; + + /* + * fifo control + */ + struct usbhs_fifo_info fifo_info; +}; + +/* + * common + */ +u16 usbhs_read(struct usbhs_priv *priv, u32 reg); +void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data); +void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); + +#define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f) +#define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f) + +/* + * sysconfig + */ +void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +void usbhs_sys_function_pullup(struct usbhs_priv *priv, int enable); +void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode); + +/* + * usb request + */ +void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); +void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); + +/* + * bus + */ +void usbhs_bus_send_sof_enable(struct usbhs_priv *priv); +void usbhs_bus_send_reset(struct usbhs_priv *priv); +int usbhs_bus_get_speed(struct usbhs_priv *priv); +int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable); +void usbhsc_hotplug(struct usbhs_priv *priv); + +/* + * frame + */ +int usbhs_frame_get_num(struct usbhs_priv *priv); + +/* + * device config + */ +int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub, + u16 hubport, u16 speed); + +/* + * interrupt functions + */ +void usbhs_xxxsts_clear(struct usbhs_priv *priv, u16 sts_reg, u16 bit); + +/* + * data + */ +#define usbhs_get_dparam(priv, param) (priv->dparam.param) +#define usbhs_priv_to_dev(priv) (&priv->pdev->dev) + +#endif /* RENESAS_USB_DRIVER_H */ diff --git a/drivers/usb/gadget/rcar/fifo.c b/drivers/usb/gadget/rcar/fifo.c new file mode 100644 index 00000000000..6016b2987d5 --- /dev/null +++ b/drivers/usb/gadget/rcar/fifo.c @@ -0,0 +1,1067 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#include <linux/delay.h> +#include <linux/io.h> +#include "common.h" +#include "pipe.h" + +#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) + +#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ + +/* + * packet initialize + */ +void usbhs_pkt_init(struct usbhs_pkt *pkt) +{ + INIT_LIST_HEAD(&pkt->node); +} + +/* + * packet control function + */ +static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); + struct device *dev = usbhs_priv_to_dev(priv); + + dev_err(dev, "null handler\n"); + + return -EINVAL; +} + +static const struct usbhs_pkt_handle usbhsf_null_handler = { + .prepare = usbhsf_null_handle, + .try_run = usbhsf_null_handle, +}; + +void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, + void (*done)(struct usbhs_priv *priv, + struct usbhs_pkt *pkt), + void *buf, int len, int zero, int sequence) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + + if (!done) { + dev_err(dev, "no done function\n"); + return; + } + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + if (!pipe->handler) { + dev_err(dev, "no handler function\n"); + pipe->handler = &usbhsf_null_handler; + } + + list_move_tail(&pkt->node, &pipe->list); + + /* + * each pkt must hold own handler. + * because handler might be changed by its situation. + * dma handler -> pio handler. + */ + pkt->pipe = pipe; + pkt->buf = buf; + pkt->handler = pipe->handler; + pkt->length = len; + pkt->zero = zero; + pkt->actual = 0; + pkt->done = done; + pkt->sequence = sequence; + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ +} + +static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) +{ + list_del_init(&pkt->node); +} + +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) +{ + return list_first_entry_or_null(&pipe->list, struct usbhs_pkt, node); +} + +static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo); +static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, + struct usbhs_pkt *pkt); +#define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) +#define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) +static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map); +static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable); +static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable); +struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) +{ + struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); + unsigned long flags; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + usbhs_pipe_disable(pipe); + + if (!pkt) + pkt = __usbhsf_pkt_get(pipe); + + if (pkt) { + struct dma_chan *chan = NULL; + + if (fifo) + chan = usbhsf_dma_chan_get(fifo, pkt); + if (chan) + usbhsf_dma_unmap(pkt); + + usbhs_pipe_clear_without_sequence(pipe, 0, 0); + usbhs_pipe_running(pipe, 0); + + __usbhsf_pkt_del(pkt); + } + + if (fifo) + usbhsf_fifo_unselect(pipe, fifo); + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + return pkt; +} + +enum { + USBHSF_PKT_PREPARE, + USBHSF_PKT_TRY_RUN, + USBHSF_PKT_DMA_DONE, +}; + +static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_pkt *pkt; + struct device *dev = usbhs_priv_to_dev(priv); + int (*func)(struct usbhs_pkt *pkt, int *is_done); + unsigned long flags; + int ret = 0; + int is_done = 0; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + pkt = __usbhsf_pkt_get(pipe); + if (!pkt) { + ret = -EINVAL; + goto __usbhs_pkt_handler_end; + } + + switch (type) { + case USBHSF_PKT_PREPARE: + func = pkt->handler->prepare; + break; + case USBHSF_PKT_TRY_RUN: + func = pkt->handler->try_run; + break; + case USBHSF_PKT_DMA_DONE: + func = pkt->handler->dma_done; + break; + default: + dev_err(dev, "unknown pkt handler\n"); + goto __usbhs_pkt_handler_end; + } + + if (likely(func)) + ret = func(pkt, &is_done); + + if (is_done) + __usbhsf_pkt_del(pkt); + +__usbhs_pkt_handler_end: + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + if (is_done) { + pkt->done(priv, pkt); + usbhs_pkt_start(pipe); + } + + return ret; +} + +void usbhs_pkt_start(struct usbhs_pipe *pipe) +{ + usbhsf_pkt_handler(pipe, USBHSF_PKT_PREPARE); +} + +/* + * irq enable/disable function + */ +#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_bempsts, e) +#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, irq_brdysts, e) +#define usbhsf_irq_callback_ctrl(pipe, status, enable) \ + ({ \ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ + struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ + u16 status = (1 << usbhs_pipe_number(pipe)); \ + if (!mod) \ + return; \ + if (enable) \ + mod->status |= status; \ + else \ + mod->status &= ~status; \ + usbhs_irq_callback_update(priv, mod); \ + }) + +static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable) +{ + /* + * And DCP pipe can NOT use "ready interrupt" for "send" + * it should use "empty" interrupt. + * see + * "Operation" - "Interrupt Function" - "BRDY Interrupt" + * + * on the other hand, normal pipe can use "ready interrupt" for "send" + * even though it is single/double buffer + */ + if (usbhs_pipe_is_dcp(pipe)) + usbhsf_irq_empty_ctrl(pipe, enable); + else + usbhsf_irq_ready_ctrl(pipe, enable); +} + +static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable) +{ + usbhsf_irq_ready_ctrl(pipe, enable); +} + +/* + * FIFO ctrl + */ +static void usbhsf_send_terminator(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + usbhs_bset(priv, fifo->ctr, BVAL, BVAL); +} + +static int usbhsf_fifo_barrier(struct usbhs_priv *priv, + struct usbhs_fifo *fifo) +{ + /* The FIFO port is accessible */ + if (usbhs_read(priv, fifo->ctr) & FRDY) + return 0; + + return -EBUSY; +} + +static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + int ret = 0; + + if (!usbhs_pipe_is_dcp(pipe)) { + /* + * This driver checks the pipe condition first to avoid -EBUSY + * from usbhsf_fifo_barrier() if the pipe is RX direction and + * empty. + */ + if (usbhs_pipe_is_dir_in(pipe)) + ret = usbhs_pipe_is_accessible(pipe); + if (!ret) + ret = usbhsf_fifo_barrier(priv, fifo); + } + + /* + * if non-DCP pipe, this driver should set BCLR when + * usbhsf_fifo_barrier() returns 0. + */ + if (!ret) + usbhs_write(priv, fifo->ctr, BCLR); +} + +static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, + struct usbhs_fifo *fifo) +{ + return usbhs_read(priv, fifo->ctr) & DTLN_MASK; +} + +static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + usbhs_pipe_select_fifo(pipe, NULL); + usbhs_write(priv, fifo->sel, 0); +} + +static int usbhsf_fifo_select(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo, + int write) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int timeout = 1024; + u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ + u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ + + if (usbhs_pipe_is_busy(pipe) || + usbhsf_fifo_is_busy(fifo)) + return -EBUSY; + + if (usbhs_pipe_is_dcp(pipe)) { + base |= (1 == write) << 5; /* ISEL */ + + if (usbhs_mod_is_host(priv)) + usbhs_dcp_dir_for_host(pipe, write); + } + + /* "base" will be used below */ + usbhs_write(priv, fifo->sel, base | MBW_32); + + /* check ISEL and CURPIPE value */ + while (timeout--) { + if (base == (mask & usbhs_read(priv, fifo->sel))) { + usbhs_pipe_select_fifo(pipe, fifo); + return 0; + } + udelay(10); + } + + dev_err(dev, "fifo select error\n"); + + return -EIO; +} + +/* + * DCP status stage + */ +static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + struct device *dev = usbhs_priv_to_dev(priv); + int ret; + + usbhs_pipe_disable(pipe); + + ret = usbhsf_fifo_select(pipe, fifo, 1); + if (ret < 0) { + dev_err(dev, "%s() failed\n", __func__); + return ret; + } + + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ + + usbhsf_fifo_clear(pipe, fifo); + usbhsf_send_terminator(pipe, fifo); + + usbhsf_fifo_unselect(pipe, fifo); + + usbhsf_tx_irq_ctrl(pipe, 1); + usbhs_pipe_enable(pipe); + + return ret; +} + +static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + struct device *dev = usbhs_priv_to_dev(priv); + int ret; + + usbhs_pipe_disable(pipe); + + ret = usbhsf_fifo_select(pipe, fifo, 0); + if (ret < 0) { + dev_err(dev, "%s() fail\n", __func__); + return ret; + } + + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ + usbhsf_fifo_clear(pipe, fifo); + + usbhsf_fifo_unselect(pipe, fifo); + + usbhsf_rx_irq_ctrl(pipe, 1); + usbhs_pipe_enable(pipe); + + return ret; + +} + +static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + + if (pkt->handler == &usbhs_dcp_status_stage_in_handler) + usbhsf_tx_irq_ctrl(pipe, 0); + else + usbhsf_rx_irq_ctrl(pipe, 0); + + pkt->actual = pkt->length; + *is_done = 1; + + return 0; +} + +const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = { + .prepare = usbhs_dcp_dir_switch_to_write, + .try_run = usbhs_dcp_dir_switch_done, +}; + +const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = { + .prepare = usbhs_dcp_dir_switch_to_read, + .try_run = usbhs_dcp_dir_switch_done, +}; + +/* + * DCP data stage (push) + */ +static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ + + /* + * change handler to PIO push + */ + pkt->handler = &usbhs_fifo_pio_push_handler; + + return pkt->handler->prepare(pkt, is_done); +} + +const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = { + .prepare = usbhsf_dcp_data_stage_try_push, +}; + +/* + * DCP data stage (pop) + */ +static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt, + int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); + + if (usbhs_pipe_is_busy(pipe)) + return 0; + + /* + * prepare pop for DCP should + * - change DCP direction, + * - clear fifo + * - DATA1 + */ + usbhs_pipe_disable(pipe); + + usbhs_pipe_sequence_data1(pipe); /* DATA1 */ + + usbhsf_fifo_select(pipe, fifo, 0); + usbhsf_fifo_clear(pipe, fifo); + usbhsf_fifo_unselect(pipe, fifo); + + /* + * change handler to PIO pop + */ + pkt->handler = &usbhs_fifo_pio_pop_handler; + + return pkt->handler->prepare(pkt, is_done); +} + +const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = { + .prepare = usbhsf_dcp_data_stage_prepare_pop, +}; + +/* + * PIO push handler + */ +static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + void __iomem *addr = priv->base + fifo->port; + u8 *buf; + int maxp = usbhs_pipe_get_maxpacket(pipe); + int total_len; + int i, ret, len; + int is_short; + + usbhs_pipe_data_sequence(pipe, pkt->sequence); + pkt->sequence = -1; /* -1 sequence will be ignored */ + + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); + + ret = usbhsf_fifo_select(pipe, fifo, 1); + if (ret < 0) + return 0; + + ret = usbhs_pipe_is_accessible(pipe); + if (ret < 0) { + /* inaccessible pipe is not an error */ + ret = 0; + goto usbhs_fifo_write_busy; + } + + ret = usbhsf_fifo_barrier(priv, fifo); + if (ret < 0) + goto usbhs_fifo_write_busy; + + buf = pkt->buf + pkt->actual; + len = pkt->length - pkt->actual; + len = min(len, maxp); + total_len = len; + is_short = total_len < maxp; + + /* + * FIXME + * + * 32-bit access only + */ + if (len >= 4 && !((unsigned long)buf & 0x03)) { + iowrite32_rep(addr, buf, len / 4); + len %= 4; + buf += total_len - len; + } + + /* the rest operation */ + if (usbhs_get_dparam(priv, cfifo_byte_addr)) { + for (i = 0; i < len; i++) + iowrite8(buf[i], addr + (i & 0x03)); + } else { + for (i = 0; i < len; i++) + iowrite8(buf[i], addr + (0x03 - (i & 0x03))); + } + + /* + * variable update + */ + pkt->actual += total_len; + + if (pkt->actual < pkt->length) + *is_done = 0; /* there are remainder data */ + else if (is_short) + *is_done = 1; /* short packet */ + else + *is_done = !pkt->zero; /* send zero packet ? */ + + /* + * pipe/irq handling + */ + if (is_short) + usbhsf_send_terminator(pipe, fifo); + + usbhsf_tx_irq_ctrl(pipe, !*is_done); + usbhs_pipe_running(pipe, !*is_done); + usbhs_pipe_enable(pipe); + + dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", + usbhs_pipe_number(pipe), + pkt->length, pkt->actual, *is_done, pkt->zero); + + usbhsf_fifo_unselect(pipe, fifo); + + return 0; + +usbhs_fifo_write_busy: + usbhsf_fifo_unselect(pipe, fifo); + + /* + * pipe is busy. + * retry in interrupt + */ + usbhsf_tx_irq_ctrl(pipe, 1); + usbhs_pipe_running(pipe, 1); + + return ret; +} + +static int usbhsf_pio_prepare_push(struct usbhs_pkt *pkt, int *is_done) +{ + if (usbhs_pipe_is_running(pkt->pipe)) + return 0; + + return usbhsf_pio_try_push(pkt, is_done); +} + +const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { + .prepare = usbhsf_pio_prepare_push, + .try_run = usbhsf_pio_try_push, +}; + +/* + * PIO pop handler + */ +static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); + + if (usbhs_pipe_is_busy(pipe)) + return 0; + + if (usbhs_pipe_is_running(pipe)) + return 0; + + /* + * pipe enable to prepare packet receive + */ + usbhs_pipe_data_sequence(pipe, pkt->sequence); + pkt->sequence = -1; /* -1 sequence will be ignored */ + + if (usbhs_pipe_is_dcp(pipe)) + usbhsf_fifo_clear(pipe, fifo); + + usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length); + usbhs_pipe_enable(pipe); + usbhs_pipe_running(pipe, 1); + usbhsf_rx_irq_ctrl(pipe, 1); + + return 0; +} + +static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + void __iomem *addr = priv->base + fifo->port; + u8 *buf; + u32 data = 0; + int maxp = usbhs_pipe_get_maxpacket(pipe); + int rcv_len, len; + int i, ret; + int total_len = 0; + + ret = usbhsf_fifo_select(pipe, fifo, 0); + if (ret < 0) + return 0; + + ret = usbhsf_fifo_barrier(priv, fifo); + if (ret < 0) + goto usbhs_fifo_read_busy; + + rcv_len = usbhsf_fifo_rcv_len(priv, fifo); + + buf = pkt->buf + pkt->actual; + len = pkt->length - pkt->actual; + len = min(len, rcv_len); + total_len = len; + + /* + * update actual length first here to decide disable pipe. + * if this pipe keeps BUF status and all data were popped, + * then, next interrupt/token will be issued again + */ + pkt->actual += total_len; + + if ((pkt->actual == pkt->length) || /* receive all data */ + (total_len < maxp)) { /* short packet */ + *is_done = 1; + usbhsf_rx_irq_ctrl(pipe, 0); + usbhs_pipe_running(pipe, 0); + /* + * If function mode, since this controller is possible to enter + * Control Write status stage at this timing, this driver + * should not disable the pipe. If such a case happens, this + * controller is not able to complete the status stage. + */ + if (!usbhs_mod_is_host(priv) && !usbhs_pipe_is_dcp(pipe)) + usbhs_pipe_disable(pipe); /* disable pipe first */ + } + + /* + * Buffer clear if Zero-Length packet + * + * see + * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" + */ + if (0 == rcv_len) { + pkt->zero = 1; + usbhsf_fifo_clear(pipe, fifo); + goto usbhs_fifo_read_end; + } + + /* + * FIXME + * + * 32-bit access only + */ + if (len >= 4 && !((unsigned long)buf & 0x03)) { + ioread32_rep(addr, buf, len / 4); + len %= 4; + buf += total_len - len; + } + + /* the rest operation */ + for (i = 0; i < len; i++) { + if (!(i & 0x03)) + data = ioread32(addr); + + buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; + } + +usbhs_fifo_read_end: + dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", + usbhs_pipe_number(pipe), + pkt->length, pkt->actual, *is_done, pkt->zero); + +usbhs_fifo_read_busy: + usbhsf_fifo_unselect(pipe, fifo); + + return ret; +} + +const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = { + .prepare = usbhsf_prepare_pop, + .try_run = usbhsf_pio_try_pop, +}; + +/* + * DCP ctrol statge handler + */ +static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) +{ + usbhs_dcp_control_transfer_done(pkt->pipe); + + *is_done = 1; + + return 0; +} + +const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { + .prepare = usbhsf_ctrl_stage_end, + .try_run = usbhsf_ctrl_stage_end, +}; + +/* + * DMA fifo functions + */ +static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, + struct usbhs_pkt *pkt) +{ + if (&usbhs_fifo_dma_push_handler == pkt->handler) + return fifo->tx_chan; + + if (&usbhs_fifo_dma_pop_handler == pkt->handler) + return fifo->rx_chan; + + return NULL; +} + +#define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) +#define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) +static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, + struct usbhs_fifo *fifo, + u16 dreqe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + usbhs_bset(priv, fifo->sel, DREQE, dreqe); +} + +static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + + return info->dma_map_ctrl(pkt, map); +} + +/* + * DMA push handler + */ +static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + + if (usbhs_pipe_is_busy(pipe)) + return 0; + + /* + * change handler to PIO + */ + pkt->handler = &usbhs_fifo_pio_push_handler; + + return pkt->handler->prepare(pkt, is_done); +} + +static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + int is_short = pkt->trans % usbhs_pipe_get_maxpacket(pipe); + + pkt->actual += pkt->trans; + + if (pkt->actual < pkt->length) + *is_done = 0; /* there are remainder data */ + else if (is_short) + *is_done = 1; /* short packet */ + else + *is_done = !pkt->zero; /* send zero packet? */ + + usbhs_pipe_running(pipe, !*is_done); + + usbhsf_dma_stop(pipe, pipe->fifo); + usbhsf_dma_unmap(pkt); + usbhsf_fifo_unselect(pipe, pipe->fifo); + + if (!*is_done) { + /* change handler to PIO */ + pkt->handler = &usbhs_fifo_pio_push_handler; + return pkt->handler->try_run(pkt, is_done); + } + + return 0; +} + +const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { + .prepare = usbhsf_dma_prepare_push, + .dma_done = usbhsf_dma_push_done, +}; + +/* + * DMA pop handler + */ + +static int usbhsf_dma_prepare_pop_with_rx_irq(struct usbhs_pkt *pkt, + int *is_done) +{ + return usbhsf_prepare_pop(pkt, is_done); +} + +static int usbhsf_dma_prepare_pop(struct usbhs_pkt *pkt, int *is_done) +{ + return usbhsf_dma_prepare_pop_with_rx_irq(pkt, is_done); +} + +static int usbhsf_dma_try_pop_with_rx_irq(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + + if (usbhs_pipe_is_busy(pipe)) + return 0; + + /* + * change handler to PIO + */ + pkt->handler = &usbhs_fifo_pio_pop_handler; + + return pkt->handler->try_run(pkt, is_done); +} + +static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); + + BUG_ON(usbhs_get_dparam(priv, has_usb_dmac)); + + return usbhsf_dma_try_pop_with_rx_irq(pkt, is_done); +} + +static int usbhsf_dma_pop_done_with_rx_irq(struct usbhs_pkt *pkt, int *is_done) +{ + struct usbhs_pipe *pipe = pkt->pipe; + int maxp = usbhs_pipe_get_maxpacket(pipe); + + usbhsf_dma_stop(pipe, pipe->fifo); + usbhsf_dma_unmap(pkt); + usbhsf_fifo_unselect(pipe, pipe->fifo); + + pkt->actual += pkt->trans; + + if ((pkt->actual == pkt->length) || /* receive all data */ + (pkt->trans < maxp)) { /* short packet */ + *is_done = 1; + usbhs_pipe_running(pipe, 0); + } else { + /* re-enable */ + usbhs_pipe_running(pipe, 0); + usbhsf_prepare_pop(pkt, is_done); + } + + return 0; +} + +static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) +{ + return usbhsf_dma_pop_done_with_rx_irq(pkt, is_done); +} + +const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { + .prepare = usbhsf_dma_prepare_pop, + .try_run = usbhsf_dma_try_pop, + .dma_done = usbhsf_dma_pop_done +}; + +/* + * irq functions + */ +static int usbhsf_irq_empty(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + struct usbhs_pipe *pipe; + struct device *dev = usbhs_priv_to_dev(priv); + int i, ret; + + if (!irq_state->bempsts) { + dev_err(dev, "debug %s !!\n", __func__); + return -EIO; + } + + dev_dbg(dev, "irq empty [0x%04x]\n", irq_state->bempsts); + + /* + * search interrupted "pipe" + * not "uep". + */ + usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + if (!(irq_state->bempsts & (1 << i))) + continue; + + ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); + if (ret < 0) + dev_err(dev, "irq_empty run_error %d : %d\n", i, ret); + } + + return 0; +} + +static int usbhsf_irq_ready(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + struct usbhs_pipe *pipe; + struct device *dev = usbhs_priv_to_dev(priv); + int i, ret; + + if (!irq_state->brdysts) { + dev_err(dev, "debug %s !!\n", __func__); + return -EIO; + } + + dev_dbg(dev, "irq ready [0x%04x]\n", irq_state->brdysts); + + /* + * search interrupted "pipe" + * not "uep". + */ + usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + if (!(irq_state->brdysts & (1 << i))) + continue; + + ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); + if (ret < 0) + dev_err(dev, "irq_ready run_error %d : %d\n", i, ret); + } + + return 0; +} + +void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ + + /* clear DCP FIFO of transmission */ + if (usbhsf_fifo_select(pipe, fifo, 1) < 0) + return; + usbhsf_fifo_clear(pipe, fifo); + usbhsf_fifo_unselect(pipe, fifo); + + /* clear DCP FIFO of reception */ + if (usbhsf_fifo_select(pipe, fifo, 0) < 0) + return; + usbhsf_fifo_clear(pipe, fifo); + usbhsf_fifo_unselect(pipe, fifo); +} + +/* + * fifo init + */ +void usbhs_fifo_init(struct usbhs_priv *priv) +{ + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); + struct usbhs_fifo *dfifo; + int i; + + mod->irq_empty = usbhsf_irq_empty; + mod->irq_ready = usbhsf_irq_ready; + mod->irq_bempsts = 0; + mod->irq_brdysts = 0; + + cfifo->pipe = NULL; + usbhs_for_each_dfifo(priv, dfifo, i) + dfifo->pipe = NULL; +} + +void usbhs_fifo_quit(struct usbhs_priv *priv) +{ + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + + mod->irq_empty = NULL; + mod->irq_ready = NULL; + mod->irq_bempsts = 0; + mod->irq_brdysts = 0; +} + +#define __USBHS_DFIFO_INIT(priv, fifo, channel, fifo_port) \ +do { \ + fifo = usbhsf_get_dnfifo(priv, channel); \ + fifo->name = "D"#channel"FIFO"; \ + fifo->port = fifo_port; \ + fifo->sel = D##channel##FIFOSEL; \ + fifo->ctr = D##channel##FIFOCTR; \ + fifo->tx_slave.shdma_slave.slave_id = \ + usbhs_get_dparam(priv, d##channel##_tx_id); \ + fifo->rx_slave.shdma_slave.slave_id = \ + usbhs_get_dparam(priv, d##channel##_rx_id); \ +} while (0) + +#define USBHS_DFIFO_INIT(priv, fifo, channel) \ + __USBHS_DFIFO_INIT(priv, fifo, channel, D##channel##FIFO) +#define USBHS_DFIFO_INIT_NO_PORT(priv, fifo, channel) \ + __USBHS_DFIFO_INIT(priv, fifo, channel, 0) + +int usbhs_fifo_probe(struct usbhs_priv *priv) +{ + struct usbhs_fifo *fifo; + + /* CFIFO */ + fifo = usbhsf_get_cfifo(priv); + fifo->name = "CFIFO"; + fifo->port = CFIFO; + fifo->sel = CFIFOSEL; + fifo->ctr = CFIFOCTR; + + /* DFIFO */ + USBHS_DFIFO_INIT(priv, fifo, 0); + USBHS_DFIFO_INIT(priv, fifo, 1); + USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 2); + USBHS_DFIFO_INIT_NO_PORT(priv, fifo, 3); + + return 0; +} + +void usbhs_fifo_remove(struct usbhs_priv *priv) +{ +} diff --git a/drivers/usb/gadget/rcar/fifo.h b/drivers/usb/gadget/rcar/fifo.h new file mode 100644 index 00000000000..86746ca9bdd --- /dev/null +++ b/drivers/usb/gadget/rcar/fifo.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#ifndef RENESAS_USB_FIFO_H +#define RENESAS_USB_FIFO_H + +#include <dma.h> +#include "pipe.h" + +/* + * Drivers, using this library are expected to embed struct shdma_dev, + * struct shdma_chan, struct shdma_desc, and struct shdma_slave + * in their respective device, channel, descriptor and slave objects. + */ + +struct shdma_slave { + int slave_id; +}; + +/* Used by slave DMA clients to request DMA to/from a specific peripheral */ +struct sh_dmae_slave { + struct shdma_slave shdma_slave; /* Set by the platform */ +}; + +struct usbhs_fifo { + char *name; + u32 port; /* xFIFO */ + u32 sel; /* xFIFOSEL */ + u32 ctr; /* xFIFOCTR */ + + struct usbhs_pipe *pipe; + + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + + struct sh_dmae_slave tx_slave; + struct sh_dmae_slave rx_slave; +}; + +#define USBHS_MAX_NUM_DFIFO 4 +struct usbhs_fifo_info { + struct usbhs_fifo cfifo; + struct usbhs_fifo dfifo[USBHS_MAX_NUM_DFIFO]; +}; +#define usbhsf_get_dnfifo(p, n) (&((p)->fifo_info.dfifo[n])) +#define usbhs_for_each_dfifo(priv, dfifo, i) \ + for ((i) = 0; \ + ((i) < USBHS_MAX_NUM_DFIFO) && \ + ((dfifo) = usbhsf_get_dnfifo(priv, (i))); \ + (i)++) + +struct usbhs_pkt_handle; +struct usbhs_pkt { + struct list_head node; + struct usbhs_pipe *pipe; + const struct usbhs_pkt_handle *handler; + void (*done)(struct usbhs_priv *priv, + struct usbhs_pkt *pkt); + struct work_struct work; + dma_addr_t dma; + const struct dmaengine_result *dma_result; + void *buf; + int length; + int trans; + int actual; + int zero; + int sequence; +}; + +struct usbhs_pkt_handle { + int (*prepare)(struct usbhs_pkt *pkt, int *is_done); + int (*try_run)(struct usbhs_pkt *pkt, int *is_done); + int (*dma_done)(struct usbhs_pkt *pkt, int *is_done); +}; + +/* + * fifo + */ +int usbhs_fifo_probe(struct usbhs_priv *priv); +void usbhs_fifo_remove(struct usbhs_priv *priv); +void usbhs_fifo_init(struct usbhs_priv *priv); +void usbhs_fifo_quit(struct usbhs_priv *priv); +void usbhs_fifo_clear_dcp(struct usbhs_pipe *pipe); + +/* + * packet info + */ +extern const struct usbhs_pkt_handle usbhs_fifo_pio_push_handler; +extern const struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler; +extern const struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler; + +extern const struct usbhs_pkt_handle usbhs_fifo_dma_push_handler; +extern const struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler; + +extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler; +extern const struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler; + +extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler; +extern const struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler; + +void usbhs_pkt_init(struct usbhs_pkt *pkt); +void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, + void (*done)(struct usbhs_priv *priv, + struct usbhs_pkt *pkt), + void *buf, int len, int zero, int sequence); +struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); +void usbhs_pkt_start(struct usbhs_pipe *pipe); +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe); + +#endif /* RENESAS_USB_FIFO_H */ diff --git a/drivers/usb/gadget/rcar/mod.c b/drivers/usb/gadget/rcar/mod.c new file mode 100644 index 00000000000..f5f8d169e17 --- /dev/null +++ b/drivers/usb/gadget/rcar/mod.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#include "common.h" +#include "mod.h" + +/* + * autonomy + * + * these functions are used if platform doesn't have external phy. + * -> there is no "notify_hotplug" callback from platform + * -> call "notify_hotplug" by itself + * -> use own interrupt to connect/disconnect + * -> it mean module clock is always ON + * ~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + usbhsc_hotplug(priv); + + return 0; +} + +void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + info->irq_vbus = usbhsm_autonomy_irq_vbus; + + usbhs_irq_callback_update(priv, NULL); +} + +/* + * host / gadget functions + * + * renesas_usbhs host/gadget can register itself by below functions. + * these functions are called when probe + * + */ +void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + info->mod[id] = mod; + mod->priv = priv; +} + +struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + struct usbhs_mod *ret = NULL; + + switch (id) { + case USBHS_HOST: + case USBHS_GADGET: + ret = info->mod[id]; + break; + } + + return ret; +} + +int usbhs_mod_is_host(struct usbhs_priv *priv) +{ + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + if (!mod) + return -EINVAL; + + return info->mod[USBHS_HOST] == mod; +} + +struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + return info->curt; +} + +int usbhs_mod_change(struct usbhs_priv *priv, int id) +{ + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + struct usbhs_mod *mod = NULL; + int ret = 0; + + /* id < 0 mean no current */ + switch (id) { + case USBHS_HOST: + case USBHS_GADGET: + mod = info->mod[id]; + break; + default: + ret = -EINVAL; + } + info->curt = mod; + + return ret; +} + +irqreturn_t usbhs_interrupt(int irq, void *data); +int usbhs_mod_probe(struct usbhs_priv *priv) +{ + int ret; + + /* + * install host/gadget driver + */ + ret = usbhs_mod_host_probe(priv); + if (ret < 0) + return ret; + + ret = usbhs_mod_gadget_probe(priv); + if (ret < 0) + goto mod_init_host_err; + + return ret; + +mod_init_host_err: + usbhs_mod_host_remove(priv); + + return ret; +} + +void usbhs_mod_remove(struct usbhs_priv *priv) +{ + usbhs_mod_host_remove(priv); + usbhs_mod_gadget_remove(priv); +} + +/* + * status functions + */ +int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) +{ + return (int)irq_state->intsts0 & DVSQ_MASK; +} + +int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state) +{ + /* + * return value + * + * IDLE_SETUP_STAGE + * READ_DATA_STAGE + * READ_STATUS_STAGE + * WRITE_DATA_STAGE + * WRITE_STATUS_STAGE + * NODATA_STATUS_STAGE + * SEQUENCE_ERROR + */ + return (int)irq_state->intsts0 & CTSQ_MASK; +} + +static int usbhs_status_get_each_irq(struct usbhs_priv *priv, + struct usbhs_irq_state *state) +{ + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + u16 intenb0, intenb1; + unsigned long flags; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + state->intsts0 = usbhs_read(priv, INTSTS0); + intenb0 = usbhs_read(priv, INTENB0); + + if (usbhs_mod_is_host(priv)) { + state->intsts1 = usbhs_read(priv, INTSTS1); + intenb1 = usbhs_read(priv, INTENB1); + } else { + state->intsts1 = intenb1 = 0; + } + + /* mask */ + if (mod) { + state->brdysts = usbhs_read(priv, BRDYSTS); + state->nrdysts = usbhs_read(priv, NRDYSTS); + state->bempsts = usbhs_read(priv, BEMPSTS); + + state->bempsts &= mod->irq_bempsts; + state->brdysts &= mod->irq_brdysts; + } + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + return 0; +} + +/* + * interrupt + */ +#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */ +#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */ +irqreturn_t usbhs_interrupt(int irq, void *data) +{ + struct usbhs_priv *priv = data; + struct usbhs_irq_state irq_state; + + if (usbhs_status_get_each_irq(priv, &irq_state) < 0) + return IRQ_NONE; + + /* + * clear interrupt + * + * The hardware is _very_ picky to clear interrupt bit. + * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value. + * + * see + * "Operation" + * - "Control Transfer (DCP)" + * - Function :: VALID bit should 0 + */ + usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC); + if (usbhs_mod_is_host(priv)) + usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC); + + /* + * The driver should not clear the xxxSTS after the line of + * "call irq callback functions" because each "if" statement is + * possible to call the callback function for avoiding any side effects. + */ + if (irq_state.intsts0 & BRDY) + usbhs_write(priv, BRDYSTS, ~irq_state.brdysts); + usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts); + if (irq_state.intsts0 & BEMP) + usbhs_write(priv, BEMPSTS, ~irq_state.bempsts); + + /* + * call irq callback functions + * see also + * usbhs_irq_setting_update + */ + + /* INTSTS0 */ + if (irq_state.intsts0 & VBINT) + usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); + + if (irq_state.intsts0 & DVST) + usbhs_mod_call(priv, irq_dev_state, priv, &irq_state); + + if (irq_state.intsts0 & CTRT) + usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state); + + if (irq_state.intsts0 & BEMP) + usbhs_mod_call(priv, irq_empty, priv, &irq_state); + + if (irq_state.intsts0 & BRDY) + usbhs_mod_call(priv, irq_ready, priv, &irq_state); + + if (usbhs_mod_is_host(priv)) { + /* INTSTS1 */ + if (irq_state.intsts1 & ATTCH) + usbhs_mod_call(priv, irq_attch, priv, &irq_state); + + if (irq_state.intsts1 & DTCH) + usbhs_mod_call(priv, irq_dtch, priv, &irq_state); + + if (irq_state.intsts1 & SIGN) + usbhs_mod_call(priv, irq_sign, priv, &irq_state); + + if (irq_state.intsts1 & SACK) + usbhs_mod_call(priv, irq_sack, priv, &irq_state); + } + return IRQ_HANDLED; +} + +void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) +{ + u16 intenb0 = 0; + u16 intenb1 = 0; + struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); + + /* + * BEMPENB/BRDYENB are picky. + * below method is required + * + * - clear INTSTS0 + * - update BEMPENB/BRDYENB + * - update INTSTS0 + */ + usbhs_write(priv, INTENB0, 0); + if (usbhs_mod_is_host(priv)) + usbhs_write(priv, INTENB1, 0); + + usbhs_write(priv, BEMPENB, 0); + usbhs_write(priv, BRDYENB, 0); + + /* + * see also + * usbhs_interrupt + */ + + if (info->irq_vbus) + intenb0 |= VBSE; + + if (mod) { + /* + * INTSTS0 + */ + if (mod->irq_ctrl_stage) + intenb0 |= CTRE; + + if (mod->irq_dev_state) + intenb0 |= DVSE; + + if (mod->irq_empty && mod->irq_bempsts) { + usbhs_write(priv, BEMPENB, mod->irq_bempsts); + intenb0 |= BEMPE; + } + + if (mod->irq_ready && mod->irq_brdysts) { + usbhs_write(priv, BRDYENB, mod->irq_brdysts); + intenb0 |= BRDYE; + } + + if (usbhs_mod_is_host(priv)) { + /* + * INTSTS1 + */ + if (mod->irq_attch) + intenb1 |= ATTCHE; + + if (mod->irq_dtch) + intenb1 |= DTCHE; + + if (mod->irq_sign) + intenb1 |= SIGNE; + + if (mod->irq_sack) + intenb1 |= SACKE; + } + } + + if (intenb0) + usbhs_write(priv, INTENB0, intenb0); + + if (usbhs_mod_is_host(priv) && intenb1) + usbhs_write(priv, INTENB1, intenb1); +} diff --git a/drivers/usb/gadget/rcar/mod.h b/drivers/usb/gadget/rcar/mod.h new file mode 100644 index 00000000000..b670e950a28 --- /dev/null +++ b/drivers/usb/gadget/rcar/mod.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#ifndef RENESAS_USB_MOD_H +#define RENESAS_USB_MOD_H + +#include "common.h" + +/* + * struct + */ +struct usbhs_irq_state { + u16 intsts0; + u16 intsts1; + u16 brdysts; + u16 nrdysts; + u16 bempsts; +}; + +struct usbhs_mod { + char *name; + + /* + * entry point from common.c + */ + int (*start)(struct usbhs_priv *priv); + int (*stop)(struct usbhs_priv *priv); + + /* + * INTSTS0 + */ + + /* DVST (DVSQ) */ + int (*irq_dev_state)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + /* CTRT (CTSQ) */ + int (*irq_ctrl_stage)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + /* BEMP / BEMPSTS */ + int (*irq_empty)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + u16 irq_bempsts; + + /* BRDY / BRDYSTS */ + int (*irq_ready)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + u16 irq_brdysts; + + /* + * INTSTS1 + */ + + /* ATTCHE */ + int (*irq_attch)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + /* DTCHE */ + int (*irq_dtch)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + /* SIGN */ + int (*irq_sign)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + /* SACK */ + int (*irq_sack)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); + + struct usbhs_priv *priv; +}; + +struct usbhs_mod_info { + struct usbhs_mod *mod[USBHS_MAX]; + struct usbhs_mod *curt; /* current mod */ + + /* + * INTSTS0 :: VBINT + * + * This function will be used as autonomy mode (runtime_pwctrl == 0) + * when the platform doesn't have own get_vbus function. + * + * This callback cannot be member of "struct usbhs_mod" because it + * will be used even though host/gadget has not been selected. + */ + int (*irq_vbus)(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state); +}; + +/* + * for host/gadget module + */ +struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id); +struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv); +void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *usb, int id); +int usbhs_mod_is_host(struct usbhs_priv *priv); +int usbhs_mod_change(struct usbhs_priv *priv, int id); +int usbhs_mod_probe(struct usbhs_priv *priv); +void usbhs_mod_remove(struct usbhs_priv *priv); + +void usbhs_mod_autonomy_mode(struct usbhs_priv *priv); +void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv); + +/* + * status functions + */ +int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state); +int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state); + +/* + * callback functions + */ +void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod); + +irqreturn_t usbhs_interrupt(int irq, void *data); + +#define usbhs_mod_call(priv, func, param...) \ + ({ \ + struct usbhs_mod *mod; \ + mod = usbhs_mod_get_current(priv); \ + !mod ? -ENODEV : \ + !mod->func ? 0 : \ + mod->func(param); \ + }) + +#define usbhs_priv_to_modinfo(priv) (&priv->mod_info) +#define usbhs_mod_info_call(priv, func, param...) \ +({ \ + struct usbhs_mod_info *info; \ + info = usbhs_priv_to_modinfo(priv); \ + !info->func ? 0 : \ + info->func(param); \ +}) + +/* + * host / gadget control + */ +#if defined(CONFIG_USB_RENESAS_USBHS_HCD) || \ + defined(CONFIG_USB_RENESAS_USBHS_HCD_MODULE) +extern int usbhs_mod_host_probe(struct usbhs_priv *priv); +extern int usbhs_mod_host_remove(struct usbhs_priv *priv); +#else +static inline int usbhs_mod_host_probe(struct usbhs_priv *priv) +{ + return 0; +} +static inline void usbhs_mod_host_remove(struct usbhs_priv *priv) +{ +} +#endif + +extern int usbhs_mod_gadget_probe(struct usbhs_priv *priv); +extern void usbhs_mod_gadget_remove(struct usbhs_priv *priv); + +#endif /* RENESAS_USB_MOD_H */ diff --git a/drivers/usb/gadget/rcar/mod_gadget.c b/drivers/usb/gadget/rcar/mod_gadget.c new file mode 100644 index 00000000000..bd9855eb4fa --- /dev/null +++ b/drivers/usb/gadget/rcar/mod_gadget.c @@ -0,0 +1,1136 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2019 Renesas Electronics Corporation + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include "common.h" + +/* + * struct + */ +struct usbhsg_request { + struct usb_request req; + struct usbhs_pkt pkt; +}; + +#define EP_NAME_SIZE 8 +struct usbhsg_gpriv; +struct usbhsg_uep { + struct usb_ep ep; + struct usbhs_pipe *pipe; + spinlock_t lock; /* protect the pipe */ + + char ep_name[EP_NAME_SIZE]; + + struct usbhsg_gpriv *gpriv; +}; + +struct usbhsg_gpriv { + struct usb_gadget gadget; + struct usbhs_mod mod; + + struct usbhsg_uep *uep; + int uep_size; + + struct usb_gadget_driver *driver; + bool vbus_active; + + u32 status; +#define USBHSG_STATUS_STARTED (1 << 0) +#define USBHSG_STATUS_REGISTERD (1 << 1) +#define USBHSG_STATUS_WEDGE (1 << 2) +#define USBHSG_STATUS_SELF_POWERED (1 << 3) +#define USBHSG_STATUS_SOFT_CONNECT (1 << 4) +}; + +struct usbhsg_recip_handle { + char *name; + int (*device)(struct usbhs_priv *priv, struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl); + int (*interface)(struct usbhs_priv *priv, struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl); + int (*endpoint)(struct usbhs_priv *priv, struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl); +}; + +/* + * macro + */ +#define usbhsg_priv_to_gpriv(priv) \ + container_of( \ + usbhs_mod_get(priv, USBHS_GADGET), \ + struct usbhsg_gpriv, mod) + +#define __usbhsg_for_each_uep(start, pos, g, i) \ + for ((i) = start; \ + ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \ + (i)++) + +#define usbhsg_for_each_uep(pos, gpriv, i) \ + __usbhsg_for_each_uep(1, pos, gpriv, i) + +#define usbhsg_for_each_uep_with_dcp(pos, gpriv, i) \ + __usbhsg_for_each_uep(0, pos, gpriv, i) + +#define usbhsg_gadget_to_gpriv(g)\ + container_of(g, struct usbhsg_gpriv, gadget) + +#define usbhsg_req_to_ureq(r)\ + container_of(r, struct usbhsg_request, req) + +#define usbhsg_ep_to_uep(e) container_of(e, struct usbhsg_uep, ep) +#define usbhsg_gpriv_to_dev(gp) usbhs_priv_to_dev((gp)->mod.priv) +#define usbhsg_gpriv_to_priv(gp) ((gp)->mod.priv) +#define usbhsg_gpriv_to_dcp(gp) ((gp)->uep) +#define usbhsg_gpriv_to_nth_uep(gp, i) ((gp)->uep + i) +#define usbhsg_uep_to_gpriv(u) ((u)->gpriv) +#define usbhsg_uep_to_pipe(u) ((u)->pipe) +#define usbhsg_pipe_to_uep(p) ((p)->mod_private) +#define usbhsg_is_dcp(u) ((u) == usbhsg_gpriv_to_dcp((u)->gpriv)) + +#define usbhsg_ureq_to_pkt(u) (&(u)->pkt) +#define usbhsg_pkt_to_ureq(i) \ + container_of(i, struct usbhsg_request, pkt) + +#define usbhsg_is_not_connected(gp) ((gp)->gadget.speed == USB_SPEED_UNKNOWN) + +/* status */ +#define usbhsg_status_init(gp) do {(gp)->status = 0; } while (0) +#define usbhsg_status_set(gp, b) (gp->status |= b) +#define usbhsg_status_clr(gp, b) (gp->status &= ~b) +#define usbhsg_status_has(gp, b) (gp->status & b) + +/* + * queue push/pop + */ +static void __usbhsg_queue_pop(struct usbhsg_uep *uep, + struct usbhsg_request *ureq, + int status) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + + if (pipe) + dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); + + ureq->req.status = status; + spin_unlock(usbhs_priv_to_lock(priv)); + usb_gadget_giveback_request(&uep->ep, &ureq->req); + spin_lock(usbhs_priv_to_lock(priv)); +} + +static void usbhsg_queue_pop(struct usbhsg_uep *uep, + struct usbhsg_request *ureq, + int status) +{ + unsigned long flags; + + usbhs_lock(priv, flags); + __usbhsg_queue_pop(uep, ureq, status); + usbhs_unlock(priv, flags); +} + +static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) +{ + struct usbhs_pipe *pipe = pkt->pipe; + struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); + struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); + unsigned long flags; + + ureq->req.actual = pkt->actual; + + usbhs_lock(priv, flags); + if (uep) + __usbhsg_queue_pop(uep, ureq, 0); + usbhs_unlock(priv, flags); +} + +static void usbhsg_queue_push(struct usbhsg_uep *uep, + struct usbhsg_request *ureq) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); + struct usb_request *req = &ureq->req; + + req->actual = 0; + req->status = -EINPROGRESS; + usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, + req->buf, req->length, req->zero, -1); + usbhs_pkt_start(pipe); + + dev_dbg(dev, "pipe %d : queue push (%d)\n", + usbhs_pipe_number(pipe), + req->length); +} + +/* + * dma map/unmap + */ +static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +{ + return -1; +} + +/* + * USB_TYPE_STANDARD / clear feature functions + */ +static int usbhsg_recip_handler_std_control_done(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); + + usbhs_dcp_control_transfer_done(pipe); + + return 0; +} + +static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + + if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) { + usbhs_pipe_disable(pipe); + usbhs_pipe_sequence_data0(pipe); + usbhs_pipe_enable(pipe); + } + + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + + usbhs_pkt_start(pipe); + + return 0; +} + +static struct usbhsg_recip_handle req_clear_feature = { + .name = "clear feature", + .device = usbhsg_recip_handler_std_control_done, + .interface = usbhsg_recip_handler_std_control_done, + .endpoint = usbhsg_recip_handler_std_clear_endpoint, +}; + +/* + * USB_TYPE_STANDARD / set feature functions + */ +static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + switch (le16_to_cpu(ctrl->wValue)) { + case USB_DEVICE_TEST_MODE: + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + udelay(100); + usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex) >> 8); + break; + default: + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + break; + } + + return 0; +} + +static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + + usbhs_pipe_stall(pipe); + + usbhsg_recip_handler_std_control_done(priv, uep, ctrl); + + return 0; +} + +static struct usbhsg_recip_handle req_set_feature = { + .name = "set feature", + .device = usbhsg_recip_handler_std_set_device, + .interface = usbhsg_recip_handler_std_control_done, + .endpoint = usbhsg_recip_handler_std_set_endpoint, +}; + +/* + * USB_TYPE_STANDARD / get status functions + */ +static void __usbhsg_recip_send_complete(struct usb_ep *ep, + struct usb_request *req) +{ + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + + /* free allocated recip-buffer/usb_request */ + kfree(ureq->pkt.buf); + usb_ep_free_request(ep, req); +} + +static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, + unsigned short status) +{ + struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usb_request *req; + __le16 *buf; + + /* alloc new usb_request for recip */ + req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); + if (!req) { + dev_err(dev, "recip request allocation fail\n"); + return; + } + + /* alloc recip data buffer */ + buf = kmalloc(sizeof(*buf), GFP_ATOMIC); + if (!buf) { + usb_ep_free_request(&dcp->ep, req); + return; + } + + /* recip data is status */ + *buf = cpu_to_le16(status); + + /* allocated usb_request/buffer will be freed */ + req->complete = __usbhsg_recip_send_complete; + req->buf = buf; + req->length = sizeof(*buf); + req->zero = 0; + + /* push packet */ + pipe->handler = &usbhs_fifo_pio_push_handler; + usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req)); +} + +static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + unsigned short status = 0; + + if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED)) + status = 1 << USB_DEVICE_SELF_POWERED; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + unsigned short status = 0; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, + struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + unsigned short status = 0; + + if (usbhs_pipe_is_stall(pipe)) + status = 1 << USB_ENDPOINT_HALT; + + __usbhsg_recip_send_status(gpriv, status); + + return 0; +} + +static struct usbhsg_recip_handle req_get_status = { + .name = "get status", + .device = usbhsg_recip_handler_std_get_device, + .interface = usbhsg_recip_handler_std_get_interface, + .endpoint = usbhsg_recip_handler_std_get_endpoint, +}; + +/* + * USB_TYPE handler + */ +static int usbhsg_recip_run_handle(struct usbhs_priv *priv, + struct usbhsg_recip_handle *handler, + struct usb_ctrlrequest *ctrl) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usbhsg_uep *uep; + struct usbhs_pipe *pipe; + int recip = ctrl->bRequestType & USB_RECIP_MASK; + int nth = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; + int ret = 0; + int (*func)(struct usbhs_priv *priv, struct usbhsg_uep *uep, + struct usb_ctrlrequest *ctrl); + char *msg; + + uep = usbhsg_gpriv_to_nth_uep(gpriv, nth); + pipe = usbhsg_uep_to_pipe(uep); + if (!pipe) { + dev_err(dev, "wrong recip request\n"); + return -EINVAL; + } + + switch (recip) { + case USB_RECIP_DEVICE: + msg = "DEVICE"; + func = handler->device; + break; + case USB_RECIP_INTERFACE: + msg = "INTERFACE"; + func = handler->interface; + break; + case USB_RECIP_ENDPOINT: + msg = "ENDPOINT"; + func = handler->endpoint; + break; + default: + dev_warn(dev, "unsupported RECIP(%d)\n", recip); + func = NULL; + ret = -EINVAL; + } + + if (func) { + dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); + ret = func(priv, uep, ctrl); + } + + return ret; +} + +/* + * irq functions + * + * it will be called from usbhs_interrupt + */ +static int usbhsg_irq_dev_state(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + int state = usbhs_status_get_device_state(irq_state); + + gpriv->gadget.speed = usbhs_bus_get_speed(priv); + + dev_dbg(dev, "state = %x : speed : %d\n", state, gpriv->gadget.speed); + + if (gpriv->gadget.speed != USB_SPEED_UNKNOWN && + (state & SUSPENDED_STATE)) { + if (gpriv->driver && gpriv->driver->suspend) + gpriv->driver->suspend(&gpriv->gadget); + usb_gadget_set_state(&gpriv->gadget, USB_STATE_SUSPENDED); + } + + return 0; +} + +static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, + struct usbhs_irq_state *irq_state) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + struct usb_ctrlrequest ctrl; + struct usbhsg_recip_handle *recip_handler = NULL; + int stage = usbhs_status_get_ctrl_stage(irq_state); + int ret = 0; + + dev_dbg(dev, "stage = %d\n", stage); + + /* + * see Manual + * + * "Operation" + * - "Interrupt Function" + * - "Control Transfer Stage Transition Interrupt" + * - Fig. "Control Transfer Stage Transitions" + */ + + switch (stage) { + case READ_DATA_STAGE: + pipe->handler = &usbhs_fifo_pio_push_handler; + break; + case WRITE_DATA_STAGE: + pipe->handler = &usbhs_fifo_pio_pop_handler; + break; + case NODATA_STATUS_STAGE: + pipe->handler = &usbhs_ctrl_stage_end_handler; + break; + case READ_STATUS_STAGE: + case WRITE_STATUS_STAGE: + usbhs_dcp_control_transfer_done(pipe); + fallthrough; + default: + return ret; + } + + /* + * get usb request + */ + usbhs_usbreq_get_val(priv, &ctrl); + + switch (ctrl.bRequestType & USB_TYPE_MASK) { + case USB_TYPE_STANDARD: + switch (ctrl.bRequest) { + case USB_REQ_CLEAR_FEATURE: + recip_handler = &req_clear_feature; + break; + case USB_REQ_SET_FEATURE: + recip_handler = &req_set_feature; + break; + case USB_REQ_GET_STATUS: + recip_handler = &req_get_status; + break; + } + } + + /* + * setup stage / run recip + */ + if (recip_handler) + ret = usbhsg_recip_run_handle(priv, recip_handler, &ctrl); + else + ret = gpriv->driver->setup(&gpriv->gadget, &ctrl); + + if (ret < 0) + usbhs_pipe_stall(pipe); + + return ret; +} + +/* + * + * usb_dcp_ops + * + */ +static int usbhsg_pipe_disable(struct usbhsg_uep *uep) +{ + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhs_pkt *pkt; + + while (1) { + pkt = usbhs_pkt_pop(pipe, NULL); + if (!pkt) + break; + + usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ESHUTDOWN); + } + + usbhs_pipe_disable(pipe); + + return 0; +} + +/* + * + * usb_ep_ops + * + */ +static int usbhsg_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct usbhs_pipe *pipe; + int ret = -EIO; + unsigned long flags; + + usbhs_lock(priv, flags); + + /* + * if it already have pipe, + * nothing to do + */ + if (uep->pipe) { + usbhs_pipe_clear(uep->pipe); + usbhs_pipe_sequence_data0(uep->pipe); + ret = 0; + goto usbhsg_ep_enable_end; + } + + pipe = usbhs_pipe_malloc(priv, + usb_endpoint_type(desc), + usb_endpoint_dir_in(desc)); + if (pipe) { + uep->pipe = pipe; + pipe->mod_private = uep; + + /* set epnum / maxp */ + usbhs_pipe_config_update(pipe, 0, + usb_endpoint_num(desc), + usb_endpoint_maxp(desc)); + + /* + * usbhs_fifo_dma_push/pop_handler try to + * use dmaengine if possible. + * It will use pio handler if impossible. + */ + if (usb_endpoint_dir_in(desc)) { + pipe->handler = &usbhs_fifo_dma_push_handler; + } else { + pipe->handler = &usbhs_fifo_dma_pop_handler; + usbhs_xxxsts_clear(priv, BRDYSTS, + usbhs_pipe_number(pipe)); + } + + ret = 0; + } + +usbhsg_ep_enable_end: + usbhs_unlock(priv, flags); + + return ret; +} + +static int usbhsg_ep_disable(struct usb_ep *ep) +{ + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhs_pipe *pipe; + unsigned long flags; + + spin_lock_irqsave(&uep->lock, flags); + pipe = usbhsg_uep_to_pipe(uep); + if (!pipe) + goto out; + + usbhsg_pipe_disable(uep); + usbhs_pipe_free(pipe); + + uep->pipe->mod_private = NULL; + uep->pipe = NULL; + +out: + spin_unlock_irqrestore(&uep->lock, flags); + + return 0; +} + +static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct usbhsg_request *ureq; + + ureq = kzalloc(sizeof *ureq, gfp_flags); + if (!ureq) + return NULL; + + usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); + + return &ureq->req; +} + +static void usbhsg_ep_free_request(struct usb_ep *ep, + struct usb_request *req) +{ + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + + WARN_ON(!list_empty(&ureq->pkt.node)); + kfree(ureq); +} + +static int usbhsg_ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags) +{ + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + + /* param check */ + if (usbhsg_is_not_connected(gpriv) || + unlikely(!gpriv->driver) || + unlikely(!pipe)) + return -ESHUTDOWN; + + usbhsg_queue_push(uep, ureq); + + return 0; +} + +static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); + struct usbhs_pipe *pipe; + unsigned long flags; + + spin_lock_irqsave(&uep->lock, flags); + pipe = usbhsg_uep_to_pipe(uep); + if (pipe) + usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); + + /* + * To dequeue a request, this driver should call the usbhsg_queue_pop() + * even if the pipe is NULL. + */ + usbhsg_queue_pop(uep, ureq, -ECONNRESET); + spin_unlock_irqrestore(&uep->lock, flags); + + return 0; +} + +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe); +static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) +{ + struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct device *dev = usbhsg_gpriv_to_dev(gpriv); + unsigned long flags; + int ret = 0; + + dev_dbg(dev, "set halt %d (pipe %d)\n", + halt, usbhs_pipe_number(pipe)); + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + /* + * According to usb_ep_set_halt()'s description, this function should + * return -EAGAIN if the IN endpoint has any queue or data. Note + * that the usbhs_pipe_is_dir_in() returns false if the pipe is an + * IN endpoint in the gadget mode. + */ + if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) || + usbhs_pipe_contains_transmittable_data(pipe))) { + ret = -EAGAIN; + goto out; + } + + if (halt) + usbhs_pipe_stall(pipe); + else + usbhs_pipe_disable(pipe); + + if (halt && wedge) + usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); + +out: + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + return ret; +} + +static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) +{ + return __usbhsg_ep_set_halt_wedge(ep, value, 0); +} + +static int usbhsg_ep_set_wedge(struct usb_ep *ep) +{ + return __usbhsg_ep_set_halt_wedge(ep, 1, 1); +} + +static const struct usb_ep_ops usbhsg_ep_ops = { + .enable = usbhsg_ep_enable, + .disable = usbhsg_ep_disable, + + .alloc_request = usbhsg_ep_alloc_request, + .free_request = usbhsg_ep_free_request, + + .queue = usbhsg_ep_queue, + .dequeue = usbhsg_ep_dequeue, + + .set_halt = usbhsg_ep_set_halt, + .set_wedge = usbhsg_ep_set_wedge, +}; + +/* + * pullup control + */ +static int usbhsg_can_pullup(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + return gpriv->driver && + usbhsg_status_has(gpriv, USBHSG_STATUS_SOFT_CONNECT); +} + +static void usbhsg_update_pullup(struct usbhs_priv *priv) +{ + if (usbhsg_can_pullup(priv)) + usbhs_sys_function_pullup(priv, 1); + else + usbhs_sys_function_pullup(priv, 0); +} + +/* + * usb module start/end + */ +static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + int ret = 0; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + usbhsg_status_set(gpriv, status); + if (!(usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && + usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD))) + ret = -1; /* not ready */ + + usbhs_unlock(priv, flags); + /******************** spin unlock ********************/ + + if (ret < 0) + return 0; /* not ready is not error */ + + /* + * enable interrupt and systems if ready + */ + dev_dbg(dev, "start gadget\n"); + + /* + * pipe initialize and enable DCP + */ + usbhs_fifo_init(priv); + usbhs_pipe_init(priv, + usbhsg_dma_map_ctrl); + + /* dcp init instead of usbhsg_ep_enable() */ + dcp->pipe = usbhs_dcp_malloc(priv); + dcp->pipe->mod_private = dcp; + usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); + + /* + * system config enble + * - HI speed + * - function + * - usb module + */ + usbhs_sys_function_ctrl(priv, 1); + usbhsg_update_pullup(priv); + + /* + * enable irq callback + */ + mod->irq_dev_state = usbhsg_irq_dev_state; + mod->irq_ctrl_stage = usbhsg_irq_ctrl_stage; + usbhs_irq_callback_update(priv, mod); + + return 0; +} + +static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + struct usbhsg_uep *uep; + struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + int ret = 0, i; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + usbhsg_status_clr(gpriv, status); + if (!usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && + !usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD)) + ret = -1; /* already done */ + + usbhs_unlock(priv, flags); + /******************** spin unlock ********************/ + + if (ret < 0) + return 0; /* already done is not error */ + + /* + * disable interrupt and systems if 1st try + */ + usbhs_fifo_quit(priv); + + /* disable all irq */ + mod->irq_dev_state = NULL; + mod->irq_ctrl_stage = NULL; + usbhs_irq_callback_update(priv, mod); + + gpriv->gadget.speed = USB_SPEED_UNKNOWN; + + /* disable sys */ + usbhs_sys_set_test_mode(priv, 0); + usbhs_sys_function_ctrl(priv, 0); + + /* disable all eps */ + usbhsg_for_each_uep_with_dcp(uep, gpriv, i) + usbhsg_ep_disable(&uep->ep); + + dev_dbg(dev, "stop gadget\n"); + + return 0; +} + +/* + * VBUS provided by the PHY + */ +static void usbhs_mod_phy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = &priv->mod_info; + + info->irq_vbus = NULL; + + usbhs_irq_callback_update(priv, NULL); +} + +/* + * + * linux usb function + * + */ +static int usbhsg_gadget_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + if (!driver || !driver->setup) + return -EINVAL; + + /* get vbus using phy versions */ + usbhs_mod_phy_mode(priv); + + /* first hook up the driver ... */ + gpriv->driver = driver; + + return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); +} + +static int usbhsg_gadget_stop(struct usb_gadget *gadget) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); + + gpriv->driver = NULL; + + return 0; +} + +/* + * usb gadget ops + */ +static int usbhsg_get_frame(struct usb_gadget *gadget) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + return usbhs_frame_get_num(priv); +} + +static int usbhsg_pullup(struct usb_gadget *gadget, int is_on) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + unsigned long flags; + + usbhs_lock(priv, flags); + if (is_on) + usbhsg_status_set(gpriv, USBHSG_STATUS_SOFT_CONNECT); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_SOFT_CONNECT); + usbhsg_update_pullup(priv); + usbhs_unlock(priv, flags); + + return 0; +} + +static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + + if (is_self) + usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED); + + return 0; +} + +static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + + gpriv->vbus_active = !!is_active; + + usbhsc_hotplug(priv); + + return 0; +} + +static const struct usb_gadget_ops usbhsg_gadget_ops = { + .get_frame = usbhsg_get_frame, + .set_selfpowered = usbhsg_set_selfpowered, + .udc_start = usbhsg_gadget_start, + .udc_stop = usbhsg_gadget_stop, + .pullup = usbhsg_pullup, + .vbus_session = usbhsg_vbus_session, +}; + +static int usbhsg_start(struct usbhs_priv *priv) +{ + return usbhsg_try_start(priv, USBHSG_STATUS_STARTED); +} + +static int usbhsg_stop(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + /* cable disconnect */ + if (gpriv->driver && + gpriv->driver->disconnect) + gpriv->driver->disconnect(&gpriv->gadget); + + return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); +} + +int usbhs_mod_gadget_probe(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv; + struct usbhsg_uep *uep; + struct device *dev = usbhs_priv_to_dev(priv); + struct renesas_usbhs_driver_pipe_config *pipe_configs = + usbhs_get_dparam(priv, pipe_configs); + int pipe_size = usbhs_get_dparam(priv, pipe_size); + int i; + int ret; + + gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); + if (!gpriv) + return -ENOMEM; + + uep = kcalloc(pipe_size, sizeof(struct usbhsg_uep), GFP_KERNEL); + if (!uep) { + ret = -ENOMEM; + goto usbhs_mod_gadget_probe_err_gpriv; + } + + /* + * CAUTION + * + * There is no guarantee that it is possible to access usb module here. + * Don't accesses to it. + * The accesse will be enable after "usbhsg_start" + */ + + /* + * register itself + */ + usbhs_mod_register(priv, &gpriv->mod, USBHS_GADGET); + + /* init gpriv */ + gpriv->mod.name = "gadget"; + gpriv->mod.start = usbhsg_start; + gpriv->mod.stop = usbhsg_stop; + gpriv->uep = uep; + gpriv->uep_size = pipe_size; + usbhsg_status_init(gpriv); + + /* + * init gadget + */ + gpriv->gadget.dev.parent = dev; + gpriv->gadget.name = "renesas_usbhs_udc"; + gpriv->gadget.ops = &usbhsg_gadget_ops; + gpriv->gadget.max_speed = USB_SPEED_HIGH; + + INIT_LIST_HEAD(&gpriv->gadget.ep_list); + + /* + * init usb_ep + */ + usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { + uep->gpriv = gpriv; + uep->pipe = NULL; + snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); + + uep->ep.name = uep->ep_name; + uep->ep.ops = &usbhsg_ep_ops; + INIT_LIST_HEAD(&uep->ep.ep_list); + spin_lock_init(&uep->lock); + + /* init DCP */ + if (usbhsg_is_dcp(uep)) { + gpriv->gadget.ep0 = &uep->ep; + usb_ep_set_maxpacket_limit(&uep->ep, 64); + uep->ep.caps.type_control = true; + } else { + /* init normal pipe */ + if (pipe_configs[i].type == USB_ENDPOINT_XFER_ISOC) + uep->ep.caps.type_iso = true; + if (pipe_configs[i].type == USB_ENDPOINT_XFER_BULK) + uep->ep.caps.type_bulk = true; + if (pipe_configs[i].type == USB_ENDPOINT_XFER_INT) + uep->ep.caps.type_int = true; + usb_ep_set_maxpacket_limit(&uep->ep, + pipe_configs[i].bufsize); + list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); + } + uep->ep.caps.dir_in = true; + uep->ep.caps.dir_out = true; + } + + ret = usb_add_gadget_udc(dev, &gpriv->gadget); + if (ret) + goto err_add_udc; + + + dev_info(dev, "gadget probed\n"); + + return 0; + +err_add_udc: + kfree(gpriv->uep); + +usbhs_mod_gadget_probe_err_gpriv: + kfree(gpriv); + + return ret; +} + +void usbhs_mod_gadget_remove(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + usb_del_gadget_udc(&gpriv->gadget); + + kfree(gpriv->uep); + kfree(gpriv); +} + +struct usb_gadget *usbhsg_get_gadget(struct usbhs_priv *priv) +{ + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + return &gpriv->gadget; +} diff --git a/drivers/usb/gadget/rcar/pipe.c b/drivers/usb/gadget/rcar/pipe.c new file mode 100644 index 00000000000..a2b24f38144 --- /dev/null +++ b/drivers/usb/gadget/rcar/pipe.c @@ -0,0 +1,849 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#include <linux/delay.h> +#include "common.h" +#include "pipe.h" + +/* + * macros + */ +#define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) + +#define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) +#define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) +#define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) +#define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) + +/* + * for debug + */ +static char *usbhsp_pipe_name[] = { + [USB_ENDPOINT_XFER_CONTROL] = "DCP", + [USB_ENDPOINT_XFER_BULK] = "BULK", + [USB_ENDPOINT_XFER_INT] = "INT", + [USB_ENDPOINT_XFER_ISOC] = "ISO", +}; + +char *usbhs_pipe_name(struct usbhs_pipe *pipe) +{ + return usbhsp_pipe_name[usbhs_pipe_type(pipe)]; +} + +static struct renesas_usbhs_driver_pipe_config +*usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num) +{ + struct renesas_usbhs_driver_pipe_config *pipe_configs = + usbhs_get_dparam(priv, pipe_configs); + + return &pipe_configs[pipe_num]; +} + +/* + * DCPCTR/PIPEnCTR functions + */ +static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + int offset = usbhsp_addr_offset(pipe); + + if (usbhs_pipe_is_dcp(pipe)) + usbhs_bset(priv, DCPCTR, mask, val); + else + usbhs_bset(priv, PIPEnCTR + offset, mask, val); +} + +static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + int offset = usbhsp_addr_offset(pipe); + + if (usbhs_pipe_is_dcp(pipe)) + return usbhs_read(priv, DCPCTR); + else + return usbhs_read(priv, PIPEnCTR + offset); +} + +/* + * DCP/PIPE functions + */ +static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, + u16 dcp_reg, u16 pipe_reg, + u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + if (usbhs_pipe_is_dcp(pipe)) + usbhs_bset(priv, dcp_reg, mask, val); + else + usbhs_bset(priv, pipe_reg, mask, val); +} + +static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, + u16 dcp_reg, u16 pipe_reg) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + if (usbhs_pipe_is_dcp(pipe)) + return usbhs_read(priv, dcp_reg); + else + return usbhs_read(priv, pipe_reg); +} + +/* + * DCPCFG/PIPECFG functions + */ +static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); +} + +static u16 usbhsp_pipe_cfg_get(struct usbhs_pipe *pipe) +{ + return __usbhsp_pipe_xxx_get(pipe, DCPCFG, PIPECFG); +} + +/* + * PIPEnTRN/PIPEnTRE functions + */ +static void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRN addresses were mapped randomly. + */ +#define CASE_PIPExTRN(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRN; \ + break; + + switch (num) { + CASE_PIPExTRN(1); + CASE_PIPExTRN(2); + CASE_PIPExTRN(3); + CASE_PIPExTRN(4); + CASE_PIPExTRN(5); + CASE_PIPExTRN(B); + CASE_PIPExTRN(C); + CASE_PIPExTRN(D); + CASE_PIPExTRN(E); + CASE_PIPExTRN(F); + CASE_PIPExTRN(9); + CASE_PIPExTRN(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +static void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int num = usbhs_pipe_number(pipe); + u16 reg; + + /* + * It is impossible to calculate address, + * since PIPEnTRE addresses were mapped randomly. + */ +#define CASE_PIPExTRE(a) \ + case 0x ## a: \ + reg = PIPE ## a ## TRE; \ + break; + + switch (num) { + CASE_PIPExTRE(1); + CASE_PIPExTRE(2); + CASE_PIPExTRE(3); + CASE_PIPExTRE(4); + CASE_PIPExTRE(5); + CASE_PIPExTRE(B); + CASE_PIPExTRE(C); + CASE_PIPExTRE(D); + CASE_PIPExTRE(E); + CASE_PIPExTRE(F); + CASE_PIPExTRE(9); + CASE_PIPExTRE(A); + default: + dev_err(dev, "unknown pipe (%d)\n", num); + return; + } + + __usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val); +} + +/* + * PIPEBUF + */ +static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + if (usbhs_pipe_is_dcp(pipe)) + return; + + __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); +} + +/* + * DCPMAXP/PIPEMAXP + */ +static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) +{ + __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); +} + +/* + * pipe control functions + */ +static void usbhsp_pipe_select(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + /* + * On pipe, this is necessary before + * accesses to below registers. + * + * PIPESEL : usbhsp_pipe_select + * PIPECFG : usbhsp_pipe_cfg_xxx + * PIPEBUF : usbhsp_pipe_buf_xxx + * PIPEMAXP : usbhsp_pipe_maxp_xxx + * PIPEPERI + */ + + /* + * if pipe is dcp, no pipe is selected. + * it is no problem, because dcp have its register + */ + usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); +} + +static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + int timeout = 1024; + u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK; + + /* + * make sure.... + * + * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is + * specified by the CURPIPE bits. + * When changing the setting of this bit after changing + * the PID bits for the selected pipe from BUF to NAK, + * check that CSSTS = 0 and PBUSY = 0. + */ + + /* + * CURPIPE bit = 0 + * + * see also + * "Operation" + * - "Pipe Control" + * - "Pipe Control Registers Switching Procedure" + */ + usbhs_write(priv, CFIFOSEL, 0); + usbhs_pipe_disable(pipe); + + do { + if (!(usbhsp_pipectrl_get(pipe) & mask)) + return 0; + + udelay(10); + + } while (timeout--); + + return -EBUSY; +} + +int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) +{ + u16 val; + + val = usbhsp_pipectrl_get(pipe); + if (val & BSTS) + return 0; + + return -EBUSY; +} + +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) +{ + u16 val; + + /* Do not support for DCP pipe */ + if (usbhs_pipe_is_dcp(pipe)) + return false; + + val = usbhsp_pipectrl_get(pipe); + if (val & INBUFM) + return true; + + return false; +} + +/* + * PID ctrl + */ +static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) +{ + u16 pid = usbhsp_pipectrl_get(pipe); + + pid &= PID_MASK; + + /* + * see + * "Pipe n Control Register" - "PID" + */ + switch (pid) { + case PID_STALL11: + usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); + fallthrough; + case PID_STALL10: + usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); + } +} + +void usbhs_pipe_disable(struct usbhs_pipe *pipe) +{ + int timeout = 1024; + u16 val; + + /* see "Pipe n Control Register" - "PID" */ + __usbhsp_pid_try_nak_if_stall(pipe); + + usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); + + do { + val = usbhsp_pipectrl_get(pipe); + val &= PBUSY; + if (!val) + break; + + udelay(10); + } while (timeout--); +} + +void usbhs_pipe_enable(struct usbhs_pipe *pipe) +{ + /* see "Pipe n Control Register" - "PID" */ + __usbhsp_pid_try_nak_if_stall(pipe); + + usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); +} + +void usbhs_pipe_stall(struct usbhs_pipe *pipe) +{ + u16 pid = usbhsp_pipectrl_get(pipe); + + pid &= PID_MASK; + + /* + * see + * "Pipe n Control Register" - "PID" + */ + switch (pid) { + case PID_NAK: + usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); + break; + case PID_BUF: + usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); + break; + } +} + +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) +{ + u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; + + return (int)(pid == PID_STALL10 || pid == PID_STALL11); +} + +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len) +{ + if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) + return; + + /* + * clear and disable transfer counter for IN/OUT pipe + */ + usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR); + + /* + * Only IN direction bulk pipe can use transfer count. + * Without using this function, + * received data will break if it was large data size. + * see PIPEnTRN/PIPEnTRE for detail + */ + if (usbhs_pipe_is_dir_in(pipe)) { + int maxp = usbhs_pipe_get_maxpacket(pipe); + + usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp)); + usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */ + } +} + + +/* + * pipe setup + */ +static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host, + int dir_in, u16 *pipecfg) +{ + u16 type = 0; + u16 bfre = 0; + u16 dblb = 0; + u16 cntmd = 0; + u16 dir = 0; + u16 epnum = 0; + u16 shtnak = 0; + static const u16 type_array[] = { + [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, + [USB_ENDPOINT_XFER_INT] = TYPE_INT, + [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, + }; + + if (usbhs_pipe_is_dcp(pipe)) + return -EINVAL; + + /* + * PIPECFG + * + * see + * - "Register Descriptions" - "PIPECFG" register + * - "Features" - "Pipe configuration" + * - "Operation" - "Pipe Control" + */ + + /* TYPE */ + type = type_array[usbhs_pipe_type(pipe)]; + + /* BFRE */ + if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || + usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) + bfre = 0; /* FIXME */ + + /* DBLB: see usbhs_pipe_config_update() */ + + /* CNTMD */ + if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) + cntmd = 0; /* FIXME */ + + /* DIR */ + if (dir_in) + usbhsp_flags_set(pipe, IS_DIR_HOST); + + if (!!is_host ^ !!dir_in) + dir |= DIR_OUT; + + if (!dir) + usbhsp_flags_set(pipe, IS_DIR_IN); + + /* SHTNAK */ + if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) && + !dir) + shtnak = SHTNAK; + + /* EPNUM */ + epnum = 0; /* see usbhs_pipe_config_update() */ + *pipecfg = type | + bfre | + dblb | + cntmd | + dir | + shtnak | + epnum; + return 0; +} + +static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct device *dev = usbhs_priv_to_dev(priv); + int pipe_num = usbhs_pipe_number(pipe); + u16 buff_size; + u16 bufnmb; + u16 bufnmb_cnt; + struct renesas_usbhs_driver_pipe_config *pipe_config = + usbhsp_get_pipe_config(priv, pipe_num); + + /* + * PIPEBUF + * + * see + * - "Register Descriptions" - "PIPEBUF" register + * - "Features" - "Pipe configuration" + * - "Operation" - "FIFO Buffer Memory" + * - "Operation" - "Pipe Control" + */ + buff_size = pipe_config->bufsize; + bufnmb = pipe_config->bufnum; + + /* change buff_size to register value */ + bufnmb_cnt = (buff_size / 64) - 1; + + dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n", + pipe_num, buff_size, bufnmb); + + return (0x1f & bufnmb_cnt) << 10 | + (0xff & bufnmb) << 0; +} + +void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, + u16 epnum, u16 maxp) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + int pipe_num = usbhs_pipe_number(pipe); + struct renesas_usbhs_driver_pipe_config *pipe_config = + usbhsp_get_pipe_config(priv, pipe_num); + u16 dblb = pipe_config->double_buf ? DBLB : 0; + + if (devsel > 0xA) { + struct device *dev = usbhs_priv_to_dev(priv); + + dev_err(dev, "devsel error %d\n", devsel); + + devsel = 0; + } + + usbhsp_pipe_barrier(pipe); + + pipe->maxp = maxp; + + usbhsp_pipe_select(pipe); + usbhsp_pipe_maxp_set(pipe, 0xFFFF, + (devsel << 12) | + maxp); + + if (!usbhs_pipe_is_dcp(pipe)) + usbhsp_pipe_cfg_set(pipe, 0x000F | DBLB, epnum | dblb); +} + +/* + * pipe control + */ +int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) +{ + /* + * see + * usbhs_pipe_config_update() + * usbhs_dcp_malloc() + */ + return pipe->maxp; +} + +int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) +{ + return usbhsp_flags_has(pipe, IS_DIR_IN); +} + +int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) +{ + return usbhsp_flags_has(pipe, IS_DIR_HOST); +} + +int usbhs_pipe_is_running(struct usbhs_pipe *pipe) +{ + return usbhsp_flags_has(pipe, IS_RUNNING); +} + +void usbhs_pipe_running(struct usbhs_pipe *pipe, int running) +{ + if (running) + usbhsp_flags_set(pipe, IS_RUNNING); + else + usbhsp_flags_clr(pipe, IS_RUNNING); +} + +void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) +{ + u16 mask = (SQCLR | SQSET); + u16 val; + + /* + * sequence + * 0 : data0 + * 1 : data1 + * -1 : no change + */ + switch (sequence) { + case 0: + val = SQCLR; + break; + case 1: + val = SQSET; + break; + default: + return; + } + + usbhsp_pipectrl_set(pipe, mask, val); +} + +static int usbhs_pipe_get_data_sequence(struct usbhs_pipe *pipe) +{ + return !!(usbhsp_pipectrl_get(pipe) & SQMON); +} + +void usbhs_pipe_clear(struct usbhs_pipe *pipe) +{ + if (usbhs_pipe_is_dcp(pipe)) { + usbhs_fifo_clear_dcp(pipe); + } else { + usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); + usbhsp_pipectrl_set(pipe, ACLRM, 0); + } +} + +/* Should call usbhsp_pipe_select() before */ +void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, + int needs_bfre, int bfre_enable) +{ + int sequence; + + usbhsp_pipe_select(pipe); + sequence = usbhs_pipe_get_data_sequence(pipe); + if (needs_bfre) + usbhsp_pipe_cfg_set(pipe, BFRE, bfre_enable ? BFRE : 0); + usbhs_pipe_clear(pipe); + usbhs_pipe_data_sequence(pipe, sequence); +} + +void usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable) +{ + if (usbhs_pipe_is_dcp(pipe)) + return; + + usbhsp_pipe_select(pipe); + /* check if the driver needs to change the BFRE value */ + if (!(enable ^ !!(usbhsp_pipe_cfg_get(pipe) & BFRE))) + return; + + usbhs_pipe_clear_without_sequence(pipe, 1, enable); +} + +static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) +{ + struct usbhs_pipe *pos, *pipe; + int i; + + /* + * find target pipe + */ + pipe = NULL; + usbhs_for_each_pipe_with_dcp(pos, priv, i) { + if (!usbhs_pipe_type_is(pos, type)) + continue; + if (usbhsp_flags_has(pos, IS_USED)) + continue; + + pipe = pos; + break; + } + + if (!pipe) + return NULL; + + /* + * initialize pipe flags + */ + usbhsp_flags_init(pipe); + usbhsp_flags_set(pipe, IS_USED); + + return pipe; +} + +static void usbhsp_put_pipe(struct usbhs_pipe *pipe) +{ + usbhsp_flags_init(pipe); +} + +void usbhs_pipe_init(struct usbhs_priv *priv, + int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) +{ + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct usbhs_pipe *pipe; + int i; + + usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + usbhsp_flags_init(pipe); + pipe->fifo = NULL; + pipe->mod_private = NULL; + INIT_LIST_HEAD(&pipe->list); + + /* pipe force init */ + usbhs_pipe_clear(pipe); + } + + info->dma_map_ctrl = dma_map_ctrl; +} + +struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, + int endpoint_type, + int dir_in) +{ + struct device *dev = usbhs_priv_to_dev(priv); + struct usbhs_pipe *pipe; + int is_host = usbhs_mod_is_host(priv); + int ret; + u16 pipecfg, pipebuf; + + pipe = usbhsp_get_pipe(priv, endpoint_type); + if (!pipe) { + dev_err(dev, "can't get pipe (%s)\n", + usbhsp_pipe_name[endpoint_type]); + return NULL; + } + + INIT_LIST_HEAD(&pipe->list); + + usbhs_pipe_disable(pipe); + + /* make sure pipe is not busy */ + ret = usbhsp_pipe_barrier(pipe); + if (ret < 0) { + dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); + return NULL; + } + + if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { + dev_err(dev, "can't setup pipe\n"); + return NULL; + } + + pipebuf = usbhsp_setup_pipebuff(pipe); + + usbhsp_pipe_select(pipe); + usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); + usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); + usbhs_pipe_clear(pipe); + + usbhs_pipe_sequence_data0(pipe); + + dev_dbg(dev, "enable pipe %d : %s (%s)\n", + usbhs_pipe_number(pipe), + usbhs_pipe_name(pipe), + usbhs_pipe_is_dir_in(pipe) ? "in" : "out"); + + /* + * epnum / maxp are still not set to this pipe. + * call usbhs_pipe_config_update() after this function !! + */ + + return pipe; +} + +void usbhs_pipe_free(struct usbhs_pipe *pipe) +{ + usbhsp_pipe_select(pipe); + usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0); + usbhsp_put_pipe(pipe); +} + +void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) +{ + if (pipe->fifo) + pipe->fifo->pipe = NULL; + + pipe->fifo = fifo; + + if (fifo) + fifo->pipe = pipe; +} + + +/* + * dcp control + */ +struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) +{ + struct usbhs_pipe *pipe; + + pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); + if (!pipe) + return NULL; + + INIT_LIST_HEAD(&pipe->list); + + /* + * call usbhs_pipe_config_update() after this function !! + */ + + return pipe; +} + +void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + + WARN_ON(!usbhs_pipe_is_dcp(pipe)); + + usbhs_pipe_enable(pipe); + + if (!usbhs_mod_is_host(priv)) /* funconly */ + usbhsp_pipectrl_set(pipe, CCPL, CCPL); +} + +void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out) +{ + usbhsp_pipe_cfg_set(pipe, DIR_OUT, + dir_out ? DIR_OUT : 0); +} + +/* + * pipe module function + */ +int usbhs_pipe_probe(struct usbhs_priv *priv) +{ + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct usbhs_pipe *pipe; + struct device *dev = usbhs_priv_to_dev(priv); + struct renesas_usbhs_driver_pipe_config *pipe_configs = + usbhs_get_dparam(priv, pipe_configs); + int pipe_size = usbhs_get_dparam(priv, pipe_size); + int i; + + /* This driver expects 1st pipe is DCP */ + if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) { + dev_err(dev, "1st PIPE is not DCP\n"); + return -EINVAL; + } + + info->pipe = kcalloc(pipe_size, sizeof(struct usbhs_pipe), + GFP_KERNEL); + if (!info->pipe) + return -ENOMEM; + + info->size = pipe_size; + + /* + * init pipe + */ + usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + pipe->priv = priv; + + usbhs_pipe_type(pipe) = + pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK; + + dev_dbg(dev, "pipe %x\t: %s\n", + i, usbhsp_pipe_name[pipe_configs[i].type]); + } + + return 0; +} + +void usbhs_pipe_remove(struct usbhs_priv *priv) +{ + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + + kfree(info->pipe); +} diff --git a/drivers/usb/gadget/rcar/pipe.h b/drivers/usb/gadget/rcar/pipe.h new file mode 100644 index 00000000000..01c15178a28 --- /dev/null +++ b/drivers/usb/gadget/rcar/pipe.h @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB driver + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + */ +#ifndef RENESAS_USB_PIPE_H +#define RENESAS_USB_PIPE_H + +#include "common.h" +#include "fifo.h" + +/* + * struct + */ +struct usbhs_pipe { + u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */ + + struct usbhs_priv *priv; + struct usbhs_fifo *fifo; + struct list_head list; + + int maxp; + + u32 flags; +#define USBHS_PIPE_FLAGS_IS_USED (1 << 0) +#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1) +#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2) +#define USBHS_PIPE_FLAGS_IS_RUNNING (1 << 3) + + const struct usbhs_pkt_handle *handler; + + void *mod_private; +}; + +struct usbhs_pipe_info { + struct usbhs_pipe *pipe; + int size; /* array size of "pipe" */ + + int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map); +}; + +/* + * pipe list + */ +#define __usbhs_for_each_pipe(start, pos, info, i) \ + for ((i) = start; \ + ((i) < (info)->size) && ((pos) = (info)->pipe + (i)); \ + (i)++) + +#define usbhs_for_each_pipe(pos, priv, i) \ + __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i) + +#define usbhs_for_each_pipe_with_dcp(pos, priv, i) \ + __usbhs_for_each_pipe(0, pos, &((priv)->pipe_info), i) + +/* + * data + */ +#define usbhs_priv_to_pipeinfo(pr) (&(pr)->pipe_info) + +/* + * pipe control + */ +char *usbhs_pipe_name(struct usbhs_pipe *pipe); +struct usbhs_pipe +*usbhs_pipe_malloc(struct usbhs_priv *priv, int endpoint_type, int dir_in); +void usbhs_pipe_free(struct usbhs_pipe *pipe); +int usbhs_pipe_probe(struct usbhs_priv *priv); +void usbhs_pipe_remove(struct usbhs_priv *priv); +int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); +int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); +int usbhs_pipe_is_running(struct usbhs_pipe *pipe); +void usbhs_pipe_running(struct usbhs_pipe *pipe, int running); + +void usbhs_pipe_init(struct usbhs_priv *priv, + int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); +int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); +void usbhs_pipe_clear(struct usbhs_pipe *pipe); +void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, + int needs_bfre, int bfre_enable); +int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); +void usbhs_pipe_enable(struct usbhs_pipe *pipe); +void usbhs_pipe_disable(struct usbhs_pipe *pipe); +void usbhs_pipe_stall(struct usbhs_pipe *pipe); +int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); +void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len); +void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); +void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, + u16 epnum, u16 maxp); +void usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable); + +#define usbhs_pipe_sequence_data0(pipe) usbhs_pipe_data_sequence(pipe, 0) +#define usbhs_pipe_sequence_data1(pipe) usbhs_pipe_data_sequence(pipe, 1) +void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data); + +#define usbhs_pipe_to_priv(p) ((p)->priv) +#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe) +#define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p)) +#define usbhs_pipe_to_fifo(p) ((p)->fifo) +#define usbhs_pipe_is_busy(p) usbhs_pipe_to_fifo(p) + +#define usbhs_pipe_type(p) ((p)->pipe_type) +#define usbhs_pipe_type_is(p, t) ((p)->pipe_type == t) + +/* + * dcp control + */ +struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv); +void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe); +void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out); + +#endif /* RENESAS_USB_PIPE_H */ diff --git a/drivers/usb/gadget/rcar/renesas_usb.h b/drivers/usb/gadget/rcar/renesas_usb.h new file mode 100644 index 00000000000..8155e3dcaf6 --- /dev/null +++ b/drivers/usb/gadget/rcar/renesas_usb.h @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * Renesas USB + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * Ported to u-boot + * Copyright (C) 2016 GlobalLogic + */ +#ifndef RENESAS_USB_H +#define RENESAS_USB_H + +#include <linux/usb/ch9.h> +#include <linux/compat.h> + +struct platform_device { + const char *name; + struct device dev; +}; + +/* + * module type + * + * it will be return value from get_id + */ +enum { + USBHS_HOST = 0, + USBHS_GADGET, + USBHS_MAX, +}; + +/* + * parameters for renesas usbhs + * + * some register needs USB chip specific parameters. + * This struct show it to driver + */ + +struct renesas_usbhs_driver_pipe_config { + u8 type; /* USB_ENDPOINT_XFER_xxx */ + u16 bufsize; + u8 bufnum; + bool double_buf; +}; +#define RENESAS_USBHS_PIPE(_type, _size, _num, _double_buf) { \ + .type = (_type), \ + .bufsize = (_size), \ + .bufnum = (_num), \ + .double_buf = (_double_buf), \ + } + +struct renesas_usbhs_driver_param { + /* + * pipe settings + */ + struct renesas_usbhs_driver_pipe_config *pipe_configs; + int pipe_size; /* pipe_configs array size */ + + /* + * option: + * + * for BUSWAIT :: BWAIT + * see + * renesas_usbhs/common.c :: usbhsc_set_buswait() + * */ + int buswait_bwait; + + /* + * option: + * + * delay time from notify_hotplug callback + */ + int detection_delay; /* msec */ + + /* + * option: + * + * dma id for dmaengine + * The data transfer direction on D0FIFO/D1FIFO should be + * fixed for keeping consistency. + * So, the platform id settings will be.. + * .d0_tx_id = xx_TX, + * .d1_rx_id = xx_RX, + * or + * .d1_tx_id = xx_TX, + * .d0_rx_id = xx_RX, + */ + int d0_tx_id; + int d0_rx_id; + int d1_tx_id; + int d1_rx_id; + int d2_tx_id; + int d2_rx_id; + int d3_tx_id; + int d3_rx_id; + + /* + * option: + * + * pio <--> dma border. + */ + int pio_dma_border; /* default is 64byte */ + + uintptr_t type; + u32 enable_gpio; + + /* + * option: + */ + u32 has_otg:1; /* for controlling PWEN/EXTLP */ + u32 has_sudmac:1; /* for SUDMAC */ + u32 has_usb_dmac:1; /* for USB-DMAC */ + u32 cfifo_byte_addr:1; /* CFIFO is byte addressable */ +#define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */ + u32 multi_clks:1; + u32 has_new_pipe_configs:1; +}; + +#define USBHS_TYPE_RCAR_GEN3 2 + +struct usbhs_priv; +struct usb_gadget *usbhsg_get_gadget(struct usbhs_priv *priv); + +#endif /* RENESAS_USB_H */ diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index 467c566f6d3..4b6a8fdfeee 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -2,9 +2,9 @@ # # USB peripheral controller drivers -ifndef CONFIG_$(SPL_)DM_USB_GADGET +ifndef CONFIG_$(XPL_)DM_USB_GADGET obj-$(CONFIG_USB_DWC3_GADGET) += udc-core.o endif -obj-$(CONFIG_$(SPL_)DM_USB_GADGET) += udc-core.o +obj-$(CONFIG_$(XPL_)DM_USB_GADGET) += udc-core.o obj-y += udc-uclass.o diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 9e880195ec6..301bb9fdee1 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -3,13 +3,13 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -ifdef CONFIG_$(SPL_)DM_USB +ifdef CONFIG_$(XPL_)DM_USB obj-y += usb-uclass.o obj-$(CONFIG_SANDBOX) += usb-sandbox.o endif -ifdef CONFIG_$(SPL_TPL_)USB_STORAGE -obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += usb_bootdev.o +ifdef CONFIG_$(PHASE_)USB_STORAGE +obj-$(CONFIG_$(PHASE_)BOOTSTD) += usb_bootdev.o endif # ohci diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 343893b9f19..7c73eb66b60 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -66,9 +66,24 @@ enum usb_ctlr_type { USB_CTRL_COUNT, }; +struct tegra_utmip_config { + u32 hssync_start_delay; + u32 elastic_limit; + u32 idle_wait_delay; + u32 term_range_adj; + bool xcvr_setup_use_fuses; + u32 xcvr_setup; + u32 xcvr_lsfslew; + u32 xcvr_lsrslew; + u32 xcvr_hsslew; + u32 hssquelch_level; + u32 hsdiscon_level; +}; + /* Information about a USB port */ struct fdt_usb { struct ehci_ctrl ehci; + struct tegra_utmip_config utmip_config; struct usb_ctlr *reg; /* address of registers in physical memory */ unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */ unsigned ulpi:1; /* 1 if port has external ULPI transceiver */ @@ -192,15 +207,6 @@ static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { { 0x028, 0x01, 0x01, 0x0, 0, 0x02, 0x2F, 0x08, 0x76, 65000, 5 } }; -/* UTMIP Idle Wait Delay */ -static const u8 utmip_idle_wait_delay = 17; - -/* UTMIP Elastic limit */ -static const u8 utmip_elastic_limit = 16; - -/* UTMIP High Speed Sync Start Delay */ -static const u8 utmip_hs_sync_start_delay = 9; - struct fdt_usb_controller { /* flag to determine whether controller supports hostpc register */ u32 has_hostpc:1; @@ -377,6 +383,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config, u32 b_sess_valid_mask, val; int loop_count; const unsigned *timing; + struct tegra_utmip_config *utmip_config = &config->utmip_config; struct usb_ctlr *usbctlr = config->reg; struct clk_rst_ctlr *clkrst; struct usb_ctlr *usb1ctlr; @@ -463,16 +470,29 @@ static int init_utmi_usb_controller(struct fdt_usb *config, /* Recommended PHY settings for EYE diagram */ val = readl(&usbctlr->utmip_xcvr_cfg0); - clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK, - 0x4 << UTMIP_XCVR_SETUP_SHIFT); - clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK, - 0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT); - clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK, - 0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT); + + if (!utmip_config->xcvr_setup_use_fuses) { + clrsetbits_le32(&val, UTMIP_XCVR_SETUP(~0), + UTMIP_XCVR_SETUP(utmip_config->xcvr_setup)); + clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB(~0), + UTMIP_XCVR_SETUP_MSB(utmip_config->xcvr_setup)); + } + + clrsetbits_le32(&val, UTMIP_XCVR_LSFSLEW(~0), + UTMIP_XCVR_LSFSLEW(utmip_config->xcvr_lsfslew)); + clrsetbits_le32(&val, UTMIP_XCVR_LSRSLEW(~0), + UTMIP_XCVR_LSRSLEW(utmip_config->xcvr_lsrslew)); + + clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW(~0), + UTMIP_XCVR_HSSLEW(utmip_config->xcvr_hsslew)); + clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB(~0), + UTMIP_XCVR_HSSLEW_MSB(utmip_config->xcvr_hsslew)); writel(val, &usbctlr->utmip_xcvr_cfg0); + clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_XCVR_TERM_RANGE_ADJ_MASK, - 0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT); + utmip_config->term_range_adj << + UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT); /* Some registers can be controlled from USB1 only. */ if (config->periph_id != PERIPH_ID_USBD) { @@ -485,9 +505,11 @@ static int init_utmi_usb_controller(struct fdt_usb *config, val = readl(&usb1ctlr->utmip_bias_cfg0); setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB); clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK, - 0x1 << UTMIP_HSDISCON_LEVEL_SHIFT); + utmip_config->hsdiscon_level << + UTMIP_HSDISCON_LEVEL_SHIFT); clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK, - 0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT); + utmip_config->hssquelch_level << + UTMIP_HSSQUELCH_LEVEL_SHIFT); writel(val, &usb1ctlr->utmip_bias_cfg0); /* Miscellaneous setting mentioned in Programming Guide */ @@ -521,7 +543,11 @@ static int init_utmi_usb_controller(struct fdt_usb *config, setbits_le32(&usbctlr->utmip_bat_chrg_cfg0, UTMIP_PD_CHRG); clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_XCVR_LSBIAS_SE); - setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL); + + if (utmip_config->xcvr_setup_use_fuses) + setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL); + else + clrbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL); /* * Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT @@ -535,15 +561,16 @@ static int init_utmi_usb_controller(struct fdt_usb *config, /* Set PLL enable delay count and Crystal frequency count */ val = readl(&usbctlr->utmip_hsrx_cfg0); clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK, - utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT); + utmip_config->idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT); clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK, - utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT); + utmip_config->elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT); writel(val, &usbctlr->utmip_hsrx_cfg0); /* Configure the UTMIP_HS_SYNC_START_DLY */ clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1, UTMIP_HS_SYNC_START_DLY_MASK, - utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT); + utmip_config->hssync_start_delay << + UTMIP_HS_SYNC_START_DLY_SHIFT); /* Preceed the crystal clock disable by >100ns delay. */ udelay(1); @@ -763,6 +790,69 @@ static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config) return 0; } +static void fdt_decode_usb_phy(struct udevice *dev) +{ + struct fdt_usb *priv = dev_get_priv(dev); + struct tegra_utmip_config *utmip_config = &priv->utmip_config; + u32 usb_phy_phandle; + ofnode usb_phy_node; + int ret; + + ret = ofnode_read_u32(dev_ofnode(dev), "nvidia,phy", &usb_phy_phandle); + if (ret) + log_debug("%s: required usb phy node isn't provided\n", __func__); + + usb_phy_node = ofnode_get_by_phandle(usb_phy_phandle); + if (!ofnode_valid(usb_phy_node) || !ofnode_is_enabled(usb_phy_node)) { + log_debug("%s: failed to find usb phy node or it is disabled\n", __func__); + utmip_config->xcvr_setup_use_fuses = true; + } else { + utmip_config->xcvr_setup_use_fuses = + ofnode_read_bool(usb_phy_node, "nvidia,xcvr-setup-use-fuses"); + } + + utmip_config->hssync_start_delay = + ofnode_read_u32_default(usb_phy_node, + "nvidia,hssync-start-delay", 0x9); + + utmip_config->elastic_limit = + ofnode_read_u32_default(usb_phy_node, + "nvidia,elastic-limit", 0x10); + + utmip_config->idle_wait_delay = + ofnode_read_u32_default(usb_phy_node, + "nvidia,idle-wait-delay", 0x11); + + utmip_config->term_range_adj = + ofnode_read_u32_default(usb_phy_node, + "nvidia,term-range-adj", 0x7); + + utmip_config->xcvr_lsfslew = + ofnode_read_u32_default(usb_phy_node, + "nvidia,xcvr-lsfslew", 0x0); + + utmip_config->xcvr_lsrslew = + ofnode_read_u32_default(usb_phy_node, + "nvidia,xcvr-lsrslew", 0x3); + + utmip_config->xcvr_hsslew = + ofnode_read_u32_default(usb_phy_node, + "nvidia,xcvr-hsslew", 0x8); + + utmip_config->hssquelch_level = + ofnode_read_u32_default(usb_phy_node, + "nvidia,hssquelch-level", 0x2); + + utmip_config->hsdiscon_level = + ofnode_read_u32_default(usb_phy_node, + "nvidia,hsdiscon-level", 0x1); + + if (!utmip_config->xcvr_setup_use_fuses) { + ofnode_read_u32(usb_phy_node, "nvidia,xcvr-setup", + &utmip_config->xcvr_setup); + } +} + int usb_common_init(struct fdt_usb *config, enum usb_init_type init) { int ret = 0; @@ -850,6 +940,8 @@ static int ehci_usb_of_to_plat(struct udevice *dev) priv->type = dev_get_driver_data(dev); + fdt_decode_usb_phy(dev); + return 0; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 68cf08e0b6b..34eb4536f0e 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -17,6 +17,7 @@ #include <log.h> #include <asm/byteorder.h> #include <usb.h> +#include <watchdog.h> #include <asm/unaligned.h> #include <linux/bug.h> #include <linux/errno.h> @@ -796,6 +797,8 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, /* Calculate length for next transfer */ addr += trb_buff_len; trb_buff_len = min((length - running_total), TRB_MAX_BUFF_SIZE); + + schedule(); } while (running_total < length); giveback_first_trb(udev, ep_index, start_cycle, start_trb); diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index f8e14eabfb2..26fee141f6e 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -266,7 +266,7 @@ U_BOOT_DRIVER(mtu3_peripheral) = { #endif #if defined(CONFIG_SPL_USB_HOST) || \ - (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) + (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST)) static int mtu3_host_probe(struct udevice *dev) { struct ssusb_mtk *ssusb = dev_to_ssusb(dev->parent); @@ -334,7 +334,7 @@ static int mtu3_glue_bind(struct udevice *parent) #endif #if defined(CONFIG_SPL_USB_HOST) || \ - (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) + (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST)) case USB_DR_MODE_HOST: dev_dbg(parent, "%s: dr_mode: host\n", __func__); driver = "mtu3-host"; diff --git a/drivers/usb/tcpm/Kconfig b/drivers/usb/tcpm/Kconfig new file mode 100644 index 00000000000..9be4b496e82 --- /dev/null +++ b/drivers/usb/tcpm/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 + +config TYPEC_TCPM + tristate "USB Type-C Port Controller Manager" + depends on DM + help + The Type-C Port Controller Manager provides a USB PD and USB Type-C + state machine for use with Type-C Port Controllers. + +config TYPEC_FUSB302 + tristate "Fairchild FUSB302 Type-C chip driver" + depends on DM && DM_I2C && TYPEC_TCPM + help + The Fairchild FUSB302 Type-C chip driver that works with + Type-C Port Controller Manager to provide USB PD and USB + Type-C functionalities. diff --git a/drivers/usb/tcpm/Makefile b/drivers/usb/tcpm/Makefile new file mode 100644 index 00000000000..668d33155bf --- /dev/null +++ b/drivers/usb/tcpm/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_TYPEC_TCPM) += tcpm.o tcpm-uclass.o +obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o diff --git a/drivers/usb/tcpm/fusb302.c b/drivers/usb/tcpm/fusb302.c new file mode 100644 index 00000000000..fe93ff3d339 --- /dev/null +++ b/drivers/usb/tcpm/fusb302.c @@ -0,0 +1,1323 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2016-2017 Google, Inc + * + * Fairchild FUSB302 Type-C Chip Driver + */ + +#include <dm.h> +#include <i2c.h> +#include <asm/gpio.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <dm/device_compat.h> +#include <usb/tcpm.h> +#include "fusb302_reg.h" + +#define FUSB302_MAX_MSG_LEN 0x1F + +enum toggling_mode { + TOGGLING_MODE_OFF, + TOGGLING_MODE_DRP, + TOGGLING_MODE_SNK, + TOGGLING_MODE_SRC, +}; + +enum src_current_status { + SRC_CURRENT_DEFAULT, + SRC_CURRENT_MEDIUM, + SRC_CURRENT_HIGH, +}; + +static const u8 ra_mda_value[] = { + [SRC_CURRENT_DEFAULT] = 4, /* 210mV */ + [SRC_CURRENT_MEDIUM] = 9, /* 420mV */ + [SRC_CURRENT_HIGH] = 18, /* 798mV */ +}; + +static const u8 rd_mda_value[] = { + [SRC_CURRENT_DEFAULT] = 38, /* 1638mV */ + [SRC_CURRENT_MEDIUM] = 38, /* 1638mV */ + [SRC_CURRENT_HIGH] = 61, /* 2604mV */ +}; + +struct fusb302_chip { + enum toggling_mode toggling_mode; + enum src_current_status src_current_status; + bool intr_togdone; + bool intr_bc_lvl; + bool intr_comp_chng; + + /* port status */ + bool vconn_on; + bool vbus_present; + enum typec_cc_polarity cc_polarity; + enum typec_cc_status cc1; + enum typec_cc_status cc2; +}; + +static int fusb302_i2c_write(struct udevice *dev, u8 address, u8 data) +{ + int ret; + + ret = dm_i2c_write(dev, address, &data, 1); + if (ret) + dev_err(dev, "cannot write 0x%02x to 0x%02x, ret=%d\n", + data, address, ret); + + return ret; +} + +static int fusb302_i2c_block_write(struct udevice *dev, u8 address, + u8 length, const u8 *data) +{ + int ret; + + if (!length) + return 0; + + ret = dm_i2c_write(dev, address, data, length); + if (ret) + dev_err(dev, "cannot block write 0x%02x, len=%d, ret=%d\n", + address, length, ret); + + return ret; +} + +static int fusb302_i2c_read(struct udevice *dev, u8 address, u8 *data) +{ + int ret, retries; + + for (retries = 0; retries < 3; retries++) { + ret = dm_i2c_read(dev, address, data, 1); + if (ret == 0) + return ret; + dev_err(dev, "cannot read %02x, ret=%d\n", address, ret); + } + + return ret; +} + +static int fusb302_i2c_block_read(struct udevice *dev, u8 address, + u8 length, u8 *data) +{ + int ret; + + if (!length) + return 0; + + ret = dm_i2c_read(dev, address, data, length); + if (ret) + dev_err(dev, "cannot block read 0x%02x, len=%d, ret=%d\n", + address, length, ret); + return ret; +} + +static int fusb302_i2c_mask_write(struct udevice *dev, u8 address, + u8 mask, u8 value) +{ + int ret; + u8 data; + + ret = fusb302_i2c_read(dev, address, &data); + if (ret) + return ret; + data &= ~mask; + data |= value; + ret = fusb302_i2c_write(dev, address, data); + if (ret) + return ret; + + return ret; +} + +static int fusb302_i2c_set_bits(struct udevice *dev, u8 address, u8 set_bits) +{ + return fusb302_i2c_mask_write(dev, address, 0x00, set_bits); +} + +static int fusb302_i2c_clear_bits(struct udevice *dev, u8 address, u8 clear_bits) +{ + return fusb302_i2c_mask_write(dev, address, clear_bits, 0x00); +} + +static int fusb302_sw_reset(struct udevice *dev) +{ + int ret = fusb302_i2c_write(dev, FUSB_REG_RESET, FUSB_REG_RESET_SW_RESET); + + if (ret) + dev_err(dev, "cannot sw reset the fusb302: %d\n", ret); + + return ret; +} + +static int fusb302_enable_tx_auto_retries(struct udevice *dev, u8 retry_count) +{ + int ret; + + ret = fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL3, retry_count | + FUSB_REG_CONTROL3_AUTO_RETRY); + + return ret; +} + +/* + * mask all interrupt on the chip + */ +static int fusb302_mask_interrupt(struct udevice *dev) +{ + int ret; + + ret = fusb302_i2c_write(dev, FUSB_REG_MASK, 0xFF); + if (ret) + return ret; + ret = fusb302_i2c_write(dev, FUSB_REG_MASKA, 0xFF); + if (ret) + return ret; + ret = fusb302_i2c_write(dev, FUSB_REG_MASKB, 0xFF); + if (ret) + return ret; + ret = fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_INT_MASK); + return ret; +} + +/* + * initialize interrupt on the chip + * - unmasked interrupt: VBUS_OK + */ +static int fusb302_init_interrupt(struct udevice *dev) +{ + int ret; + + ret = fusb302_i2c_write(dev, FUSB_REG_MASK, + 0xFF & ~FUSB_REG_MASK_VBUSOK); + if (ret) + return ret; + ret = fusb302_i2c_write(dev, FUSB_REG_MASKA, 0xFF); + if (ret) + return ret; + ret = fusb302_i2c_write(dev, FUSB_REG_MASKB, 0xFF); + if (ret) + return ret; + ret = fusb302_i2c_clear_bits(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_INT_MASK); + return ret; +} + +static int fusb302_set_power_mode(struct udevice *dev, u8 power_mode) +{ + int ret; + + ret = fusb302_i2c_write(dev, FUSB_REG_POWER, power_mode); + + return ret; +} + +static int fusb302_init(struct udevice *dev) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + u8 data; + + ret = fusb302_sw_reset(dev); + if (ret) + return ret; + ret = fusb302_enable_tx_auto_retries(dev, FUSB_REG_CONTROL3_N_RETRIES_3); + if (ret) + return ret; + ret = fusb302_init_interrupt(dev); + if (ret) + return ret; + ret = fusb302_set_power_mode(dev, FUSB_REG_POWER_PWR_ALL); + if (ret) + return ret; + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &data); + if (ret) + return ret; + chip->vbus_present = !!(data & FUSB_REG_STATUS0_VBUSOK); + ret = fusb302_i2c_read(dev, FUSB_REG_DEVICE_ID, &data); + if (ret) + return ret; + dev_info(dev, "fusb302 device ID: 0x%02x\n", data); + + return ret; +} + +static int fusb302_get_vbus(struct udevice *dev) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + + return chip->vbus_present ? 1 : 0; +} + +static int fusb302_set_src_current(struct udevice *dev, + enum src_current_status status) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + + chip->src_current_status = status; + switch (status) { + case SRC_CURRENT_DEFAULT: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_HOST_CUR_MASK, + FUSB_REG_CONTROL0_HOST_CUR_DEF); + break; + case SRC_CURRENT_MEDIUM: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_HOST_CUR_MASK, + FUSB_REG_CONTROL0_HOST_CUR_MED); + break; + case SRC_CURRENT_HIGH: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_HOST_CUR_MASK, + FUSB_REG_CONTROL0_HOST_CUR_HIGH); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int fusb302_set_toggling(struct udevice *dev, + enum toggling_mode mode) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + + /* first disable toggling */ + ret = fusb302_i2c_clear_bits(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_TOGGLE); + if (ret) + return ret; + /* mask interrupts for SRC or SNK */ + ret = fusb302_i2c_set_bits(dev, FUSB_REG_MASK, + FUSB_REG_MASK_BC_LVL | + FUSB_REG_MASK_COMP_CHNG); + if (ret) + return ret; + chip->intr_bc_lvl = false; + chip->intr_comp_chng = false; + /* configure toggling mode: none/snk/src/drp */ + switch (mode) { + case TOGGLING_MODE_OFF: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_MODE_MASK, + FUSB_REG_CONTROL2_MODE_NONE); + break; + case TOGGLING_MODE_SNK: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_MODE_MASK, + FUSB_REG_CONTROL2_MODE_UFP); + break; + case TOGGLING_MODE_SRC: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_MODE_MASK, + FUSB_REG_CONTROL2_MODE_DFP); + break; + case TOGGLING_MODE_DRP: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_MODE_MASK, + FUSB_REG_CONTROL2_MODE_DRP); + break; + default: + break; + } + + if (ret) + return ret; + + if (mode == TOGGLING_MODE_OFF) { + /* mask TOGDONE interrupt */ + ret = fusb302_i2c_set_bits(dev, FUSB_REG_MASKA, + FUSB_REG_MASKA_TOGDONE); + if (ret) + return ret; + chip->intr_togdone = false; + } else { + /* Datasheet says vconn MUST be off when toggling */ + if (chip->vconn_on) + dev_warn(dev, "Vconn is on during toggle start\n"); + /* unmask TOGDONE interrupt */ + ret = fusb302_i2c_clear_bits(dev, FUSB_REG_MASKA, + FUSB_REG_MASKA_TOGDONE); + if (ret) + return ret; + chip->intr_togdone = true; + /* start toggling */ + ret = fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL2, + FUSB_REG_CONTROL2_TOGGLE); + if (ret) + return ret; + /* during toggling, consider cc as Open */ + chip->cc1 = TYPEC_CC_OPEN; + chip->cc2 = TYPEC_CC_OPEN; + } + chip->toggling_mode = mode; + + return ret; +} + +static const enum src_current_status cc_src_current[] = { + [TYPEC_CC_OPEN] = SRC_CURRENT_DEFAULT, + [TYPEC_CC_RA] = SRC_CURRENT_DEFAULT, + [TYPEC_CC_RD] = SRC_CURRENT_DEFAULT, + [TYPEC_CC_RP_DEF] = SRC_CURRENT_DEFAULT, + [TYPEC_CC_RP_1_5] = SRC_CURRENT_MEDIUM, + [TYPEC_CC_RP_3_0] = SRC_CURRENT_HIGH, +}; + +static int fusb302_set_cc(struct udevice *dev, enum typec_cc_status cc) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + const u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN | + FUSB_REG_SWITCHES0_CC2_PU_EN | + FUSB_REG_SWITCHES0_CC1_PD_EN | + FUSB_REG_SWITCHES0_CC2_PD_EN; + u8 rd_mda, switches0_data = 0x00; + int ret; + + switch (cc) { + case TYPEC_CC_OPEN: + break; + case TYPEC_CC_RD: + switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN | + FUSB_REG_SWITCHES0_CC2_PD_EN; + break; + case TYPEC_CC_RP_DEF: + case TYPEC_CC_RP_1_5: + case TYPEC_CC_RP_3_0: + switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ? + FUSB_REG_SWITCHES0_CC1_PU_EN : + FUSB_REG_SWITCHES0_CC2_PU_EN; + break; + default: + dev_err(dev, "unsupported CC value: %s\n", + typec_cc_status_name[cc]); + ret = -EINVAL; + goto done; + } + + ret = fusb302_set_toggling(dev, TOGGLING_MODE_OFF); + if (ret) { + dev_err(dev, "cannot set toggling mode: %d\n", ret); + goto done; + } + + ret = fusb302_i2c_mask_write(dev, FUSB_REG_SWITCHES0, + switches0_mask, switches0_data); + if (ret) { + dev_err(dev, "cannot set pull-up/-down: %d\n", ret); + goto done; + } + /* reset the cc status */ + chip->cc1 = TYPEC_CC_OPEN; + chip->cc2 = TYPEC_CC_OPEN; + + /* adjust current for SRC */ + ret = fusb302_set_src_current(dev, cc_src_current[cc]); + if (ret) { + dev_err(dev, "cannot set src current %s: %d\n", + typec_cc_status_name[cc], ret); + goto done; + } + + /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */ + switch (cc) { + case TYPEC_CC_RP_DEF: + case TYPEC_CC_RP_1_5: + case TYPEC_CC_RP_3_0: + rd_mda = rd_mda_value[cc_src_current[cc]]; + ret = fusb302_i2c_write(dev, FUSB_REG_MEASURE, rd_mda); + if (ret) { + dev_err(dev, "cannot set SRC measure value: %d\n", ret); + goto done; + } + ret = fusb302_i2c_mask_write(dev, FUSB_REG_MASK, + FUSB_REG_MASK_BC_LVL | + FUSB_REG_MASK_COMP_CHNG, + FUSB_REG_MASK_BC_LVL); + if (ret) { + dev_err(dev, "cannot set SRC irq: %d\n", ret); + goto done; + } + chip->intr_comp_chng = true; + break; + case TYPEC_CC_RD: + ret = fusb302_i2c_mask_write(dev, FUSB_REG_MASK, + FUSB_REG_MASK_BC_LVL | + FUSB_REG_MASK_COMP_CHNG, + FUSB_REG_MASK_COMP_CHNG); + if (ret) { + dev_err(dev, "cannot set SRC irq: %d\n", ret); + goto done; + } + chip->intr_bc_lvl = true; + break; + default: + break; + } +done: + return ret; +} + +static int fusb302_get_cc(struct udevice *dev, enum typec_cc_status *cc1, + enum typec_cc_status *cc2) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + + *cc1 = chip->cc1; + *cc2 = chip->cc2; + dev_dbg(dev, "get cc1 = %s, cc2 = %s\n", typec_cc_status_name[*cc1], + typec_cc_status_name[*cc2]); + + return 0; +} + +static int fusb302_set_vconn(struct udevice *dev, bool on) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + u8 switches0_data = 0x00; + u8 switches0_mask = FUSB_REG_SWITCHES0_VCONN_CC1 | + FUSB_REG_SWITCHES0_VCONN_CC2; + + if (chip->vconn_on == on) { + ret = 0; + dev_dbg(dev, "vconn is already %s\n", on ? "on" : "off"); + goto done; + } + if (on) { + switches0_data = (chip->cc_polarity == TYPEC_POLARITY_CC1) ? + FUSB_REG_SWITCHES0_VCONN_CC2 : + FUSB_REG_SWITCHES0_VCONN_CC1; + } + ret = fusb302_i2c_mask_write(dev, FUSB_REG_SWITCHES0, + switches0_mask, switches0_data); + if (ret) + goto done; + dev_dbg(dev, "set vconn = %s\n", on ? "on" : "off"); +done: + return ret; +} + +static int fusb302_set_vbus(struct udevice *dev, bool on, bool charge) +{ + return 0; +} + +static int fusb302_pd_tx_flush(struct udevice *dev) +{ + return fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL0, + FUSB_REG_CONTROL0_TX_FLUSH); +} + +static int fusb302_pd_rx_flush(struct udevice *dev) +{ + return fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL1, + FUSB_REG_CONTROL1_RX_FLUSH); +} + +static int fusb302_pd_set_auto_goodcrc(struct udevice *dev, bool on) +{ + if (on) + return fusb302_i2c_set_bits(dev, FUSB_REG_SWITCHES1, + FUSB_REG_SWITCHES1_AUTO_GCRC); + return fusb302_i2c_clear_bits(dev, FUSB_REG_SWITCHES1, + FUSB_REG_SWITCHES1_AUTO_GCRC); +} + +static int fusb302_pd_set_interrupts(struct udevice *dev, bool on) +{ + int ret; + u8 mask_interrupts = FUSB_REG_MASK_COLLISION; + u8 maska_interrupts = FUSB_REG_MASKA_RETRYFAIL | + FUSB_REG_MASKA_HARDSENT | + FUSB_REG_MASKA_TX_SUCCESS | + FUSB_REG_MASKA_HARDRESET; + u8 maskb_interrupts = FUSB_REG_MASKB_GCRCSENT; + + ret = on ? + fusb302_i2c_clear_bits(dev, FUSB_REG_MASK, mask_interrupts) : + fusb302_i2c_set_bits(dev, FUSB_REG_MASK, mask_interrupts); + if (ret) + return ret; + ret = on ? + fusb302_i2c_clear_bits(dev, FUSB_REG_MASKA, maska_interrupts) : + fusb302_i2c_set_bits(dev, FUSB_REG_MASKA, maska_interrupts); + if (ret) + return ret; + ret = on ? + fusb302_i2c_clear_bits(dev, FUSB_REG_MASKB, maskb_interrupts) : + fusb302_i2c_set_bits(dev, FUSB_REG_MASKB, maskb_interrupts); + return ret; +} + +static int fusb302_set_pd_rx(struct udevice *dev, bool on) +{ + int ret; + + ret = fusb302_pd_rx_flush(dev); + if (ret) { + dev_err(dev, "cannot flush pd rx buffer: %d\n", ret); + goto done; + } + ret = fusb302_pd_tx_flush(dev); + if (ret) { + dev_err(dev, "cannot flush pd tx buffer: %d\n", ret); + goto done; + } + ret = fusb302_pd_set_auto_goodcrc(dev, on); + if (ret) { + dev_err(dev, "cannot turn %s auto GoodCRC: %d\n", + on ? "on" : "off", ret); + goto done; + } + ret = fusb302_pd_set_interrupts(dev, on); + if (ret) { + dev_err(dev, "cannot turn %s pd interrupts: %d\n", + on ? "on" : "off", ret); + goto done; + } + dev_dbg(dev, "set pd RX %s\n", on ? "on" : "off"); +done: + return ret; +} + +static int fusb302_set_roles(struct udevice *dev, bool attached, + enum typec_role pwr, enum typec_data_role data) +{ + int ret; + u8 switches1_mask = FUSB_REG_SWITCHES1_POWERROLE | + FUSB_REG_SWITCHES1_DATAROLE; + u8 switches1_data = 0x00; + + if (pwr == TYPEC_SOURCE) + switches1_data |= FUSB_REG_SWITCHES1_POWERROLE; + if (data == TYPEC_HOST) + switches1_data |= FUSB_REG_SWITCHES1_DATAROLE; + ret = fusb302_i2c_mask_write(dev, FUSB_REG_SWITCHES1, + switches1_mask, switches1_data); + if (ret) { + dev_err(dev, "unable to set pd header %s, %s, ret=%d\n", + typec_role_name[pwr], typec_data_role_name[data], ret); + goto done; + } + dev_dbg(dev, "pd header : %s, %s\n", typec_role_name[pwr], + typec_data_role_name[data]); +done: + + return ret; +} + +static int fusb302_start_toggling(struct udevice *dev, + enum typec_port_type port_type, + enum typec_cc_status cc) +{ + enum toggling_mode mode = TOGGLING_MODE_OFF; + int ret; + + switch (port_type) { + case TYPEC_PORT_SRC: + mode = TOGGLING_MODE_SRC; + break; + case TYPEC_PORT_SNK: + mode = TOGGLING_MODE_SNK; + break; + case TYPEC_PORT_DRP: + mode = TOGGLING_MODE_DRP; + break; + } + + ret = fusb302_set_src_current(dev, cc_src_current[cc]); + if (ret) { + dev_err(dev, "unable to set src current %s, ret=%d", + typec_cc_status_name[cc], ret); + goto done; + } + ret = fusb302_set_toggling(dev, mode); + if (ret) { + dev_err(dev, "unable to start drp toggling: %d\n", ret); + goto done; + } + dev_info(dev, "fusb302 start drp toggling\n"); +done: + + return ret; +} + +static int fusb302_pd_send_message(struct udevice *dev, + const struct pd_message *msg) +{ + int ret; + /* SOP tokens */ + u8 buf[40] = {FUSB302_TKN_SYNC1, FUSB302_TKN_SYNC1, FUSB302_TKN_SYNC1, + FUSB302_TKN_SYNC2}; + u8 pos = 4; + int len; + + len = pd_header_cnt_le(msg->header) * 4; + /* plug 2 for header */ + len += 2; + if (len > FUSB302_MAX_MSG_LEN) { + dev_err(dev, "PD message too long %d (incl. header)", len); + return -EINVAL; + } + /* packsym tells the FUSB302 chip that the next X bytes are payload */ + buf[pos++] = FUSB302_TKN_PACKSYM | (len & FUSB302_MAX_MSG_LEN); + memcpy(&buf[pos], &msg->header, sizeof(msg->header)); + pos += sizeof(msg->header); + + len -= 2; + memcpy(&buf[pos], msg->payload, len); + pos += len; + + /* CRC */ + buf[pos++] = FUSB302_TKN_JAMCRC; + /* EOP */ + buf[pos++] = FUSB302_TKN_EOP; + /* turn tx off after sending message */ + buf[pos++] = FUSB302_TKN_TXOFF; + /* start transmission */ + buf[pos++] = FUSB302_TKN_TXON; + + ret = fusb302_i2c_block_write(dev, FUSB_REG_FIFOS, pos, buf); + if (ret) + return ret; + dev_dbg(dev, "Send PD message (header=0x%x len=%d)\n", msg->header, len); + + return ret; +} + +static int fusb302_pd_send_hardreset(struct udevice *dev) +{ + return fusb302_i2c_set_bits(dev, FUSB_REG_CONTROL3, + FUSB_REG_CONTROL3_SEND_HARDRESET); +} + +static const char * const transmit_type_name[] = { + [TCPC_TX_SOP] = "SOP", + [TCPC_TX_SOP_PRIME] = "SOP'", + [TCPC_TX_SOP_PRIME_PRIME] = "SOP''", + [TCPC_TX_SOP_DEBUG_PRIME] = "DEBUG'", + [TCPC_TX_SOP_DEBUG_PRIME_PRIME] = "DEBUG''", + [TCPC_TX_HARD_RESET] = "HARD_RESET", + [TCPC_TX_CABLE_RESET] = "CABLE_RESET", + [TCPC_TX_BIST_MODE_2] = "BIST_MODE_2", +}; + +static int fusb302_pd_transmit(struct udevice *dev, enum tcpm_transmit_type type, + const struct pd_message *msg, unsigned int negotiated_rev) +{ + int ret; + + switch (type) { + case TCPC_TX_SOP: + /* nRetryCount 3 in P2.0 spec, whereas 2 in PD3.0 spec */ + ret = fusb302_enable_tx_auto_retries(dev, negotiated_rev > PD_REV20 ? + FUSB_REG_CONTROL3_N_RETRIES_2 : + FUSB_REG_CONTROL3_N_RETRIES_3); + if (ret) + dev_err(dev, "cannot update retry count: %d\n", ret); + + ret = fusb302_pd_send_message(dev, msg); + if (ret) + dev_err(dev, "cannot send PD message: %d\n", ret); + break; + case TCPC_TX_HARD_RESET: + ret = fusb302_pd_send_hardreset(dev); + if (ret) + dev_err(dev, "cannot send hardreset: %d\n", ret); + break; + default: + dev_err(dev, "type %s not supported", transmit_type_name[type]); + ret = -EINVAL; + } + + return ret; +} + +static enum typec_cc_status fusb302_bc_lvl_to_cc(u8 bc_lvl) +{ + if (bc_lvl == FUSB_REG_STATUS0_BC_LVL_1230_MAX) + return TYPEC_CC_RP_3_0; + if (bc_lvl == FUSB_REG_STATUS0_BC_LVL_600_1230) + return TYPEC_CC_RP_1_5; + if (bc_lvl == FUSB_REG_STATUS0_BC_LVL_200_600) + return TYPEC_CC_RP_DEF; + return TYPEC_CC_OPEN; +} + +static void fusb302_bc_lvl_handler(struct udevice *dev) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + enum typec_cc_status cc_status; + u8 status0, bc_lvl; + int ret; + + if (!chip->intr_bc_lvl) { + dev_err(dev, "BC_LVL interrupt is turned off, abort\n"); + goto done; + } + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &status0); + if (ret) + goto done; + + dev_dbg(dev, "BC_LVL handler, status0 = 0x%02x\n", status0); + if (status0 & FUSB_REG_STATUS0_ACTIVITY) + dev_info(dev, "CC activities detected, delay handling\n"); + bc_lvl = status0 & FUSB_REG_STATUS0_BC_LVL_MASK; + cc_status = fusb302_bc_lvl_to_cc(bc_lvl); + if (chip->cc_polarity == TYPEC_POLARITY_CC1) { + if (chip->cc1 != cc_status) { + dev_dbg(dev, "cc1: %s -> %s\n", + typec_cc_status_name[chip->cc1], + typec_cc_status_name[cc_status]); + chip->cc1 = cc_status; + tcpm_cc_change(dev); + } + } else { + if (chip->cc2 != cc_status) { + dev_dbg(dev, "cc2: %s -> %s\n", + typec_cc_status_name[chip->cc2], + typec_cc_status_name[cc_status]); + chip->cc2 = cc_status; + tcpm_cc_change(dev); + } + } + +done: + return; +} + +static int fusb302_enter_low_power_mode(struct udevice *dev, + bool attached, bool pd_capable) +{ + unsigned int reg; + int ret; + + ret = fusb302_mask_interrupt(dev); + if (ret) + return ret; + if (attached && pd_capable) + reg = FUSB_REG_POWER_PWR_MEDIUM; + else if (attached) + reg = FUSB_REG_POWER_PWR_LOW; + else + reg = 0; + + return fusb302_set_power_mode(dev, reg); +} + +static const char * const cc_polarity_name[] = { + [TYPEC_POLARITY_CC1] = "Polarity_CC1", + [TYPEC_POLARITY_CC2] = "Polarity_CC2", +}; + +static int fusb302_set_cc_polarity_and_pull(struct udevice *dev, + enum typec_cc_polarity cc_polarity, + bool pull_up, bool pull_down) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + u8 switches0_data = 0x00; + u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN | + FUSB_REG_SWITCHES1_TXCC2_EN; + u8 switches1_data = 0x00; + + if (pull_down) + switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN | + FUSB_REG_SWITCHES0_CC2_PD_EN; + + if (cc_polarity == TYPEC_POLARITY_CC1) { + switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC1; + if (chip->vconn_on) + switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2; + if (pull_up) + switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN; + switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN; + } else { + switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC2; + if (chip->vconn_on) + switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1; + if (pull_up) + switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN; + switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN; + } + ret = fusb302_i2c_write(dev, FUSB_REG_SWITCHES0, switches0_data); + if (ret) + return ret; + ret = fusb302_i2c_mask_write(dev, FUSB_REG_SWITCHES1, + switches1_mask, switches1_data); + if (ret) + return ret; + chip->cc_polarity = cc_polarity; + + return ret; +} + +static int fusb302_handle_togdone_snk(struct udevice *dev, + u8 togdone_result) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + int ret; + u8 status0; + u8 bc_lvl; + enum typec_cc_polarity cc_polarity; + enum typec_cc_status cc_status_active, cc1, cc2; + + /* set polarity and pull_up, pull_down */ + cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ? + TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2; + ret = fusb302_set_cc_polarity_and_pull(dev, cc_polarity, false, true); + if (ret) { + dev_err(dev, "cannot set cc polarity %s, ret = %d\n", + cc_polarity_name[cc_polarity], ret); + return ret; + } + /* fusb302_set_cc_polarity() has set the correct measure block */ + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &status0); + if (ret < 0) + return ret; + bc_lvl = status0 & FUSB_REG_STATUS0_BC_LVL_MASK; + cc_status_active = fusb302_bc_lvl_to_cc(bc_lvl); + /* restart toggling if the cc status on the active line is OPEN */ + if (cc_status_active == TYPEC_CC_OPEN) { + dev_info(dev, "restart toggling as CC_OPEN detected\n"); + ret = fusb302_set_toggling(dev, chip->toggling_mode); + return ret; + } + /* update tcpm with the new cc value */ + cc1 = (cc_polarity == TYPEC_POLARITY_CC1) ? + cc_status_active : TYPEC_CC_OPEN; + cc2 = (cc_polarity == TYPEC_POLARITY_CC2) ? + cc_status_active : TYPEC_CC_OPEN; + if (chip->cc1 != cc1 || chip->cc2 != cc2) { + chip->cc1 = cc1; + chip->cc2 = cc2; + tcpm_cc_change(dev); + } + /* turn off toggling */ + ret = fusb302_set_toggling(dev, TOGGLING_MODE_OFF); + if (ret) { + dev_err(dev, "cannot set toggling mode off, ret=%d\n", ret); + return ret; + } + /* unmask bc_lvl interrupt */ + ret = fusb302_i2c_clear_bits(dev, FUSB_REG_MASK, FUSB_REG_MASK_BC_LVL); + if (ret) { + dev_err(dev, "cannot unmask bc_lcl irq, ret=%d\n", ret); + return ret; + } + chip->intr_bc_lvl = true; + dev_dbg(dev, "detected cc1=%s, cc2=%s\n", + typec_cc_status_name[cc1], + typec_cc_status_name[cc2]); + + return ret; +} + +/* On error returns < 0, otherwise a typec_cc_status value */ +static int fusb302_get_src_cc_status(struct udevice *dev, + enum typec_cc_polarity cc_polarity, + enum typec_cc_status *cc) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + u8 ra_mda = ra_mda_value[chip->src_current_status]; + u8 rd_mda = rd_mda_value[chip->src_current_status]; + u8 switches0_data, status0; + int ret; + + /* Step 1: Set switches so that we measure the right CC pin */ + switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ? + FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 : + FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2; + ret = fusb302_i2c_write(dev, FUSB_REG_SWITCHES0, switches0_data); + if (ret < 0) + return ret; + + fusb302_i2c_read(dev, FUSB_REG_SWITCHES0, &status0); + dev_dbg(dev, "get_src_cc_status switches: 0x%0x", status0); + + /* Step 2: Set compararator volt to differentiate between Open and Rd */ + ret = fusb302_i2c_write(dev, FUSB_REG_MEASURE, rd_mda); + if (ret) + return ret; + + udelay(100); + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &status0); + if (ret) + return ret; + + dev_dbg(dev, "get_src_cc_status rd_mda status0: 0x%0x", status0); + if (status0 & FUSB_REG_STATUS0_COMP) { + *cc = TYPEC_CC_OPEN; + return 0; + } + + /* Step 3: Set compararator input to differentiate between Rd and Ra. */ + ret = fusb302_i2c_write(dev, FUSB_REG_MEASURE, ra_mda); + if (ret) + return ret; + + udelay(100); + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &status0); + if (ret) + return ret; + + dev_dbg(dev, "get_src_cc_status ra_mda status0: 0x%0x", status0); + if (status0 & FUSB_REG_STATUS0_COMP) + *cc = TYPEC_CC_RD; + else + *cc = TYPEC_CC_RA; + + return 0; +} + +static int fusb302_handle_togdone_src(struct udevice *dev, + u8 togdone_result) +{ + /* + * - set polarity (measure cc, vconn, tx) + * - set pull_up, pull_down + * - set cc1, cc2, and update to tcpm state machine + * - set I_COMP interrupt on + */ + struct fusb302_chip *chip = dev_get_priv(dev); + u8 rd_mda = rd_mda_value[chip->src_current_status]; + enum toggling_mode toggling_mode = chip->toggling_mode; + enum typec_cc_polarity cc_polarity; + enum typec_cc_status cc1, cc2; + int ret; + + /* + * The toggle-engine will stop in a src state if it sees either Ra or + * Rd. Determine the status for both CC pins, starting with the one + * where toggling stopped, as that is where the switches point now. + */ + if (togdone_result == FUSB_REG_STATUS1A_TOGSS_SRC1) + ret = fusb302_get_src_cc_status(dev, TYPEC_POLARITY_CC1, &cc1); + else + ret = fusb302_get_src_cc_status(dev, TYPEC_POLARITY_CC2, &cc2); + if (ret) + return ret; + /* we must turn off toggling before we can measure the other pin */ + ret = fusb302_set_toggling(dev, TOGGLING_MODE_OFF); + if (ret) { + dev_err(dev, "cannot set toggling mode off, ret=%d\n", ret); + return ret; + } + /* get the status of the other pin */ + if (togdone_result == FUSB_REG_STATUS1A_TOGSS_SRC1) + ret = fusb302_get_src_cc_status(dev, TYPEC_POLARITY_CC2, &cc2); + else + ret = fusb302_get_src_cc_status(dev, TYPEC_POLARITY_CC1, &cc1); + if (ret) + return ret; + + /* determine polarity based on the status of both pins */ + if (cc1 == TYPEC_CC_RD && (cc2 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_RA)) { + cc_polarity = TYPEC_POLARITY_CC1; + } else if (cc2 == TYPEC_CC_RD && + (cc1 == TYPEC_CC_OPEN || cc1 == TYPEC_CC_RA)) { + cc_polarity = TYPEC_POLARITY_CC2; + } else { + dev_err(dev, "unexpected CC status cc1=%s, cc2=%s, restarting toggling\n", + typec_cc_status_name[cc1], + typec_cc_status_name[cc2]); + return fusb302_set_toggling(dev, toggling_mode); + } + /* set polarity and pull_up, pull_down */ + ret = fusb302_set_cc_polarity_and_pull(dev, cc_polarity, true, false); + if (ret < 0) { + dev_err(dev, "cannot set cc polarity %s, ret=%d\n", + cc_polarity_name[cc_polarity], ret); + return ret; + } + /* update tcpm with the new cc value */ + if (chip->cc1 != cc1 || chip->cc2 != cc2) { + chip->cc1 = cc1; + chip->cc2 = cc2; + tcpm_cc_change(dev); + } + /* set MDAC to Rd threshold, and unmask I_COMP for unplug detection */ + ret = fusb302_i2c_write(dev, FUSB_REG_MEASURE, rd_mda); + if (ret) + return ret; + /* unmask comp_chng interrupt */ + ret = fusb302_i2c_clear_bits(dev, FUSB_REG_MASK, + FUSB_REG_MASK_COMP_CHNG); + if (ret) { + dev_err(dev, "cannot unmask comp_chng irq, ret=%d\n", ret); + return ret; + } + chip->intr_comp_chng = true; + dev_dbg(dev, "detected cc1=%s, cc2=%s\n", + typec_cc_status_name[cc1], + typec_cc_status_name[cc2]); + + return ret; +} + +static int fusb302_handle_togdone(struct udevice *dev) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + u8 togdone_result, status1a; + int ret; + + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS1A, &status1a); + if (ret < 0) + return ret; + togdone_result = (status1a >> FUSB_REG_STATUS1A_TOGSS_POS) & + FUSB_REG_STATUS1A_TOGSS_MASK; + switch (togdone_result) { + case FUSB_REG_STATUS1A_TOGSS_SNK1: + case FUSB_REG_STATUS1A_TOGSS_SNK2: + return fusb302_handle_togdone_snk(dev, togdone_result); + case FUSB_REG_STATUS1A_TOGSS_SRC1: + case FUSB_REG_STATUS1A_TOGSS_SRC2: + return fusb302_handle_togdone_src(dev, togdone_result); + case FUSB_REG_STATUS1A_TOGSS_AA: + /* doesn't support */ + dev_err(dev, "AudioAccessory not supported\n"); + fusb302_set_toggling(dev, chip->toggling_mode); + break; + default: + dev_err(dev, "TOGDONE with an invalid state: %d\n", + togdone_result); + fusb302_set_toggling(dev, chip->toggling_mode); + break; + } + return ret; +} + +static int fusb302_pd_reset(struct udevice *dev) +{ + return fusb302_i2c_set_bits(dev, FUSB_REG_RESET, + FUSB_REG_RESET_PD_RESET); +} + +static int fusb302_pd_read_message(struct udevice *dev, + struct pd_message *msg) +{ + int len, ret; + u8 crc[4]; + u8 token; + + /* first SOP token */ + ret = fusb302_i2c_read(dev, FUSB_REG_FIFOS, &token); + if (ret) + return ret; + ret = fusb302_i2c_block_read(dev, FUSB_REG_FIFOS, 2, + (u8 *)&msg->header); + if (ret) + return ret; + len = pd_header_cnt_le(msg->header) * 4; + /* add 4 to length to include the CRC */ + if (len > PD_MAX_PAYLOAD * 4) { + dev_err(dev, "PD message too long %d\n", len); + return -EINVAL; + } + if (len > 0) { + ret = fusb302_i2c_block_read(dev, FUSB_REG_FIFOS, len, + (u8 *)msg->payload); + if (ret) + return ret; + } + /* another 4 bytes to read CRC out */ + ret = fusb302_i2c_block_read(dev, FUSB_REG_FIFOS, 4, crc); + if (ret) + return ret; + dev_dbg(dev, "Received PD message (header=0x%x len=%d)\n", msg->header, len); + + /* + * Check if we've read off a GoodCRC message. If so then indicate to + * TCPM that the previous transmission has completed. Otherwise we pass + * the received message over to TCPM for processing. + * + * We make this check here instead of basing the reporting decision on + * the IRQ event type, as it's possible for the chip to report the + * TX_SUCCESS and GCRCSENT events out of order on occasion, so we need + * to check the message type to ensure correct reporting to TCPM. + */ + if (!len && (pd_header_type_le(msg->header) == PD_CTRL_GOOD_CRC)) + tcpm_pd_transmit_complete(dev, TCPC_TX_SUCCESS); + else + tcpm_pd_receive(dev, msg); + + return ret; +} + +static void fusb302_interrupt_handle(struct udevice *dev) +{ + struct fusb302_chip *chip = dev_get_priv(dev); + u8 interrupt; + u8 interrupta; + u8 interruptb; + u8 status0; + bool vbus_present; + bool comp_result; + bool intr_togdone; + bool intr_bc_lvl; + bool intr_comp_chng; + struct pd_message pd_msg; + int ret; + + /* grab a snapshot of intr flags */ + intr_togdone = chip->intr_togdone; + intr_bc_lvl = chip->intr_bc_lvl; + intr_comp_chng = chip->intr_comp_chng; + + ret = fusb302_i2c_read(dev, FUSB_REG_INTERRUPT, &interrupt); + if (ret) + return; + ret = fusb302_i2c_read(dev, FUSB_REG_INTERRUPTA, &interrupta); + if (ret) + return; + ret = fusb302_i2c_read(dev, FUSB_REG_INTERRUPTB, &interruptb); + if (ret) + return; + ret = fusb302_i2c_read(dev, FUSB_REG_STATUS0, &status0); + if (ret) + return; + + /* + * Since we are polling the IRQs, avoid printing messages when there + * no interrupts at all to avoid spamming the log. + */ + if (interrupt != 0 || interrupta != 0 || interruptb != 0) + dev_dbg(dev, "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x, status0: 0x%02x\n", + interrupt, interrupta, interruptb, status0); + + if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) { + vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK); + dev_dbg(dev, "IRQ: VBUS_OK, vbus=%s\n", + vbus_present ? "On" : "Off"); + if (vbus_present != chip->vbus_present) { + chip->vbus_present = vbus_present; + tcpm_vbus_change(dev); + } + } + + if ((interrupta & FUSB_REG_INTERRUPTA_TOGDONE) && intr_togdone) { + dev_dbg(dev, "IRQ: TOGDONE\n"); + ret = fusb302_handle_togdone(dev); + if (ret) { + dev_err(dev, "handle togdone error: %d\n", ret); + return; + } + } + + if ((interrupt & FUSB_REG_INTERRUPT_BC_LVL) && intr_bc_lvl) { + dev_dbg(dev, "IRQ: BC_LVL, handler pending\n"); + fusb302_bc_lvl_handler(dev); + } + + if ((interrupt & FUSB_REG_INTERRUPT_COMP_CHNG) && intr_comp_chng) { + comp_result = !!(status0 & FUSB_REG_STATUS0_COMP); + dev_dbg(dev, "IRQ: COMP_CHNG, comp=%s\n", + comp_result ? "true" : "false"); + if (comp_result) { + /* cc level > Rd_threshold, detach */ + chip->cc1 = TYPEC_CC_OPEN; + chip->cc2 = TYPEC_CC_OPEN; + tcpm_cc_change(dev); + } + } + + if (interrupt & FUSB_REG_INTERRUPT_COLLISION) { + dev_dbg(dev, "IRQ: PD collision\n"); + tcpm_pd_transmit_complete(dev, TCPC_TX_FAILED); + } + + if (interrupta & FUSB_REG_INTERRUPTA_RETRYFAIL) { + dev_dbg(dev, "IRQ: PD retry failed\n"); + tcpm_pd_transmit_complete(dev, TCPC_TX_FAILED); + } + + if (interrupta & FUSB_REG_INTERRUPTA_HARDSENT) { + dev_dbg(dev, "IRQ: PD hardreset sent\n"); + ret = fusb302_pd_reset(dev); + if (ret) { + dev_err(dev, "cannot PD reset, ret=%d\n", ret); + return; + } + tcpm_pd_transmit_complete(dev, TCPC_TX_SUCCESS); + } + + if (interrupta & FUSB_REG_INTERRUPTA_TX_SUCCESS) { + dev_dbg(dev, "IRQ: PD tx success\n"); + ret = fusb302_pd_read_message(dev, &pd_msg); + if (ret) { + dev_err(dev, "cannot read in PD message, ret=%d\n", ret); + return; + } + } + + if (interrupta & FUSB_REG_INTERRUPTA_HARDRESET) { + dev_dbg(dev, "IRQ: PD received hardreset\n"); + ret = fusb302_pd_reset(dev); + if (ret) { + dev_err(dev, "cannot PD reset, ret=%d\n", ret); + return; + } + tcpm_pd_hard_reset(dev); + } + + if (interruptb & FUSB_REG_INTERRUPTB_GCRCSENT) { + dev_dbg(dev, "IRQ: PD sent good CRC\n"); + ret = fusb302_pd_read_message(dev, &pd_msg); + if (ret) { + dev_err(dev, "cannot read in PD message, ret=%d\n", ret); + return; + } + } +} + +static void fusb302_poll_event(struct udevice *dev) +{ + fusb302_interrupt_handle(dev); +} + +static int fusb302_get_connector_node(struct udevice *dev, ofnode *connector_node) +{ + *connector_node = dev_read_subnode(dev, "connector"); + if (!ofnode_valid(*connector_node)) { + dev_err(dev, "'connector' node is not found\n"); + return -ENODEV; + } + + return 0; +} + +static struct dm_tcpm_ops fusb302_ops = { + .get_connector_node = fusb302_get_connector_node, + .init = fusb302_init, + .get_vbus = fusb302_get_vbus, + .set_cc = fusb302_set_cc, + .get_cc = fusb302_get_cc, + .set_vconn = fusb302_set_vconn, + .set_vbus = fusb302_set_vbus, + .set_pd_rx = fusb302_set_pd_rx, + .set_roles = fusb302_set_roles, + .start_toggling = fusb302_start_toggling, + .pd_transmit = fusb302_pd_transmit, + .poll_event = fusb302_poll_event, + .enter_low_power_mode = fusb302_enter_low_power_mode, +}; + +static const struct udevice_id fusb302_ids[] = { + { .compatible = "fcs,fusb302" }, + { } +}; + +U_BOOT_DRIVER(fusb302) = { + .name = "fusb302", + .id = UCLASS_TCPM, + .of_match = fusb302_ids, + .ops = &fusb302_ops, + .priv_auto = sizeof(struct fusb302_chip), +}; diff --git a/drivers/usb/tcpm/fusb302_reg.h b/drivers/usb/tcpm/fusb302_reg.h new file mode 100644 index 00000000000..edc0e4b0f1e --- /dev/null +++ b/drivers/usb/tcpm/fusb302_reg.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2016-2017 Google, Inc + * + * Fairchild FUSB302 Type-C Chip Driver + */ + +#ifndef FUSB302_REG_H +#define FUSB302_REG_H + +#define FUSB_REG_DEVICE_ID 0x01 +#define FUSB_REG_SWITCHES0 0x02 +#define FUSB_REG_SWITCHES0_CC2_PU_EN BIT(7) +#define FUSB_REG_SWITCHES0_CC1_PU_EN BIT(6) +#define FUSB_REG_SWITCHES0_VCONN_CC2 BIT(5) +#define FUSB_REG_SWITCHES0_VCONN_CC1 BIT(4) +#define FUSB_REG_SWITCHES0_MEAS_CC2 BIT(3) +#define FUSB_REG_SWITCHES0_MEAS_CC1 BIT(2) +#define FUSB_REG_SWITCHES0_CC2_PD_EN BIT(1) +#define FUSB_REG_SWITCHES0_CC1_PD_EN BIT(0) +#define FUSB_REG_SWITCHES1 0x03 +#define FUSB_REG_SWITCHES1_POWERROLE BIT(7) +#define FUSB_REG_SWITCHES1_SPECREV1 BIT(6) +#define FUSB_REG_SWITCHES1_SPECREV0 BIT(5) +#define FUSB_REG_SWITCHES1_DATAROLE BIT(4) +#define FUSB_REG_SWITCHES1_AUTO_GCRC BIT(2) +#define FUSB_REG_SWITCHES1_TXCC2_EN BIT(1) +#define FUSB_REG_SWITCHES1_TXCC1_EN BIT(0) +#define FUSB_REG_MEASURE 0x04 +#define FUSB_REG_MEASURE_MDAC5 BIT(7) +#define FUSB_REG_MEASURE_MDAC4 BIT(6) +#define FUSB_REG_MEASURE_MDAC3 BIT(5) +#define FUSB_REG_MEASURE_MDAC2 BIT(4) +#define FUSB_REG_MEASURE_MDAC1 BIT(3) +#define FUSB_REG_MEASURE_MDAC0 BIT(2) +#define FUSB_REG_MEASURE_VBUS BIT(1) +#define FUSB_REG_MEASURE_XXXX5 BIT(0) +#define FUSB_REG_CONTROL0 0x06 +#define FUSB_REG_CONTROL0_TX_FLUSH BIT(6) +#define FUSB_REG_CONTROL0_INT_MASK BIT(5) +#define FUSB_REG_CONTROL0_HOST_CUR_MASK (0xC) +#define FUSB_REG_CONTROL0_HOST_CUR_HIGH (0xC) +#define FUSB_REG_CONTROL0_HOST_CUR_MED (0x8) +#define FUSB_REG_CONTROL0_HOST_CUR_DEF (0x4) +#define FUSB_REG_CONTROL0_TX_START BIT(0) +#define FUSB_REG_CONTROL1 0x07 +#define FUSB_REG_CONTROL1_ENSOP2DB BIT(6) +#define FUSB_REG_CONTROL1_ENSOP1DB BIT(5) +#define FUSB_REG_CONTROL1_BIST_MODE2 BIT(4) +#define FUSB_REG_CONTROL1_RX_FLUSH BIT(2) +#define FUSB_REG_CONTROL1_ENSOP2 BIT(1) +#define FUSB_REG_CONTROL1_ENSOP1 BIT(0) +#define FUSB_REG_CONTROL2 0x08 +#define FUSB_REG_CONTROL2_MODE BIT(1) +#define FUSB_REG_CONTROL2_MODE_MASK (0x6) +#define FUSB_REG_CONTROL2_MODE_DFP (0x6) +#define FUSB_REG_CONTROL2_MODE_UFP (0x4) +#define FUSB_REG_CONTROL2_MODE_DRP (0x2) +#define FUSB_REG_CONTROL2_MODE_NONE (0x0) +#define FUSB_REG_CONTROL2_TOGGLE BIT(0) +#define FUSB_REG_CONTROL3 0x09 +#define FUSB_REG_CONTROL3_SEND_HARDRESET BIT(6) +#define FUSB_REG_CONTROL3_BIST_TMODE BIT(5) /* 302B Only */ +#define FUSB_REG_CONTROL3_AUTO_HARDRESET BIT(4) +#define FUSB_REG_CONTROL3_AUTO_SOFTRESET BIT(3) +#define FUSB_REG_CONTROL3_N_RETRIES BIT(1) +#define FUSB_REG_CONTROL3_N_RETRIES_MASK (0x6) +#define FUSB_REG_CONTROL3_N_RETRIES_3 (0x6) +#define FUSB_REG_CONTROL3_N_RETRIES_2 (0x4) +#define FUSB_REG_CONTROL3_N_RETRIES_1 (0x2) +#define FUSB_REG_CONTROL3_AUTO_RETRY BIT(0) +#define FUSB_REG_MASK 0x0A +#define FUSB_REG_MASK_VBUSOK BIT(7) +#define FUSB_REG_MASK_ACTIVITY BIT(6) +#define FUSB_REG_MASK_COMP_CHNG BIT(5) +#define FUSB_REG_MASK_CRC_CHK BIT(4) +#define FUSB_REG_MASK_ALERT BIT(3) +#define FUSB_REG_MASK_WAKE BIT(2) +#define FUSB_REG_MASK_COLLISION BIT(1) +#define FUSB_REG_MASK_BC_LVL BIT(0) +#define FUSB_REG_POWER 0x0B +#define FUSB_REG_POWER_PWR BIT(0) +#define FUSB_REG_POWER_PWR_LOW 0x1 +#define FUSB_REG_POWER_PWR_MEDIUM 0x3 +#define FUSB_REG_POWER_PWR_HIGH 0x7 +#define FUSB_REG_POWER_PWR_ALL 0xF +#define FUSB_REG_RESET 0x0C +#define FUSB_REG_RESET_PD_RESET BIT(1) +#define FUSB_REG_RESET_SW_RESET BIT(0) +#define FUSB_REG_MASKA 0x0E +#define FUSB_REG_MASKA_OCP_TEMP BIT(7) +#define FUSB_REG_MASKA_TOGDONE BIT(6) +#define FUSB_REG_MASKA_SOFTFAIL BIT(5) +#define FUSB_REG_MASKA_RETRYFAIL BIT(4) +#define FUSB_REG_MASKA_HARDSENT BIT(3) +#define FUSB_REG_MASKA_TX_SUCCESS BIT(2) +#define FUSB_REG_MASKA_SOFTRESET BIT(1) +#define FUSB_REG_MASKA_HARDRESET BIT(0) +#define FUSB_REG_MASKB 0x0F +#define FUSB_REG_MASKB_GCRCSENT BIT(0) +#define FUSB_REG_STATUS0A 0x3C +#define FUSB_REG_STATUS0A_SOFTFAIL BIT(5) +#define FUSB_REG_STATUS0A_RETRYFAIL BIT(4) +#define FUSB_REG_STATUS0A_POWER BIT(2) +#define FUSB_REG_STATUS0A_RX_SOFT_RESET BIT(1) +#define FUSB_REG_STATUS0A_RX_HARD_RESET BIT(0) +#define FUSB_REG_STATUS1A 0x3D +#define FUSB_REG_STATUS1A_TOGSS BIT(3) +#define FUSB_REG_STATUS1A_TOGSS_RUNNING 0x0 +#define FUSB_REG_STATUS1A_TOGSS_SRC1 0x1 +#define FUSB_REG_STATUS1A_TOGSS_SRC2 0x2 +#define FUSB_REG_STATUS1A_TOGSS_SNK1 0x5 +#define FUSB_REG_STATUS1A_TOGSS_SNK2 0x6 +#define FUSB_REG_STATUS1A_TOGSS_AA 0x7 +#define FUSB_REG_STATUS1A_TOGSS_POS (3) +#define FUSB_REG_STATUS1A_TOGSS_MASK (0x7) +#define FUSB_REG_STATUS1A_RXSOP2DB BIT(2) +#define FUSB_REG_STATUS1A_RXSOP1DB BIT(1) +#define FUSB_REG_STATUS1A_RXSOP BIT(0) +#define FUSB_REG_INTERRUPTA 0x3E +#define FUSB_REG_INTERRUPTA_OCP_TEMP BIT(7) +#define FUSB_REG_INTERRUPTA_TOGDONE BIT(6) +#define FUSB_REG_INTERRUPTA_SOFTFAIL BIT(5) +#define FUSB_REG_INTERRUPTA_RETRYFAIL BIT(4) +#define FUSB_REG_INTERRUPTA_HARDSENT BIT(3) +#define FUSB_REG_INTERRUPTA_TX_SUCCESS BIT(2) +#define FUSB_REG_INTERRUPTA_SOFTRESET BIT(1) +#define FUSB_REG_INTERRUPTA_HARDRESET BIT(0) +#define FUSB_REG_INTERRUPTB 0x3F +#define FUSB_REG_INTERRUPTB_GCRCSENT BIT(0) +#define FUSB_REG_STATUS0 0x40 +#define FUSB_REG_STATUS0_VBUSOK BIT(7) +#define FUSB_REG_STATUS0_ACTIVITY BIT(6) +#define FUSB_REG_STATUS0_COMP BIT(5) +#define FUSB_REG_STATUS0_CRC_CHK BIT(4) +#define FUSB_REG_STATUS0_ALERT BIT(3) +#define FUSB_REG_STATUS0_WAKE BIT(2) +#define FUSB_REG_STATUS0_BC_LVL_MASK 0x03 +#define FUSB_REG_STATUS0_BC_LVL_0_200 0x0 +#define FUSB_REG_STATUS0_BC_LVL_200_600 0x1 +#define FUSB_REG_STATUS0_BC_LVL_600_1230 0x2 +#define FUSB_REG_STATUS0_BC_LVL_1230_MAX 0x3 +#define FUSB_REG_STATUS0_BC_LVL1 BIT(1) +#define FUSB_REG_STATUS0_BC_LVL0 BIT(0) +#define FUSB_REG_STATUS1 0x41 +#define FUSB_REG_STATUS1_RXSOP2 BIT(7) +#define FUSB_REG_STATUS1_RXSOP1 BIT(6) +#define FUSB_REG_STATUS1_RX_EMPTY BIT(5) +#define FUSB_REG_STATUS1_RX_FULL BIT(4) +#define FUSB_REG_STATUS1_TX_EMPTY BIT(3) +#define FUSB_REG_STATUS1_TX_FULL BIT(2) +#define FUSB_REG_INTERRUPT 0x42 +#define FUSB_REG_INTERRUPT_VBUSOK BIT(7) +#define FUSB_REG_INTERRUPT_ACTIVITY BIT(6) +#define FUSB_REG_INTERRUPT_COMP_CHNG BIT(5) +#define FUSB_REG_INTERRUPT_CRC_CHK BIT(4) +#define FUSB_REG_INTERRUPT_ALERT BIT(3) +#define FUSB_REG_INTERRUPT_WAKE BIT(2) +#define FUSB_REG_INTERRUPT_COLLISION BIT(1) +#define FUSB_REG_INTERRUPT_BC_LVL BIT(0) +#define FUSB_REG_FIFOS 0x43 + +/* Tokens defined for the FUSB302 TX FIFO */ +enum fusb302_txfifo_tokens { + FUSB302_TKN_TXON = 0xA1, + FUSB302_TKN_SYNC1 = 0x12, + FUSB302_TKN_SYNC2 = 0x13, + FUSB302_TKN_SYNC3 = 0x1B, + FUSB302_TKN_RST1 = 0x15, + FUSB302_TKN_RST2 = 0x16, + FUSB302_TKN_PACKSYM = 0x80, + FUSB302_TKN_JAMCRC = 0xFF, + FUSB302_TKN_EOP = 0x14, + FUSB302_TKN_TXOFF = 0xFE, +}; + +#endif diff --git a/drivers/usb/tcpm/tcpm-internal.h b/drivers/usb/tcpm/tcpm-internal.h new file mode 100644 index 00000000000..56144209002 --- /dev/null +++ b/drivers/usb/tcpm/tcpm-internal.h @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2015-2017 Google, Inc + * Copyright 2024 Collabora + */ + +#ifndef __LINUX_USB_TCPM_INTERNAL_H +#define __LINUX_USB_TCPM_INTERNAL_H + +#define FOREACH_TCPM_STATE(S) \ + S(INVALID_STATE), \ + S(TOGGLING), \ + S(SRC_UNATTACHED), \ + S(SRC_ATTACH_WAIT), \ + S(SRC_ATTACHED), \ + S(SRC_STARTUP), \ + S(SRC_SEND_CAPABILITIES), \ + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ + S(SRC_NEGOTIATE_CAPABILITIES), \ + S(SRC_TRANSITION_SUPPLY), \ + S(SRC_READY), \ + S(SRC_WAIT_NEW_CAPABILITIES), \ + \ + S(SNK_UNATTACHED), \ + S(SNK_ATTACH_WAIT), \ + S(SNK_DEBOUNCED), \ + S(SNK_ATTACHED), \ + S(SNK_STARTUP), \ + S(SNK_DISCOVERY), \ + S(SNK_DISCOVERY_DEBOUNCE), \ + S(SNK_DISCOVERY_DEBOUNCE_DONE), \ + S(SNK_WAIT_CAPABILITIES), \ + S(SNK_NEGOTIATE_CAPABILITIES), \ + S(SNK_TRANSITION_SINK), \ + S(SNK_TRANSITION_SINK_VBUS), \ + S(SNK_READY), \ + \ + S(HARD_RESET_SEND), \ + S(HARD_RESET_START), \ + S(SRC_HARD_RESET_VBUS_OFF), \ + S(SRC_HARD_RESET_VBUS_ON), \ + S(SNK_HARD_RESET_SINK_OFF), \ + S(SNK_HARD_RESET_WAIT_VBUS), \ + S(SNK_HARD_RESET_SINK_ON), \ + \ + S(SOFT_RESET), \ + S(SOFT_RESET_SEND), \ + \ + S(DR_SWAP_ACCEPT), \ + S(DR_SWAP_CHANGE_DR), \ + \ + S(ERROR_RECOVERY), \ + S(PORT_RESET), \ + S(PORT_RESET_WAIT_OFF) + +#define GENERATE_TCPM_ENUM(e) e +#define GENERATE_TCPM_STRING(s) #s +#define TCPM_POLL_EVENT_TIME_OUT 2000 + +enum tcpm_state { + FOREACH_TCPM_STATE(GENERATE_TCPM_ENUM) +}; + +enum pd_msg_request { + PD_MSG_NONE = 0, + PD_MSG_CTRL_REJECT, + PD_MSG_CTRL_WAIT, + PD_MSG_CTRL_NOT_SUPP, + PD_MSG_DATA_SINK_CAP, + PD_MSG_DATA_SOURCE_CAP, +}; + +struct tcpm_port { + enum typec_port_type typec_type; + int typec_prefer_role; + + enum typec_role vconn_role; + enum typec_role pwr_role; + enum typec_data_role data_role; + + struct typec_partner *partner; + + enum typec_cc_status cc_req; + enum typec_cc_status cc1; + enum typec_cc_status cc2; + enum typec_cc_polarity polarity; + + bool attached; + bool connected; + int poll_event_cnt; + enum typec_port_type port_type; + + /* + * Set to true when vbus is greater than VSAFE5V min. + * Set to false when vbus falls below vSinkDisconnect max threshold. + */ + bool vbus_present; + + /* + * Set to true when vbus is less than VSAFE0V max. + * Set to false when vbus is greater than VSAFE0V max. + */ + bool vbus_vsafe0v; + + bool vbus_never_low; + bool vbus_source; + bool vbus_charge; + + int try_role; + + enum pd_msg_request queued_message; + + enum tcpm_state enter_state; + enum tcpm_state prev_state; + enum tcpm_state state; + enum tcpm_state delayed_state; + unsigned long delay_ms; + + bool state_machine_running; + + bool tx_complete; + enum tcpm_transmit_status tx_status; + + unsigned int negotiated_rev; + unsigned int message_id; + unsigned int caps_count; + unsigned int hard_reset_count; + bool pd_capable; + bool explicit_contract; + unsigned int rx_msgid; + + /* Partner capabilities/requests */ + u32 sink_request; + u32 source_caps[PDO_MAX_OBJECTS]; + unsigned int nr_source_caps; + u32 sink_caps[PDO_MAX_OBJECTS]; + unsigned int nr_sink_caps; + + /* + * whether to wait for the Type-C device to send the DR_SWAP Message flag + * For Type-C device with Dual-Role Power and Dual-Role Data, the port side + * is used as sink + ufp, then the tcpm framework needs to wait for Type-C + * device to initiate DR_swap Message. + */ + bool wait_dr_swap_message; + + /* Local capabilities */ + u32 src_pdo[PDO_MAX_OBJECTS]; + unsigned int nr_src_pdo; + u32 snk_pdo[PDO_MAX_OBJECTS]; + unsigned int nr_snk_pdo; + + unsigned int operating_snk_mw; + bool update_sink_caps; + + /* Requested current / voltage to the port partner */ + u32 req_current_limit; + u32 req_supply_voltage; + /* Actual current / voltage limit of the local port */ + u32 current_limit; + u32 supply_voltage; + + /* port belongs to a self powered device */ + bool self_powered; + + unsigned long delay_target; +}; + +extern const char * const tcpm_states[]; + +int tcpm_post_probe(struct udevice *dev); + +#endif diff --git a/drivers/usb/tcpm/tcpm-uclass.c b/drivers/usb/tcpm/tcpm-uclass.c new file mode 100644 index 00000000000..d4fe260e0db --- /dev/null +++ b/drivers/usb/tcpm/tcpm-uclass.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 Collabora Ltd. + * + * USB Power Delivery protocol stack. + */ + +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/uclass.h> +#include <linux/err.h> +#include <usb/tcpm.h> +#include "tcpm-internal.h" + +int tcpm_get_voltage(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->supply_voltage; +} + +int tcpm_get_current(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->current_limit; +} + +enum typec_orientation tcpm_get_orientation(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + switch (port->polarity) { + case TYPEC_POLARITY_CC1: + return TYPEC_ORIENTATION_NORMAL; + case TYPEC_POLARITY_CC2: + return TYPEC_ORIENTATION_REVERSE; + default: + return TYPEC_ORIENTATION_NONE; + } +} + +const char *tcpm_get_state(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return tcpm_states[port->state]; +} + +int tcpm_get_pd_rev(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->negotiated_rev; +} + +enum typec_role tcpm_get_pwr_role(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->pwr_role; +} + +enum typec_data_role tcpm_get_data_role(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->data_role; +} + +bool tcpm_is_connected(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return port->connected; +} + +int tcpm_get(int index, struct udevice **devp) +{ + return uclass_get_device(UCLASS_TCPM, index, devp); +} + +static int tcpm_post_bind(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + const char *cap_str; + ofnode node; + int ret; + + /* + * USB Power Delivery (USB PD) specification requires, that communication + * with a sink happens within roughly 5 seconds. Otherwise the source + * might assume that the sink does not support USB PD. Starting to do + * USB PD communication after that results in a hard reset, which briefly + * removes any power from the USB-C port. + * + * On systems with alternative power supplies this is not an issue, but + * systems, which get soleley powered through their USB-C port will end + * up losing their power supply and doing a board level reset. The hard + * reset will also restart the 5 second timeout. That means a operating + * system initializing USB PD will put the system into a boot loop when + * it takes more than 5 seconds from cold boot to the operating system + * starting to transmit USB PD messages. + * + * The issue can be avoided by doing the initial USB PD communication + * in U-Boot. The operating system can then re-negotiate by doing a + * soft reset, which does not trigger removal of the supply voltage. + * + * Since the TCPM state machine is quite complex and depending on the + * remote side can take quite some time to finish, this tries to limit + * the automatic probing to systems probably relying on power being + * provided by the USB-C port(s): + * + * 1. self-powered devices won't reset when the USB-C port looses power + * 2. if the power is allowed to go into anything else than sink mode + * it is not the only power source + */ + ret = drvops->get_connector_node(dev, &node); + if (ret) + return ret; + + if (ofnode_read_bool(node, "self-powered")) + return 0; + + cap_str = ofnode_read_string(node, "power-role"); + if (!cap_str) + return -EINVAL; + + if (strcmp("sink", cap_str)) + return 0; + + /* Do not auto-probe PD controller when PD is disabled */ + if (ofnode_read_bool(node, "pd-disable")) + return 0; + + dev_info(dev, "probing Type-C port manager..."); + + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + + return 0; +} + +UCLASS_DRIVER(tcpm) = { + .id = UCLASS_TCPM, + .name = "tcpm", + .per_device_plat_auto = sizeof(struct tcpm_port), + .post_bind = tcpm_post_bind, + .post_probe = tcpm_post_probe, +}; diff --git a/drivers/usb/tcpm/tcpm.c b/drivers/usb/tcpm/tcpm.c new file mode 100644 index 00000000000..0aee57cb2f4 --- /dev/null +++ b/drivers/usb/tcpm/tcpm.c @@ -0,0 +1,2288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2015-2017 Google, Inc + * + * USB Power Delivery protocol stack. + */ + +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/devres.h> +#include <linux/compat.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <time.h> +#include <usb/tcpm.h> +#include "tcpm-internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +const char * const tcpm_states[] = { + FOREACH_TCPM_STATE(GENERATE_TCPM_STRING) +}; + +const char * const typec_pd_rev_name[] = { + [PD_REV10] = "rev1", + [PD_REV20] = "rev2", + [PD_REV30] = "rev3", +}; + +const char * const typec_role_name[] = { + [TYPEC_SINK] = "sink", + [TYPEC_SOURCE] = "source", +}; + +const char * const typec_data_role_name[] = { + [TYPEC_DEVICE] = "device", + [TYPEC_HOST] = "host", +}; + +const char * const typec_orientation_name[] = { + [TYPEC_ORIENTATION_NONE] = "none", + [TYPEC_ORIENTATION_NORMAL] = "normal", + [TYPEC_ORIENTATION_REVERSE] = "reverse", +}; + +const char * const typec_cc_status_name[] = { + [TYPEC_CC_OPEN] = "open", + [TYPEC_CC_RA] = "ra", + [TYPEC_CC_RD] = "rd", + [TYPEC_CC_RP_DEF] = "rp-def", + [TYPEC_CC_RP_1_5] = "rp-1.5", + [TYPEC_CC_RP_3_0] = "rp-3.0", +}; + +static inline bool tcpm_cc_is_sink(enum typec_cc_status cc) +{ + return cc == TYPEC_CC_RP_DEF || + cc == TYPEC_CC_RP_1_5 || + cc == TYPEC_CC_RP_3_0; +} + +static inline bool tcpm_port_is_sink(struct tcpm_port *port) +{ + bool cc1_is_snk = tcpm_cc_is_sink(port->cc1); + bool cc2_is_snk = tcpm_cc_is_sink(port->cc2); + + return (cc1_is_snk && !cc2_is_snk) || + (cc2_is_snk && !cc1_is_snk); +} + +static inline bool tcpm_cc_is_source(enum typec_cc_status cc) +{ + return cc == TYPEC_CC_RD; +} + +static inline bool tcpm_port_is_source(struct tcpm_port *port) +{ + bool cc1_is_src = tcpm_cc_is_source(port->cc1); + bool cc2_is_src = tcpm_cc_is_source(port->cc2); + + return (cc1_is_src && !cc2_is_src) || + (cc2_is_src && !cc1_is_src); +} + +static inline bool tcpm_try_src(struct tcpm_port *port) +{ + return port->try_role == TYPEC_SOURCE && + port->port_type == TYPEC_PORT_DRP; +} + +static inline void tcpm_reset_event_cnt(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + port->poll_event_cnt = 0; +} + +static enum tcpm_state tcpm_default_state(struct tcpm_port *port) +{ + if (port->port_type == TYPEC_PORT_DRP) { + if (port->try_role == TYPEC_SINK) + return SNK_UNATTACHED; + else if (port->try_role == TYPEC_SOURCE) + return SRC_UNATTACHED; + } else if (port->port_type == TYPEC_PORT_SNK) { + return SNK_UNATTACHED; + } + return SRC_UNATTACHED; +} + +static bool tcpm_port_is_disconnected(struct tcpm_port *port) +{ + return (!port->attached && port->cc1 == TYPEC_CC_OPEN && + port->cc2 == TYPEC_CC_OPEN) || + (port->attached && ((port->polarity == TYPEC_POLARITY_CC1 && + port->cc1 == TYPEC_CC_OPEN) || + (port->polarity == TYPEC_POLARITY_CC2 && + port->cc2 == TYPEC_CC_OPEN))); +} + +static void tcpm_set_cc(struct udevice *dev, enum typec_cc_status cc) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + + dev_dbg(dev, "TCPM: set cc = %d\n", cc); + port->cc_req = cc; + drvops->set_cc(dev, cc); +} + +/* + * Determine RP value to set based on maximum current supported + * by a port if configured as source. + * Returns CC value to report to link partner. + */ +static enum typec_cc_status tcpm_rp_cc(struct tcpm_port *port) +{ + const u32 *src_pdo = port->src_pdo; + int nr_pdo = port->nr_src_pdo; + int i; + + /* + * Search for first entry with matching voltage. + * It should report the maximum supported current. + */ + for (i = 0; i < nr_pdo; i++) { + const u32 pdo = src_pdo[i]; + + if (pdo_type(pdo) == PDO_TYPE_FIXED && + pdo_fixed_voltage(pdo) == 5000) { + unsigned int curr = pdo_max_current(pdo); + + if (curr >= 3000) + return TYPEC_CC_RP_3_0; + else if (curr >= 1500) + return TYPEC_CC_RP_1_5; + return TYPEC_CC_RP_DEF; + } + } + + return TYPEC_CC_RP_DEF; +} + +static void tcpm_check_and_run_delayed_work(struct udevice *dev); + +static bool tcpm_transmit_helper(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + + drvops->poll_event(dev); + udelay(500); + tcpm_check_and_run_delayed_work(dev); + return port->tx_complete; +} + +static int tcpm_pd_transmit(struct udevice *dev, + enum tcpm_transmit_type type, + const struct pd_message *msg) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + u32 timeout_us = PD_T_TCPC_TX_TIMEOUT * 1000; + bool tx_complete; + int ret; + + if (msg) + dev_dbg(dev, "TCPM: PD TX, header: %#x\n", + le16_to_cpu(msg->header)); + else + dev_dbg(dev, "TCPM: PD TX, type: %#x\n", type); + + port->tx_complete = false; + ret = drvops->pd_transmit(dev, type, msg, port->negotiated_rev); + if (ret < 0) + return ret; + + /* + * At this point we basically need to block until the TCPM controller + * returns successful transmission. Since this is usually done using + * the generic interrupt status bits, we poll for any events. That + * will clear the interrupt status, so we also need to process any + * of the incoming events. This means we will do more processing and + * thus let's give everything a bit more time. + */ + timeout_us *= 5; + ret = read_poll_timeout(tcpm_transmit_helper, tx_complete, + !tx_complete, false, timeout_us, dev); + if (ret < 0) { + dev_err(dev, "TCPM: PD transmit data failed: %d\n", ret); + return ret; + } + + switch (port->tx_status) { + case TCPC_TX_SUCCESS: + port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK; + break; + case TCPC_TX_DISCARDED: + ret = -EAGAIN; + break; + case TCPC_TX_FAILED: + default: + ret = -EIO; + break; + } + + return ret; +} + +void tcpm_pd_transmit_complete(struct udevice *dev, + enum tcpm_transmit_status status) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + dev_dbg(dev, "TCPM: PD TX complete, status: %u\n", status); + tcpm_reset_event_cnt(dev); + port->tx_status = status; + port->tx_complete = true; +} + +static int tcpm_set_polarity(struct udevice *dev, + enum typec_cc_polarity polarity) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + int ret; + + dev_dbg(dev, "TCPM: set polarity = %d\n", polarity); + + if (drvops->set_polarity) { + ret = drvops->set_polarity(dev, polarity); + if (ret < 0) + return ret; + } + + port->polarity = polarity; + + return 0; +} + +static int tcpm_set_vconn(struct udevice *dev, bool enable) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + dev_dbg(dev, "TCPM: set vconn = %d\n", enable); + + ret = drvops->set_vconn(dev, enable); + if (!ret) + port->vconn_role = enable ? TYPEC_SOURCE : TYPEC_SINK; + + return ret; +} + +static inline u32 tcpm_get_current_limit(struct tcpm_port *port) +{ + switch (port->polarity ? port->cc2 : port->cc1) { + case TYPEC_CC_RP_1_5: + return 1500; + case TYPEC_CC_RP_3_0: + return 3000; + case TYPEC_CC_RP_DEF: + default: + return 0; + } +} + +static int tcpm_set_current_limit(struct udevice *dev, u32 max_ma, u32 mv) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret = -EOPNOTSUPP; + + dev_info(dev, "TCPM: set voltage limit = %u mV\n", mv); + dev_info(dev, "TCPM: set current limit = %u mA\n", max_ma); + + port->supply_voltage = mv; + port->current_limit = max_ma; + + return ret; +} + +static int tcpm_set_attached_state(struct udevice *dev, bool attached) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + + return drvops->set_roles(dev, attached, port->pwr_role, + port->data_role); +} + +static int tcpm_set_roles(struct udevice *dev, bool attached, + enum typec_role role, enum typec_data_role data) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + ret = drvops->set_roles(dev, attached, role, data); + if (ret < 0) + return ret; + + port->pwr_role = role; + port->data_role = data; + + return 0; +} + +static int tcpm_pd_send_source_caps(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + struct pd_message msg; + int i; + + memset(&msg, 0, sizeof(msg)); + + if (!port->nr_src_pdo) { + /* No source capabilities defined, sink only */ + msg.header = PD_HEADER_LE(PD_CTRL_REJECT, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, 0); + } else { + msg.header = PD_HEADER_LE(PD_DATA_SOURCE_CAP, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, + port->nr_src_pdo); + } + + for (i = 0; i < port->nr_src_pdo; i++) + msg.payload[i] = cpu_to_le32(port->src_pdo[i]); + + return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg); +} + +static int tcpm_pd_send_sink_caps(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + struct pd_message msg; + unsigned int i; + + memset(&msg, 0, sizeof(msg)); + + if (!port->nr_snk_pdo) { + /* No sink capabilities defined, source only */ + msg.header = PD_HEADER_LE(PD_CTRL_REJECT, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, 0); + } else { + msg.header = PD_HEADER_LE(PD_DATA_SINK_CAP, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, + port->nr_snk_pdo); + } + + for (i = 0; i < port->nr_snk_pdo; i++) + msg.payload[i] = cpu_to_le32(port->snk_pdo[i]); + + return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg); +} + +static void tcpm_state_machine(struct udevice *dev); + +static inline void tcpm_timer_uninit(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + port->delay_target = 0; +} + +static void tcpm_timer_init(struct udevice *dev, uint32_t ms) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + unsigned long time_us = ms * 1000; + + port->delay_target = timer_get_us() + time_us; +} + +static void tcpm_check_and_run_delayed_work(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + /* no delayed state changes scheduled */ + if (port->delay_target == 0) + return; + + /* it's not yet time */ + if (timer_get_us() < port->delay_target) + return; + + tcpm_timer_uninit(dev); + tcpm_state_machine(dev); +} + +static void mod_tcpm_delayed_work(struct udevice *dev, unsigned int delay_ms) +{ + if (delay_ms) { + tcpm_timer_init(dev, delay_ms); + } else { + tcpm_timer_uninit(dev); + tcpm_state_machine(dev); + } +} + +static void tcpm_set_state(struct udevice *dev, enum tcpm_state state, + unsigned int delay_ms) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + if (delay_ms) { + dev_dbg(dev, "TCPM: pending state change %s -> %s @ %u ms [%s]\n", + tcpm_states[port->state], tcpm_states[state], delay_ms, + typec_pd_rev_name[port->negotiated_rev]); + port->delayed_state = state; + mod_tcpm_delayed_work(dev, delay_ms); + port->delay_ms = delay_ms; + } else { + dev_dbg(dev, "TCPM: state change %s -> %s\n", + tcpm_states[port->state], tcpm_states[state]); + port->delayed_state = INVALID_STATE; + port->prev_state = port->state; + port->state = state; + /* + * Don't re-queue the state machine work item if we're currently + * in the state machine and we're immediately changing states. + * tcpm_state_machine_work() will continue running the state + * machine. + */ + if (!port->state_machine_running) + mod_tcpm_delayed_work(dev, 0); + } +} + +static void tcpm_set_state_cond(struct udevice *dev, enum tcpm_state state, + unsigned int delay_ms) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + if (port->enter_state == port->state) + tcpm_set_state(dev, state, delay_ms); + else + dev_dbg(dev, "TCPM: skipped %sstate change %s -> %s [%u ms], context state %s [%s]\n", + delay_ms ? "delayed " : "", + tcpm_states[port->state], tcpm_states[state], + delay_ms, tcpm_states[port->enter_state], + typec_pd_rev_name[port->negotiated_rev]); +} + +static void tcpm_queue_message(struct udevice *dev, + enum pd_msg_request message) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + port->queued_message = message; + mod_tcpm_delayed_work(dev, 0); +} + +enum pdo_err { + PDO_NO_ERR, + PDO_ERR_NO_VSAFE5V, + PDO_ERR_VSAFE5V_NOT_FIRST, + PDO_ERR_PDO_TYPE_NOT_IN_ORDER, + PDO_ERR_FIXED_NOT_SORTED, + PDO_ERR_VARIABLE_BATT_NOT_SORTED, + PDO_ERR_DUPE_PDO, + PDO_ERR_PPS_APDO_NOT_SORTED, + PDO_ERR_DUPE_PPS_APDO, +}; + +static const char * const pdo_err_msg[] = { + [PDO_ERR_NO_VSAFE5V] = + " err: source/sink caps should at least have vSafe5V", + [PDO_ERR_VSAFE5V_NOT_FIRST] = + " err: vSafe5V Fixed Supply Object Shall always be the first object", + [PDO_ERR_PDO_TYPE_NOT_IN_ORDER] = + " err: PDOs should be in the following order: Fixed; Battery; Variable", + [PDO_ERR_FIXED_NOT_SORTED] = + " err: Fixed supply pdos should be in increasing order of their fixed voltage", + [PDO_ERR_VARIABLE_BATT_NOT_SORTED] = + " err: Variable/Battery supply pdos should be in increasing order of their minimum voltage", + [PDO_ERR_DUPE_PDO] = + " err: Variable/Batt supply pdos cannot have same min/max voltage", + [PDO_ERR_PPS_APDO_NOT_SORTED] = + " err: Programmable power supply apdos should be in increasing order of their maximum voltage", + [PDO_ERR_DUPE_PPS_APDO] = + " err: Programmable power supply apdos cannot have same min/max voltage and max current", +}; + +static enum pdo_err tcpm_caps_err(struct udevice *dev, const u32 *pdo, + unsigned int nr_pdo) +{ + unsigned int i; + + /* Should at least contain vSafe5v */ + if (nr_pdo < 1) + return PDO_ERR_NO_VSAFE5V; + + /* The vSafe5V Fixed Supply Object Shall always be the first object */ + if (pdo_type(pdo[0]) != PDO_TYPE_FIXED || + pdo_fixed_voltage(pdo[0]) != VSAFE5V) + return PDO_ERR_VSAFE5V_NOT_FIRST; + + for (i = 1; i < nr_pdo; i++) { + if (pdo_type(pdo[i]) < pdo_type(pdo[i - 1])) { + return PDO_ERR_PDO_TYPE_NOT_IN_ORDER; + } else if (pdo_type(pdo[i]) == pdo_type(pdo[i - 1])) { + enum pd_pdo_type type = pdo_type(pdo[i]); + + switch (type) { + /* + * The remaining Fixed Supply Objects, if + * present, shall be sent in voltage order; + * lowest to highest. + */ + case PDO_TYPE_FIXED: + if (pdo_fixed_voltage(pdo[i]) <= + pdo_fixed_voltage(pdo[i - 1])) + return PDO_ERR_FIXED_NOT_SORTED; + break; + /* + * The Battery Supply Objects and Variable + * supply, if present shall be sent in Minimum + * Voltage order; lowest to highest. + */ + case PDO_TYPE_VAR: + case PDO_TYPE_BATT: + if (pdo_min_voltage(pdo[i]) < + pdo_min_voltage(pdo[i - 1])) + return PDO_ERR_VARIABLE_BATT_NOT_SORTED; + else if ((pdo_min_voltage(pdo[i]) == + pdo_min_voltage(pdo[i - 1])) && + (pdo_max_voltage(pdo[i]) == + pdo_max_voltage(pdo[i - 1]))) + return PDO_ERR_DUPE_PDO; + break; + /* + * The Programmable Power Supply APDOs, if present, + * shall be sent in Maximum Voltage order; + * lowest to highest. + */ + case PDO_TYPE_APDO: + if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS) + break; + + if (pdo_pps_apdo_max_voltage(pdo[i]) < + pdo_pps_apdo_max_voltage(pdo[i - 1])) + return PDO_ERR_PPS_APDO_NOT_SORTED; + else if (pdo_pps_apdo_min_voltage(pdo[i]) == + pdo_pps_apdo_min_voltage(pdo[i - 1]) && + pdo_pps_apdo_max_voltage(pdo[i]) == + pdo_pps_apdo_max_voltage(pdo[i - 1]) && + pdo_pps_apdo_max_current(pdo[i]) == + pdo_pps_apdo_max_current(pdo[i - 1])) + return PDO_ERR_DUPE_PPS_APDO; + break; + default: + dev_err(dev, "TCPM: Unknown pdo type\n"); + } + } + } + + return PDO_NO_ERR; +} + +static int tcpm_validate_caps(struct udevice *dev, const u32 *pdo, + unsigned int nr_pdo) +{ + enum pdo_err err_index = tcpm_caps_err(dev, pdo, nr_pdo); + + if (err_index != PDO_NO_ERR) { + dev_err(dev, "TCPM:%s\n", pdo_err_msg[err_index]); + return -EINVAL; + } + + return 0; +} + +/* + * PD (data, control) command handling functions + */ +static inline enum tcpm_state ready_state(struct tcpm_port *port) +{ + if (port->pwr_role == TYPEC_SOURCE) + return SRC_READY; + else + return SNK_READY; +} + +static void tcpm_pd_data_request(struct udevice *dev, + const struct pd_message *msg) +{ + enum pd_data_msg_type type = pd_header_type_le(msg->header); + struct tcpm_port *port = dev_get_uclass_plat(dev); + unsigned int cnt = pd_header_cnt_le(msg->header); + unsigned int rev = pd_header_rev_le(msg->header); + unsigned int i; + + switch (type) { + case PD_DATA_SOURCE_CAP: + for (i = 0; i < cnt; i++) + port->source_caps[i] = le32_to_cpu(msg->payload[i]); + + port->nr_source_caps = cnt; + + tcpm_validate_caps(dev, port->source_caps, + port->nr_source_caps); + + /* + * Adjust revision in subsequent message headers, as required, + * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't + * support Rev 1.0 so just do nothing in that scenario. + */ + if (rev == PD_REV10) + break; + + if (rev < PD_MAX_REV) + port->negotiated_rev = rev; + + if ((pdo_type(port->source_caps[0]) == PDO_TYPE_FIXED) && + (port->source_caps[0] & PDO_FIXED_DUAL_ROLE) && + (port->source_caps[0] & PDO_FIXED_DATA_SWAP)) { + /* Dual role power and data, eg: self-powered Type-C */ + port->wait_dr_swap_message = true; + } else { + /* Non-Dual role power, eg: adapter */ + port->wait_dr_swap_message = false; + } + + /* + * This message may be received even if VBUS is not + * present. This is quite unexpected; see USB PD + * specification, sections 8.3.3.6.3.1 and 8.3.3.6.3.2. + * However, at the same time, we must be ready to + * receive this message and respond to it 15ms after + * receiving PS_RDY during power swap operations, no matter + * if VBUS is available or not (USB PD specification, + * section 6.5.9.2). + * So we need to accept the message either way, + * but be prepared to keep waiting for VBUS after it was + * handled. + */ + tcpm_set_state(dev, SNK_NEGOTIATE_CAPABILITIES, 0); + break; + case PD_DATA_REQUEST: + /* + * Adjust revision in subsequent message headers, as required, + * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't + * support Rev 1.0 so just reject in that scenario. + */ + if (rev == PD_REV10) { + tcpm_queue_message(dev, PD_MSG_CTRL_REJECT); + break; + } + + if (rev < PD_MAX_REV) + port->negotiated_rev = rev; + + port->sink_request = le32_to_cpu(msg->payload[0]); + + tcpm_set_state(dev, SRC_NEGOTIATE_CAPABILITIES, 0); + break; + case PD_DATA_SINK_CAP: + /* We don't do anything with this at the moment... */ + for (i = 0; i < cnt; i++) + port->sink_caps[i] = le32_to_cpu(msg->payload[i]); + + port->nr_sink_caps = cnt; + break; + default: + break; + } +} + +static void tcpm_pd_ctrl_request(struct udevice *dev, + const struct pd_message *msg) +{ + enum pd_ctrl_msg_type type = pd_header_type_le(msg->header); + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum tcpm_state next_state; + + switch (type) { + case PD_CTRL_GOOD_CRC: + case PD_CTRL_PING: + break; + case PD_CTRL_GET_SOURCE_CAP: + switch (port->state) { + case SRC_READY: + case SNK_READY: + tcpm_queue_message(dev, PD_MSG_DATA_SOURCE_CAP); + break; + default: + tcpm_queue_message(dev, PD_MSG_CTRL_REJECT); + break; + } + break; + case PD_CTRL_GET_SINK_CAP: + switch (port->state) { + case SRC_READY: + case SNK_READY: + tcpm_queue_message(dev, PD_MSG_DATA_SINK_CAP); + break; + default: + tcpm_queue_message(dev, PD_MSG_CTRL_REJECT); + break; + } + break; + case PD_CTRL_GOTO_MIN: + break; + case PD_CTRL_PS_RDY: + switch (port->state) { + case SNK_TRANSITION_SINK: + if (port->vbus_present) { + tcpm_set_current_limit(dev, + port->req_current_limit, + port->req_supply_voltage); + port->explicit_contract = true; + tcpm_set_state(dev, SNK_READY, 0); + } else { + /* + * Seen after power swap. Keep waiting for VBUS + * in a transitional state. + */ + tcpm_set_state(dev, + SNK_TRANSITION_SINK_VBUS, 0); + } + break; + default: + break; + } + break; + case PD_CTRL_REJECT: + case PD_CTRL_WAIT: + case PD_CTRL_NOT_SUPP: + switch (port->state) { + case SNK_NEGOTIATE_CAPABILITIES: + /* USB PD specification, Figure 8-43 */ + if (port->explicit_contract) + next_state = SNK_READY; + else + next_state = SNK_WAIT_CAPABILITIES; + + tcpm_set_state(dev, next_state, 0); + break; + default: + break; + } + break; + case PD_CTRL_ACCEPT: + switch (port->state) { + case SNK_NEGOTIATE_CAPABILITIES: + tcpm_set_state(dev, SNK_TRANSITION_SINK, 0); + break; + case SOFT_RESET_SEND: + port->message_id = 0; + port->rx_msgid = -1; + if (port->pwr_role == TYPEC_SOURCE) + next_state = SRC_SEND_CAPABILITIES; + else + next_state = SNK_WAIT_CAPABILITIES; + tcpm_set_state(dev, next_state, 0); + break; + default: + break; + } + break; + case PD_CTRL_SOFT_RESET: + tcpm_set_state(dev, SOFT_RESET, 0); + break; + case PD_CTRL_DR_SWAP: + if (port->port_type != TYPEC_PORT_DRP) { + tcpm_queue_message(dev, PD_MSG_CTRL_REJECT); + break; + } + /* + * 6.3.9: If an alternate mode is active, a request to swap + * alternate modes shall trigger a port reset. + */ + switch (port->state) { + case SRC_READY: + case SNK_READY: + tcpm_set_state(dev, DR_SWAP_ACCEPT, 0); + break; + default: + tcpm_queue_message(dev, PD_MSG_CTRL_WAIT); + break; + } + break; + case PD_CTRL_PR_SWAP: + case PD_CTRL_VCONN_SWAP: + case PD_CTRL_GET_SOURCE_CAP_EXT: + case PD_CTRL_GET_STATUS: + case PD_CTRL_FR_SWAP: + case PD_CTRL_GET_PPS_STATUS: + case PD_CTRL_GET_COUNTRY_CODES: + /* Currently not supported */ + dev_err(dev, "TCPM: Currently not supported type %#x\n", type); + tcpm_queue_message(dev, PD_MSG_CTRL_NOT_SUPP); + break; + default: + dev_err(dev, "TCPM: Unrecognized ctrl message type %#x\n", type); + break; + } +} + +static void tcpm_pd_rx_handler(struct udevice *dev, + const struct pd_message *msg) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + unsigned int cnt = pd_header_cnt_le(msg->header); + bool remote_is_host, local_is_host; + + dev_dbg(dev, "TCPM: PD RX, header: %#x [%d]\n", + le16_to_cpu(msg->header), port->attached); + + if (port->attached) { + enum pd_ctrl_msg_type type = pd_header_type_le(msg->header); + unsigned int msgid = pd_header_msgid_le(msg->header); + + /* + * USB PD standard, 6.6.1.2: + * "... if MessageID value in a received Message is the + * same as the stored value, the receiver shall return a + * GoodCRC Message with that MessageID value and drop + * the Message (this is a retry of an already received + * Message). Note: this shall not apply to the Soft_Reset + * Message which always has a MessageID value of zero." + */ + if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET) + return; + port->rx_msgid = msgid; + + /* + * If both ends believe to be DFP/host, we have a data role + * mismatch. + */ + remote_is_host = !!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE); + local_is_host = port->data_role == TYPEC_HOST; + if (remote_is_host == local_is_host) { + dev_err(dev, "TCPM: data role mismatch, initiating error recovery\n"); + tcpm_set_state(dev, ERROR_RECOVERY, 0); + } else { + if (cnt) + tcpm_pd_data_request(dev, msg); + else + tcpm_pd_ctrl_request(dev, msg); + } + } +} + +void tcpm_pd_receive(struct udevice *dev, const struct pd_message *msg) +{ + tcpm_reset_event_cnt(dev); + tcpm_pd_rx_handler(dev, msg); +} + +static int tcpm_pd_send_control(struct udevice *dev, + enum pd_ctrl_msg_type type) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + struct pd_message msg; + + memset(&msg, 0, sizeof(msg)); + msg.header = PD_HEADER_LE(type, port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, 0); + + return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg); +} + +/* + * Send queued message without affecting state. + * Return true if state machine should go back to sleep, + * false otherwise. + */ +static bool tcpm_send_queued_message(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum pd_msg_request queued_message; + int max_messages = 100; + + do { + queued_message = port->queued_message; + port->queued_message = PD_MSG_NONE; + max_messages--; + + switch (queued_message) { + case PD_MSG_CTRL_WAIT: + tcpm_pd_send_control(dev, PD_CTRL_WAIT); + break; + case PD_MSG_CTRL_REJECT: + tcpm_pd_send_control(dev, PD_CTRL_REJECT); + break; + case PD_MSG_CTRL_NOT_SUPP: + tcpm_pd_send_control(dev, PD_CTRL_NOT_SUPP); + break; + case PD_MSG_DATA_SINK_CAP: + tcpm_pd_send_sink_caps(dev); + break; + case PD_MSG_DATA_SOURCE_CAP: + tcpm_pd_send_source_caps(dev); + break; + default: + break; + } + } while (max_messages > 0 && port->queued_message != PD_MSG_NONE); + + if (!max_messages) + dev_err(dev, "Aborted sending of too many queued messages\n"); + + return false; +} + +static int tcpm_pd_check_request(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + u32 pdo, rdo = port->sink_request; + unsigned int max, op, pdo_max, index; + enum pd_pdo_type type; + + index = rdo_index(rdo); + if (!index || index > port->nr_src_pdo) + return -EINVAL; + + pdo = port->src_pdo[index - 1]; + type = pdo_type(pdo); + switch (type) { + case PDO_TYPE_FIXED: + case PDO_TYPE_VAR: + max = rdo_max_current(rdo); + op = rdo_op_current(rdo); + pdo_max = pdo_max_current(pdo); + + if (op > pdo_max) + return -EINVAL; + if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH)) + return -EINVAL; + + if (type == PDO_TYPE_FIXED) + dev_dbg(dev, "TCPM: Requested %u mV, %u mA for %u / %u mA\n", + pdo_fixed_voltage(pdo), pdo_max, op, max); + else + dev_dbg(dev, "TCPM: Requested %u -> %u mV, %u mA for %u / %u mA\n", + pdo_min_voltage(pdo), pdo_max_voltage(pdo), + pdo_max, op, max); + break; + case PDO_TYPE_BATT: + max = rdo_max_power(rdo); + op = rdo_op_power(rdo); + pdo_max = pdo_max_power(pdo); + + if (op > pdo_max) + return -EINVAL; + if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH)) + return -EINVAL; + dev_info(dev, "TCPM: Requested %u -> %u mV, %u mW for %u / %u mW\n", + pdo_min_voltage(pdo), pdo_max_voltage(pdo), + pdo_max, op, max); + break; + default: + return -EINVAL; + } + + return 0; +} + +#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y)) +#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y)) + +static int tcpm_pd_select_pdo(struct udevice *dev, int *sink_pdo, + int *src_pdo) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + unsigned int i, j, max_src_mv = 0, min_src_mv = 0, max_mw = 0, + max_mv = 0, src_mw = 0, src_ma = 0, max_snk_mv = 0, + min_snk_mv = 0; + int ret = -EINVAL; + + /* + * Select the source PDO providing the most power which has a + * matchig sink cap. + */ + for (i = 0; i < port->nr_source_caps; i++) { + u32 pdo = port->source_caps[i]; + enum pd_pdo_type type = pdo_type(pdo); + + switch (type) { + case PDO_TYPE_FIXED: + max_src_mv = pdo_fixed_voltage(pdo); + min_src_mv = max_src_mv; + break; + case PDO_TYPE_BATT: + case PDO_TYPE_VAR: + max_src_mv = pdo_max_voltage(pdo); + min_src_mv = pdo_min_voltage(pdo); + break; + case PDO_TYPE_APDO: + continue; + default: + dev_err(dev, "TCPM: Invalid source PDO type, ignoring\n"); + continue; + } + + switch (type) { + case PDO_TYPE_FIXED: + case PDO_TYPE_VAR: + src_ma = pdo_max_current(pdo); + src_mw = src_ma * min_src_mv / 1000; + break; + case PDO_TYPE_BATT: + src_mw = pdo_max_power(pdo); + break; + case PDO_TYPE_APDO: + continue; + default: + dev_err(dev, "TCPM: Invalid source PDO type, ignoring\n"); + continue; + } + + for (j = 0; j < port->nr_snk_pdo; j++) { + pdo = port->snk_pdo[j]; + + switch (pdo_type(pdo)) { + case PDO_TYPE_FIXED: + max_snk_mv = pdo_fixed_voltage(pdo); + min_snk_mv = max_snk_mv; + break; + case PDO_TYPE_BATT: + case PDO_TYPE_VAR: + max_snk_mv = pdo_max_voltage(pdo); + min_snk_mv = pdo_min_voltage(pdo); + break; + case PDO_TYPE_APDO: + continue; + default: + dev_err(dev, "TCPM: Invalid sink PDO type, ignoring\n"); + continue; + } + + if (max_src_mv <= max_snk_mv && min_src_mv >= min_snk_mv) { + /* Prefer higher voltages if available */ + if ((src_mw == max_mw && min_src_mv > max_mv) || + src_mw > max_mw) { + *src_pdo = i; + *sink_pdo = j; + max_mw = src_mw; + max_mv = min_src_mv; + ret = 0; + } + } + } + } + + return ret; +} + +static int tcpm_pd_build_request(struct udevice *dev, u32 *rdo) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + unsigned int mv, ma, mw, flags; + unsigned int max_ma, max_mw; + enum pd_pdo_type type; + u32 pdo, matching_snk_pdo; + int src_pdo_index = 0; + int snk_pdo_index = 0; + int ret; + + ret = tcpm_pd_select_pdo(dev, &snk_pdo_index, &src_pdo_index); + if (ret < 0) + return ret; + + pdo = port->source_caps[src_pdo_index]; + matching_snk_pdo = port->snk_pdo[snk_pdo_index]; + type = pdo_type(pdo); + + switch (type) { + case PDO_TYPE_FIXED: + mv = pdo_fixed_voltage(pdo); + break; + case PDO_TYPE_BATT: + case PDO_TYPE_VAR: + mv = pdo_min_voltage(pdo); + break; + default: + dev_err(dev, "TCPM: Invalid PDO selected!\n"); + return -EINVAL; + } + + /* Select maximum available current within the sink pdo's limit */ + if (type == PDO_TYPE_BATT) { + mw = min_power(pdo, matching_snk_pdo); + ma = 1000 * mw / mv; + } else { + ma = min_current(pdo, matching_snk_pdo); + mw = ma * mv / 1000; + } + + flags = RDO_USB_COMM | RDO_NO_SUSPEND; + + /* Set mismatch bit if offered power is less than operating power */ + max_ma = ma; + max_mw = mw; + if (mw < port->operating_snk_mw) { + flags |= RDO_CAP_MISMATCH; + if (type == PDO_TYPE_BATT && + (pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo))) + max_mw = pdo_max_power(matching_snk_pdo); + else if (pdo_max_current(matching_snk_pdo) > + pdo_max_current(pdo)) + max_ma = pdo_max_current(matching_snk_pdo); + } + + dev_dbg(dev, "TCPM: cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d\n", + port->cc_req, port->cc1, port->cc2, port->vbus_source, + port->vconn_role == TYPEC_SOURCE ? "source" : "sink", + port->polarity); + + if (type == PDO_TYPE_BATT) { + *rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags); + + dev_info(dev, "TCPM: requesting PDO %d: %u mV, %u mW%s\n", + src_pdo_index, mv, mw, + flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); + } else { + *rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags); + + dev_info(dev, "TCPM: requesting PDO %d: %u mV, %u mA%s\n", + src_pdo_index, mv, ma, + flags & RDO_CAP_MISMATCH ? " [mismatch]" : ""); + } + + port->req_current_limit = ma; + port->req_supply_voltage = mv; + + return 0; +} + +static int tcpm_pd_send_request(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + struct pd_message msg; + int ret; + u32 rdo; + + ret = tcpm_pd_build_request(dev, &rdo); + if (ret < 0) + return ret; + + memset(&msg, 0, sizeof(msg)); + msg.header = PD_HEADER_LE(PD_DATA_REQUEST, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, 1); + msg.payload[0] = cpu_to_le32(rdo); + + return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg); +} + +static int tcpm_set_vbus(struct udevice *dev, bool enable) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + int ret; + + if (enable && port->vbus_charge) + return -EINVAL; + + dev_dbg(dev, "TCPM: set vbus = %d charge = %d\n", + enable, port->vbus_charge); + + ret = drvops->set_vbus(dev, enable, port->vbus_charge); + if (ret < 0) + return ret; + + port->vbus_source = enable; + return 0; +} + +static int tcpm_set_charge(struct udevice *dev, bool charge) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + if (charge && port->vbus_source) + return -EINVAL; + + if (charge != port->vbus_charge) { + dev_dbg(dev, "TCPM: set vbus = %d charge = %d\n", + port->vbus_source, charge); + ret = drvops->set_vbus(dev, port->vbus_source, + charge); + if (ret < 0) + return ret; + } + port->vbus_charge = charge; + return 0; +} + +static bool tcpm_start_toggling(struct udevice *dev, enum typec_cc_status cc) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + if (!drvops->start_toggling) + return false; + + dev_dbg(dev, "TCPM: Start toggling\n"); + ret = drvops->start_toggling(dev, port->port_type, cc); + return ret == 0; +} + +static int tcpm_init_vbus(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + ret = drvops->set_vbus(dev, false, false); + port->vbus_source = false; + port->vbus_charge = false; + return ret; +} + +static int tcpm_init_vconn(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + ret = drvops->set_vconn(dev, false); + port->vconn_role = TYPEC_SINK; + return ret; +} + +static inline void tcpm_typec_connect(struct tcpm_port *port) +{ + if (!port->connected) + port->connected = true; +} + +static int tcpm_src_attach(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum typec_cc_polarity polarity = + port->cc2 == TYPEC_CC_RD ? TYPEC_POLARITY_CC2 + : TYPEC_POLARITY_CC1; + int ret; + + if (port->attached) + return 0; + + ret = tcpm_set_polarity(dev, polarity); + if (ret < 0) + return ret; + + ret = tcpm_set_roles(dev, true, TYPEC_SOURCE, TYPEC_HOST); + if (ret < 0) + return ret; + + ret = drvops->set_pd_rx(dev, true); + if (ret < 0) + goto out_disable_mux; + + /* + * USB Type-C specification, version 1.2, + * chapter 4.5.2.2.8.1 (Attached.SRC Requirements) + * Enable VCONN only if the non-RD port is set to RA. + */ + if ((polarity == TYPEC_POLARITY_CC1 && port->cc2 == TYPEC_CC_RA) || + (polarity == TYPEC_POLARITY_CC2 && port->cc1 == TYPEC_CC_RA)) { + ret = tcpm_set_vconn(dev, true); + if (ret < 0) + goto out_disable_pd; + } + + ret = tcpm_set_vbus(dev, true); + if (ret < 0) + goto out_disable_vconn; + + port->pd_capable = false; + + port->partner = NULL; + + port->attached = true; + + return 0; + +out_disable_vconn: + tcpm_set_vconn(dev, false); +out_disable_pd: + drvops->set_pd_rx(dev, false); +out_disable_mux: + dev_err(dev, "TCPM: CC connected in %s as DFP\n", + polarity ? "CC2" : "CC1"); + return 0; +} + +static inline void tcpm_typec_disconnect(struct tcpm_port *port) +{ + if (port->connected) { + port->partner = NULL; + port->connected = false; + } +} + +static void tcpm_reset_port(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + + tcpm_timer_uninit(dev); + tcpm_typec_disconnect(port); + tcpm_reset_event_cnt(dev); + port->wait_dr_swap_message = false; + port->attached = false; + port->pd_capable = false; + + /* + * First Rx ID should be 0; set this to a sentinel of -1 so that + * we can check tcpm_pd_rx_handler() if we had seen it before. + */ + port->rx_msgid = -1; + + drvops->set_pd_rx(dev, false); + tcpm_init_vbus(dev); /* also disables charging */ + tcpm_init_vconn(dev); + tcpm_set_current_limit(dev, 0, 0); + tcpm_set_polarity(dev, TYPEC_POLARITY_CC1); + tcpm_set_attached_state(dev, false); + port->nr_sink_caps = 0; +} + +static void tcpm_detach(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + if (tcpm_port_is_disconnected(port)) + port->hard_reset_count = 0; + + if (!port->attached) + return; + + tcpm_reset_port(dev); +} + +static void tcpm_src_detach(struct udevice *dev) +{ + tcpm_detach(dev); +} + +static int tcpm_snk_attach(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + if (port->attached) + return 0; + + ret = tcpm_set_polarity(dev, port->cc2 != TYPEC_CC_OPEN ? + TYPEC_POLARITY_CC2 : TYPEC_POLARITY_CC1); + if (ret < 0) + return ret; + + ret = tcpm_set_roles(dev, true, TYPEC_SINK, TYPEC_DEVICE); + if (ret < 0) + return ret; + + port->pd_capable = false; + + port->partner = NULL; + + port->attached = true; + dev_info(dev, "TCPM: CC connected in %s as UFP\n", + port->cc1 != TYPEC_CC_OPEN ? "CC1" : "CC2"); + + return 0; +} + +static void tcpm_snk_detach(struct udevice *dev) +{ + tcpm_detach(dev); +} + +static inline enum tcpm_state hard_reset_state(struct tcpm_port *port) +{ + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) + return HARD_RESET_SEND; + if (port->pd_capable) + return ERROR_RECOVERY; + if (port->pwr_role == TYPEC_SOURCE) + return SRC_UNATTACHED; + if (port->state == SNK_WAIT_CAPABILITIES) + return SNK_READY; + return SNK_UNATTACHED; +} + +static inline enum tcpm_state unattached_state(struct tcpm_port *port) +{ + if (port->port_type == TYPEC_PORT_DRP) { + if (port->pwr_role == TYPEC_SOURCE) + return SRC_UNATTACHED; + else + return SNK_UNATTACHED; + } else if (port->port_type == TYPEC_PORT_SRC) { + return SRC_UNATTACHED; + } + + return SNK_UNATTACHED; +} + +static void run_state_machine(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + int ret; + + port->enter_state = port->state; + switch (port->state) { + case TOGGLING: + break; + /* SRC states */ + case SRC_UNATTACHED: + tcpm_src_detach(dev); + if (tcpm_start_toggling(dev, tcpm_rp_cc(port))) { + tcpm_set_state(dev, TOGGLING, 0); + break; + } + tcpm_set_cc(dev, tcpm_rp_cc(port)); + if (port->port_type == TYPEC_PORT_DRP) + tcpm_set_state(dev, SNK_UNATTACHED, PD_T_DRP_SNK); + break; + case SRC_ATTACH_WAIT: + if (tcpm_port_is_source(port)) + tcpm_set_state(dev, SRC_ATTACHED, PD_T_CC_DEBOUNCE); + break; + + case SRC_ATTACHED: + ret = tcpm_src_attach(dev); + /* + * Currently, vbus control is not implemented, + * and the SRC detection process cannot be fully implemented. + */ + tcpm_set_state(dev, SRC_READY, 0); + break; + case SRC_STARTUP: + port->caps_count = 0; + port->negotiated_rev = PD_MAX_REV; + port->message_id = 0; + port->rx_msgid = -1; + port->explicit_contract = false; + tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0); + break; + case SRC_SEND_CAPABILITIES: + port->caps_count++; + if (port->caps_count > PD_N_CAPS_COUNT) { + tcpm_set_state(dev, SRC_READY, 0); + break; + } + ret = tcpm_pd_send_source_caps(dev); + if (ret < 0) { + tcpm_set_state(dev, SRC_SEND_CAPABILITIES, + PD_T_SEND_SOURCE_CAP); + } else { + /* + * Per standard, we should clear the reset counter here. + * However, that can result in state machine hang-ups. + * Reset it only in READY state to improve stability. + */ + /* port->hard_reset_count = 0; */ + port->caps_count = 0; + port->pd_capable = true; + tcpm_set_state_cond(dev, SRC_SEND_CAPABILITIES_TIMEOUT, + PD_T_SEND_SOURCE_CAP); + } + break; + case SRC_SEND_CAPABILITIES_TIMEOUT: + /* + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. + * + * PD 2.0 sinks are supposed to accept src-capabilities with a + * 3.0 header and simply ignore any src PDOs which the sink does + * not understand such as PPS but some 2.0 sinks instead ignore + * the entire PD_DATA_SOURCE_CAP message, causing contract + * negotiation to fail. + * + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try + * sending src-capabilities with a lower PD revision to + * make these broken sinks work. + */ + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) { + tcpm_set_state(dev, HARD_RESET_SEND, 0); + } else if (port->negotiated_rev > PD_REV20) { + port->negotiated_rev--; + port->hard_reset_count = 0; + tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0); + } else { + tcpm_set_state(dev, hard_reset_state(port), 0); + } + break; + case SRC_NEGOTIATE_CAPABILITIES: + ret = tcpm_pd_check_request(dev); + if (ret < 0) { + tcpm_pd_send_control(dev, PD_CTRL_REJECT); + if (!port->explicit_contract) { + tcpm_set_state(dev, + SRC_WAIT_NEW_CAPABILITIES, 0); + } else { + tcpm_set_state(dev, SRC_READY, 0); + } + } else { + tcpm_pd_send_control(dev, PD_CTRL_ACCEPT); + tcpm_set_state(dev, SRC_TRANSITION_SUPPLY, + PD_T_SRC_TRANSITION); + } + break; + case SRC_TRANSITION_SUPPLY: + /* XXX: regulator_set_voltage(vbus, ...) */ + tcpm_pd_send_control(dev, PD_CTRL_PS_RDY); + port->explicit_contract = true; + tcpm_set_state_cond(dev, SRC_READY, 0); + break; + case SRC_READY: + port->hard_reset_count = 0; + + tcpm_typec_connect(port); + break; + case SRC_WAIT_NEW_CAPABILITIES: + /* Nothing to do... */ + break; + + /* SNK states */ + case SNK_UNATTACHED: + tcpm_snk_detach(dev); + if (tcpm_start_toggling(dev, TYPEC_CC_RD)) { + tcpm_set_state(dev, TOGGLING, 0); + break; + } + tcpm_set_cc(dev, TYPEC_CC_RD); + if (port->port_type == TYPEC_PORT_DRP) + tcpm_set_state(dev, SRC_UNATTACHED, PD_T_DRP_SRC); + break; + case SNK_ATTACH_WAIT: + if ((port->cc1 == TYPEC_CC_OPEN && + port->cc2 != TYPEC_CC_OPEN) || + (port->cc1 != TYPEC_CC_OPEN && + port->cc2 == TYPEC_CC_OPEN)) + tcpm_set_state(dev, SNK_DEBOUNCED, + PD_T_CC_DEBOUNCE); + else if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, SNK_UNATTACHED, + PD_T_CC_DEBOUNCE); + break; + case SNK_DEBOUNCED: + if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, SNK_UNATTACHED, PD_T_PD_DEBOUNCE); + else if (port->vbus_present) + tcpm_set_state(dev, SNK_ATTACHED, 0); + else + /* Wait for VBUS, but not forever */ + tcpm_set_state(dev, PORT_RESET, PD_T_PS_SOURCE_ON); + break; + case SNK_ATTACHED: + ret = tcpm_snk_attach(dev); + if (ret < 0) + tcpm_set_state(dev, SNK_UNATTACHED, 0); + else + tcpm_set_state(dev, SNK_STARTUP, 0); + break; + case SNK_STARTUP: + port->negotiated_rev = PD_MAX_REV; + port->message_id = 0; + port->rx_msgid = -1; + port->explicit_contract = false; + tcpm_set_state(dev, SNK_DISCOVERY, 0); + break; + case SNK_DISCOVERY: + if (port->vbus_present) { + tcpm_set_current_limit(dev, + tcpm_get_current_limit(port), + 5000); + tcpm_set_charge(dev, true); + tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0); + break; + } + /* + * For DRP, timeouts differ. Also, handling is supposed to be + * different and much more complex (dead battery detection; + * see USB power delivery specification, section 8.3.3.6.1.5.1). + */ + tcpm_set_state(dev, hard_reset_state(port), + port->port_type == TYPEC_PORT_DRP ? + PD_T_DB_DETECT : PD_T_NO_RESPONSE); + break; + case SNK_DISCOVERY_DEBOUNCE: + tcpm_set_state(dev, SNK_DISCOVERY_DEBOUNCE_DONE, + PD_T_CC_DEBOUNCE); + break; + case SNK_DISCOVERY_DEBOUNCE_DONE: + tcpm_set_state(dev, unattached_state(port), 0); + break; + case SNK_WAIT_CAPABILITIES: + ret = drvops->set_pd_rx(dev, true); + if (ret < 0) { + tcpm_set_state(dev, SNK_READY, 0); + break; + } + /* + * If VBUS has never been low, and we time out waiting + * for source cap, try a soft reset first, in case we + * were already in a stable contract before this boot. + * Do this only once. + */ + if (port->vbus_never_low) { + port->vbus_never_low = false; + tcpm_set_state(dev, SOFT_RESET_SEND, + PD_T_SINK_WAIT_CAP); + } else { + tcpm_set_state(dev, hard_reset_state(port), + PD_T_SINK_WAIT_CAP); + } + break; + case SNK_NEGOTIATE_CAPABILITIES: + port->pd_capable = true; + port->hard_reset_count = 0; + ret = tcpm_pd_send_request(dev); + if (ret < 0) { + /* Let the Source send capabilities again. */ + tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0); + } else { + tcpm_set_state_cond(dev, hard_reset_state(port), + PD_T_SENDER_RESPONSE); + } + break; + case SNK_TRANSITION_SINK: + case SNK_TRANSITION_SINK_VBUS: + tcpm_set_state(dev, hard_reset_state(port), + PD_T_PS_TRANSITION); + break; + case SNK_READY: + port->update_sink_caps = false; + tcpm_typec_connect(port); + /* + * Here poll_event_cnt is cleared, waiting for self-powered Type-C devices + * to send DR_swap Messge until 1s (TCPM_POLL_EVENT_TIME_OUT * 500us)timeout + */ + if (port->wait_dr_swap_message) + tcpm_reset_event_cnt(dev); + + break; + + /* Hard_Reset states */ + case HARD_RESET_SEND: + tcpm_pd_transmit(dev, TCPC_TX_HARD_RESET, NULL); + tcpm_set_state(dev, HARD_RESET_START, 0); + port->wait_dr_swap_message = false; + break; + case HARD_RESET_START: + port->hard_reset_count++; + drvops->set_pd_rx(dev, false); + port->nr_sink_caps = 0; + if (port->pwr_role == TYPEC_SOURCE) + tcpm_set_state(dev, SRC_HARD_RESET_VBUS_OFF, + PD_T_PS_HARD_RESET); + else + tcpm_set_state(dev, SNK_HARD_RESET_SINK_OFF, 0); + break; + case SRC_HARD_RESET_VBUS_OFF: + tcpm_set_vconn(dev, true); + tcpm_set_vbus(dev, false); + tcpm_set_roles(dev, port->self_powered, TYPEC_SOURCE, + TYPEC_HOST); + tcpm_set_state(dev, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER); + break; + case SRC_HARD_RESET_VBUS_ON: + tcpm_set_vconn(dev, true); + tcpm_set_vbus(dev, true); + drvops->set_pd_rx(dev, true); + tcpm_set_attached_state(dev, true); + tcpm_set_state(dev, SRC_UNATTACHED, PD_T_PS_SOURCE_ON); + break; + case SNK_HARD_RESET_SINK_OFF: + tcpm_set_vconn(dev, false); + if (port->pd_capable) + tcpm_set_charge(dev, false); + tcpm_set_roles(dev, port->self_powered, TYPEC_SINK, + TYPEC_DEVICE); + /* + * VBUS may or may not toggle, depending on the adapter. + * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON + * directly after timeout. + */ + tcpm_set_state(dev, SNK_HARD_RESET_SINK_ON, PD_T_SAFE_0V); + break; + case SNK_HARD_RESET_WAIT_VBUS: + /* Assume we're disconnected if VBUS doesn't come back. */ + tcpm_set_state(dev, SNK_UNATTACHED, + PD_T_SRC_RECOVER_MAX + PD_T_SRC_TURN_ON); + break; + case SNK_HARD_RESET_SINK_ON: + /* Note: There is no guarantee that VBUS is on in this state */ + /* + * XXX: + * The specification suggests that dual mode ports in sink + * mode should transition to state PE_SRC_Transition_to_default. + * See USB power delivery specification chapter 8.3.3.6.1.3. + * This would mean to + * - turn off VCONN, reset power supply + * - request hardware reset + * - turn on VCONN + * - Transition to state PE_Src_Startup + * SNK only ports shall transition to state Snk_Startup + * (see chapter 8.3.3.3.8). + * Similar, dual-mode ports in source mode should transition + * to PE_SNK_Transition_to_default. + */ + if (port->pd_capable) { + tcpm_set_current_limit(dev, + tcpm_get_current_limit(port), + 5000); + tcpm_set_charge(dev, true); + } + tcpm_set_attached_state(dev, true); + tcpm_set_state(dev, SNK_STARTUP, 0); + break; + + /* Soft_Reset states */ + case SOFT_RESET: + port->message_id = 0; + port->rx_msgid = -1; + tcpm_pd_send_control(dev, PD_CTRL_ACCEPT); + if (port->pwr_role == TYPEC_SOURCE) + tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0); + else + tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0); + break; + case SOFT_RESET_SEND: + port->message_id = 0; + port->rx_msgid = -1; + if (tcpm_pd_send_control(dev, PD_CTRL_SOFT_RESET)) + tcpm_set_state_cond(dev, hard_reset_state(port), 0); + else + tcpm_set_state_cond(dev, hard_reset_state(port), + PD_T_SENDER_RESPONSE); + break; + + /* DR_Swap states */ + case DR_SWAP_ACCEPT: + tcpm_pd_send_control(dev, PD_CTRL_ACCEPT); + tcpm_set_state_cond(dev, DR_SWAP_CHANGE_DR, 0); + break; + case DR_SWAP_CHANGE_DR: + if (port->data_role == TYPEC_HOST) { + tcpm_set_roles(dev, true, port->pwr_role, + TYPEC_DEVICE); + } else { + tcpm_set_roles(dev, true, port->pwr_role, + TYPEC_HOST); + } + /* DR_swap process complete, wait_dr_swap_message is cleared */ + port->wait_dr_swap_message = false; + tcpm_set_state(dev, ready_state(port), 0); + break; + case ERROR_RECOVERY: + tcpm_set_state(dev, PORT_RESET, 0); + break; + case PORT_RESET: + tcpm_reset_port(dev); + if (port->self_powered) + tcpm_set_cc(dev, TYPEC_CC_OPEN); + else + tcpm_set_cc(dev, tcpm_default_state(port) == SNK_UNATTACHED ? + TYPEC_CC_RD : tcpm_rp_cc(port)); + tcpm_set_state(dev, PORT_RESET_WAIT_OFF, + PD_T_ERROR_RECOVERY); + break; + case PORT_RESET_WAIT_OFF: + tcpm_set_state(dev, + tcpm_default_state(port), + port->vbus_present ? PD_T_PS_SOURCE_OFF : 0); + break; + default: + dev_err(dev, "TCPM: Unexpected port state %d\n", port->state); + break; + } +} + +static void tcpm_state_machine(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum tcpm_state prev_state; + + mutex_lock(&port->lock); + port->state_machine_running = true; + + if (port->queued_message && tcpm_send_queued_message(dev)) + goto done; + + /* If we were queued due to a delayed state change, update it now */ + if (port->delayed_state) { + dev_dbg(dev, "TCPM: state change %s -> %s [delayed %ld ms]\n", + tcpm_states[port->state], + tcpm_states[port->delayed_state], port->delay_ms); + port->prev_state = port->state; + port->state = port->delayed_state; + port->delayed_state = INVALID_STATE; + } + + /* + * Continue running as long as we have (non-delayed) state changes + * to make. + */ + do { + prev_state = port->state; + run_state_machine(dev); + if (port->queued_message) + tcpm_send_queued_message(dev); + } while (port->state != prev_state && !port->delayed_state); + +done: + port->state_machine_running = false; + mutex_unlock(&port->lock); +} + +static void _tcpm_cc_change(struct udevice *dev, enum typec_cc_status cc1, + enum typec_cc_status cc2) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum typec_cc_status old_cc1, old_cc2; + enum tcpm_state new_state; + + old_cc1 = port->cc1; + old_cc2 = port->cc2; + port->cc1 = cc1; + port->cc2 = cc2; + + dev_dbg(dev, "TCPM: CC1: %u -> %u, CC2: %u -> %u [state %s, polarity %d, %s]\n", + old_cc1, cc1, old_cc2, cc2, tcpm_states[port->state], + port->polarity, + tcpm_port_is_disconnected(port) ? "disconnected" : "connected"); + + switch (port->state) { + case TOGGLING: + if (tcpm_port_is_source(port)) + tcpm_set_state(dev, SRC_ATTACH_WAIT, 0); + else if (tcpm_port_is_sink(port)) + tcpm_set_state(dev, SNK_ATTACH_WAIT, 0); + break; + case SRC_UNATTACHED: + case SRC_ATTACH_WAIT: + if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, SRC_UNATTACHED, 0); + else if (cc1 != old_cc1 || cc2 != old_cc2) + tcpm_set_state(dev, SRC_ATTACH_WAIT, 0); + break; + case SRC_ATTACHED: + case SRC_SEND_CAPABILITIES: + case SRC_READY: + if (tcpm_port_is_disconnected(port) || + !tcpm_port_is_source(port)) + tcpm_set_state(dev, SRC_UNATTACHED, 0); + break; + case SNK_UNATTACHED: + if (tcpm_port_is_sink(port)) + tcpm_set_state(dev, SNK_ATTACH_WAIT, 0); + break; + case SNK_ATTACH_WAIT: + if ((port->cc1 == TYPEC_CC_OPEN && + port->cc2 != TYPEC_CC_OPEN) || + (port->cc1 != TYPEC_CC_OPEN && + port->cc2 == TYPEC_CC_OPEN)) + new_state = SNK_DEBOUNCED; + else if (tcpm_port_is_disconnected(port)) + new_state = SNK_UNATTACHED; + else + break; + if (new_state != port->delayed_state) + tcpm_set_state(dev, SNK_ATTACH_WAIT, 0); + break; + case SNK_DEBOUNCED: + if (tcpm_port_is_disconnected(port)) + new_state = SNK_UNATTACHED; + else if (port->vbus_present) + new_state = tcpm_try_src(port) ? INVALID_STATE : SNK_ATTACHED; + else + new_state = SNK_UNATTACHED; + if (new_state != port->delayed_state) + tcpm_set_state(dev, SNK_DEBOUNCED, 0); + break; + case SNK_READY: + if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, unattached_state(port), 0); + else if (!port->pd_capable && + (cc1 != old_cc1 || cc2 != old_cc2)) + tcpm_set_current_limit(dev, + tcpm_get_current_limit(port), + 5000); + break; + + case SNK_DISCOVERY: + /* CC line is unstable, wait for debounce */ + if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, SNK_DISCOVERY_DEBOUNCE, 0); + break; + case SNK_DISCOVERY_DEBOUNCE: + break; + + case PORT_RESET: + case PORT_RESET_WAIT_OFF: + /* + * State set back to default mode once the timer completes. + * Ignore CC changes here. + */ + break; + default: + /* + * While acting as sink and auto vbus discharge is enabled, Allow disconnect + * to be driven by vbus disconnect. + */ + if (tcpm_port_is_disconnected(port)) + tcpm_set_state(dev, unattached_state(port), 0); + break; + } +} + +static void _tcpm_pd_vbus_on(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + dev_dbg(dev, "TCPM: VBUS on event\n"); + port->vbus_present = true; + /* + * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly + * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here. + */ + port->vbus_vsafe0v = false; + + switch (port->state) { + case SNK_TRANSITION_SINK_VBUS: + port->explicit_contract = true; + tcpm_set_state(dev, SNK_READY, 0); + break; + case SNK_DISCOVERY: + tcpm_set_state(dev, SNK_DISCOVERY, 0); + break; + case SNK_DEBOUNCED: + tcpm_set_state(dev, SNK_ATTACHED, 0); + break; + case SNK_HARD_RESET_WAIT_VBUS: + tcpm_set_state(dev, SNK_HARD_RESET_SINK_ON, 0); + break; + case SRC_ATTACHED: + tcpm_set_state(dev, SRC_STARTUP, 0); + break; + case SRC_HARD_RESET_VBUS_ON: + tcpm_set_state(dev, SRC_STARTUP, 0); + break; + + case PORT_RESET: + case PORT_RESET_WAIT_OFF: + /* + * State set back to default mode once the timer completes. + * Ignore vbus changes here. + */ + break; + + default: + break; + } +} + +static void _tcpm_pd_vbus_off(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + dev_dbg(dev, "TCPM: VBUS off event\n"); + port->vbus_present = false; + port->vbus_never_low = false; + switch (port->state) { + case SNK_HARD_RESET_SINK_OFF: + tcpm_set_state(dev, SNK_HARD_RESET_WAIT_VBUS, 0); + break; + case HARD_RESET_SEND: + break; + case SNK_ATTACH_WAIT: + tcpm_set_state(dev, SNK_UNATTACHED, 0); + break; + + case SNK_NEGOTIATE_CAPABILITIES: + break; + + case PORT_RESET_WAIT_OFF: + tcpm_set_state(dev, tcpm_default_state(port), 0); + break; + + case PORT_RESET: + /* + * State set back to default mode once the timer completes. + * Ignore vbus changes here. + */ + break; + + default: + if (port->pwr_role == TYPEC_SINK && port->attached) + tcpm_set_state(dev, SNK_UNATTACHED, 0); + break; + } +} + +void tcpm_cc_change(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + enum typec_cc_status cc1, cc2; + + tcpm_reset_event_cnt(dev); + if (drvops->get_cc(dev, &cc1, &cc2) == 0) + _tcpm_cc_change(dev, cc1, cc2); +} + +void tcpm_vbus_change(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + bool vbus; + + tcpm_reset_event_cnt(dev); + vbus = drvops->get_vbus(dev); + if (vbus) + _tcpm_pd_vbus_on(dev); + else + _tcpm_pd_vbus_off(dev); +} + +void tcpm_pd_hard_reset(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + + tcpm_reset_event_cnt(dev); + dev_dbg(dev, "TCPM: Received hard reset\n"); + + /* If a hard reset message is received during the port reset process, + * we should ignore it, that is, do not set port->state to HARD_RESET_START. + */ + if (port->state == PORT_RESET || port->state == PORT_RESET_WAIT_OFF) + return; + + /* + * If we keep receiving hard reset requests, executing the hard reset + * must have failed. Revert to error recovery if that happens. + */ + tcpm_set_state(dev, + port->hard_reset_count < PD_N_HARD_RESET_COUNT ? + HARD_RESET_START : ERROR_RECOVERY, + 0); +} + +static void tcpm_init(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + enum typec_cc_status cc1, cc2; + + drvops->init(dev); + + tcpm_reset_port(dev); + + /* + * XXX + * Should possibly wait for VBUS to settle if it was enabled locally + * since tcpm_reset_port() will disable VBUS. + */ + port->vbus_present = drvops->get_vbus(dev); + if (port->vbus_present) + port->vbus_never_low = true; + + /* + * 1. When vbus_present is true, voltage on VBUS is already at VSAFE5V. + * So implicitly vbus_vsafe0v = false. + * + * 2. When vbus_present is false and TCPC does NOT support querying + * vsafe0v status, then, it's best to assume vbus is at VSAFE0V i.e. + * vbus_vsafe0v is true. + * + * 3. When vbus_present is false and TCPC does support querying vsafe0v, + * then, query tcpc for vsafe0v status. + */ + if (port->vbus_present) + port->vbus_vsafe0v = false; + else + port->vbus_vsafe0v = true; + + tcpm_set_state(dev, tcpm_default_state(port), 0); + + if (drvops->get_cc(dev, &cc1, &cc2) == 0) + _tcpm_cc_change(dev, cc1, cc2); +} + +static int tcpm_fw_get_caps(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + ofnode node; + const char *cap_str; + int ret; + u32 mw; + + ret = drvops->get_connector_node(dev, &node); + if (ret) + return ret; + + cap_str = ofnode_read_string(node, "power-role"); + if (!cap_str) + return -EINVAL; + + if (!strcmp("dual", cap_str)) + port->typec_type = TYPEC_PORT_DRP; + else if (!strcmp("source", cap_str)) + port->typec_type = TYPEC_PORT_SRC; + else if (!strcmp("sink", cap_str)) + port->typec_type = TYPEC_PORT_SNK; + else + return -EINVAL; + + port->port_type = port->typec_type; + + if (port->port_type == TYPEC_PORT_SNK) + goto sink; + + /* Get source pdos */ + ret = ofnode_read_size(node, "source-pdos") / sizeof(u32); + if (ret <= 0) + return -EINVAL; + + port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS); + ret = ofnode_read_u32_array(node, "source-pdos", + port->src_pdo, port->nr_src_pdo); + if (ret || tcpm_validate_caps(dev, port->src_pdo, port->nr_src_pdo)) + return -EINVAL; + + if (port->port_type == TYPEC_PORT_SRC) + return 0; + + /* Get the preferred power role for DRP */ + cap_str = ofnode_read_string(node, "try-power-role"); + if (!cap_str) + return -EINVAL; + + if (!strcmp("sink", cap_str)) + port->typec_prefer_role = TYPEC_SINK; + else if (!strcmp("source", cap_str)) + port->typec_prefer_role = TYPEC_SOURCE; + else + return -EINVAL; + + if (port->typec_prefer_role < 0) + return -EINVAL; +sink: + /* Get sink pdos */ + ret = ofnode_read_size(node, "sink-pdos") / sizeof(u32); + if (ret <= 0) + return -EINVAL; + + port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS); + ret = ofnode_read_u32_array(node, "sink-pdos", + port->snk_pdo, port->nr_snk_pdo); + if (ret || tcpm_validate_caps(dev, port->snk_pdo, port->nr_snk_pdo)) + return -EINVAL; + + if (ofnode_read_u32_array(node, "op-sink-microwatt", &mw, 1)) + return -EINVAL; + port->operating_snk_mw = mw / 1000; + + port->self_powered = ofnode_read_bool(node, "self-powered"); + + return 0; +} + +static int tcpm_port_init(struct udevice *dev) +{ + struct tcpm_port *port = dev_get_uclass_plat(dev); + int err; + + err = tcpm_fw_get_caps(dev); + if (err < 0) { + dev_err(dev, "TCPM: please check the dts config: %d\n", err); + return err; + } + + port->try_role = port->typec_prefer_role; + port->port_type = port->typec_type; + + tcpm_init(dev); + + dev_info(dev, "TCPM: init finished\n"); + + return 0; +} + +static void tcpm_poll_event(struct udevice *dev) +{ + const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev); + struct tcpm_port *port = dev_get_uclass_plat(dev); + + if (!drvops->get_vbus(dev)) + return; + + while (port->poll_event_cnt < TCPM_POLL_EVENT_TIME_OUT) { + if (!port->wait_dr_swap_message && + (port->state == SNK_READY || port->state == SRC_READY)) + break; + + drvops->poll_event(dev); + port->poll_event_cnt++; + udelay(500); + tcpm_check_and_run_delayed_work(dev); + } + + if (port->state != SNK_READY && port->state != SRC_READY) + dev_warn(dev, "TCPM: exit in state %s\n", + tcpm_states[port->state]); + + /* + * At this time, call the callback function of the respective pd chip + * to enter the low-power mode. In order to reduce the time spent on + * the PD chip driver as much as possible, the tcpm framework does not + * fully process the communication initiated by the device,so it should + * be noted that we can disable the internal oscillator, etc., but do + * not turn off the power of the transceiver module, otherwise the + * self-powered Type-C device will initiate a Message(eg: self-powered + * Type-C hub initiates a SINK capability request(PD_CTRL_GET_SINK_CAP)) + * and the pd chip cannot reply to GoodCRC, causing the self-powered Type-C + * device to switch vbus to vSafe5v, or even turn off vbus. + */ + if (!drvops->enter_low_power_mode) + return; + + if (drvops->enter_low_power_mode(dev, port->attached, port->pd_capable)) + dev_err(dev, "TCPM: failed to enter low power\n"); + else + dev_info(dev, "TCPM: PD chip enter low power mode\n"); +} + +int tcpm_post_probe(struct udevice *dev) +{ + int ret = tcpm_port_init(dev); + + if (ret < 0) { + dev_err(dev, "failed to tcpm port init\n"); + return ret; + } + + tcpm_poll_event(dev); + + return 0; +} diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e79694fd19..3c3cebaacd0 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -599,6 +599,15 @@ config VIDEO_LCD_SAMSUNG_LTL106HL02 LCD module found in Microsoft Surface 2. The panel has a FullHD resolution (1920x1080). +config VIDEO_LCD_SHARP_LQ101R1SX01 + tristate "Sharp LQ101R1SX01 2560x1600 DSI video mode panel" + depends on PANEL && BACKLIGHT + select VIDEO_MIPI_DSI + help + Say Y here if you want to enable support for Sharp LQ101R1SX01 + LCD module found in ASUS Transformer TF701T. The panel has a + WQXGA resolution (2560x1600). + config VIDEO_LCD_SSD2828 bool "SSD2828 bridge chip" ---help--- diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f3f70cd04a1..5a00438ce06 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -4,12 +4,12 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de. ifdef CONFIG_DM -obj-$(CONFIG_$(SPL_TPL_)BACKLIGHT) += backlight-uclass.o +obj-$(CONFIG_$(PHASE_)BACKLIGHT) += backlight-uclass.o obj-$(CONFIG_BACKLIGHT_GPIO) += backlight_gpio.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_backlight.o -obj-$(CONFIG_$(SPL_TPL_)CONSOLE_NORMAL) += console_normal.o +obj-$(CONFIG_$(PHASE_)CONSOLE_NORMAL) += console_normal.o obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o -ifdef CONFIG_$(SPL_TPL_)CONSOLE_NORMAL +ifdef CONFIG_$(PHASE_)CONSOLE_NORMAL obj-y += console_core.o else ifdef CONFIG_CONSOLE_ROTATION obj-y += console_core.o @@ -18,14 +18,14 @@ obj-$(CONFIG_CONSOLE_ROTATION) += console_core.o obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/ obj-$(CONFIG_DISPLAY) += display-uclass.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi-host-uclass.o -obj-$(CONFIG_$(SPL_TPL_)VIDEO) += video-uclass.o vidconsole-uclass.o -obj-$(CONFIG_$(SPL_TPL_)VIDEO) += video_bmp.o -obj-$(CONFIG_$(SPL_TPL_)PANEL) += panel-uclass.o +obj-$(CONFIG_$(PHASE_)VIDEO) += video-uclass.o vidconsole-uclass.o +obj-$(CONFIG_$(PHASE_)VIDEO) += video_bmp.o +obj-$(CONFIG_$(PHASE_)PANEL) += panel-uclass.o obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o -obj-$(CONFIG_$(SPL_TPL_)SIMPLE_PANEL) += simple_panel.o +obj-$(CONFIG_$(PHASE_)SIMPLE_PANEL) += simple_panel.o obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o -obj-$(CONFIG_$(SPL_TPL_)BMP) += bmp.o +obj-$(CONFIG_$(PHASE_)BMP) += bmp.o endif @@ -34,7 +34,7 @@ obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-${CONFIG_VIDEO_STM32} += stm32/ obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ -obj-${CONFIG_$(SPL_)VIDEO_TIDSS} += tidss/ +obj-${CONFIG_$(XPL_)VIDEO_TIDSS} += tidss/ obj-y += ti/ obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o @@ -64,6 +64,7 @@ obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o obj-$(CONFIG_VIDEO_LCD_RENESAS_R69328) += renesas-r69328.o obj-$(CONFIG_VIDEO_LCD_SAMSUNG_LTL106HL02) += samsung-ltl106hl02.o +obj-$(CONFIG_VIDEO_LCD_SHARP_LQ101R1SX01) += sharp-lq101r1sx01.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index c435162d3f9..17a29817664 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -802,7 +802,7 @@ static int truetype_entry_save(struct udevice *dev, struct abuf *buf) struct console_tt_store store; const uint size = sizeof(store); - if (spl_phase() <= PHASE_SPL) + if (xpl_phase() <= PHASE_SPL) return -ENOSYS; /* @@ -826,7 +826,7 @@ static int truetype_entry_restore(struct udevice *dev, struct abuf *buf) struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_store store; - if (spl_phase() <= PHASE_SPL) + if (xpl_phase() <= PHASE_SPL) return -ENOSYS; memcpy(&store, abuf_data(buf), sizeof(store)); @@ -853,7 +853,7 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, uint out, val; int ret; - if (spl_phase() <= PHASE_SPL) + if (xpl_phase() <= PHASE_SPL) return -ENOSYS; if (!visible) diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index 587df7beb9b..1631dc38416 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -418,8 +418,8 @@ static int meson_dw_hdmi_probe(struct udevice *dev) } if (!ret) { - ret = regulator_set_enable(supply, true); - if (ret) + ret = regulator_set_enable_if_allowed(supply, true); + if (ret && ret != -ENOSYS) return ret; } #endif diff --git a/drivers/video/sharp-lq101r1sx01.c b/drivers/video/sharp-lq101r1sx01.c new file mode 100644 index 00000000000..5d8453fd796 --- /dev/null +++ b/drivers/video/sharp-lq101r1sx01.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sharp LQ101R1SX01 DSI panel driver + * + * Copyright (C) 2014 NVIDIA Corporation + * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <backlight.h> +#include <dm.h> +#include <panel.h> +#include <log.h> +#include <mipi_dsi.h> +#include <linux/delay.h> +#include <power/regulator.h> + +struct sharp_lq101r1sx01_priv { + struct udevice *backlight; + struct udevice *panel_sec; + struct udevice *vcc; +}; + +static struct display_timing default_timing = { + .pixelclock.typ = 278000000, + .hactive.typ = 2560, + .hfront_porch.typ = 128, + .hback_porch.typ = 64, + .hsync_len.typ = 64, + .vactive.typ = 1600, + .vfront_porch.typ = 4, + .vback_porch.typ = 8, + .vsync_len.typ = 32, +}; + +static int sharp_lq101r1sx01_write(struct mipi_dsi_device *dsi, + u16 offset, u8 value) +{ + u8 payload[3] = { offset >> 8, offset & 0xff, value }; + int ret; + + ret = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); + if (ret < 0) { + log_debug("%s: failed to write %02x to %04x: %zd\n", + __func__, value, offset, ret); + return ret; + } + + ret = mipi_dsi_dcs_nop(dsi); + if (ret < 0) { + log_debug("%s: failed to send DCS nop: %zd\n", + __func__, ret); + return ret; + } + + udelay(20); + + return 0; +} + +static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + struct display_timing *timing) +{ + int ret; + + ret = mipi_dsi_dcs_set_column_address(left, 0, + timing->hactive.typ / 2 - 1); + if (ret < 0) { + log_debug("%s: failed to set column address: %d\n", + __func__, ret); + return ret; + } + + ret = mipi_dsi_dcs_set_page_address(left, 0, timing->vactive.typ - 1); + if (ret < 0) { + log_debug("%s: failed to set page address: %d\n", + __func__, ret); + return ret; + } + + ret = mipi_dsi_dcs_set_column_address(right, timing->hactive.typ / 2, + timing->hactive.typ - 1); + if (ret < 0) { + log_debug("%s: failed to set column address: %d\n", + __func__, ret); + return ret; + } + + ret = mipi_dsi_dcs_set_page_address(right, 0, timing->vactive.typ - 1); + if (ret < 0) { + log_debug("%s: failed to set page address: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int sharp_lq101r1sx01_enable_backlight(struct udevice *dev) +{ + struct sharp_lq101r1sx01_priv *priv = dev_get_priv(dev); + + if (!priv->panel_sec) + return 0; + + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); + struct mipi_dsi_panel_plat *plat_sec = dev_get_plat(priv->panel_sec); + struct mipi_dsi_device *link1 = plat->device; + struct mipi_dsi_device *link2 = plat_sec->device; + int ret; + + ret = mipi_dsi_dcs_exit_sleep_mode(link1); + if (ret < 0) { + log_debug("%s: failed to exit sleep mode: %d\n", + __func__, ret); + return ret; + } + + /* set left-right mode */ + ret = sharp_lq101r1sx01_write(link1, 0x1000, 0x2a); + if (ret < 0) { + log_debug("%s: failed to set left-right mode: %d\n", + __func__, ret); + return ret; + } + + /* enable command mode */ + ret = sharp_lq101r1sx01_write(link1, 0x1001, 0x01); + if (ret < 0) { + log_debug("%s: failed to enable command mode: %d\n", + __func__, ret); + return ret; + } + + ret = mipi_dsi_dcs_set_pixel_format(link1, MIPI_DCS_PIXEL_FMT_24BIT); + if (ret < 0) { + log_debug("%s: failed to set pixel format: %d\n", + __func__, ret); + return ret; + } + + /* + * TODO: The device supports both left-right and even-odd split + * configurations, but this driver currently supports only the left- + * right split. To support a different mode a mechanism needs to be + * put in place to communicate the configuration back to the DSI host + * controller. + */ + ret = sharp_setup_symmetrical_split(link1, link2, &default_timing); + if (ret < 0) { + log_debug("%s: failed to set up symmetrical split: %d\n", + __func__, ret); + return ret; + } + + ret = mipi_dsi_dcs_set_display_on(link1); + if (ret < 0) { + log_debug("%s: failed to set panel on: %d\n", + __func__, ret); + return ret; + } + mdelay(20); + + return 0; +} + +static int sharp_lq101r1sx01_set_backlight(struct udevice *dev, int percent) +{ + struct sharp_lq101r1sx01_priv *priv = dev_get_priv(dev); + int ret; + + if (!priv->panel_sec) + return 0; + + ret = backlight_enable(priv->backlight); + if (ret) + return ret; + + return backlight_set_brightness(priv->backlight, percent); +} + +static int sharp_lq101r1sx01_timings(struct udevice *dev, + struct display_timing *timing) +{ + memcpy(timing, &default_timing, sizeof(*timing)); + return 0; +} + +static int sharp_lq101r1sx01_of_to_plat(struct udevice *dev) +{ + struct sharp_lq101r1sx01_priv *priv = dev_get_priv(dev); + int ret; + + /* If node has no link2 it is secondary panel */ + if (!dev_read_bool(dev, "link2")) + return 0; + + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, + "link2", &priv->panel_sec); + if (ret) { + log_debug("%s: cannot get secondary panel: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + log_debug("%s: cannot get backlight: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "power-supply", &priv->vcc); + if (ret) { + log_debug("%s: cannot get power-supply: ret = %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int sharp_lq101r1sx01_hw_init(struct udevice *dev) +{ + struct sharp_lq101r1sx01_priv *priv = dev_get_priv(dev); + int ret; + + if (!priv->panel_sec) + return 0; + + ret = regulator_set_enable_if_allowed(priv->vcc, 1); + if (ret) { + log_debug("%s: enabling power-supply failed (%d)\n", + __func__, ret); + return ret; + } + + /* + * According to the datasheet, the panel needs around 10 ms to fully + * power up. At least another 120 ms is required before exiting sleep + * mode to make sure the panel is ready. Throw in another 20 ms for + * good measure. + */ + mdelay(150); + + return 0; +} + +static int sharp_lq101r1sx01_probe(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); + + /* fill characteristics of DSI data link */ + plat->lanes = 4; + plat->format = MIPI_DSI_FMT_RGB888; + + return sharp_lq101r1sx01_hw_init(dev); +} + +static const struct panel_ops sharp_lq101r1sx01_ops = { + .enable_backlight = sharp_lq101r1sx01_enable_backlight, + .set_backlight = sharp_lq101r1sx01_set_backlight, + .get_display_timing = sharp_lq101r1sx01_timings, +}; + +static const struct udevice_id sharp_lq101r1sx01_ids[] = { + { .compatible = "sharp,lq101r1sx01" }, + { } +}; + +U_BOOT_DRIVER(sharp_lq101r1sx01) = { + .name = "sharp_lq101r1sx01", + .id = UCLASS_PANEL, + .of_match = sharp_lq101r1sx01_ids, + .ops = &sharp_lq101r1sx01_ops, + .of_to_plat = sharp_lq101r1sx01_of_to_plat, + .probe = sharp_lq101r1sx01_probe, + .plat_auto = sizeof(struct mipi_dsi_panel_plat), + .priv_auto = sizeof(struct sharp_lq101r1sx01_priv), +}; diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index cb518b149cb..239b006744d 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -27,7 +27,8 @@ static int simple_video_probe(struct udevice *dev) return -EINVAL; } - debug("%s: base=%llx, size=%llu\n", __func__, base, size); + debug("%s: base=%llx, size=%llu\n", + __func__, (unsigned long long)base, (unsigned long long)size); /* * TODO is there some way to reserve the framebuffer diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index accabbf4dbb..d24aa375b39 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -26,8 +26,6 @@ #include "tegra-dc.h" -DECLARE_GLOBAL_DATA_PTR; - /* Holder of Tegra per-SOC DC differences */ struct tegra_dc_soc_info { bool has_timer; diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 35a8e6c176b..6327266dd22 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -20,6 +20,7 @@ #include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> +#include <asm/arch-tegra/clk_rst.h> #include "tegra-dc.h" #include "tegra-dsi.h" @@ -50,6 +51,10 @@ struct tegra_dsi_priv { int host_fifo_depth; u32 version; + + /* for ganged-mode support */ + struct udevice *master; + struct udevice *slave; }; static void tegra_dc_enable_controller(struct udevice *dev) @@ -595,6 +600,17 @@ static void tegra_dsi_set_phy_timing(struct dsi_timing_reg *ptiming, writel(value, &ptiming->dsi_bta_timing); } +static void tegra_dsi_ganged_enable(struct udevice *dev, unsigned int start, + unsigned int size) +{ + struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct dsi_ganged_mode_reg *ganged = &priv->dsi->ganged; + + writel(start, &ganged->ganged_mode_start); + writel(size << 16 | size, &ganged->ganged_mode_size); + writel(DSI_GANGED_MODE_CONTROL_ENABLE, &ganged->ganged_mode_ctrl); +} + static void tegra_dsi_configure(struct udevice *dev, unsigned long mode_flags) { @@ -679,9 +695,19 @@ static void tegra_dsi_configure(struct udevice *dev, writel(hact << 16 | hbp, &len->dsi_pkt_len_2_3); writel(hfp, &len->dsi_pkt_len_4_5); writel(0x0f0f << 16, &len->dsi_pkt_len_6_7); + + /* set SOL delay (for non-burst mode only) */ + writel(8 * mul / div, &misc->dsi_sol_delay); } else { - /* 1 byte (DCS command) + pixel data */ - value = 1 + timing->hactive.typ * mul / div; + if (priv->master || priv->slave) { + /* + * For ganged mode, assume symmetric left-right mode. + */ + value = 1 + (timing->hactive.typ / 2) * mul / div; + } else { + /* 1 byte (DCS command) + pixel data */ + value = 1 + timing->hactive.typ * mul / div; + } writel(0, &len->dsi_pkt_len_0_1); writel(value << 16, &len->dsi_pkt_len_2_3); @@ -691,10 +717,40 @@ static void tegra_dsi_configure(struct udevice *dev, value = MIPI_DCS_WRITE_MEMORY_START << 8 | MIPI_DCS_WRITE_MEMORY_CONTINUE; writel(value, &len->dsi_dcs_cmds); + + /* set SOL delay */ + if (priv->master || priv->slave) { + unsigned long delay, bclk, bclk_ganged; + unsigned int lanes = device->lanes; + unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ + + timing->hback_porch.typ + timing->hsync_len.typ; + + /* SOL to valid, valid to FIFO and FIFO write delay */ + delay = 4 + 4 + 2; + delay = DIV_ROUND_UP(delay * mul, div * lanes); + /* FIFO read delay */ + delay = delay + 6; + + bclk = DIV_ROUND_UP(htotal * mul, div * lanes); + bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); + value = bclk - bclk_ganged + delay + 20; + } else { + /* TODO: revisit for non-ganged mode */ + value = 8 * mul / div; + } + + writel(value, &misc->dsi_sol_delay); } - /* set SOL delay (for non-burst mode only) */ - writel(8 * mul / div, &misc->dsi_sol_delay); + if (priv->slave) { + /* + * TODO: Support modes other than symmetrical left-right + * split. + */ + tegra_dsi_ganged_enable(dev, 0, timing->hactive.typ / 2); + tegra_dsi_ganged_enable(priv->slave, timing->hactive.typ / 2, + timing->hactive.typ / 2); + } } static int tegra_dsi_encoder_enable(struct udevice *dev) @@ -774,6 +830,9 @@ static int tegra_dsi_encoder_enable(struct udevice *dev) value |= DSI_POWER_CONTROL_ENABLE; writel(value, &misc->dsi_pwr_ctrl); + if (priv->slave) + tegra_dsi_encoder_enable(priv->slave); + return 0; } @@ -803,6 +862,14 @@ static void tegra_dsi_init_clocks(struct udevice *dev) unsigned int mul, div; unsigned long bclk, plld; + if (!priv->slave) { + /* Change DSIB clock parent to match DSIA */ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); /* DSIB_CLK_SRC */ + } + tegra_dsi_get_muldiv(device->format, &mul, &div); bclk = (priv->timing.pixelclock.typ * mul) / @@ -854,6 +921,24 @@ static void tegra_dsi_init_clocks(struct udevice *dev) reset_set_enable(priv->dsi_clk, 0); } +static int tegra_dsi_ganged_probe(struct udevice *dev) +{ + struct tegra_dsi_priv *mpriv = dev_get_priv(dev); + struct udevice *gangster; + + uclass_get_device_by_phandle(UCLASS_PANEL, dev, + "nvidia,ganged-mode", &gangster); + if (gangster) { + /* Ganged mode is set */ + struct tegra_dsi_priv *spriv = dev_get_priv(gangster); + + mpriv->slave = gangster; + spriv->master = dev; + } + + return 0; +} + static int tegra_dsi_bridge_probe(struct udevice *dev) { struct tegra_dsi_priv *priv = dev_get_priv(dev); @@ -873,6 +958,8 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) priv->video_fifo_depth = 1920; priv->host_fifo_depth = 64; + tegra_dsi_ganged_probe(dev); + ret = reset_get_by_name(dev, "dsi", &reset_ctl); if (ret) { log_debug("%s: reset_get_by_name() failed: %d\n", diff --git a/drivers/video/tegra20/tegra-dsi.h b/drivers/video/tegra20/tegra-dsi.h index 69dac4bd1b8..683c5e31a34 100644 --- a/drivers/video/tegra20/tegra-dsi.h +++ b/drivers/video/tegra20/tegra-dsi.h @@ -98,9 +98,9 @@ struct dsi_timeout_reg { uint dsi_to_tally; /* _DSI_TO_TALLY_0 */ }; -/* DSI PAD control register 0x04b ~ 0x04e */ +/* DSI PAD control register 0x04b ~ 0x052 */ struct dsi_pad_ctrl_reg { - /* Address 0x04b ~ 0x04e */ + /* Address 0x04b ~ 0x052 */ uint pad_ctrl; /* _PAD_CONTROL_0 */ uint pad_ctrl_cd; /* _PAD_CONTROL_CD_0 */ uint pad_cd_status; /* _PAD_CD_STATUS_0 */ @@ -111,6 +111,14 @@ struct dsi_pad_ctrl_reg { uint pad_ctrl_4; /* _PAD_CONTROL_4 */ }; +/* DSI ganged mode register 0x053 ~ 0x04e */ +struct dsi_ganged_mode_reg { + /* Address 0x053 ~ 0x055 */ + uint ganged_mode_ctrl; /* _DSI_GANGED_MODE_CONTROL_0 */ + uint ganged_mode_start; /* _DSI_GANGED_MODE_START_0 */ + uint ganged_mode_size; /* _DSI_GANGED_MODE_SIZE_0 */ +}; + /* Display Serial Interface (DSI_) regs */ struct dsi_ctlr { struct dsi_syncpt_reg syncpt; /* SYNCPT register 0x000 ~ 0x002 */ @@ -133,6 +141,7 @@ struct dsi_ctlr { uint reserved5[4]; /* reserved_5[4] */ struct dsi_pad_ctrl_reg pad; /* PAD registers 0x04b ~ 0x04e */ + struct dsi_ganged_mode_reg ganged; /* GANGED registers 0x053 ~ 0x055 */ }; #define DSI_POWER_CONTROL_ENABLE BIT(0) @@ -202,6 +211,8 @@ struct dsi_ctlr { #define DSI_PAD_PREEMP_PD(x) (((x) & 0x3) << 4) #define DSI_PAD_PREEMP_PU(x) (((x) & 0x3) << 0) +#define DSI_GANGED_MODE_CONTROL_ENABLE BIT(0) + /* * pixel format as used in the DSI_CONTROL_FORMAT field */ diff --git a/drivers/video/tidss/Makefile b/drivers/video/tidss/Makefile index a29cee2a414..f0cbe1d4ed1 100644 --- a/drivers/video/tidss/Makefile +++ b/drivers/video/tidss/Makefile @@ -9,4 +9,4 @@ # Author: Tomi Valkeinen <tomi.valkeinen@ti.com> -obj-${CONFIG_$(SPL_)VIDEO_TIDSS} = tidss_drv.o +obj-${CONFIG_$(XPL_)VIDEO_TIDSS} = tidss_drv.o diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 80e7adf6a1a..ebe96bf0c2f 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -94,7 +94,9 @@ static void vidconsole_newline(struct udevice *dev) priv->ycur += priv->y_charsize; /* Check if we need to scroll the terminal */ - if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) { + if (vid_priv->rot % 2 ? + priv->ycur + priv->x_charsize > vid_priv->xsize : + priv->ycur + priv->y_charsize > vid_priv->ysize) { vidconsole_move_rows(dev, 0, rows, priv->rows - rows); for (i = 0; i < rows; i++) vidconsole_set_row(dev, priv->rows - i - 1, diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 41bb7647fda..a5b3e898066 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -128,7 +128,7 @@ int video_reserve(ulong *addrp) struct udevice *dev; ulong size; - if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && spl_phase() == PHASE_BOARD_F) + if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && xpl_phase() == PHASE_BOARD_F) return 0; gd->video_top = *addrp; @@ -294,6 +294,9 @@ static const struct vid_rgb colours[VID_COLOUR_COUNT] = { { 0xff, 0x00, 0xff }, /* bright magenta */ { 0x00, 0xff, 0xff }, /* bright cyan */ { 0xff, 0xff, 0xff }, /* white */ + + /* an extra one for menus */ + { 0x40, 0x40, 0x40 }, /* dark gray */ }; u32 video_index_to_colour(struct video_priv *priv, enum colour_idx idx) @@ -421,7 +424,7 @@ bool video_is_active(void) struct udevice *dev; /* Assume video to be active if SPL passed video hand-off to U-boot */ - if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && spl_phase() > PHASE_SPL) + if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && xpl_phase() > PHASE_SPL) return true; for (uclass_find_first_device(UCLASS_VIDEO, &dev); @@ -573,7 +576,7 @@ static int video_post_probe(struct udevice *dev) * NOTE: * This assumes that reserved video memory only uses a single framebuffer */ - if (spl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) { + if (xpl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) { struct video_handoff *ho; ho = bloblist_add(BLOBLISTT_U_BOOT_VIDEO, sizeof(*ho), 0); diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c index 3404f61eba5..2f999fc8bbe 100644 --- a/drivers/virtio/virtio_blk.c +++ b/drivers/virtio/virtio_blk.c @@ -18,30 +18,82 @@ struct virtio_blk_priv { struct virtqueue *vq; }; +static const u32 feature[] = { + VIRTIO_BLK_F_WRITE_ZEROES +}; + +static void virtio_blk_init_header_sg(struct udevice *dev, u64 sector, u32 type, + struct virtio_blk_outhdr *out_hdr, struct virtio_sg *sg) +{ + const bool sector_is_needed = type == VIRTIO_BLK_T_IN || + type == VIRTIO_BLK_T_OUT; + + out_hdr->type = cpu_to_virtio32(dev, type); + out_hdr->sector = cpu_to_virtio64(dev, sector_is_needed ? sector : 0); + + sg->addr = out_hdr; + sg->length = sizeof(*out_hdr); +} + +static void virtio_blk_init_write_zeroes_sg(struct udevice *dev, u64 sector, lbaint_t blkcnt, + struct virtio_blk_discard_write_zeroes *wz, + struct virtio_sg *sg) +{ + wz->sector = cpu_to_virtio64(dev, sector); + wz->num_sectors = cpu_to_virtio32(dev, blkcnt); + wz->flags = cpu_to_virtio32(dev, 0); + + sg->addr = wz; + sg->length = sizeof(*wz); +} + +static void virtio_blk_init_status_sg(u8 *status, struct virtio_sg *sg) +{ + sg->addr = status; + sg->length = sizeof(*status); +} + +static void virtio_blk_init_data_sg(void *buffer, lbaint_t blkcnt, struct virtio_sg *sg) +{ + sg->addr = buffer; + sg->length = blkcnt * 512; +} + static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, lbaint_t blkcnt, void *buffer, u32 type) { struct virtio_blk_priv *priv = dev_get_priv(dev); + struct virtio_blk_outhdr out_hdr; + struct virtio_blk_discard_write_zeroes wz_hdr; unsigned int num_out = 0, num_in = 0; + struct virtio_sg hdr_sg, wz_sg, data_sg, status_sg; struct virtio_sg *sgs[3]; u8 status; int ret; - struct virtio_blk_outhdr out_hdr = { - .type = cpu_to_virtio32(dev, type), - .sector = cpu_to_virtio64(dev, sector), - }; - struct virtio_sg hdr_sg = { &out_hdr, sizeof(out_hdr) }; - struct virtio_sg data_sg = { buffer, blkcnt * 512 }; - struct virtio_sg status_sg = { &status, sizeof(status) }; - + virtio_blk_init_header_sg(dev, sector, type, &out_hdr, &hdr_sg); sgs[num_out++] = &hdr_sg; - if (type & VIRTIO_BLK_T_OUT) - sgs[num_out++] = &data_sg; - else - sgs[num_out + num_in++] = &data_sg; - + switch (type) { + case VIRTIO_BLK_T_IN: + case VIRTIO_BLK_T_OUT: + virtio_blk_init_data_sg(buffer, blkcnt, &data_sg); + if (type & VIRTIO_BLK_T_OUT) + sgs[num_out++] = &data_sg; + else + sgs[num_out + num_in++] = &data_sg; + break; + + case VIRTIO_BLK_T_WRITE_ZEROES: + virtio_blk_init_write_zeroes_sg(dev, sector, blkcnt, &wz_hdr, &wz_sg); + sgs[num_out++] = &wz_sg; + break; + + default: + return -EINVAL; + } + + virtio_blk_init_status_sg(&status, &status_sg); sgs[num_out + num_in++] = &status_sg; log_debug("dev=%s, active=%d, priv=%p, priv->vq=%p\n", dev->name, device_active(dev), priv, priv->vq); @@ -75,6 +127,15 @@ static ulong virtio_blk_write(struct udevice *dev, lbaint_t start, VIRTIO_BLK_T_OUT); } +static ulong virtio_blk_erase(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt) +{ + if (!virtio_has_feature(dev, VIRTIO_BLK_F_WRITE_ZEROES)) + return -EOPNOTSUPP; + + return virtio_blk_do_req(dev, start, blkcnt, NULL, VIRTIO_BLK_T_WRITE_ZEROES); +} + static int virtio_blk_bind(struct udevice *dev) { struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent); @@ -104,7 +165,8 @@ static int virtio_blk_bind(struct udevice *dev) desc->bdev = dev; /* Indicate what driver features we support */ - virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0); + virtio_driver_features_init(uc_priv, feature, ARRAY_SIZE(feature), + NULL, 0); return 0; } @@ -131,6 +193,7 @@ static int virtio_blk_probe(struct udevice *dev) static const struct blk_ops virtio_blk_ops = { .read = virtio_blk_read, .write = virtio_blk_write, + .erase = virtio_blk_erase, }; U_BOOT_DRIVER(virtio_blk) = { diff --git a/drivers/virtio/virtio_blk.h b/drivers/virtio/virtio_blk.h index 8d8e02fa2ea..b37ba264df4 100644 --- a/drivers/virtio/virtio_blk.h +++ b/drivers/virtio/virtio_blk.h @@ -17,6 +17,8 @@ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */ #define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ #define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */ +#define VIRTIO_BLK_F_DISCARD 13 /* Discard is supported */ +#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* Write zeroes is supported */ /* Legacy feature bits */ #ifndef VIRTIO_BLK_NO_LEGACY @@ -65,6 +67,39 @@ struct __packed virtio_blk_config { /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */ __u16 num_queues; + + /* the next 3 entries are guarded by VIRTIO_BLK_F_DISCARD */ + /* + * The maximum discard sectors (in 512-byte sectors) for + * one segment. + */ + __u32 max_discard_sectors; + /* + * The maximum number of discard segments in a + * discard command. + */ + __u32 max_discard_seg; + /* Discard commands must be aligned to this number of sectors. */ + __u32 discard_sector_alignment; + + /* the next 3 entries are guarded by VIRTIO_BLK_F_WRITE_ZEROES */ + /* + * The maximum number of write zeroes sectors (in 512-byte sectors) in + * one segment. + */ + __u32 max_write_zeroes_sectors; + /* + * The maximum number of segments in a write zeroes + * command. + */ + __u32 max_write_zeroes_seg; + /* + * Set if a VIRTIO_BLK_T_WRITE_ZEROES request may result in the + * deallocation of one or more of the sectors. + */ + __u8 write_zeroes_may_unmap; + + __u8 unused1[3]; }; /* @@ -93,6 +128,9 @@ struct __packed virtio_blk_config { /* Get device ID command */ #define VIRTIO_BLK_T_GET_ID 8 +/* Write zeroes command */ +#define VIRTIO_BLK_T_WRITE_ZEROES 13 + #ifndef VIRTIO_BLK_NO_LEGACY /* Barrier before this op */ #define VIRTIO_BLK_T_BARRIER 0x80000000 @@ -112,6 +150,15 @@ struct virtio_blk_outhdr { __virtio64 sector; }; +struct virtio_blk_discard_write_zeroes { + /* discard/write zeroes start sector */ + __virtio64 sector; + /* number of discard/write zeroes sectors */ + __virtio32 num_sectors; + /* flags for this range */ + __virtio32 flags; +}; + #ifndef VIRTIO_BLK_NO_LEGACY struct virtio_scsi_inhdr { __virtio32 errors; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0c3e9913318..0e45f0a0922 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -169,6 +169,19 @@ config WDT_CORTINA This driver support all CPU ISAs supported by Cortina Access CAxxxx SoCs. +config WDT_DA9063 + bool "DA9063 watchdog timer support" + depends on WDT && DM_PMIC_DA9063 + help + Enable support for the watchdog timer in Dialog DA9063. + +config WDT_DAVINCI + bool "DaVinci watchdog timer support" + depends on WDT + help + Select this to enable the watchdog timer for DaVinci SoCs such as the + OMAP-L138. + config WDT_GPIO bool "External gpio watchdog support" depends on WDT @@ -178,6 +191,15 @@ config WDT_GPIO doc/device-tree-bindings/watchdog/gpio-wdt.txt for information on how to describe the watchdog in device tree. +config SPL_WDT_GPIO + bool "External gpio watchdog support in SPL" + depends on SPL_WDT + depends on SPL_DM_GPIO + depends on SPL_OF_REAL + default WDT_GPIO + help + Support for external watchdog fed by toggling a gpio in SPL. + config WDT_MAX6370 bool "MAX6370 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 7b39adcf0ff..0b107c008f7 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o -obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o +obj-$(CONFIG_$(PHASE_)WDT) += wdt-uclass.o obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o obj-$(CONFIG_WDT_ALARM_SANDBOX) += sandbox_alarm-wdt.o obj-$(CONFIG_WDT_APPLE) += apple_wdt.o @@ -29,8 +29,10 @@ obj-$(CONFIG_WDT_BOOKE) += booke_wdt.o obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_DA9063) += da9063-wdt.o +obj-$(CONFIG_WDT_DAVINCI) += davinci_wdt.o obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o -obj-$(CONFIG_WDT_GPIO) += gpio_wdt.o +obj-$(CONFIG_$(SPL_TPL_)WDT_GPIO) += gpio_wdt.o obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o obj-$(CONFIG_WDT_MCF) += mcf_wdt.o obj-$(CONFIG_WDT_MESON_GXBB) += meson_gxbb_wdt.o diff --git a/drivers/watchdog/da9063-wdt.c b/drivers/watchdog/da9063-wdt.c new file mode 100644 index 00000000000..b7216b57863 --- /dev/null +++ b/drivers/watchdog/da9063-wdt.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Based on the Linux drivers/watchdog/da9063_wdt.c file. + * + * Watchdog driver for DA9063 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: Mariusz Wojtasik <mariusz.wojtasik@diasemi.com> + * + * Ported to U-Boot by Fabio Estevam <festevam@denx.de> + * + */ + +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <i2c.h> +#include <linux/delay.h> +#include <wdt.h> + +#define DA9063_REG_CONTROL_D 0x11 +/* DA9063_REG_CONTROL_D (addr=0x11) */ +#define DA9063_TWDSCALE_MASK 0x0 +#define DA9063_TWDSCALE_DISABLE 0 +#define DA9063_REG_CONTROL_F 0x13 +/* DA9063_REG_CONTROL_F (addr=0x13) */ +#define DA9063_WATCHDOG 0x01 +#define DA9063_SHUTDOWN 0x02 + +/* + * Watchdog selector to timeout in seconds. + * 0: WDT disabled; + * others: timeout = 2048 ms * 2^(TWDSCALE-1). + */ +static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 }; + +#define DA9063_TWDSCALE_DISABLE 0 +#define DA9063_TWDSCALE_MIN 1 +#define DA9063_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1) + +static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) +{ + unsigned int i; + + for (i = DA9063_TWDSCALE_MIN; i <= DA9063_TWDSCALE_MAX; i++) { + if (wdt_timeout[i] >= secs) + return i; + } + + return DA9063_TWDSCALE_MAX; +} + +static int da9063_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + return dm_i2c_read(dev->parent, reg, buff, len); +} + +static int da9063_write(struct udevice *dev, uint reg, const u8 *buff, int len) +{ + return dm_i2c_write(dev->parent, reg, buff, len); +} + +static int da9063_wdt_disable_timer(struct udevice *dev) +{ + u8 val; + + da9063_read(dev, DA9063_REG_CONTROL_D, &val, 1); + val &= ~DA9063_TWDSCALE_MASK; + val |= DA9063_TWDSCALE_DISABLE; + da9063_write(dev, DA9063_REG_CONTROL_D, &val, 1); + + return 0; +} + +static int da9063_wdt_update_timeout(struct udevice *dev, unsigned int timeout) +{ + unsigned int regval; + int ret; + u8 val; + + /* + * The watchdog triggers a reboot if a timeout value is already + * programmed because the timeout value combines two functions + * in one: indicating the counter limit and starting the watchdog. + * The watchdog must be disabled to be able to change the timeout + * value if the watchdog is already running. Then we can set the + * new timeout value which enables the watchdog again. + */ + ret = da9063_wdt_disable_timer(dev); + if (ret) + return ret; + + udelay(300); + + regval = da9063_wdt_timeout_to_sel(timeout); + + da9063_read(dev, DA9063_REG_CONTROL_D, &val, 1); + val &= ~DA9063_TWDSCALE_MASK; + val |= regval; + da9063_write(dev, DA9063_REG_CONTROL_D, &val, 1); + + return 0; +} + +static int da9063_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + return da9063_wdt_update_timeout(dev, timeout); +} + +static int da9063_wdt_stop(struct udevice *dev) +{ + return da9063_wdt_disable_timer(dev); +} + +static int da9063_wdt_reset(struct udevice *dev) +{ + u8 val = DA9063_WATCHDOG; + + return da9063_write(dev, DA9063_REG_CONTROL_F, &val, 1); +} + +static int da9063_wdt_expire_now(struct udevice *dev, ulong flags) +{ + u8 val = DA9063_SHUTDOWN; + + return da9063_write(dev, DA9063_REG_CONTROL_F, &val, 1); +} + +static const struct wdt_ops da9063_wdt_ops = { + .start = da9063_wdt_start, + .stop = da9063_wdt_stop, + .reset = da9063_wdt_reset, + .expire_now = da9063_wdt_expire_now, +}; + +static const struct udevice_id da9063_wdt_ids[] = { + { .compatible = "dlg,da9063-watchdog", }, + {} +}; + +U_BOOT_DRIVER(da9063_wdt) = { + .name = "da9063-wdt", + .id = UCLASS_WDT, + .of_match = da9063_wdt_ids, + .ops = &da9063_wdt_ops, + .flags = DM_FLAG_PROBE_AFTER_BIND, +}; diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c new file mode 100644 index 00000000000..fa8d7842e94 --- /dev/null +++ b/drivers/watchdog/davinci_wdt.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DaVinci Watchdog driver + * + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <wdt.h> + +/* Control Register */ +#define DAVINCI_WDT_ID 0x00 +#define DAVINCI_WDT_TIM12 0x10 +#define DAVINCI_WDT_TIM34 0x14 +#define DAVINCI_WDT_PRD12 0x18 +#define DAVINCI_WDT_PRD34 0x1C +#define DAVINCI_WDT_TCR 0x20 +#define DAVINCI_WDT_TGCR 0x24 +#define DAVINCI_WDT_WDTCR 0x28 + +#define DAVINCI_TCR_CONT_EN BIT(7) + +#define DAVINCI_TGCR_PLUSEN BIT(4) +#define DAVINCI_TGCR_WDT_MODE BIT(3) +#define DAVINCI_TGCR_TIM34RS BIT(1) +#define DAVINCI_TGCR_TIM12RS BIT(0) + +#define DAVINCI_WDTCR_INVALID_KEY (0x5555 << 16) +#define DAVINCI_WDTCR_WDKEY0 (0xA5C6 << 16) +#define DAVINCI_WDTCR_WDKEY1 (0xDA7E << 16) +#define DAVINCI_WDTCR_WDFLAG BIT(15) +#define DAVINCI_WDTCR_WDEN BIT(14) + +#define DEFAULT_THRESHOLD 0xA03200000 + +struct davinci_wdt_priv { + void __iomem *base; + struct clk *ref_clk; +}; + +static int davinci_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct davinci_wdt_priv *priv = dev_get_priv(dev); + ulong rate = clk_get_rate(priv->ref_clk); + u64 threshold; + + if (!rate) + threshold = DEFAULT_THRESHOLD; + else + threshold = rate * timeout_ms / 1000; + + /* Reset control registers */ + writel(0, priv->base + DAVINCI_WDT_TCR); + writel(0, priv->base + DAVINCI_WDT_TGCR); + + /* Enable watchdog mode and timers */ + writel(DAVINCI_TGCR_WDT_MODE | DAVINCI_TGCR_TIM12RS | DAVINCI_TGCR_TIM34RS, + priv->base + DAVINCI_WDT_TGCR); + + /* Reset counters */ + writel(0, priv->base + DAVINCI_WDT_TIM12); + writel(0, priv->base + DAVINCI_WDT_TIM34); + + /* Set timeout threshold */ + writel(threshold & 0xFFFFFFFF, priv->base + DAVINCI_WDT_PRD12); + writel(threshold >> 32, priv->base + DAVINCI_WDT_PRD34); + + /* Enable counter */ + writel(DAVINCI_TCR_CONT_EN, priv->base + DAVINCI_WDT_TCR); + + /* Go to watchdog's active state */ + writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR); + writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR); + + return 0; +} + +static int davinci_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct davinci_wdt_priv *priv = dev_get_priv(dev); + + writel(DAVINCI_WDTCR_INVALID_KEY, priv->base + DAVINCI_WDT_WDTCR); + + return 0; +} + +static int davinci_wdt_restart(struct udevice *dev) +{ + struct davinci_wdt_priv *priv = dev_get_priv(dev); + + writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY0, priv->base + DAVINCI_WDT_WDTCR); + writel(DAVINCI_WDTCR_WDEN | DAVINCI_WDTCR_WDKEY1, priv->base + DAVINCI_WDT_WDTCR); + + return 0; +} + +static int davinci_wdt_probe(struct udevice *dev) +{ + struct davinci_wdt_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -EFAULT; + + priv->ref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(priv->ref_clk)) + return PTR_ERR(priv->ref_clk); + + return 0; +} + +static const struct wdt_ops davinci_wdt_ops = { + .start = davinci_wdt_start, + .reset = davinci_wdt_restart, + .expire_now = davinci_wdt_expire_now, +}; + +static const struct udevice_id davinci_wdt_ids[] = { + {.compatible = "ti,davinci-wdt"}, + {} +}; + +U_BOOT_DRIVER(davinci_wdt) = { + .name = "davinci_wdt", + .id = UCLASS_WDT, + .probe = davinci_wdt_probe, + .of_match = davinci_wdt_ids, + .ops = &davinci_wdt_ops, + .priv_auto = sizeof(struct davinci_wdt_priv), +}; diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 2920c2c751f..e889861e917 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -45,14 +45,32 @@ static int gpio_wdt_start(struct udevice *dev, u64 timeout, ulong flags) if (priv->always_running) return 0; - return -ENOSYS; + dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_OUT); + gpio_wdt_reset(dev); + + return 0; +} + +static int gpio_wdt_stop(struct udevice *dev) +{ + struct gpio_wdt_priv *priv = dev_get_priv(dev); + + if (priv->always_running) + return -EOPNOTSUPP; + + if (priv->hw_algo == HW_ALGO_TOGGLE) + dm_gpio_set_dir_flags(&priv->gpio, GPIOD_IS_IN); + else + dm_gpio_set_value(&priv->gpio, 1); + + return 0; } static int dm_probe(struct udevice *dev) { struct gpio_wdt_priv *priv = dev_get_priv(dev); - int ret; const char *algo = dev_read_string(dev, "hw_algo"); + int ret, flags; if (!algo) return -EINVAL; @@ -64,7 +82,9 @@ static int dm_probe(struct udevice *dev) return -EINVAL; priv->always_running = dev_read_bool(dev, "always-running"); - ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); + flags = priv->always_running || priv->hw_algo == HW_ALGO_LEVEL ? + GPIOD_IS_OUT : GPIOD_IS_IN; + ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags); if (ret < 0) { dev_err(dev, "Request for wdt gpio failed: %d\n", ret); return ret; @@ -78,6 +98,7 @@ static int dm_probe(struct udevice *dev) static const struct wdt_ops gpio_wdt_ops = { .start = gpio_wdt_start, + .stop = gpio_wdt_stop, .reset = gpio_wdt_reset, }; |