summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/adc/adc-uclass.c4
-rw-r--r--drivers/adc/rockchip-saradc.c9
-rw-r--r--drivers/ata/Kconfig12
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/ahci_generic.c (renamed from drivers/ata/ahci_mvebu.c)17
-rw-r--r--drivers/block/blk-uclass.c19
-rw-r--r--drivers/block/rkmtd.c21
-rw-r--r--drivers/clk/imx/clk-imxrt1050.c3
-rw-r--r--drivers/clk/rockchip/clk_px30.c105
-rw-r--r--drivers/core/acpi.c16
-rw-r--r--drivers/cpu/Kconfig7
-rw-r--r--drivers/cpu/Makefile2
-rw-r--r--drivers/cpu/armv8_cpu.c151
-rw-r--r--drivers/cpu/armv8_cpu.h31
-rw-r--r--drivers/cpu/bcm283x_cpu.c214
-rw-r--r--drivers/ddr/altera/sdram_n5x.c1
-rw-r--r--drivers/ddr/altera/sdram_soc64.c1
-rw-r--r--drivers/ddr/imx/imx9/Kconfig5
-rw-r--r--drivers/dfu/dfu_sf.c16
-rw-r--r--drivers/gpio/dwapb_gpio.c4
-rw-r--r--drivers/gpio/mcp230xx_gpio.c1
-rw-r--r--drivers/i2c/mxc_i2c.c16
-rw-r--r--drivers/i2c/rz_riic.c1
-rw-r--r--drivers/led/led_sw_blink.c1
-rw-r--r--drivers/misc/irq-uclass.c66
-rw-r--r--drivers/mmc/fsl_esdhc_imx.c15
-rw-r--r--drivers/mtd/spi/Kconfig5
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c31
-rw-r--r--drivers/net/Kconfig38
-rw-r--r--drivers/net/dc2114x.c133
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/ksz9477.c241
-rw-r--r--drivers/net/phy/motorcomm.c505
-rw-r--r--drivers/net/rtl8139.c2
-rw-r--r--drivers/pci/pcie_brcmstb.c101
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx.c25
-rw-r--r--drivers/power/domain/imx8m-power-domain.c18
-rw-r--r--drivers/serial/serial_pl01x.c24
-rw-r--r--drivers/spi/zynq_qspi.c2
-rw-r--r--drivers/usb/host/Kconfig8
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/xhci-generic.c75
-rw-r--r--drivers/watchdog/Kconfig16
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/davinci_wdt.c131
-rw-r--r--drivers/watchdog/gpio_wdt.c27
46 files changed, 1895 insertions, 233 deletions
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/Kconfig b/drivers/ata/Kconfig
index 6cca561f974..4fbb63a148a 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -78,14 +78,16 @@ config MTK_AHCI
Enable this driver to support Sata devices through
Mediatek AHCI controller (e.g. MT7622).
-config AHCI_MVEBU
- bool "Marvell EBU AHCI SATA support"
- depends on ARCH_MVEBU || ARCH_OCTEON
+config AHCI_GENERIC
+ bool "Generic AHCI SATA support"
+ depends on OF_CONTROL
select SCSI_AHCI
select SCSI
help
- This option enables support for the Marvell EBU SoC's
- onboard AHCI SATA.
+ This option enables support for generic onboard AHCI SATA controller
+ that do not need platform specific quirks, like emulated devices,
+ Marvell EBU SoC's onboard AHCI SATA controllers or Cavium's Octeon
+ 7130 AHCI controllers.
If unsure, say N.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index ee10c4445b0..69fa9b707e0 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -14,6 +14,6 @@ obj-$(CONFIG_SATA) += sata.o sata_bootdev.o
obj-$(CONFIG_SATA_CEVA) += sata_ceva.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_SIL) += sata_sil.o
-obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o
+obj-$(CONFIG_AHCI_GENERIC) += ahci_generic.o
obj-$(CONFIG_SUNXI_AHCI) += ahci_sunxi.o
obj-$(CONFIG_MTK_AHCI) += mtk_ahci.o
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_generic.c
index f6e2d6bee45..6e5a6cbafd8 100644
--- a/drivers/ata/ahci_mvebu.c
+++ b/drivers/ata/ahci_generic.c
@@ -16,7 +16,7 @@ __weak int board_ahci_enable(void)
return 0;
}
-static int mvebu_ahci_bind(struct udevice *dev)
+static int generic_ahci_bind(struct udevice *dev)
{
struct udevice *scsi_dev;
int ret;
@@ -30,7 +30,7 @@ static int mvebu_ahci_bind(struct udevice *dev)
return 0;
}
-static int mvebu_ahci_probe(struct udevice *dev)
+static int generic_ahci_probe(struct udevice *dev)
{
/*
* Board specific SATA / AHCI enable code, e.g. enable the
@@ -43,18 +43,19 @@ static int mvebu_ahci_probe(struct udevice *dev)
return 0;
}
-static const struct udevice_id mvebu_ahci_ids[] = {
+static const struct udevice_id generic_ahci_ids[] = {
{ .compatible = "marvell,armada-380-ahci" },
{ .compatible = "marvell,armada-3700-ahci" },
{ .compatible = "marvell,armada-8k-ahci" },
{ .compatible = "cavium,octeon-7130-ahci" },
+ { .compatible = "generic-ahci" },
{ }
};
-U_BOOT_DRIVER(ahci_mvebu_drv) = {
- .name = "ahci_mvebu",
+U_BOOT_DRIVER(ahci_generic_drv) = {
+ .name = "ahci_generic",
.id = UCLASS_AHCI,
- .of_match = mvebu_ahci_ids,
- .bind = mvebu_ahci_bind,
- .probe = mvebu_ahci_probe,
+ .of_match = generic_ahci_ids,
+ .bind = generic_ahci_bind,
+ .probe = generic_ahci_probe,
};
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/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c
index 788e0650a92..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));
diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c
index 22ede1c38a8..ad7e1c0f246 100644
--- a/drivers/clk/rockchip/clk_px30.c
+++ b/drivers/clk/rockchip/clk_px30.c
@@ -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/core/acpi.c b/drivers/core/acpi.c
index 9f784228921..4763963914b 100644
--- a/drivers/core/acpi.c
+++ b/drivers/core/acpi.c
@@ -48,6 +48,7 @@ enum method_t {
METHOD_FILL_SSDT,
METHOD_INJECT_DSDT,
METHOD_SETUP_NHLT,
+ METHOD_FILL_MADT,
};
/* Prototype for all methods */
@@ -282,6 +283,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method)
switch (method) {
case METHOD_WRITE_TABLES:
return aops->write_tables;
+ case METHOD_FILL_MADT:
+ return aops->fill_madt;
case METHOD_FILL_SSDT:
return aops->fill_ssdt;
case METHOD_INJECT_DSDT:
@@ -328,6 +331,19 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent,
return 0;
}
+int acpi_fill_madt_subtbl(struct acpi_ctx *ctx)
+{
+ int ret;
+
+ log_debug("Writing MADT table\n");
+ ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_MADT, TYPE_NONE);
+ log_debug("Writing MADT finished, err=%d\n", ret);
+ if (ret)
+ return log_msg_ret("build", ret);
+
+ return ret;
+}
+
int acpi_fill_ssdt(struct acpi_ctx *ctx)
{
void *start = ctx->current;
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index 5c06cd9f60e..4cc3679c009 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -26,6 +26,13 @@ config CPU_RISCV
help
Support CPU cores for RISC-V architecture.
+config CPU_ARMV8
+ bool "Enable generic ARMv8 CPU driver"
+ depends on CPU && ARM64
+ select IRQ
+ help
+ Support CPU cores for armv8 architecture.
+
config CPU_MICROBLAZE
bool "Enable Microblaze CPU driver"
depends on CPU && MICROBLAZE
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index bc75d9b974e..eaf494706e2 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -6,10 +6,12 @@
obj-$(CONFIG_CPU) += cpu-uclass.o
+obj-$(CONFIG_ARCH_BCM283X) += bcm283x_cpu.o
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o
obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
obj-$(CONFIG_ARCH_MEDIATEK) += mtk_cpu.o
+obj-$(CONFIG_CPU_ARMV8) += armv8_cpu.o
obj-$(CONFIG_CPU_IMX) += imx8_cpu.o
obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
diff --git a/drivers/cpu/armv8_cpu.c b/drivers/cpu/armv8_cpu.c
new file mode 100644
index 00000000000..4eedfe5e2c5
--- /dev/null
+++ b/drivers/cpu/armv8_cpu.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 9elements GmbH
+ */
+#include <cpu.h>
+#include <dm.h>
+#include <irq.h>
+#include <acpi/acpigen.h>
+#include <asm/armv8/cpu.h>
+#include <asm/io.h>
+#include <dm/acpi.h>
+#include <linux/bitops.h>
+#include <linux/printk.h>
+#include <linux/sizes.h>
+
+static int armv8_cpu_get_desc(const struct udevice *dev, char *buf, int size)
+{
+ int cpuid;
+
+ cpuid = (read_midr() & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT;
+
+ snprintf(buf, size, "CPU MIDR %04x", cpuid);
+
+ return 0;
+}
+
+static int armv8_cpu_get_info(const struct udevice *dev,
+ struct cpu_info *info)
+{
+ info->cpu_freq = 0;
+ info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
+
+ return 0;
+}
+
+static int armv8_cpu_get_count(const struct udevice *dev)
+{
+ return uclass_id_count(UCLASS_CPU);
+}
+
+#ifdef CONFIG_ACPIGEN
+int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ uint core_id = dev_seq(dev);
+
+ acpigen_write_processor_device(ctx, core_id);
+
+ return 0;
+}
+
+int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx)
+{
+ struct acpi_madt_gicc *gicc;
+ struct cpu_plat *cpu_plat;
+ struct udevice *gic;
+ u64 gicc_gicv = 0;
+ u64 gicc_gich = 0;
+ u64 gicc_gicr_base = 0;
+ u64 gicc_phys_base = 0;
+ u32 gicc_perf_gsiv = 0;
+ u64 gicc_mpidr;
+ u32 gicc_vgic_maint_irq = 0;
+ int addr_index;
+ fdt_addr_t addr;
+ int ret;
+ struct irq req_irq;
+
+ cpu_plat = dev_get_parent_plat(dev);
+ if (!cpu_plat)
+ return 0;
+
+ ret = irq_get_interrupt_parent(dev, &gic);
+ if (ret) {
+ log_err("%s: Failed to find interrupt parent for %s\n",
+ __func__, dev->name);
+ return -ENODEV;
+ }
+
+ addr_index = 1;
+
+ if (device_is_compatible(gic, "arm,gic-v3")) {
+ addr = dev_read_addr_index(gic, addr_index++);
+ if (addr != FDT_ADDR_T_NONE)
+ gicc_gicr_base = addr;
+ }
+
+ addr = dev_read_addr_index(gic, addr_index++);
+ if (addr != FDT_ADDR_T_NONE)
+ gicc_phys_base = addr;
+
+ addr = dev_read_addr_index(gic, addr_index++);
+ if (addr != FDT_ADDR_T_NONE)
+ gicc_gich = addr;
+
+ addr = dev_read_addr_index(gic, addr_index++);
+ if (addr != FDT_ADDR_T_NONE)
+ gicc_gicv = addr;
+
+ ret = irq_get_by_index(gic, 0, &req_irq);
+ if (!ret)
+ gicc_vgic_maint_irq = req_irq.id;
+
+ gicc_mpidr = dev_read_u64_default(dev, "reg", 0);
+ if (!gicc_mpidr)
+ gicc_mpidr = dev_read_u32_default(dev, "reg", 0);
+
+ /*
+ * gicc_vgic_maint_irq and gicc_gicv are the same for every CPU
+ */
+ gicc = ctx->current;
+ acpi_write_madt_gicc(gicc,
+ dev_seq(dev),
+ gicc_perf_gsiv, /* FIXME: needs a PMU driver */
+ gicc_phys_base,
+ gicc_gicv,
+ gicc_gich,
+ gicc_vgic_maint_irq,
+ gicc_gicr_base,
+ gicc_mpidr,
+ 0); /* FIXME: Not defined in DT */
+
+ acpi_inc(ctx, gicc->length);
+
+ return 0;
+}
+
+struct acpi_ops armv8_cpu_acpi_ops = {
+ .fill_ssdt = armv8_cpu_fill_ssdt,
+ .fill_madt = armv8_cpu_fill_madt,
+};
+#endif
+
+static const struct cpu_ops cpu_ops = {
+ .get_count = armv8_cpu_get_count,
+ .get_desc = armv8_cpu_get_desc,
+ .get_info = armv8_cpu_get_info,
+};
+
+static const struct udevice_id cpu_ids[] = {
+ { .compatible = "arm,armv8" },
+ {}
+};
+
+U_BOOT_DRIVER(arm_cpu) = {
+ .name = "arm-cpu",
+ .id = UCLASS_CPU,
+ .of_match = cpu_ids,
+ .ops = &cpu_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+ ACPI_OPS_PTR(&armv8_cpu_acpi_ops)
+};
diff --git a/drivers/cpu/armv8_cpu.h b/drivers/cpu/armv8_cpu.h
new file mode 100644
index 00000000000..48c705e98de
--- /dev/null
+++ b/drivers/cpu/armv8_cpu.h
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 9elements GmbH
+ */
+#include <dm/acpi.h>
+#include <dm/device.h>
+
+#ifndef _ARMV8_CPU_H_
+#define _ARMV8_CPU_H_
+
+/**
+ * armv8_cpu_fill_ssdt() - Fill the SSDT
+ * Parses the FDT and writes the SSDT nodes.
+ *
+ * @dev: cpu device to generate ACPI tables for
+ * @ctx: ACPI context pointer
+ * @return: 0 if OK, or a negative error code.
+ */
+int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx);
+
+/**
+ * armv8_cpu_fill_madt() - Fill the MADT
+ * Parses the FDT and writes the MADT subtables.
+ *
+ * @dev: cpu device to generate ACPI tables for
+ * @ctx: ACPI context pointer
+ * @return: 0 if OK, or a negative error code.
+ */
+int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx);
+
+#endif \ No newline at end of file
diff --git a/drivers/cpu/bcm283x_cpu.c b/drivers/cpu/bcm283x_cpu.c
new file mode 100644
index 00000000000..59a7b142c95
--- /dev/null
+++ b/drivers/cpu/bcm283x_cpu.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 9elements GmbH
+ */
+
+#include <cpu.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <acpi/acpigen.h>
+#include <asm/armv8/cpu.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/global_data.h>
+#include <asm/system.h>
+#include <asm-generic/sections.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include "armv8_cpu.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct bcm_plat {
+ u64 release_addr;
+};
+
+static int cpu_bcm_get_desc(const struct udevice *dev, char *buf, int size)
+{
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+ const char *name;
+
+ if (size < 32)
+ return -ENOSPC;
+
+ if (device_is_compatible(dev, "arm,cortex-a53"))
+ name = "A53";
+ else if (device_is_compatible(dev, "arm,cortex-a72"))
+ name = "A72";
+ else
+ name = "?";
+
+ snprintf(buf, size, "Broadcom Cortex-%s at %u MHz\n",
+ name, plat->timebase_freq);
+
+ return 0;
+}
+
+static int cpu_bcm_get_info(const struct udevice *dev, struct cpu_info *info)
+{
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+
+ info->cpu_freq = plat->timebase_freq * 1000;
+ info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
+
+ return 0;
+}
+
+static int cpu_bcm_get_count(const struct udevice *dev)
+{
+ return uclass_id_count(UCLASS_CPU);
+}
+
+static int cpu_bcm_get_vendor(const struct udevice *dev, char *buf, int size)
+{
+ snprintf(buf, size, "Broadcom");
+
+ return 0;
+}
+
+static int cpu_bcm_is_current(struct udevice *dev)
+{
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+
+ if (plat->cpu_id == (read_mpidr() & 0xffff))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * bcm_cpu_on - Releases the secondary CPU from it's spintable
+ *
+ * Write the CPU's spintable mailbox and let the CPU enter U-Boot.
+ *
+ * @dev: Device to start
+ * @return: zero on success or error code on failure.
+ */
+static int bcm_cpu_on(struct udevice *dev)
+{
+ struct bcm_plat *plat = dev_get_plat(dev);
+ ulong *start_address;
+
+ if (plat->release_addr == ~0ULL)
+ return -ENODATA;
+
+ start_address = map_physmem(plat->release_addr, sizeof(uintptr_t), MAP_NOCACHE);
+
+ /* Point secondary CPU to U-Boot entry */
+ *start_address = (uintptr_t)_start;
+
+ /* Make sure the other CPUs see the written start address */
+ if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
+ flush_dcache_all();
+
+ /* Send an event to wake up the secondary CPU. */
+ asm("dsb ishst\n"
+ "sev");
+
+ unmap_physmem(start_address, MAP_NOCACHE);
+
+ return 0;
+}
+
+static const struct cpu_ops cpu_bcm_ops = {
+ .get_desc = cpu_bcm_get_desc,
+ .get_info = cpu_bcm_get_info,
+ .get_count = cpu_bcm_get_count,
+ .get_vendor = cpu_bcm_get_vendor,
+ .is_current = cpu_bcm_is_current,
+};
+
+static const struct udevice_id cpu_bcm_ids[] = {
+ { .compatible = "arm,cortex-a53" }, /* RPi 3 */
+ { .compatible = "arm,cortex-a72" }, /* RPi 4 */
+ { }
+};
+
+static int bcm_cpu_bind(struct udevice *dev)
+{
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+
+ plat->cpu_id = dev_read_addr(dev);
+
+ return 0;
+}
+
+/**
+ * bcm_cpu_of_to_plat - Gather spin-table release address
+ *
+ * Read the spin-table release address to allow all seconary CPUs to enter
+ * U-Boot when necessary.
+ *
+ * @dev: Device to start
+ */
+static int bcm_cpu_of_to_plat(struct udevice *dev)
+{
+ struct bcm_plat *plat = dev_get_plat(dev);
+ const char *prop;
+
+ if (CONFIG_IS_ENABLED(ARMV8_MULTIENTRY)) {
+ plat->release_addr = ~0ULL;
+
+ prop = dev_read_string(dev, "enable-method");
+ if (!prop || strcmp(prop, "spin-table"))
+ return -ENODEV;
+
+ plat->release_addr = dev_read_u64_default(dev, "cpu-release-addr", ~0ULL);
+
+ if (plat->release_addr == ~0ULL)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int bcm_cpu_probe(struct udevice *dev)
+{
+ struct cpu_plat *plat = dev_get_parent_plat(dev);
+ struct clk clk;
+ int ret;
+
+ /* Get a clock if it exists */
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (!ret) {
+ ret = clk_enable(&clk);
+ if (ret && (ret != -ENOSYS || ret != -EOPNOTSUPP))
+ return ret;
+ ret = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ plat->timebase_freq = ret;
+ }
+
+ /*
+ * The armstub holds the secondary CPUs in a spinloop. When
+ * ARMV8_MULTIENTRY is enabled release the secondary CPUs and
+ * let them enter U-Boot as well.
+ */
+ if (CONFIG_IS_ENABLED(ARMV8_MULTIENTRY)) {
+ ret = bcm_cpu_on(dev);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+struct acpi_ops bcm283x_cpu_acpi_ops = {
+ .fill_ssdt = armv8_cpu_fill_ssdt,
+ .fill_madt = armv8_cpu_fill_madt,
+};
+
+U_BOOT_DRIVER(cpu_bcm_drv) = {
+ .name = "bcm283x_cpu",
+ .id = UCLASS_CPU,
+ .of_match = cpu_bcm_ids,
+ .ops = &cpu_bcm_ops,
+ .probe = bcm_cpu_probe,
+ .bind = bcm_cpu_bind,
+ .of_to_plat = bcm_cpu_of_to_plat,
+ .plat_auto = sizeof(struct bcm_plat),
+ ACPI_OPS_PTR(&bcm283x_cpu_acpi_ops)
+};
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/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/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/gpio/dwapb_gpio.c b/drivers/gpio/dwapb_gpio.c
index 7a6eae9ba18..04639a4cb68 100644
--- a/drivers/gpio/dwapb_gpio.c
+++ b/drivers/gpio/dwapb_gpio.c
@@ -177,7 +177,9 @@ static int gpio_dwapb_bind(struct udevice *dev)
plat->base = (void *)base;
plat->bank = bank;
- plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0);
+
+ if (ofnode_read_u32(node, "ngpios", &plat->pins))
+ plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0);
if (ofnode_read_string_index(node, "bank-name", 0,
&plat->name)) {
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/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/led/led_sw_blink.c b/drivers/led/led_sw_blink.c
index 06a43db340c..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>
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 79eb7c200dc..ac778593c96 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
return ops->read_and_clear(irq);
}
+int irq_get_interrupt_parent(const struct udevice *dev,
+ struct udevice **interrupt_parent)
+{
+ struct ofnode_phandle_args phandle_args;
+ struct udevice *irq = NULL;
+ ofnode node;
+ int ret;
+
+ if (!dev || !interrupt_parent)
+ return -EINVAL;
+
+ *interrupt_parent = NULL;
+
+ node = dev_ofnode(dev);
+ if (!ofnode_valid(node))
+ return -EINVAL;
+
+ while (ofnode_valid(node)) {
+ ret = ofnode_parse_phandle_with_args(node, "interrupt-parent",
+ NULL, 0, 0, &phandle_args);
+ if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq))
+ break;
+ node = ofnode_get_parent(node);
+ }
+
+ if (!irq) {
+ log_err("Cannot find an interrupt parent for device %s\n", dev->name);
+ return -ENODEV;
+ }
+ *interrupt_parent = irq;
+
+ return 0;
+}
+
#if CONFIG_IS_ENABLED(OF_PLATDATA)
int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
struct irq *irq)
@@ -142,10 +176,40 @@ err:
int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
{
struct ofnode_phandle_args args;
- int ret;
+ struct udevice *interrupt_parent;
+ int ret, size, i;
+ const __be32 *list;
+ u32 count;
ret = dev_read_phandle_with_args(dev, "interrupts-extended",
"#interrupt-cells", 0, index, &args);
+ if (ret) {
+ list = dev_read_prop(dev, "interrupts", &size);
+ if (!list)
+ return -ENOENT;
+
+ ret = irq_get_interrupt_parent(dev, &interrupt_parent);
+ if (ret)
+ return -ENODEV;
+ args.node = dev_ofnode(interrupt_parent);
+
+ if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) {
+ log_err("%s: could not get #interrupt-cells for %s\n",
+ __func__, dev->name);
+ return -ENOENT;
+ }
+
+ if (index * count >= size / sizeof(*list))
+ return -ENOENT;
+ if (count > OF_MAX_PHANDLE_ARGS)
+ count = OF_MAX_PHANDLE_ARGS;
+ args.args_count = count;
+ for (i = 0; i < count; i++)
+ args.args[i] = be32_to_cpup(&list[index * count + i]);
+
+ return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
+ "interrupts", index, irq);
+ }
return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
"interrupts-extended", index > 0, irq);
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index fb410104c1f..d7a45ef0ad0 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -1398,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;
@@ -1413,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"))
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 63b0fd899fd..ca60a425ba3 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -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/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index dfe92c3986e..91ae49c9484 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -294,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) },
@@ -328,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) },
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 89f7411bdf3..576cd2d50ad 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -525,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"
@@ -762,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
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/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/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/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c
index f978c64365c..f089c48f028 100644
--- a/drivers/pci/pcie_brcmstb.c
+++ b/drivers/pci/pcie_brcmstb.c
@@ -12,6 +12,7 @@
* Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
*/
+#include <asm/arch/acpi/bcm2711.h>
#include <errno.h>
#include <dm.h>
#include <dm/ofnode.h>
@@ -21,88 +22,6 @@
#include <linux/log2.h>
#include <linux/iopoll.h>
-/* Offset of the mandatory PCIe capability config registers */
-#define BRCM_PCIE_CAP_REGS 0x00ac
-
-/* The PCIe controller register offsets */
-#define PCIE_RC_CFG_VENDOR_SPECIFIC_REG1 0x0188
-#define VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc
-#define VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN 0x0
-
-#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
-#define CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
-
-#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
-#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
-
-#define PCIE_RC_DL_MDIO_ADDR 0x1100
-#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
-#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
-
-#define PCIE_MISC_MISC_CTRL 0x4008
-#define MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000
-#define MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000
-#define MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000
-#define MISC_CTRL_MAX_BURST_SIZE_128 0x0
-#define MISC_CTRL_SCB0_SIZE_MASK 0xf8000000
-
-#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
-#define PCIE_MEM_WIN0_LO(win) \
- PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4)
-
-#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
-#define PCIE_MEM_WIN0_HI(win) \
- PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4)
-
-#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
-#define RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
-
-#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034
-#define RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f
-#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038
-
-#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c
-#define RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f
-
-#define PCIE_MISC_PCIE_STATUS 0x4068
-#define STATUS_PCIE_PORT_MASK 0x80
-#define STATUS_PCIE_PORT_SHIFT 7
-#define STATUS_PCIE_DL_ACTIVE_MASK 0x20
-#define STATUS_PCIE_DL_ACTIVE_SHIFT 5
-#define STATUS_PCIE_PHYLINKUP_MASK 0x10
-#define STATUS_PCIE_PHYLINKUP_SHIFT 4
-
-#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070
-#define MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000
-#define MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0
-#define MEM_WIN0_BASE_LIMIT_BASE_HI_SHIFT 12
-#define PCIE_MEM_WIN0_BASE_LIMIT(win) \
- PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4)
-
-#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080
-#define MEM_WIN0_BASE_HI_BASE_MASK 0xff
-#define PCIE_MEM_WIN0_BASE_HI(win) \
- PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8)
-
-#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084
-#define PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff
-#define PCIE_MEM_WIN0_LIMIT_HI(win) \
- PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8)
-
-#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
-#define PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
-
-#define PCIE_MSI_INTR2_CLR 0x4508
-#define PCIE_MSI_INTR2_MASK_SET 0x4510
-
-#define PCIE_EXT_CFG_DATA 0x8000
-
-#define PCIE_EXT_CFG_INDEX 0x9000
-
-#define PCIE_RGR1_SW_INIT_1 0x9210
-#define RGR1_SW_INIT_1_PERST_MASK 0x1
-#define RGR1_SW_INIT_1_INIT_MASK 0x2
-
/* PCIe parameters */
#define BRCM_NUM_PCIE_OUT_WINS 4
@@ -447,7 +366,7 @@ static int brcm_pcie_probe(struct udevice *dev)
* This will need to be changed when support for other SoCs is added.
*/
setbits_le32(base + PCIE_RGR1_SW_INIT_1,
- RGR1_SW_INIT_1_INIT_MASK | RGR1_SW_INIT_1_PERST_MASK);
+ PCIE_RGR1_SW_INIT_1_INIT_MASK | PCIE_RGR1_SW_INIT_1_PERST_MASK);
/*
* The delay is a safety precaution to preclude the reset signal
* from looking like a glitch.
@@ -455,7 +374,7 @@ static int brcm_pcie_probe(struct udevice *dev)
udelay(100);
/* Take the bridge out of reset */
- clrbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK);
+ clrbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK);
clrbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
@@ -508,7 +427,7 @@ static int brcm_pcie_probe(struct udevice *dev)
/* Unassert the fundamental reset */
clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1,
- RGR1_SW_INIT_1_PERST_MASK);
+ PCIE_RGR1_SW_INIT_1_PERST_MASK);
/*
* Wait for 100ms after PERST# deassertion; see PCIe CEM specification
@@ -552,7 +471,7 @@ static int brcm_pcie_probe(struct udevice *dev)
* a PCIe-PCIe bridge (the default setting is to be EP mode).
*/
clrsetbits_le32(base + PCIE_RC_CFG_PRIV1_ID_VAL3,
- CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x060400);
+ PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x060400);
if (pcie->ssc) {
ret = brcm_pcie_set_ssc(pcie->base);
@@ -570,8 +489,8 @@ static int brcm_pcie_probe(struct udevice *dev)
nlw, ssc_good ? "(SSC)" : "(!SSC)");
/* PCIe->SCB endian mode for BAR */
- clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_SPECIFIC_REG1,
- VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK,
+ clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1,
+ PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK,
VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN);
/*
@@ -584,7 +503,7 @@ static int brcm_pcie_probe(struct udevice *dev)
* let's instead just unadvertise ASPM support.
*/
clrbits_le32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY,
- PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
+ LINK_CAPABILITY_ASPM_SUPPORT_MASK);
return 0;
}
@@ -595,14 +514,14 @@ static int brcm_pcie_remove(struct udevice *dev)
void __iomem *base = pcie->base;
/* Assert fundamental reset */
- setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK);
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK);
/* Turn off SerDes */
setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG,
PCIE_HARD_DEBUG_SERDES_IDDQ_MASK);
/* Shutdown bridge */
- setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK);
+ setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK);
return 0;
}
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/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/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 80c35963b8f..e6bf0c2935b 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -19,6 +19,7 @@
#include <watchdog.h>
#include <asm/io.h>
#include <serial.h>
+#include <spl.h>
#include <dm/device_compat.h>
#include <dm/platform_data/serial_pl01x.h>
#include <linux/compiler.h>
@@ -272,6 +273,28 @@ __weak struct serial_device *default_serial_console(void)
return &pl01x_serial_drv;
}
#else
+
+static int pl01x_serial_getinfo(struct udevice *dev,
+ struct serial_device_info *info)
+{
+ struct pl01x_serial_plat *plat = dev_get_plat(dev);
+
+ /* save code size */
+ if (!not_xpl())
+ return -ENOSYS;
+
+ info->type = SERIAL_CHIP_PL01X;
+ info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY;
+ info->addr = plat->base;
+ info->size = 0x1000;
+ info->reg_width = 4;
+ info->reg_shift = 2;
+ info->reg_offset = 0;
+ info->clock = plat->clock;
+
+ return 0;
+}
+
int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
{
struct pl01x_serial_plat *plat = dev_get_plat(dev);
@@ -341,6 +364,7 @@ static const struct dm_serial_ops pl01x_serial_ops = {
.pending = pl01x_serial_pending,
.getc = pl01x_serial_getc,
.setbrg = pl01x_serial_setbrg,
+ .getinfo = pl01x_serial_getinfo,
};
#if CONFIG_IS_ENABLED(OF_REAL)
diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c
index f5b3fb5c125..4aad3248d9e 100644
--- a/drivers/spi/zynq_qspi.c
+++ b/drivers/spi/zynq_qspi.c
@@ -734,7 +734,7 @@ static int zynq_qspi_set_mode(struct udevice *bus, uint mode)
return 0;
}
-bool update_stripe(const struct spi_mem_op *op)
+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 ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 6e10b629a3c..bb5893d56db 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -68,6 +68,14 @@ config USB_XHCI_MVEBU
SoCs, which includes Armada8K, Armada3700 and other Armada
family SoCs.
+config USB_XHCI_GENERIC
+ bool "Generic SoC USB 3.0 support"
+ depends on OF_CONTROL
+ default n
+ help
+ Choose this option to add support for USB 3.0 driver for SoCs
+ that do not need platform specific code, like on emulated targets.
+
config USB_XHCI_OCTEON
bool "Support for Marvell Octeon family on-chip xHCI USB controller"
depends on ARCH_OCTEON
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 792956e647a..301bb9fdee1 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
+obj-$(CONFIG_USB_XHCI_GENERIC) += xhci-generic.o
obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o
diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c
new file mode 100644
index 00000000000..355d4883176
--- /dev/null
+++ b/drivers/usb/host/xhci-generic.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 9elements GmbH
+ *
+ * GENERIC USB HOST xHCI Controller
+ */
+#include <dm.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+#include <usb/xhci.h>
+
+struct generic_xhci_plat {
+ fdt_addr_t hcd_base;
+};
+
+/**
+ * Contains pointers to register base addresses
+ * for the usb controller.
+ */
+struct generic_xhci {
+ struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
+ struct usb_plat usb_plat;
+ struct xhci_hccr *hcd;
+};
+
+static int xhci_usb_probe(struct udevice *dev)
+{
+ struct generic_xhci_plat *plat = dev_get_plat(dev);
+ struct generic_xhci *ctx = dev_get_priv(dev);
+ struct xhci_hcor *hcor;
+ int len;
+
+ ctx->hcd = (struct xhci_hccr *)phys_to_virt(plat->hcd_base);
+ len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
+ hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
+
+ return xhci_register(dev, ctx->hcd, hcor);
+}
+
+static int xhci_usb_of_to_plat(struct udevice *dev)
+{
+ struct generic_xhci_plat *plat = dev_get_plat(dev);
+
+ /*
+ * Get the base address for XHCI controller from the device node
+ */
+ plat->hcd_base = dev_read_addr(dev);
+ if (plat->hcd_base == FDT_ADDR_T_NONE) {
+ dev_dbg(dev, "Can't get the XHCI register base address\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id xhci_usb_ids[] = {
+ { .compatible = "generic-xhci" },
+ { }
+};
+
+U_BOOT_DRIVER(usb_xhci) = {
+ .name = "xhci_generic",
+ .id = UCLASS_USB,
+ .of_match = xhci_usb_ids,
+ .of_to_plat = xhci_usb_of_to_plat,
+ .probe = xhci_usb_probe,
+ .remove = xhci_deregister,
+ .ops = &xhci_usb_ops,
+ .plat_auto = sizeof(struct generic_xhci_plat),
+ .priv_auto = sizeof(struct generic_xhci),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 90bc5653ee3..0e45f0a0922 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -175,6 +175,13 @@ config WDT_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
@@ -184,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 51be6ab9abe..0b107c008f7 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -30,8 +30,9 @@ 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/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,
};